eda/drivers/SQLite: Printing query errors
[sdk] / eda / drivers / sqlite / EDASQLite.ec
index 1695626..68d3ab2 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,20 +40,20 @@ extern int __ecereVMethodID_class_OnUnserialize;
 extern int __ecereVMethodID_class_OnFree;
 private:
 
-int CollationCompare(Class type, int count1, void * data1, int count2, void * data2)
+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 };
 
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
+      ((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 *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
 
-      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
-     
       buffer1.buffer = null;
       buffer2.buffer = null;
       delete buffer1;
@@ -66,16 +66,16 @@ 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 };
+      SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
+      SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
 
       inst1 = new0 byte[type.structSize];
       inst2 = new0 byte[type.structSize];
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
+      ((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 = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
-     
       buffer1.buffer = null;
       buffer2.buffer = null;
       delete buffer1;
@@ -85,98 +85,15 @@ int CollationCompare(Class type, int count1, void * data1, int count2, void * da
       return result;
    }
    else
-      return 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)
    {
@@ -188,7 +105,7 @@ class SQLiteDataSource : DataSourceDriver
 
          // sqlite3_open(path, &db);
          // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
-         
+
          if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
             (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
          {
@@ -198,11 +115,23 @@ class SQLiteDataSource : DataSourceDriver
          }
          else
          {
+            bool success = true;
             char command[1024];
             sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
             sqlite3_exec(db, command, null, null, null);
 
-            result = SQLiteDatabase { db = db };
+            if(createOptions != readOnly)
+            {
+               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(success)
+               result = SQLiteDatabase { db = db };
          }
          delete path;
       }
@@ -225,7 +154,7 @@ class SQLiteField : Field
       delete name;
    }
 
-   String GetName()
+   const String GetName()
    {
       return name;
    }
@@ -251,10 +180,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);
    }
 
@@ -279,7 +211,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;
@@ -291,7 +223,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)
       {
@@ -302,20 +234,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;
 
@@ -323,8 +255,8 @@ 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)
          {
             table = SQLiteTable { db = this, name = CopyString(name) };
@@ -340,7 +272,7 @@ class SQLiteDatabase : Database
                   {
                      char * sql = t[nCols * r];
                      char * bracket = strchr(sql, '(');
-                     if(bracket) 
+                     if(bracket)
                      {
                         int c = 0;
                         bracket++;
@@ -370,7 +302,7 @@ class SQLiteDatabase : Database
                            dataType[c - d - 2] = 0;
 
                            while(ch && bracket[c] == ' ') c++;
-                           
+
                            if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
                            else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
                            else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
@@ -378,12 +310,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;
@@ -393,27 +325,28 @@ class SQLiteDatabase : Database
                }
                else
                {
+                  Table refTable = null;
                   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)
                      {
-                        if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || 
-                           !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") || 
-                           !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") || 
-                           !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") || 
+                        if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
+                           !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
+                           !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
+                           !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
                            !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
                            !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
                            sqliteType = SQLITE_INTEGER;
@@ -433,9 +366,14 @@ class SQLiteDatabase : Database
                      }
 
                      {
-                        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;
-                        table.fields.Add(field);
+                        if(fTable) refTable = *fTable;
+                        if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
+                           table.primaryKey = field;
+
+                        table._fields.Add(field);
                      }
                   }
                   sqlite3_finalize(statement);
@@ -469,7 +407,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;
@@ -486,9 +424,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...
@@ -547,6 +485,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)
 {
@@ -628,7 +567,7 @@ void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** va
    // Get the arguments from SQLite
    for(a : sqlFunction.args)
    {
-      ffi_type * type = (ffi_type *)ffiArg.data;
+      ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
       if(i >= n) break;
       switch(a.type)
       {
@@ -642,7 +581,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);
@@ -652,10 +591,12 @@ 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;
-               a._vTbl[__ecereVMethodID_class_OnUnserialize](a, data, buffer);
+               if(a.type == structClass)
+                  *data = new byte[a.structSize];
+               ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
                buffer._buffer = null;
                //delete buffer;
             }
@@ -758,12 +699,12 @@ void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** va
             else
             {
                SerialBuffer buffer { };
-               r._vTbl[__ecereVMethodID_class_OnSerialize](r, data, buffer);
-               sqlite3_result_text(context, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+               ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
+               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)
-               r._vTbl[__ecereVMethodID_class_OnFree](r, data);
+               ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
             }
 
             if(r.type == structClass)
@@ -823,7 +764,9 @@ void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** va
    {
       // Free instance
       void * data = *(void **)arg.data;
-      type._vTbl[__ecereVMethodID_class_OnFree](type, data);
+      ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
+      if(type.type == structClass)
+         delete data;
       // Free arg holder
       data = arg.data;
       delete data;
@@ -836,7 +779,7 @@ class SQLiteTable : Table
    char * name;
    bool mustCreate;
    SQLiteDatabase db;
-   LinkList<SQLiteField> fields { };
+   LinkList<SQLiteField> _fields { };
    char * specialStatement;
    SQLiteField primaryKey;
    FieldIndex * indexFields;
@@ -853,13 +796,13 @@ class SQLiteTable : Table
       Table refTable = null;
       Field idField = null;
       command[0] = 0;
-      
+
       if(FindField(fieldName)) return null;
 
-      if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || 
-         !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") || 
-         !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") || 
-         !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") || 
+      if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
+         !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
+         !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
+         !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
          !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
          !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
       {
@@ -895,7 +838,7 @@ class SQLiteTable : Table
       }
       if(sqliteType != SQLITE_BLOB && eClass_IsDerived(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)
          {
@@ -915,7 +858,7 @@ class SQLiteTable : Table
             PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
          }
       }
-      
+
       if(mustCreate)
       {
          if(sqliteType == SQLITE_BLOB)
@@ -967,9 +910,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;
@@ -977,14 +920,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;
             }
@@ -1042,19 +985,24 @@ class SQLiteTable : Table
       return result == SQLITE_OK;
    }
 
-   String GetName()
+   const String GetName()
    {
       return name;
    }
 
    Field GetFirstField()
    {
-      return fields.first;
+      return _fields.first;
+   }
+
+   Field GetPrimaryKey()
+   {
+      return primaryKey;
    }
 
    uint GetFieldsCount()
    {
-      return fields.count;
+      return _fields.count;
    }
 
    uint GetRowsCount()
@@ -1102,6 +1050,11 @@ class SQLiteTable : Table
       }
    }
 
