src/SqlHandler.h
branchv_0
changeset 24 884ece10575d
parent 23 d3bfbce022aa
child 25 ec793cb3e686
equal deleted inserted replaced
23:d3bfbce022aa 24:884ece10575d
   101 		const char* name = sqlite3_column_name(stmt, columnIndex);
   101 		const char* name = sqlite3_column_name(stmt, columnIndex);
   102 		if (name) return name;
   102 		if (name) return name;
   103 		else throw SqlException(L"Unable to get SQLite column name.");
   103 		else throw SqlException(L"Unable to get SQLite column name.");
   104 	}
   104 	}
   105 
   105 
   106 	relpipe::writer::TypeId getColumType(int columnIndex) {
   106 	relpipe::writer::TypeId getColumType(int columnIndex, relpipe::writer::TypeId defaultType = relpipe::writer::TypeId::STRING) {
   107 		const char* type = sqlite3_column_decltype(stmt, columnIndex);
   107 		const char* type = sqlite3_column_decltype(stmt, columnIndex);
   108 
   108 
   109 		// TODO: sqlite3_column_decltype returns value only for columns of existing tables, not for dynamic expressions – SQLite uses dynamic types
   109 		// TODO: sqlite3_column_decltype returns value only for columns of existing tables, not for dynamic expressions – SQLite uses dynamic types
       
   110 		// maybe we could write a function/module that returns result set metadata for given query (before executing it)
       
   111 		// or use at least explicit casts in SQL and modify sqlite3_column_decltype() function or add some new one to return such casted type
       
   112 		// 
   110 		// fprintf(stderr, "%d → %s\n", columnIndex, type);
   113 		// fprintf(stderr, "%d → %s\n", columnIndex, type);
   111 		// SELECT typeof(1+1); == "integer"
   114 		// SELECT typeof(1+1); == "integer"
   112 		// https://www.sqlite.org/c3ref/column_decltype.html – sqlite3_column_decltype
   115 		// https://www.sqlite.org/c3ref/column_decltype.html – sqlite3_column_decltype
   113 		// https://www.sqlite.org/c3ref/column_blob.html – sqlite3_column_type
   116 		// https://www.sqlite.org/c3ref/column_blob.html – sqlite3_column_type
   114 		// https://www.sqlite.org/datatype3.html – Datatypes In SQLite Version 3
   117 		// https://www.sqlite.org/datatype3.html – Datatypes In SQLite Version 3
   115 		// https://dba.stackexchange.com/questions/203220/sqlite-what-is-the-use-of-specifying-data-types
   118 		// https://dba.stackexchange.com/questions/203220/sqlite-what-is-the-use-of-specifying-data-types
       
   119 		// https://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg118093.html
   116 
   120 
   117 		if (type == nullptr) return relpipe::writer::TypeId::STRING;
   121 		if (type == nullptr) return relpipe::writer::TypeId::STRING;
   118 		else if (strcmp(type, "integer") == 0) return relpipe::writer::TypeId::INTEGER;
   122 		else if (strcmp(type, "integer") == 0) return relpipe::writer::TypeId::INTEGER;
   119 		else if (strcmp(type, "text") == 0) return relpipe::writer::TypeId::STRING;
   123 		else if (strcmp(type, "text") == 0) return relpipe::writer::TypeId::STRING;
   120 		else return relpipe::writer::TypeId::STRING;
   124 		else return defaultType;
   121 		// TODO: support also other data types
   125 		// TODO: support also other data types
   122 	}
   126 	}
   123 
   127 
   124 	std::string getString(int columnIndex) {
   128 	std::string getString(int columnIndex) {
   125 		const char* value = (const char*) sqlite3_column_text(stmt, columnIndex);
   129 		const char* value = (const char*) sqlite3_column_text(stmt, columnIndex);
   200 			std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(sql.str()).c_str()));
   204 			std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(sql.str()).c_str()));
   201 			while (prepared->next());
   205 			while (prepared->next());
   202 		}
   206 		}
   203 	}
   207 	}
   204 
   208 
       
   209 	relpipe::writer::TypeId findType(string_t columnName, int columnIndex, const Statement& statement, std::shared_ptr<PreparedStatement> preparedStatement) {
       
   210 		for (TypeCast typeCast : statement.typeCasts) if (typeCast.name == columnName) return relationalWriter->toTypeId(typeCast.type);
       
   211 		return preparedStatement->getColumType(columnIndex);
       
   212 	}
       
   213 
   205 	void processStatement(const Statement& statement) {
   214 	void processStatement(const Statement& statement) {
   206 		std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()));
   215 		std::shared_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()));
   207 		int columnCount = prepared->getColumnCount();
   216 		int columnCount = prepared->getColumnCount();
   208 		int parameterCount = statement.parameters.size();
   217 		int parameterCount = statement.parameters.size();
   209 
   218 
   210 		for (int i = 0; i < parameterCount; i++) {
   219 		for (int i = 0; i < parameterCount; i++) {
   211 			prepared->setString(i + 1, convertor.to_bytes(statement.parameters[i].value));
   220 			prepared->setString(i + 1, convertor.to_bytes(statement.parameters[i].value));
   212 		}
   221 		}
   213 
   222 
   214 		std::vector<relpipe::writer::AttributeMetadata> metadata;
   223 		std::vector<relpipe::writer::AttributeMetadata> metadata;
   215 		for (int i = 0; i < columnCount; i++) metadata.push_back({convertor.from_bytes(prepared->getColumName(i).c_str()), prepared->getColumType(i)});
   224 		for (int i = 0; i < columnCount; i++) {
       
   225 			string_t columnName = convertor.from_bytes(prepared->getColumName(i).c_str());
       
   226 			metadata.push_back({columnName, findType(columnName, i, statement, prepared)});
       
   227 		}
   216 		relationalWriter->startRelation(statement.relation, metadata, true);
   228 		relationalWriter->startRelation(statement.relation, metadata, true);
   217 
   229 
   218 		while (prepared->next()) {
   230 		while (prepared->next()) {
   219 			for (int i = 0; i < columnCount; i++) {
   231 			for (int i = 0; i < columnCount; i++) {
   220 				relationalWriter->writeAttribute(convertor.from_bytes(prepared->getString(i)));
   232 				relationalWriter->writeAttribute(convertor.from_bytes(prepared->getString(i)));