eda/sqlite: Setting page size to 4096 to help performance on NTFS
[sdk] / eda / drivers / sqlite / EDASQLite.ec
index 3c3313f..404c263 100644 (file)
@@ -16,7 +16,7 @@ public import "EDA"
 #include "ffi.h"
 #undef uint
 
-static void UnusedFunction()
+__attribute__((unused)) static void UnusedFunction()
 {
    int a;
    a.OnGetString(0,0,0);
@@ -40,19 +40,24 @@ extern int __ecereVMethodID_class_OnUnserialize;
 extern int __ecereVMethodID_class_OnFree;
 private:
 
-int CollationCompare(Class type, int count1, void * data1, int count2, void * data2)
+static SerialBuffer collationBuffer1 { };
+static SerialBuffer collationBuffer2 { };
+static char storage1[512];
+static char storage2[512];
+
+int CollationCompare(Class type, int count1, const void * data1, int count2, const void * data2)
 {
    if(type.type == normalClass || type.type ==  noHeadClass)
    {
       Instance inst1, inst2;
       int result;
-      SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
-      SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
+      SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
+      SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
 
       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst1, buffer1);
       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst2, buffer2);
 
-      result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
+      result = ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
 
       buffer1.buffer = null;
       buffer2.buffer = null;
@@ -66,11 +71,30 @@ int CollationCompare(Class type, int count1, void * data1, int count2, void * da
    {
       void * inst1, * inst2;
       int result;
-      SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
-      SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
-
-      inst1 = new0 byte[type.structSize];
-      inst2 = new0 byte[type.structSize];
+      //SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
+      //SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
+
+      SerialBuffer buffer1 = collationBuffer1;
+      SerialBuffer buffer2 = collationBuffer2;
+      buffer1.buffer = (byte*)data1;
+      buffer1.size = count1;
+      buffer1.count = count1;
+      buffer1.pos = 0;
+      buffer2.buffer = (byte*)data2;
+      buffer2.size = count2;
+      buffer2.count = count2;
+      buffer2.pos = 0;
+
+      if(type.structSize > 512)
+      {
+         inst1 = new0 byte[type.structSize];
+         inst2 = new0 byte[type.structSize];
+      }
+      else
+      {
+         inst1 = storage1;
+         inst2 = storage2;
+      }
       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst1, buffer1);
       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst2, buffer2);
 
@@ -78,105 +102,25 @@ int CollationCompare(Class type, int count1, void * data1, int count2, void * da
 
       buffer1.buffer = null;
       buffer2.buffer = null;
-      delete buffer1;
-      delete buffer2;
-      delete inst1;
-      delete inst2;
+      //delete buffer1;
+      //delete buffer2;
+      if(type.structSize > 512)
+      {
+         delete inst1;
+         delete inst2;
+      }
       return result;
    }
    else
-      return ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, data1, data2);
+      return ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, data1, data2);
 }
 
 public class SQLiteStaticLink { }   // Until .imp generation is fixed
 