+   Container<Field> GetFields()
+   {
+      return (Container<Field>)_fields;
+   }
+
    DriverRow CreateRow()
    {
       char command[1024];
@@ -1153,7 +1106,7 @@ class SQLiteTable : Table
       sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
 
       return SQLiteRow
-         { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt, 
+         { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
            insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
            previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
    }
@@ -1163,7 +1116,7 @@ class SQLiteTable : Table
       delete name;
       delete specialStatement;
       delete indexFields;
-      fields.Free();
+      _fields.Free();
    }
 }
 
@@ -1195,7 +1148,7 @@ class SQLiteRow : DriverRow
    // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
    bool findSysID;
    int findBindId;
-   
+
    bool Nil()
    {
       return done;
@@ -1254,7 +1207,7 @@ class SQLiteRow : DriverRow
          case previous:
          {
             // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
-            if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) || 
+            if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
                (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
             {
                result = sqlite3_step(curStatement);
@@ -1279,7 +1232,6 @@ class SQLiteRow : DriverRow
                }
                else
                {
-                  int bindId = findBindId;
                   sqlite3_reset((move == next) ? findStatement : lastFindStatement);
                   sqlite3_reset(curStatement);
                   curStatement = (move == next) ? findStatement : lastFindStatement;
@@ -1312,7 +1264,7 @@ class SQLiteRow : DriverRow
       return true;
    }
 
-   bool Query(char * queryString)
+   bool Query(const char * queryString)
    {
       bool status = true;
       int result;
@@ -1342,7 +1294,10 @@ class SQLiteRow : DriverRow
             }
          }
          else
+         {
+            printf("SQLite Query Error: %s\n", queryString);
             status = false;
+         }
       }
       else
          curStatement = null;
@@ -1356,7 +1311,7 @@ class SQLiteRow : DriverRow
       SerialBuffer buffer = null;
       switch(fld.sqliteType)
       {
-         case SQLITE_INTEGER: 
+         case SQLITE_INTEGER:
          {
             switch(dataType.typeSize)
             {
@@ -1402,15 +1357,20 @@ class SQLiteRow : DriverRow
             if((char *)data)
                result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
             else
-               result = sqlite3_bind_text(statement, pos, null, 0, SQLITE_TRANSIENT);
+               result = sqlite3_bind_null(statement, pos);
             break;
          }
          case SQLITE_BLOB:
          case SQLITE_NULL:
          {
-            buffer = SerialBuffer { };
-            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
-            result = sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+            if((void *)data)
+            {
+               buffer = SerialBuffer { };
+               ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
+               result = sqlite3_bind_text(statement, pos, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
+            }
+            else
+               result = sqlite3_bind_null(statement, pos);
             break;
          }
       }
@@ -1487,13 +1447,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);
@@ -1501,13 +1461,13 @@ 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
                   ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
 
-               type._vTbl[__ecereVMethodID_class_OnFree](type, dataPtr);
+               ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
             }
             // delete dataRow;
          }
@@ -1535,7 +1495,7 @@ class SQLiteRow : DriverRow
          result = GoToSysID(*(int *)data);
          if(result)
             findSysID = true;
-         return result;
+         return result != 0;
       }
 
       useIndex = tbl.GetIndexOrder(order, false);
@@ -1751,6 +1711,7 @@ class SQLiteRow : DriverRow
          sqlite3_reset(curStatement);
          sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
          result = sqlite3_step(curStatement);
+         done = false; // Make sure 'nil' is false
          return true;
       }
       sqlite3_reset(insertStatement);
@@ -1779,7 +1740,7 @@ class SQLiteRow : DriverRow
 
       switch(sqlFld.sqliteType)
       {
-         case SQLITE_INTEGER: 
+         case SQLITE_INTEGER:
          {
             switch(dataType.typeSize)
             {
@@ -1836,7 +1797,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);
@@ -1847,11 +1808,11 @@ 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;
 
-            dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
-           
+            ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
+
             buffer._buffer = null;
             delete buffer;
             break;
@@ -1864,7 +1825,6 @@ class SQLiteRow : DriverRow
    {
       SQLiteField sqlFld = (SQLiteField)fld;
       int result;
-      int num = sqlFld.num + 1;
       char command[1024];
 
       if(updateStatement)
@@ -1934,7 +1894,7 @@ class SQLiteRow : DriverRow
       return !result;
    }
 
-   bool SetQueryParamText(int paramID, char * data)
+   bool SetQueryParamText(int paramID, const char * data)
    {
       int result;
       if(curStatement != queryStatement)
@@ -1950,7 +1910,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)
@@ -1961,8 +1921,8 @@ class SQLiteRow : DriverRow
       sqlite3_reset(queryStatement);
       {
          SerialBuffer buffer { };
-         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;
@@ -1981,11 +1941,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);
    }
 }