What you are doing is a very bad idea indeed. a) you are circumventing the intended interface b) you are breaking encapsulation, because columnMem returns a pointer to an internal type, which is useless to you, unless you have made public all the SQLite internals c) you are assuming that type conversion of a Mem type will conserve the original fields d) you are duplicating work by calling sqlite3_column_text() twice, unless the type is numerical e) you are duplicating work by calling sqlite3_column_type() twice, instead of using the value returned from the first call f) you are using the result of a function call that is documented to be undefined in the exact context you are using it in
IMHO, you would be much better off attempting to master the official SQLite API. -----Ursprüngliche Nachricht----- Von: sqlite-users [mailto:sqlite-users-boun...@mailinglists.sqlite.org] Im Auftrag von Barone Ashura Gesendet: Dienstag, 30. Juli 2019 13:14 An: sqlite-users@mailinglists.sqlite.org Betreff: [EXTERNAL] [sqlite] sqlite3_exec without ubiqitous text conversions Hello, I have been working on an application based on SQLite for 2 years now, and recently we started running some performance profiling to check if there are areas where we can squeeze some extra performance. SQlite query execution is used almost exclusively through sqlite3_exec, and the implementation of callbacks. One of the areas of interest we identified is that every column is always passed to the callback as a c-char-string. Then we need to convert that string back to the intended data type. Apparently a consistent amount of time is spent doing this. I started looking into SQLite code and realized that int and real values retrieved from database, is actually fecthed as binary value, then converted to string, passed to the callback, and in the callback we convert it back to its original data type (as we keep track of 'true' datatype for each column). I decided to try skipping these conversions, by creating a custom implementation of sqlite3_exec, which does the following in the inside 'step' loop: if (rc == SQLITE_ROW) { azVals = azCols; for (i = 0; i < nCol; i++) { azVals[i] = (char *)sqlite3_column_text(pStmt, i); int col_type = sqlite3_column_type(pStmt, i); switch (col_type) { case SQLITE_INTEGER: case SQLITE_FLOAT: { azVals[i] = (char*)columnMem(pStmt, i); columnMallocFailure(pStmt); break; } default: { azVals[i] = (char *)sqlite3_column_text(pStmt, i); break; } } if (!azVals[i] && sqlite3_column_type(pStmt, i) != SQLITE_NULL) { sqlite3OomFault(db); goto exec_out; } } } Instead of ALWAYS converting to text, in case of INTEGER or FLOAT columns types, I fetch the address of the data through columnMem, put it in the azVals array, and go on. The callback knows which is the expected data type for the column, reads and copies data in the destination variable through a simple assignment. I am aware that forcing a 'typed' pointer into a generic char* pointer (azVals[x]), rings a looooot of alarm bells; I am, as well, aware that I could avoid sqlite3_exec, and call sqlite3_step myself. As of now the application is running smoothly and faster as far as satabase access is concerned. I am writing here to get opinions about other potential pitfalls or oversights in this approach, as well as reason why I should not proceed on this path. Thanks in advance _______________________________________________ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users ___________________________________________ Gunter Hick | Software Engineer | Scientific Games International GmbH | Klitschgasse 2-4, A-1130 Vienna | FN 157284 a, HG Wien, DVR: 0430013 | (O) +43 1 80100 - 0 May be privileged. May be confidential. Please delete if not the addressee. _______________________________________________ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users