-class SQLiteDataSource : DataSourceDriver
+class SQLiteDataSource : DirFilesDataSourceDriver
 {
    class_property(name) = "SQLite";
-   String path;
-   OldList listDatabases;
-   uint databasesCount;
-
-   String BuildLocator(DataSource ds)
-   {
-      return CopyString(ds.host);
-   }
-
-   uint GetDatabasesCount()
-   {
-      return databasesCount;
-   }
-
-   ~SQLiteDataSource()
-   {
-      delete path;
-   }
-
-   bool Connect(const String locator)
-   {
-      delete path;
-      path = CopyString(locator);
-      // TODO, use user name and password for local security?
-      // TODO, open ds in read or write mode
-      if(FileExists(path))
-      {
-         int n = 0;
-         FileListing listing { path, "sqlite" };
-         databasesCount = 0;
-         while(listing.Find())
-            databasesCount++;
-         return true;
-      }
-      return false;
-   }
-
-   bool RenameDatabase(const String name, const String rename)
-   {
-      if(name && rename && path && FileExists(path))
-      {
-         String path;
-         path = MakeDatabasePath(name);
-         if(FileExists(path))
-         {
-            bool renamed;
-            String repath;
-            repath = MakeDatabasePath(rename);
-            renamed = RenameFile(path, repath);
-            delete path;
-            delete repath;
-            return renamed;
-         }
-         delete path;
-      }
-      return false;
-   }
-
-   bool DeleteDatabase(const String name)
-   {
-      if(path && FileExists(path))
-      {
-         bool deleted;
-         String path = MakeDatabasePath(name);
-         deleted = DeleteFile(path);  // delete file seems to return true even if the file does not exist
-         databasesCount--;
-         delete path;
-         return deleted;
-      }
-      return false;
-   }
-
-   virtual String MakeDatabasePath(const String name)
-   {
-      if(name)
-      {
-         char build[MAX_LOCATION];
-         strcpy(build, path ? path : "");
-         PathCat(build, name);
-         ChangeExtension(build, "sqlite", build);
-         return CopyString(build);
-      }
-      return null;
-   }
+   class_property(databaseFileExtension) = "sqlite";
 
    Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
    {
@@ -200,19 +144,22 @@ class SQLiteDataSource : DataSourceDriver
          {
             bool success = true;
             char command[1024];
+
+            sqlite3_exec(db, "PRAGMA page_size=4096;", null, null, null);
+
             sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
-            if(sqlite3_exec(db, command, null, null, null))
+            sqlite3_exec(db, command, null, null, null);
+
+            if(createOptions != readOnly)
             {
-               if(createOptions != readOnly)
-               {
-                  sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
+               sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
+               sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
+               if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
+                  success = false;
+               else
                   sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
-                  if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
-                     success = false;
-                  else
-                     sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
-               }
             }
+
             if(success)
                result = SQLiteDatabase { db = db };
          }
@@ -237,7 +184,7 @@ class SQLiteField : Field
       delete name;
    }
 
-   String GetName()
+   const String GetName()
    {
       return name;
    }
@@ -263,11 +210,13 @@ class SQLiteField : Field
 class SQLiteDatabase : Database
 {
    sqlite3 * db;
-   AVLTree<String> collations { };
+   AVLTree<const String> collations { };
 
    ~SQLiteDatabase()
    {
       sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
+      // "Simply setting the locking-mode to NORMAL is not enough - locks are not released until the next time the database file is accessed."
+      sqlite3_exec(db, "SELECT COUNT(*) from eda_table_fields", null, null, null);
       sqlite3_close(db);
    }
 
@@ -292,7 +241,7 @@ class SQLiteDatabase : Database
    Table OpenTable(const String name, OpenOptions options)
    {
       char command[1024];
-      int result;
+      //int result;
       int nRows = 0, nCols = 0;
       char ** t;
       SQLiteTable table = null;
@@ -304,7 +253,7 @@ class SQLiteDatabase : Database
          field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
          LinkTable(table);
          incref field;
-         table.fields.Add(field);
+         table._fields.Add(field);
       }
       else if(options.type == fieldsList)
       {
@@ -315,20 +264,20 @@ class SQLiteDatabase : Database
          LinkTable(table);
          field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
          incref field;
-         table.fields.Add(field);
+         table._fields.Add(field);
          field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
          incref field;
-         table.fields.Add(field);
+         table._fields.Add(field);
          field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
          incref field;
-         table.fields.Add(field);
+         table._fields.Add(field);
       }
       else if(options.type == tableRows)
       {
          bool addFields = false;
 
          sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
-         result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
+         /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
          if(!nRows && !nCols)
             addFields = true;
 
@@ -336,7 +285,7 @@ class SQLiteDatabase : Database
 
          sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
          nCols = 0, nRows = 0;
-         result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
+         /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
 
          if((nCols || nRows) || options.create)
          {
@@ -391,12 +340,12 @@ class SQLiteDatabase : Database
 
                            sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
                               fieldName, type.name, 0);
-                           result = sqlite3_exec(db, command, null, null, null);
+                           /*result = */sqlite3_exec(db, command, null, null, null);
 
                            {
-                              SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
+                              SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table._fields.count, sqliteType = sqliteType };
                               incref field;
-                              table.fields.Add(field);
+                              table._fields.Add(field);
                            }
 
                            if(!ch || ch == ')') break;
@@ -410,17 +359,17 @@ class SQLiteDatabase : Database
                   sqlite3_stmt * statement;
 
                   sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
-                  result = sqlite3_prepare_v2(db, command, -1, &statement, null);
+                  /*result = */sqlite3_prepare_v2(db, command, -1, &statement, null);
 
                   while(sqlite3_step(statement) != SQLITE_DONE)
                   {
-                     char * fieldName = sqlite3_column_text(statement, 0);
-                     char * typeName = sqlite3_column_text(statement, 1);
+                     const char * fieldName = (const char *)sqlite3_column_text(statement, 0);
+                     const char * typeName = (const char *)sqlite3_column_text(statement, 1);
                      int length = sqlite3_column_int(statement, 2);
                      Class type = null;
                      int sqliteType = SQLITE_BLOB;
 
-                     ((Class)(&type)).OnGetDataFromString(typeName);    // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
+                     type.OnGetDataFromString(typeName);
 
                      if(type)
                      {
@@ -447,14 +396,14 @@ class SQLiteDatabase : Database
                      }
 
                      {
-                        Table * fTable = (Table *)eClass_GetProperty(type, "table");
-                        SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
+                        Table * fTable = (Table *)(intptr)eClass_GetProperty(type, "table");
+                        SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table._fields.count, sqliteType = sqliteType };
                         incref field;
                         if(fTable) refTable = *fTable;
                         if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
                            table.primaryKey = field;
 
-                        table.fields.Add(field);
+                        table._fields.Add(field);
                      }
                   }
                   sqlite3_finalize(statement);
@@ -488,7 +437,7 @@ class SQLiteDatabase : Database
       return result == SQLITE_OK;
    }
 
