src/SqlHandler.h
branchv_0
changeset 23 d3bfbce022aa
parent 20 b295f8985f13
child 24 884ece10575d
equal deleted inserted replaced
22:2135eeb1de78 23:d3bfbce022aa
   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 	// TODO: sqlite3_column_type
   106 	relpipe::writer::TypeId getColumType(int columnIndex) {
       
   107 		const char* type = sqlite3_column_decltype(stmt, columnIndex);
       
   108 
       
   109 		// TODO: sqlite3_column_decltype returns value only for columns of existing tables, not for dynamic expressions – SQLite uses dynamic types
       
   110 		// fprintf(stderr, "%d → %s\n", columnIndex, type);
       
   111 		// SELECT typeof(1+1); == "integer"
       
   112 		// https://www.sqlite.org/c3ref/column_decltype.html – sqlite3_column_decltype
       
   113 		// https://www.sqlite.org/c3ref/column_blob.html – sqlite3_column_type
       
   114 		// 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
       
   116 
       
   117 		if (type == nullptr) return relpipe::writer::TypeId::STRING;
       
   118 		else if (strcmp(type, "integer") == 0) return relpipe::writer::TypeId::INTEGER;
       
   119 		else if (strcmp(type, "text") == 0) return relpipe::writer::TypeId::STRING;
       
   120 		else return relpipe::writer::TypeId::STRING;
       
   121 		// TODO: support also other data types
       
   122 	}
   107 
   123 
   108 	std::string getString(int columnIndex) {
   124 	std::string getString(int columnIndex) {
   109 		const char* value = (const char*) sqlite3_column_text(stmt, columnIndex);
   125 		const char* value = (const char*) sqlite3_column_text(stmt, columnIndex);
   110 		return value ? value : ""; // TODO: support NULL values (when supported in relpipe format)
   126 		return value ? value : ""; // TODO: support NULL values (when supported in relpipe format)
   111 	}
   127 	}
   194 		for (int i = 0; i < parameterCount; i++) {
   210 		for (int i = 0; i < parameterCount; i++) {
   195 			prepared->setString(i + 1, convertor.to_bytes(statement.parameters[i].value));
   211 			prepared->setString(i + 1, convertor.to_bytes(statement.parameters[i].value));
   196 		}
   212 		}
   197 
   213 
   198 		std::vector<relpipe::writer::AttributeMetadata> metadata;
   214 		std::vector<relpipe::writer::AttributeMetadata> metadata;
   199 		// TODO: support also other data types
   215 		for (int i = 0; i < columnCount; i++) metadata.push_back({convertor.from_bytes(prepared->getColumName(i).c_str()), prepared->getColumType(i)});
   200 		for (int i = 0; i < columnCount; i++) metadata.push_back({convertor.from_bytes(prepared->getColumName(i).c_str()), relpipe::writer::TypeId::STRING});
       
   201 		relationalWriter->startRelation(statement.relation, metadata, true);
   216 		relationalWriter->startRelation(statement.relation, metadata, true);
   202 
   217 
   203 		while (prepared->next()) {
   218 		while (prepared->next()) {
   204 			for (int i = 0; i < columnCount; i++) {
   219 			for (int i = 0; i < columnCount; i++) {
   205 				relationalWriter->writeAttribute(convertor.from_bytes(prepared->getString(i)));
   220 				relationalWriter->writeAttribute(convertor.from_bytes(prepared->getString(i)));
   346 		// process optional SQL input
   361 		// process optional SQL input
   347 		processSqlInput(configuration.sqlAfterRelational);
   362 		processSqlInput(configuration.sqlAfterRelational);
   348 
   363 
   349 		// pass-through some relations:
   364 		// pass-through some relations:
   350 		for (const CopyRelations& copy : configuration.copyRelations) copyRelations(copy);
   365 		for (const CopyRelations& copy : configuration.copyRelations) copyRelations(copy);
   351 		
   366 
   352 		connection->transactionCommit();
   367 		connection->transactionCommit();
   353 
   368 
   354 		// delete or keep the file:
   369 		// delete or keep the file:
   355 		if (configuration.file.size()) {
   370 		if (configuration.file.size()) {
   356 			if (configuration.keepFile == KeepFile::Never || (configuration.keepFile == KeepFile::Automatic && !fileAlreadyExisted)) {
   371 			if (configuration.keepFile == KeepFile::Never || (configuration.keepFile == KeepFile::Automatic && !fileAlreadyExisted)) {