-   bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
+   bool CreateCustomFunction(const char * name, SQLCustomFunction customFunction)
    {
       bool result = false;
       Class cfClass = customFunction._class;
@@ -505,9 +454,9 @@ class SQLiteDatabase : Database
          {
             Class type = null;
             bool pointer = false;
-            String arg = tokens[c];
+            const String arg = tokens[c];
             char * space;
-            TrimLSpaces(arg, arg);
+            TrimLSpaces(tokens[c], tokens[c]);
             if(strchr(arg, '*')) pointer = true;
             if(pointer)
                // Using String for generic pointer...
@@ -566,6 +515,7 @@ class SQLiteDatabase : Database
 
 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
 FFITypesHolder structFFITypes { };
+__attribute__((unused)) static Iterator dummy; // TOFIX: forward struct declaration issues on Clang
 
 public ffi_type * FFIGetType(Class type, bool structByValue)
 {
@@ -661,7 +611,7 @@ void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** va
             if(a == class(String))
             {
                int numBytes = sqlite3_value_bytes(values[i]);
-               char * text = sqlite3_value_text(values[i]);
+               const char * text = (const char *)sqlite3_value_text(values[i]);
                *(char **)data = text ? new byte[numBytes+1] : null;
                if(text)
                   memcpy(*(char **)data, text, numBytes+1);
@@ -671,7 +621,7 @@ void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** va
                SerialBuffer buffer = staticBuffer; //{ };
                buffer.pos = 0;
                buffer._size = sqlite3_value_bytes(values[i]);
-               buffer._buffer = sqlite3_value_text(values[i]);
+               buffer._buffer = (byte *)sqlite3_value_text(values[i]);
                //buffer._buffer = sqlite3_value_blob(curStatement);
                buffer.count = buffer._size;
                if(a.type == structClass)
@@ -780,7 +730,7 @@ void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** va
             {
                SerialBuffer buffer { };
                ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
-               sqlite3_result_text(context, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+               sqlite3_result_text(context, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
                delete buffer;
 
                // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
@@ -859,7 +809,7 @@ class SQLiteTable : Table
    char * name;
    bool mustCreate;
    SQLiteDatabase db;
-   LinkList<SQLiteField> fields { };
+   LinkList<SQLiteField> _fields { };
    char * specialStatement;
    SQLiteField primaryKey;
    FieldIndex * indexFields;
@@ -916,9 +866,9 @@ class SQLiteTable : Table
             result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
          }
       }
-      if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
+      if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)) && type != class(eda::Id))
       {
-         Table * table = (Table *)eClass_GetProperty(type, "table");
+         Table * table = (Table *)(intptr)eClass_GetProperty(type, "table");
          if(table) refTable = *table;
          if(refTable)
          {
@@ -990,9 +940,9 @@ class SQLiteTable : Table
          fieldName, type.name, length);
       result = sqlite3_exec(db.db, command, null, null, null);
 
-      field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
+      field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
       incref field;
-      fields.Add(field);
+      _fields.Add(field);
       if(!primaryKey && refTable == this)
          primaryKey = field;
       return (Field)field;
@@ -1000,14 +950,14 @@ class SQLiteTable : Table
 
    Field FindField(const String name)
    {
-      for(f : fields; !strcmp(f.name, name))
+      for(f : _fields; !strcmp(f.name, name))
       {
          if(!primaryKey)
          {
             if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
             {
 
-               Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
+               Table * tablePtr = (Table *)(intptr)eClass_GetProperty(f.type, "table");
                if(tablePtr && *tablePtr == this)
                   primaryKey = f;
             }
@@ -1065,14 +1015,14 @@ class SQLiteTable : Table
       return result == SQLITE_OK;
    }
 
-   String GetName()
+   const String GetName()
    {
       return name;
    }
 
    Field GetFirstField()
    {
-      return fields.first;
+      return _fields.first;
    }
 
    Field GetPrimaryKey()
@@ -1082,7 +1032,7 @@ class SQLiteTable : Table
 
    uint GetFieldsCount()
    {
-      return fields.count;
+      return _fields.count;
    }
 
    uint GetRowsCount()
@@ -1130,6 +1080,11 @@ class SQLiteTable : Table
       }
    }
 
+   Container<Field> GetFields()
+   {
+      return (Container<Field>)_fields;
+   }
+
    DriverRow CreateRow()
    {
       char command[1024];
@@ -1191,7 +1146,7 @@ class SQLiteTable : Table
       delete name;
       delete specialStatement;
       delete indexFields;
-      fields.Free();
+      _fields.Free();
    }
 }
 
@@ -1307,7 +1262,6 @@ class SQLiteRow : DriverRow
                }
                else
                {
-                  int bindId = findBindId;
                   sqlite3_reset((move == next) ? findStatement : lastFindStatement);
                   sqlite3_reset(curStatement);
                   curStatement = (move == next) ? findStatement : lastFindStatement;
@@ -1340,7 +1294,7 @@ class SQLiteRow : DriverRow
       return true;
    }
 
-   bool Query(char * queryString)
+   bool Query(const char * queryString)
    {
       bool status = true;
       int result;
@@ -1370,7 +1324,10 @@ class SQLiteRow : DriverRow
             }
          }
          else
+         {
+            printf("SQLite Query Error: %s\n", queryString);
             status = false;
+         }
       }
       else
          curStatement = null;
@@ -1440,7 +1397,7 @@ class SQLiteRow : DriverRow
             {
                buffer = SerialBuffer { };
                ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
-               result = sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+               result = sqlite3_bind_text(statement, pos, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
             }
             else
                result = sqlite3_bind_null(statement, pos);
@@ -1520,13 +1477,13 @@ class SQLiteRow : DriverRow
                }
                if(type.type == structClass)
                {
-                  data = (int64)new0 byte[type.structSize];
-                  dataPtr = (void *) data;
+                  data = (int64)(intptr)new0 byte[type.structSize];
+                  dataPtr = (void *)(intptr)data;
                }
                // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
-               ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
+               ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)(intptr)data : &data);
                if(type.type == normalClass || type.type == noHeadClass)
-                  dataPtr = (void *) data;
+                  dataPtr = (void *)(intptr)data;
                else
                   dataPtr = &data;
                ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
@@ -1534,7 +1491,7 @@ class SQLiteRow : DriverRow
                // Reuse the buffer for Blobs...
                if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
                {
-                  sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+                  sqlite3_bind_text(stmt, (*bindId)++, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
                   delete buffer;
                }
                else
@@ -1568,7 +1525,7 @@ class SQLiteRow : DriverRow
          result = GoToSysID(*(int *)data);
          if(result)
             findSysID = true;
-         return result;
+         return result != 0;
       }
 
       useIndex = tbl.GetIndexOrder(order, false);
@@ -1870,7 +1827,7 @@ class SQLiteRow : DriverRow
          case SQLITE_TEXT:
          {
             int numBytes = sqlite3_column_bytes(curStatement, num);
-            char * text = sqlite3_column_text(curStatement, num);
+            const char * text = (const char *)sqlite3_column_text(curStatement, num);
             *(char **)data = text ? new byte[numBytes+1] : null;
             if(text)
                memcpy(*(char **)data, text, numBytes+1);
@@ -1881,7 +1838,7 @@ class SQLiteRow : DriverRow
             SerialBuffer buffer { };
             //buffer._buffer = sqlite3_column_blob(curStatement, num);
             buffer._size = sqlite3_column_bytes(curStatement, num);
-            buffer._buffer = sqlite3_column_text(curStatement, num);
+            buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
             buffer.count = buffer._size;
 
             ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
@@ -1898,12 +1855,12 @@ class SQLiteRow : DriverRow
    {
       SQLiteField sqlFld = (SQLiteField)fld;
       int result;
-      int num = sqlFld.num + 1;
       char command[1024];
 
       if(updateStatement)
          sqlite3_finalize(updateStatement);
       sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
+      // TODO: Shouldn't we cache those update statements per field?
       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
       sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
       BindData(updateStatement, 1, (SQLiteField)fld, data, null);
@@ -1968,7 +1925,7 @@ class SQLiteRow : DriverRow
       return !result;
    }
 
-   bool SetQueryParamText(int paramID, char * data)
+   bool SetQueryParamText(int paramID, const char * data)
    {
       int result;
       if(curStatement != queryStatement)
@@ -1984,7 +1941,7 @@ class SQLiteRow : DriverRow
       return !result;
    }
 
-   bool SetQueryParamObject(int paramID, void * data, Class type)
+   bool SetQueryParamObject(int paramID, const void * data, Class type)
    {
       int result;
       if(curStatement != queryStatement)
@@ -1995,8 +1952,8 @@ class SQLiteRow : DriverRow
       sqlite3_reset(queryStatement);
       {
          SerialBuffer buffer { };
-         ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
-         result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+         ((void (*)(void *, const void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
+         result = sqlite3_bind_text(queryStatement, paramID, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
          delete buffer;
       }
       return !result;
@@ -2015,11 +1972,11 @@ class SQLiteRow : DriverRow
 
    /*char * GetExtraColumn(int paramID)
    {
-      SQLiteField lastFld = tbl.fields.last;
+      SQLiteField lastFld = tbl._fields.last;
       return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
    }*/
-   char * GetColumn(int paramID)
+   const char * GetColumn(int paramID)
    {
-      return sqlite3_column_text(curStatement, paramID);
+      return (const char *)sqlite3_column_text(curStatement, paramID);
    }
 }