EDA:SQLite:SQLiteCipher: moved code common to both drivers into EDASQLiteCommon.ec...
authorRejean Loyer <rejean.loyer@gmail.com>
Sun, 29 May 2011 05:09:41 +0000 (01:09 -0400)
committerRejean Loyer <rejean.loyer@gmail.com>
Sun, 29 May 2011 05:09:41 +0000 (01:09 -0400)
eda/drivers/sqlite/EDASQLite.ec
eda/drivers/sqlite/EDASQLite.epj
eda/drivers/sqlite/EDASQLiteCommon.ec [new file with mode: 0644]
eda/drivers/sqlite/Makefile
eda/drivers/sqliteCipher/EDASQLiteCipher.ec
eda/drivers/sqliteCipher/EDASQLiteCipher.epj
eda/drivers/sqliteCipher/Makefile

index 22816eb..8b827fa 100644 (file)
@@ -8,110 +8,7 @@ public import "EDA"
 
 #include "sqlite3.h"
 
-static void UnusedFunction()
-{
-   int a;
-   a.OnGetString(0,0,0);
-   a.OnFree();
-   a.OnCopy(null);
-   a.OnCompare(null);
-   a.OnSaveEdit(null,0);
-   a.OnEdit(null,null,0,0,0,0,0);
-   a.OnDisplay(null,0,0,0,0,0,0);
-   a.OnGetDataFromString(null);
-   a.OnUnserialize(null);
-   a.OnSerialize(null);
-}
-
-default:
-extern int __ecereVMethodID_class_OnGetString;
-extern int __ecereVMethodID_class_OnGetDataFromString;
-extern int __ecereVMethodID_class_OnCompare;
-extern int __ecereVMethodID_class_OnSerialize;
-extern int __ecereVMethodID_class_OnUnserialize;
-extern int __ecereVMethodID_class_OnFree;
-private:
-
-static int CollationCompare(Class type, int count1, void * data1, int count2, 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 };
-
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
-
-      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
-     
-      buffer1.buffer = null;
-      buffer2.buffer = null;
-      delete buffer1;
-      delete buffer2;
-      inst1.OnFree();
-      inst2.OnFree();
-      return result;
-   }
-   else if(type.type == structClass)
-   {
-      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];
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
-
-      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
-     
-      buffer1.buffer = null;
-      buffer2.buffer = null;
-      delete buffer1;
-      delete buffer2;
-      delete inst1;
-      delete inst2;
-      return result;
-   }
-   else
-      return type._vTbl[__ecereVMethodID_class_OnCompare](type, data1, data2);
-}
-
-class SQLiteField : Field
-{
-   char * name;
-   Class type;
-   int length;
-   public LinkElement<SQLiteField> link;
-   int num;
-   int sqliteType;
-
-   ~SQLiteField()
-   {
-      delete name;
-   }
-
-   String GetName()
-   {
-      return name;
-   }
-   Class GetType()
-   {
-      return type;
-   }
-   int GetLength() { return length; }
-   Field GetPrev()
-   {
-      return link.prev;
-   }
-   Field GetNext()
-   {
-      return link.next;
-   }
-}
+import "EDASQLiteCommon"
 
 static class SQLiteDataSource : DataSourceDriver
 {
@@ -216,7 +113,7 @@ static class SQLiteDataSource : DataSourceDriver
             (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
          {
             // fprintf(stderr, "%s\n", s); // interesting
-            printf("Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
+            printf("EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
             sqlite3_close(db);
          }
          else
@@ -232,1239 +129,3 @@ static class SQLiteDataSource : DataSourceDriver
       return result;
    }
 }
-
-class SQLiteDatabase : Database
-{
-   sqlite3 * db;
-   AVLTree<String> collations { };
-   
-   ~SQLiteDatabase()
-   {
-      sqlite3_close(db);
-   }
-
-   uint ObjectsCount(ObjectType type)
-   {
-      // TODO
-      return 0;
-   }
-
-   bool RenameObject(ObjectType type, const String name, const String rename)
-   {
-      // TODO
-      return false;
-   }
-
-   bool DeleteObject(ObjectType type, const String name)
-   {
-      // TODO
-      return false;
-   }
-
-   Table OpenTable(const String name, OpenOptions options)
-   {
-      char command[1024];
-      int result;
-      int nRows = 0, nCols = 0;
-      char ** t;
-      SQLiteTable table = null;
-      if(options.type == tablesList)
-      {
-         SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
-         strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
-         table = SQLiteTable { db = this, specialStatement = CopyString(command) };
-         LinkTable(table);
-         incref field;
-         table.fields.Add(field);
-      }
-      else if(options.type == fieldsList)
-      {
-         SQLiteField field;
-
-         sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
-         table = SQLiteTable { db = this, specialStatement = CopyString(command) };
-         LinkTable(table);
-         field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
-         incref field;
-         table.fields.Add(field);
-         field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
-         incref field;
-         table.fields.Add(field);
-         field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
-         incref 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);
-         if(!nRows && !nCols)
-            addFields = true;
-
-         sqlite3_free_table(t);
-
-         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);
-         
-         if((nCols || nRows) || options.create)
-         {
-            table = SQLiteTable { db = this, name = CopyString(name) };
-            LinkTable(table);
-            if(!nCols && !nRows)
-               table.mustCreate = true;
-            else
-            {
-               if(addFields)
-               {
-                  int r;
-                  for(r = 1; r <= nRows; r++)      // There should be only 1 row here
-                  {
-                     char * sql = t[nCols * r];
-                     char * bracket = strchr(sql, '(');
-                     if(bracket) 
-                     {
-                        int c = 0;
-                        bracket++;
-                        while(true)
-                        {
-                           char ch;
-                           char fieldName[256];
-                           char dataType[256];
-                           int d;
-                           int start = c;
-                           int sqliteType;
-                           Class type = class(int);
-                           fieldName[0] = 0;
-                           dataType[0] = 0;
-
-                           while((ch = bracket[c++]))
-                           {
-                              if(ch == ',' || ch == ')')
-                                 break;
-                           }
-                           for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
-
-                           memcpy(fieldName, bracket + start, d - start);
-                           fieldName[d - start] = 0;
-
-                           memcpy(dataType, bracket + d + 1, c - d - 2);
-                           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); }
-                           else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
-
-                           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);
-
-                           {
-                              SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
-                              incref field;
-                              table.fields.Add(field);
-                           }
-
-                           if(!ch || ch == ')') break;
-                        }
-                     }
-                  }
-               }
-               else
-               {
-                  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);
-
-                  while(sqlite3_step(statement) != SQLITE_DONE)
-                  {
-                     char * fieldName = sqlite3_column_text(statement, 0);
-                     char * typeName = sqlite3_column_text(statement, 1);
-                     int length = sqlite3_column_int(statement, 2);
-                     Class type = null;
-                     int sqliteType;
-
-                     ((Class)(&type)).OnGetDataFromString(typeName);    // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
-
-                     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") || 
-                           !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;
-                        else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
-                           sqliteType = SQLITE_FLOAT;
-                        else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
-                           sqliteType = SQLITE_TEXT;
-                        else
-                        {
-                           if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
-                           {
-                              collations.Add(type.fullName);
-                              sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
-                           }
-                           sqliteType = SQLITE_BLOB;
-                        }
-                     }
-
-                     {
-                        SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
-                        incref field;
-                        table.fields.Add(field);
-                     }
-                  }
-                  sqlite3_finalize(statement);
-               }
-            }
-         }
-         sqlite3_free_table(t);
-      }
-      return (Table)table;
-   }
-
-   bool Begin()
-   {
-      char command[1024];
-      int result;
-      sprintf(command, "BEGIN;");
-      result = sqlite3_exec(db, command, null, null, null);
-      if(result)
-         PrintLn("BEGIN FAILED!");
-      return result == SQLITE_OK;
-   }
-
-   bool Commit()
-   {
-      char command[1024];
-      int result;
-      sprintf(command, "COMMIT;");
-      result = sqlite3_exec(db, command, null, null, null);
-      if(result)
-         PrintLn("COMMIT FAILED!");
-      return result == SQLITE_OK;
-   }
-
-   bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
-   {
-      int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
-      return result == SQLITE_OK;
-   }
-}
-
-static void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
-{
-   SQLCustomFunction sqlFunction = sqlite3_user_data(context);
-   char * text = sqlite3_value_text(*value);
-   sqlFunction.array.size = 1;
-   sqlFunction.array[0] = 0;
-   sqlFunction.Process(text);
-   sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
-}
-
-class SQLiteTable : Table
-{
-   char * name;
-   bool mustCreate;
-   SQLiteDatabase db;
-   LinkList<SQLiteField> fields { };
-   char * specialStatement;
-   SQLiteField primaryKey;
-   FieldIndex * indexFields;
-   int indexFieldsCount;
-   int64 lastID;
-
-   Field AddField(const String fieldName, Class type, int length)
-   {
-      SQLiteField field;
-      char command[1024];
-      char dataType[256];
-      int sqliteType;
-      int result;
-      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") || 
-         !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"))
-      {
-         strcpy(dataType, "INTEGER");
-         sqliteType = SQLITE_INTEGER;
-      }
-      else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
-      {
-         strcpy(dataType, "REAL");
-         sqliteType = SQLITE_FLOAT;
-      }
-      else if(!strcmp(type.name, "CIString"))
-      {
-         strcpy(dataType, "TEXT");
-         sqliteType = SQLITE_BLOB;
-      }
-      else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
-      {
-         strcpy(dataType, "TEXT");
-         sqliteType = SQLITE_TEXT;
-      }
-      else
-      {
-         //strcpy(dataType, "BLOB");
-         strcpy(dataType, "TEXT");
-         sqliteType = SQLITE_BLOB;
-
-         if(!db.collations.Find(type.fullName))
-         {
-            db.collations.Add(type.fullName);
-            result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
-         }
-      }
-      if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
-      {
-         Table * table = (Table *)eClass_GetProperty(type, "table");
-         if(table) refTable = *table;
-         if(refTable)
-         {
-            if(primaryKey || refTable != this)
-            {
-               for(idField = refTable.firstField; idField; idField = idField.next)
-                  if(eClass_IsDerived(type, idField.type)) break;
-
-               if(!idField)
-                  PrintLn("WARNING: field not yet created for class ", (String)type.name);
-            }
-            else
-               idField = primaryKey;
-         }
-         else
-         {
-            PrintLn("WARNING: Table not yet created for class ", (String)type.name);
-         }
-      }
-      
-      if(mustCreate)
-      {
-         if(sqliteType == SQLITE_BLOB)
-         {
-            if(!strcmp(type.name, "CIString"))
-               sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
-            else
-               sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
-         }
-         else if(refTable)
-         {
-            if(!idField && refTable == this)
-               sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
-            else if(idField)
-               sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
-         }
-         else
-            sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
-         result = sqlite3_exec(db.db, command, null, null, null);
-         if(result) return null;
-         mustCreate = false;
-      }
-      else
-      {
-         if(sqliteType == SQLITE_BLOB)
-         {
-            if(!strcmp(type.name, "CIString"))
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
-            else
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
-         }
-         else if(refTable)
-         {
-            if(!idField && refTable == this)
-            {
-               PrintLn("WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
-            }
-            else if(idField)
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
-         }
-         else
-            sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
-         result = sqlite3_exec(db.db, command, null, null, null);
-         if(result) return null;
-      }
-
-      sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
-         fieldName, type.name, length);
-      result = sqlite3_exec(db.db, command, null, null, null);
-
-      field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
-      incref field;
-      fields.Add(field);
-      if(!primaryKey && refTable == this)
-         primaryKey = field;
-      return (Field)field;
-   }
-
-   Field FindField(const String 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");
-               if(tablePtr && *tablePtr == this)
-                  primaryKey = f;
-            }
-         }
-         return (Field)f;
-      }
-      return null;
-   }
-
-   bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
-   {
-      char command[1024];
-      int c;
-      int result;
-      char indexName[4096];
-
-      delete indexFields;
-      indexFieldsCount = count;
-      indexFields = new FieldIndex[count];
-      memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
-
-      // TODO: USE CODED INDEX NAME INSTEAD?
-      strcpy(indexName, "index_");
-      strcat(indexName, name);
-      strcat(indexName, "_");
-      for(c = 0; c<count; c++)
-      {
-         if(fieldIndexes[c].field)
-         {
-            if(count == 1 && fieldIndexes[c].field == primaryKey)
-               return true;
-            strcat(indexName, fieldIndexes[c].field.name);
-            if(fieldIndexes[c].memberField)
-            {
-               strcat(indexName, ".");
-               strcat(indexName, fieldIndexes[c].memberField.name);
-            }
-            strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
-         }
-         else
-            return false;
-      }
-
-      sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
-      for(c = 0; c<count; c++)
-      {
-         char columnName[1024];
-         sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
-         if(c > 0) strcat(command, ", ");
-         strcat(command, columnName);
-      }
-      strcat(command, ");");
-      result = sqlite3_exec(db.db, command, null, null, null);
-
-      return result == SQLITE_OK;
-   }
-
-   String GetName()
-   {
-      return name;
-   }
-
-   Field GetFirstField()
-   {
-      return fields.first;
-   }
-
-   uint GetFieldsCount()
-   {
-      return fields.count;
-   }
-
-   uint GetRowsCount()
-   {
-      char command[1024];
-      char **t;
-      int nCols, nRows;
-      int result;
-      uint rowCount = 0;
-      sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
-      result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
-      if(result == SQLITE_OK)
-      {
-         rowCount = atoi(t[1]);
-         sqlite3_free_table(t);
-      }
-      return rowCount;
-   }
-
-   DriverRow CreateRow()
-   {
-      char command[1024];
-      sqlite3_stmt * statement;
-      sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
-
-      if(specialStatement)
-         strcpy(command, specialStatement);
-      else
-      {
-         /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
-         sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
-
-         sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
-         sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
-         /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
-
-         if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
-            sprintf(command, "SELECT ROWID, * FROM `%s`;", name);
-         else
-         {
-            int c;
-            sprintf(command, "SELECT ROWID, * FROM `%s` ORDER BY ", name);
-            for(c = 0; c < indexFieldsCount; c++)
-            {
-               char order[1024];
-               FieldIndex * fIndex = &indexFields[c];
-               order[0] = 0;
-               if(c) strcat(order, ", ");
-               strcat(order, "`");
-               strcat(order, fIndex->field.name);
-               strcat(order, "`");
-               if(fIndex->order == descending) strcat(command, " DESC");
-               strcat(command, order);
-            }
-            strcat(command, ";");
-         }
-      }
-      sqlite3_prepare_v2(db.db, command, -1, &statement, null);
-
-      sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
-      sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
-
-      sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
-      sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
-
-      return SQLiteRow
-         { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt, 
-           insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt };
-   }
-
-   ~SQLiteTable()
-   {
-      delete name;
-      delete specialStatement;
-      delete indexFields;
-      fields.Free();
-   }
-}
-
-class SQLiteRow : DriverRow
-{
-   SQLiteTable tbl;
-   sqlite3_stmt * curStatement;
-
-   sqlite3_stmt * defaultStatement;
-   sqlite3_stmt * findStatement;
-   sqlite3_stmt * sysIDStatement;
-   sqlite3_stmt * queryStatement;
-   sqlite3_stmt * findMultipleStatement;
-   sqlite3_stmt * selectRowIDsStmt;
-   sqlite3_stmt * setRowIDStmt;
-
-   sqlite3_stmt * insertStatement;
-   sqlite3_stmt * deleteStatement;
-   sqlite3_stmt * updateStatement;
-   bool done;
-   done = true;
-   int64 rowID;
-   
-   bool Nil()
-   {
-      return done;
-   }
-
-   ~SQLiteRow()
-   {
-      if(defaultStatement) sqlite3_finalize(defaultStatement);
-      if(findStatement)    sqlite3_finalize(findStatement);
-      if(findMultipleStatement)    sqlite3_finalize(findMultipleStatement);
-      if(sysIDStatement)   sqlite3_finalize(sysIDStatement);
-      if(insertStatement)  sqlite3_finalize(insertStatement);
-      if(deleteStatement)  sqlite3_finalize(deleteStatement);
-      if(updateStatement)  sqlite3_finalize(updateStatement);
-      if(queryStatement)   sqlite3_finalize(queryStatement);
-      if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
-      if(setRowIDStmt)     sqlite3_finalize(setRowIDStmt);
-   }
-
-   bool Select(MoveOptions move)
-   {
-      int result;
-      if(!curStatement)
-         curStatement = defaultStatement;
-      switch(move)
-      {
-         case first:
-         {
-            sqlite3_reset(curStatement);
-            result = sqlite3_step(curStatement);
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
-            rowID = sqlite3_column_int64(curStatement, 0);
-            break;
-         }
-         case last:
-         {
-            sqlite3_stmt * statement;
-            char command[1024];
-            sprintf(command, "SELECT MAX(ROWID) FROM `%s`", tbl.name);
-            result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
-            result = sqlite3_step(statement);
-            rowID = sqlite3_column_int64(statement, 0);
-            sqlite3_finalize(statement);
-            break;
-         }
-         case middle:
-            break;
-         case next:
-         {
-            result = sqlite3_step(curStatement);
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
-            rowID = sqlite3_column_int64(curStatement, 0);
-            break;
-         }
-         case previous:
-            break;
-         case nil:
-            sqlite3_reset(curStatement);
-            rowID = 0;
-            done = true;
-            break;
-         case here:
-            break;
-      }
-      return true;
-   }
-
-   bool Query(char * queryString)
-   {
-      bool status = true;
-      int result;
-
-      if(curStatement)
-         sqlite3_reset(curStatement);
-      if(queryStatement)
-      {
-         sqlite3_finalize(queryStatement);
-         queryStatement = null;
-      }
-
-      if(queryString)
-      {
-         result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
-         curStatement = queryStatement;
-         if(!strchr(queryString, '?'))
-         {
-            result = sqlite3_step(queryStatement);
-
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
-
-            rowID = sqlite3_column_int64(queryStatement, 0);
-         }
-      }
-      else
-         curStatement = null;
-      return status;
-   }
-
-   bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
-   {
-      char command[1024];
-      int result;
-      SQLiteField sqlFld = (SQLiteField)fld;
-      Class dataType = sqlFld.type;
-
-      if(fld == tbl.primaryKey)
-      {
-         return GoToSysID(*(int *)data);
-      }
-      
-      if(curStatement)
-         sqlite3_reset(curStatement);
-      if(findStatement)
-         sqlite3_finalize(findStatement);
-
-      sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?;", tbl.name, fld.name);
-      result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findStatement, null);
-
-      // result = sqlite3_bind_text(findStatement, 1, fld.name, strlen(fld.name), SQLITE_STATIC);
-
-      curStatement = findStatement;
-      switch(sqlFld.sqliteType)
-      {
-         case SQLITE_INTEGER: 
-         {
-            switch(dataType.typeSize)
-            {
-               case 8:
-                  sqlite3_bind_int64(findStatement, 1, (sqlite3_int64)*(int64 *)data);
-                  break;
-               case 4:
-                  sqlite3_bind_int(findStatement, 1, *(int *)data);
-                  break;
-               case 2:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(short *)data;
-                  else
-                     value = (int)*(uint16 *)data;
-                  sqlite3_bind_int(findStatement, 1, value);
-                  break;
-               }
-               case 1:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(char *)data;
-                  else
-                     value = (int)*(byte *)data;
-                  sqlite3_bind_int(findStatement, 1, value);
-                  break;
-               }
-            }
-            break;
-         }
-         case SQLITE_FLOAT:
-         {
-            if(dataType.typeSize == 8)
-               sqlite3_bind_double(findStatement, 1, *(double *)data);
-            else
-               sqlite3_bind_double(findStatement, 1, (double)*(float *)data);
-            break;
-         }
-         case SQLITE_TEXT:
-         {
-            if(data)
-               sqlite3_bind_text(findStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
-            else
-               sqlite3_bind_text(findStatement, 1, null, 0, SQLITE_STATIC);
-            break;
-         }
-         case SQLITE_BLOB:
-         case SQLITE_NULL:
-         {
-            SerialBuffer buffer { };
-
-            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
-            //sqlite3_bind_blob(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            sqlite3_bind_text(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            result = sqlite3_step(findStatement);
-
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(findStatement); delete buffer; return false; }
-
-            rowID = sqlite3_column_int64(findStatement, 0);
-
-            delete buffer;
-            return true;
-            break;
-         } 
-      }
-      result = sqlite3_step(findStatement);
-
-      done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-      if(done) { rowID = 0; sqlite3_reset(findStatement); return false; }
-
-      rowID = sqlite3_column_int64(findStatement, 0);
-      return true;
-   }
-
-   bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
-   {
-      if(numFields)
-      {
-         char command[4096];
-         int result;
-         int c;
-         Array<SerialBuffer> serialBuffers { };
-
-         if(curStatement)
-            sqlite3_reset(curStatement);
-         if(findMultipleStatement)
-            sqlite3_finalize(findMultipleStatement);
-
-         sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
-         for(c = 0; c < numFields; c++)
-         {
-            FieldFindData * fieldFind = &findData[c];
-
-            if(c) strcat(command, " AND `");
-            strcat(command, fieldFind->field.name);
-            strcat(command, "` = ?");
-         }
-         strcat(command, ";");
-
-         result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findMultipleStatement, null);
-         curStatement = findMultipleStatement;
-
-         for(c = 0; c < numFields; c++)
-         {
-            FieldFindData * fieldFind = &findData[c];
-            SQLiteField sqlFld = (SQLiteField)fieldFind->field;
-            Class dataType = sqlFld.type;
-
-            switch(sqlFld.sqliteType)
-            {
-               case SQLITE_INTEGER: 
-               {
-                  switch(dataType.typeSize)
-                  {
-                     case 8:
-                        sqlite3_bind_int64(findMultipleStatement, 1 + c, (sqlite_int64)fieldFind->value.i64);
-                        break;
-                     case 4:
-                        sqlite3_bind_int(findMultipleStatement, 1 + c, fieldFind->value.i);
-                        break;
-                     case 2:
-                     {
-                        int value;
-                        if(value < 0)
-                           value = (int)fieldFind->value.s;
-                        else
-                           value = (int)fieldFind->value.us;
-                        sqlite3_bind_int(findMultipleStatement, 1 + c, value);
-                        break;
-                     }
-                     case 1:
-                     {
-                        int value;
-                        if(value < 0)
-                           value = (int)fieldFind->value.c;
-                        else
-                           value = (int)fieldFind->value.uc;
-                        sqlite3_bind_int(findMultipleStatement, 1 + c, value);
-                        break;
-                     }
-                  }
-                  break;
-               }
-               case SQLITE_FLOAT:
-               {
-                  if(dataType.typeSize == 8)
-                     sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.d);
-                  else
-                     sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.f);
-                  break;
-               }
-               case SQLITE_TEXT:
-               {
-                  if(fieldFind->value.p)
-                     sqlite3_bind_text(findMultipleStatement, 1 + c, (char *)fieldFind->value.p, strlen(fieldFind->value.p), SQLITE_STATIC);
-                  else
-                     sqlite3_bind_text(findMultipleStatement, 1 + c, null, 0, SQLITE_STATIC);
-                  break;
-               }
-               case SQLITE_BLOB:
-               case SQLITE_NULL:
-               {
-                  SerialBuffer buffer { };
-
-                  dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, fieldFind->value.p, buffer);
-                  //sqlite3_bind_blob(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
-                  sqlite3_bind_text(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
-
-                  serialBuffers.Add(buffer);
-                  break;
-               } 
-            }
-         }
-
-         result = sqlite3_step(findMultipleStatement);
-
-         done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-         if(done)
-         {
-            rowID = 0;
-            sqlite3_reset(findMultipleStatement);
-
-            serialBuffers.Free();
-            delete serialBuffers;
-            return false;
-         }
-         else
-         {
-            rowID = sqlite3_column_int64(findMultipleStatement, 0);
-
-            serialBuffers.Free();
-            delete serialBuffers;
-            return true;
-         }
-      }
-      return false;
-   }
-
-   bool Synch(DriverRow to)
-   {
-      return true;
-   }
-
-   bool Add()
-   {
-      int result;
-      //char command[1024];
-      //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
-      //result = sqlite3_exec(tbl.db.db, command, null, null, null);
-      result = sqlite3_step(insertStatement);
-      if(result == SQLITE_DONE)     // if(result == SQLITE_OK)
-      {
-         rowID = sqlite3_last_insert_rowid(tbl.db.db);
-         if(rowID > MAXDWORD)
-         {
-            int64 lastID = tbl.lastID;
-
-            sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
-            while(true)
-            {
-               int64 id;
-               result = sqlite3_step(selectRowIDsStmt);
-               if(result == SQLITE_DONE || result != SQLITE_ROW) break;
-               id = sqlite3_column_int64(selectRowIDsStmt, 0);
-               if(id - lastID > 1) break;
-               lastID = id;
-            }
-            sqlite3_reset(selectRowIDsStmt);
-
-            sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
-            rowID = lastID + 1;
-            tbl.lastID = rowID;
-            sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
-            result = sqlite3_step(setRowIDStmt);
-            sqlite3_reset(setRowIDStmt);
-         }
-         sqlite3_reset(insertStatement);
-         curStatement = sysIDStatement;
-         sqlite3_reset(curStatement);
-         return true;
-      }
-      sqlite3_reset(insertStatement);
-      return false;
-   }
-
-   bool Delete()
-   {
-      int result;
-      //char command[1024];
-      //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
-      //result = sqlite3_exec(tbl.db.db, command, null, null, null);
-      sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
-      result = sqlite3_step(deleteStatement);
-      sqlite3_reset(deleteStatement);
-      rowID = 0;
-      return result == SQLITE_OK || result == SQLITE_DONE;
-   }
-
-   bool GetData(Field fld, typed_object &data)
-   {
-      SQLiteField sqlFld = (SQLiteField)fld;
-      int num = sqlFld.num + 1;
-      Class dataType = sqlFld.type;
-      switch(sqlFld.sqliteType)
-      {
-         case SQLITE_INTEGER: 
-         {
-            switch(dataType.typeSize)
-            {
-               case 8:
-                  if(fld == tbl.primaryKey)
-                     *(int64 *)data = rowID;
-                  else
-                     *(int64 *)data = sqlite3_column_int64(curStatement, num);
-                  break;
-               case 4:
-                  if(fld == tbl.primaryKey)
-                     *(int *)data = (int)(uint)rowID;
-                  else
-                     *(int *)data = sqlite3_column_int(curStatement, num);
-                  break;
-               case 2:
-               {
-                  int value;
-                  if(fld == tbl.primaryKey)
-                     value = (int)(uint)rowID;
-                  else
-                     value = sqlite3_column_int(curStatement, num);
-                  if(value < 0)
-                     *(short *)data = (short)value;
-                  else
-                     *(uint16 *)data = (uint16)value;
-                  break;
-               }
-               case 1:
-               {
-                  int value;
-                  if(fld == tbl.primaryKey)
-                     value = (int)(uint)rowID;
-                  else
-                     value = sqlite3_column_int(curStatement, num);
-                  if(value < 0)
-                     *(char *)data = (char)value;
-                  else
-                     *(byte *)data = (byte)value;
-                  break;
-               }
-            }
-            break;
-         }
-         case SQLITE_FLOAT:
-         {
-            double d = sqlite3_column_double(curStatement, num);
-            if(dataType.typeSize == 8)
-               *(double *)data = d;
-            else
-               *(float *)data = (float)d;
-            break;
-         }
-         case SQLITE_TEXT:
-         {
-            int numBytes = sqlite3_column_bytes(curStatement, num);
-            char * text = sqlite3_column_text(curStatement, num);
-            *(char **)data = text ? new byte[numBytes+1] : null;
-            if(text)
-               memcpy(*(char **)data, text, numBytes+1);
-            break;
-         }
-         case SQLITE_BLOB:
-         {
-            SerialBuffer buffer { };
-            //buffer._buffer = sqlite3_column_blob(curStatement, num);
-            buffer._size = sqlite3_column_bytes(curStatement, num);
-            buffer._buffer = sqlite3_column_text(curStatement, num);
-            buffer.count = buffer._size;
-
-            dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
-           
-            buffer._buffer = null;
-            delete buffer;
-            break;
-         } 
-      }
-      return true;
-   }
-
-   bool SetData(Field fld, typed_object data)
-   {
-      SQLiteField sqlFld = (SQLiteField)fld;
-      int result;
-
-      int num = sqlFld.num + 1;
-      Class dataType = sqlFld.type;
-      char command[1024];
-      //sqlite3_stmt * setStatement;
-
-      if(updateStatement)
-         sqlite3_finalize(updateStatement);
-
-      // sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = %d;", tbl.name, sqlFld.name, rowID);
-      sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
-
-      result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
-
-      //sqlite3_bind_text(updateStatement, 1, sqlFld.name, strlen(sqlFld.name), SQLITE_STATIC);
-      //sqlite3_bind_int64(updateStatement, 3, (sqlite3_int64)rowID);
-
-      sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
-      switch(sqlFld.sqliteType)
-      {
-         case SQLITE_INTEGER: 
-         {
-            switch(dataType.typeSize)
-            {
-               case 8:
-                  sqlite3_bind_int64(updateStatement, 1, (sqlite3_int64)*(int64 *)data);
-                  break;
-               case 4:
-                  sqlite3_bind_int(updateStatement, 1, *(int *)data);
-                  break;
-               case 2:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(short *)data;
-                  else
-                     value = (int)*(uint16 *)data;
-                  sqlite3_bind_int(updateStatement, 1, value);
-                  break;
-               }
-               case 1:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(char *)data;
-                  else
-                     value = (int)*(byte *)data;
-                  sqlite3_bind_int(updateStatement, 1, value);
-                  break;
-               }
-            }
-            break;
-         }
-         case SQLITE_FLOAT:
-         {
-            if(dataType.typeSize == 8)
-               sqlite3_bind_double(updateStatement, 1, *(double *)data);
-            else
-               sqlite3_bind_double(updateStatement, 1, (double)*(float *)data);
-            break;
-         }
-         case SQLITE_TEXT:
-         {
-            if(data)
-               sqlite3_bind_text(updateStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
-            else
-               sqlite3_bind_text(updateStatement, 1, null, 0, SQLITE_STATIC);
-            break;
-         }
-         case SQLITE_BLOB:
-         case SQLITE_NULL:
-         {
-            SerialBuffer buffer { };
-
-            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
-            //sqlite3_bind_blob(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            sqlite3_bind_text(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            sqlite3_step(updateStatement);
-            sqlite3_reset(updateStatement);
-            delete buffer;
-            return true;
-            break;
-         }
-      }
-      result = sqlite3_step(updateStatement);
-      sqlite3_reset(updateStatement);
-      if(fld == tbl.primaryKey)
-      {
-         rowID = *(uint *)data;
-      }
-      return result == SQLITE_DONE;
-   }
-
-   int GetSysID()
-   {
-      return (int)(uint)rowID;
-   }
-
-   bool GoToSysID(int id)
-   {
-      //char command[1024];
-      int result;
-      rowID = (uint)id;
-      //if(statement)
-         //sqlite3_finalize(statement);
-      //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
-      //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
-
-      if(curStatement)
-         sqlite3_reset(curStatement);
-
-      curStatement = sysIDStatement;
-      sqlite3_reset(sysIDStatement);
-      sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
-      result = sqlite3_step(curStatement);
-      done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-      if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
-      return !done;
-   }
-
-   bool SetQueryParam(int paramID, int value)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      sqlite3_reset(queryStatement);
-      result = sqlite3_bind_int(queryStatement, paramID, value);
-      return !result;
-   }
-
-   bool SetQueryParam64(int paramID, int64 value)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      sqlite3_reset(queryStatement);
-      result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
-      return !result;
-   }
-
-   bool SetQueryParamText(int paramID, char * data)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      sqlite3_reset(queryStatement);
-      if(data)
-         result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_STATIC);
-      else
-         result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_STATIC);
-      return !result;
-   }
-
-   bool SetQueryParamObject(int paramID, void * data, Class type)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      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);
-         delete buffer;
-      }
-      return !result;
-   }
-
-   /*char * GetExtraColumn(int paramID)
-   {
-      SQLiteField lastFld = tbl.fields.last;
-      return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
-   }*/
-   char * GetColumn(int paramID)
-   {
-      return sqlite3_column_text(curStatement, paramID);
-   }
-}
index db95e04..51971fe 100644 (file)
@@ -70,7 +70,8 @@
    "Files" : [
       "sqlite3.c",
       "sqlite3.h",
-      "EDASQLite.ec"
+      "EDASQLite.ec",
+      "EDASQLiteCommon.ec"
    ],
    "ResourcesPath" : "",
    "Resources" : [
diff --git a/eda/drivers/sqlite/EDASQLiteCommon.ec b/eda/drivers/sqlite/EDASQLiteCommon.ec
new file mode 100644 (file)
index 0000000..daf6fb2
--- /dev/null
@@ -0,0 +1,1350 @@
+#ifdef ECERE_STATIC
+public import static "ecere"
+public import static "EDA"
+#else
+public import "ecere"
+public import "EDA"
+#endif
+
+#include "sqlite3.h"
+
+static void UnusedFunction()
+{
+   int a;
+   a.OnGetString(0,0,0);
+   a.OnFree();
+   a.OnCopy(null);
+   a.OnCompare(null);
+   a.OnSaveEdit(null,0);
+   a.OnEdit(null,null,0,0,0,0,0);
+   a.OnDisplay(null,0,0,0,0,0,0);
+   a.OnGetDataFromString(null);
+   a.OnUnserialize(null);
+   a.OnSerialize(null);
+}
+
+default:
+extern int __ecereVMethodID_class_OnGetString;
+extern int __ecereVMethodID_class_OnGetDataFromString;
+extern int __ecereVMethodID_class_OnCompare;
+extern int __ecereVMethodID_class_OnSerialize;
+extern int __ecereVMethodID_class_OnUnserialize;
+extern int __ecereVMethodID_class_OnFree;
+private:
+
+static int CollationCompare(Class type, int count1, void * data1, int count2, 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 };
+
+      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
+      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
+
+      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
+     
+      buffer1.buffer = null;
+      buffer2.buffer = null;
+      delete buffer1;
+      delete buffer2;
+      inst1.OnFree();
+      inst2.OnFree();
+      return result;
+   }
+   else if(type.type == structClass)
+   {
+      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];
+      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
+      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
+
+      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
+     
+      buffer1.buffer = null;
+      buffer2.buffer = null;
+      delete buffer1;
+      delete buffer2;
+      delete inst1;
+      delete inst2;
+      return result;
+   }
+   else
+      return type._vTbl[__ecereVMethodID_class_OnCompare](type, data1, data2);
+}
+
+class SQLiteField : Field
+{
+   char * name;
+   Class type;
+   int length;
+   public LinkElement<SQLiteField> link;
+   int num;
+   int sqliteType;
+
+   ~SQLiteField()
+   {
+      delete name;
+   }
+
+   String GetName()
+   {
+      return name;
+   }
+   Class GetType()
+   {
+      return type;
+   }
+   int GetLength() { return length; }
+   Field GetPrev()
+   {
+      return link.prev;
+   }
+   Field GetNext()
+   {
+      return link.next;
+   }
+}
+
+class SQLiteDatabase : Database
+{
+   sqlite3 * db;
+   AVLTree<String> collations { };
+   
+   ~SQLiteDatabase()
+   {
+      sqlite3_close(db);
+   }
+
+   uint ObjectsCount(ObjectType type)
+   {
+      // TODO
+      return 0;
+   }
+
+   bool RenameObject(ObjectType type, const String name, const String rename)
+   {
+      // TODO
+      return false;
+   }
+
+   bool DeleteObject(ObjectType type, const String name)
+   {
+      // TODO
+      return false;
+   }
+
+   Table OpenTable(const String name, OpenOptions options)
+   {
+      char command[1024];
+      int result;
+      int nRows = 0, nCols = 0;
+      char ** t;
+      SQLiteTable table = null;
+      if(options.type == tablesList)
+      {
+         SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
+         strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
+         table = SQLiteTable { db = this, specialStatement = CopyString(command) };
+         LinkTable(table);
+         incref field;
+         table.fields.Add(field);
+      }
+      else if(options.type == fieldsList)
+      {
+         SQLiteField field;
+
+         sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
+         table = SQLiteTable { db = this, specialStatement = CopyString(command) };
+         LinkTable(table);
+         field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
+         incref field;
+         table.fields.Add(field);
+         field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
+         incref field;
+         table.fields.Add(field);
+         field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
+         incref 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);
+         if(!nRows && !nCols)
+            addFields = true;
+
+         sqlite3_free_table(t);
+
+         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);
+         
+         if((nCols || nRows) || options.create)
+         {
+            table = SQLiteTable { db = this, name = CopyString(name) };
+            LinkTable(table);
+            if(!nCols && !nRows)
+               table.mustCreate = true;
+            else
+            {
+               if(addFields)
+               {
+                  int r;
+                  for(r = 1; r <= nRows; r++)      // There should be only 1 row here
+                  {
+                     char * sql = t[nCols * r];
+                     char * bracket = strchr(sql, '(');
+                     if(bracket) 
+                     {
+                        int c = 0;
+                        bracket++;
+                        while(true)
+                        {
+                           char ch;
+                           char fieldName[256];
+                           char dataType[256];
+                           int d;
+                           int start = c;
+                           int sqliteType;
+                           Class type = class(int);
+                           fieldName[0] = 0;
+                           dataType[0] = 0;
+
+                           while((ch = bracket[c++]))
+                           {
+                              if(ch == ',' || ch == ')')
+                                 break;
+                           }
+                           for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
+
+                           memcpy(fieldName, bracket + start, d - start);
+                           fieldName[d - start] = 0;
+
+                           memcpy(dataType, bracket + d + 1, c - d - 2);
+                           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); }
+                           else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
+
+                           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);
+
+                           {
+                              SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
+                              incref field;
+                              table.fields.Add(field);
+                           }
+
+                           if(!ch || ch == ')') break;
+                        }
+                     }
+                  }
+               }
+               else
+               {
+                  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);
+
+                  while(sqlite3_step(statement) != SQLITE_DONE)
+                  {
+                     char * fieldName = sqlite3_column_text(statement, 0);
+                     char * typeName = sqlite3_column_text(statement, 1);
+                     int length = sqlite3_column_int(statement, 2);
+                     Class type = null;
+                     int sqliteType;
+
+                     ((Class)(&type)).OnGetDataFromString(typeName);    // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
+
+                     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") || 
+                           !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;
+                        else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
+                           sqliteType = SQLITE_FLOAT;
+                        else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
+                           sqliteType = SQLITE_TEXT;
+                        else
+                        {
+                           if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
+                           {
+                              collations.Add(type.fullName);
+                              sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
+                           }
+                           sqliteType = SQLITE_BLOB;
+                        }
+                     }
+
+                     {
+                        SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
+                        incref field;
+                        table.fields.Add(field);
+                     }
+                  }
+                  sqlite3_finalize(statement);
+               }
+            }
+         }
+         sqlite3_free_table(t);
+      }
+      return (Table)table;
+   }
+
+   bool Begin()
+   {
+      char command[1024];
+      int result;
+      sprintf(command, "BEGIN;");
+      result = sqlite3_exec(db, command, null, null, null);
+      if(result)
+         PrintLn("BEGIN FAILED!");
+      return result == SQLITE_OK;
+   }
+
+   bool Commit()
+   {
+      char command[1024];
+      int result;
+      sprintf(command, "COMMIT;");
+      result = sqlite3_exec(db, command, null, null, null);
+      if(result)
+         PrintLn("COMMIT FAILED!");
+      return result == SQLITE_OK;
+   }
+
+   bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
+   {
+      int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
+      return result == SQLITE_OK;
+   }
+}
+
+static void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
+{
+   SQLCustomFunction sqlFunction = sqlite3_user_data(context);
+   char * text = sqlite3_value_text(*value);
+   sqlFunction.array.size = 1;
+   sqlFunction.array[0] = 0;
+   sqlFunction.Process(text);
+   sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
+}
+
+class SQLiteTable : Table
+{
+   char * name;
+   bool mustCreate;
+   SQLiteDatabase db;
+   LinkList<SQLiteField> fields { };
+   char * specialStatement;
+   SQLiteField primaryKey;
+   FieldIndex * indexFields;
+   int indexFieldsCount;
+   int64 lastID;
+
+   Field AddField(const String fieldName, Class type, int length)
+   {
+      SQLiteField field;
+      char command[1024];
+      char dataType[256];
+      int sqliteType;
+      int result;
+      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") || 
+         !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"))
+      {
+         strcpy(dataType, "INTEGER");
+         sqliteType = SQLITE_INTEGER;
+      }
+      else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
+      {
+         strcpy(dataType, "REAL");
+         sqliteType = SQLITE_FLOAT;
+      }
+      else if(!strcmp(type.name, "CIString"))
+      {
+         strcpy(dataType, "TEXT");
+         sqliteType = SQLITE_BLOB;
+      }
+      else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
+      {
+         strcpy(dataType, "TEXT");
+         sqliteType = SQLITE_TEXT;
+      }
+      else
+      {
+         //strcpy(dataType, "BLOB");
+         strcpy(dataType, "TEXT");
+         sqliteType = SQLITE_BLOB;
+
+         if(!db.collations.Find(type.fullName))
+         {
+            db.collations.Add(type.fullName);
+            result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
+         }
+      }
+      if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
+      {
+         Table * table = (Table *)eClass_GetProperty(type, "table");
+         if(table) refTable = *table;
+         if(refTable)
+         {
+            if(primaryKey || refTable != this)
+            {
+               for(idField = refTable.firstField; idField; idField = idField.next)
+                  if(eClass_IsDerived(type, idField.type)) break;
+
+               if(!idField)
+                  PrintLn("WARNING: field not yet created for class ", (String)type.name);
+            }
+            else
+               idField = primaryKey;
+         }
+         else
+         {
+            PrintLn("WARNING: Table not yet created for class ", (String)type.name);
+         }
+      }
+      
+      if(mustCreate)
+      {
+         if(sqliteType == SQLITE_BLOB)
+         {
+            if(!strcmp(type.name, "CIString"))
+               sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
+            else
+               sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
+         }
+         else if(refTable)
+         {
+            if(!idField && refTable == this)
+               sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
+            else if(idField)
+               sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
+         }
+         else
+            sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
+         result = sqlite3_exec(db.db, command, null, null, null);
+         if(result) return null;
+         mustCreate = false;
+      }
+      else
+      {
+         if(sqliteType == SQLITE_BLOB)
+         {
+            if(!strcmp(type.name, "CIString"))
+               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
+            else
+               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
+         }
+         else if(refTable)
+         {
+            if(!idField && refTable == this)
+            {
+               PrintLn("WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
+               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
+            }
+            else if(idField)
+               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
+         }
+         else
+            sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
+         result = sqlite3_exec(db.db, command, null, null, null);
+         if(result) return null;
+      }
+
+      sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
+         fieldName, type.name, length);
+      result = sqlite3_exec(db.db, command, null, null, null);
+
+      field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
+      incref field;
+      fields.Add(field);
+      if(!primaryKey && refTable == this)
+         primaryKey = field;
+      return (Field)field;
+   }
+
+   Field FindField(const String 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");
+               if(tablePtr && *tablePtr == this)
+                  primaryKey = f;
+            }
+         }
+         return (Field)f;
+      }
+      return null;
+   }
+
+   bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
+   {
+      char command[1024];
+      int c;
+      int result;
+      char indexName[4096];
+
+      delete indexFields;
+      indexFieldsCount = count;
+      indexFields = new FieldIndex[count];
+      memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
+
+      // TODO: USE CODED INDEX NAME INSTEAD?
+      strcpy(indexName, "index_");
+      strcat(indexName, name);
+      strcat(indexName, "_");
+      for(c = 0; c<count; c++)
+      {
+         if(fieldIndexes[c].field)
+         {
+            if(count == 1 && fieldIndexes[c].field == primaryKey)
+               return true;
+            strcat(indexName, fieldIndexes[c].field.name);
+            if(fieldIndexes[c].memberField)
+            {
+               strcat(indexName, ".");
+               strcat(indexName, fieldIndexes[c].memberField.name);
+            }
+            strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
+         }
+         else
+            return false;
+      }
+
+      sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
+      for(c = 0; c<count; c++)
+      {
+         char columnName[1024];
+         sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
+         if(c > 0) strcat(command, ", ");
+         strcat(command, columnName);
+      }
+      strcat(command, ");");
+      result = sqlite3_exec(db.db, command, null, null, null);
+
+      return result == SQLITE_OK;
+   }
+
+   String GetName()
+   {
+      return name;
+   }
+
+   Field GetFirstField()
+   {
+      return fields.first;
+   }
+
+   uint GetFieldsCount()
+   {
+      return fields.count;
+   }
+
+   uint GetRowsCount()
+   {
+      char command[1024];
+      char **t;
+      int nCols, nRows;
+      int result;
+      uint rowCount = 0;
+      sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
+      result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
+      if(result == SQLITE_OK)
+      {
+         rowCount = atoi(t[1]);
+         sqlite3_free_table(t);
+      }
+      return rowCount;
+   }
+
+   DriverRow CreateRow()
+   {
+      char command[1024];
+      sqlite3_stmt * statement;
+      sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
+
+      if(specialStatement)
+         strcpy(command, specialStatement);
+      else
+      {
+         /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
+         sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
+         sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
+         sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
+
+         sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
+         sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
+         sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
+         sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
+         /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
+         sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
+
+         if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
+            sprintf(command, "SELECT ROWID, * FROM `%s`;", name);
+         else
+         {
+            int c;
+            sprintf(command, "SELECT ROWID, * FROM `%s` ORDER BY ", name);
+            for(c = 0; c < indexFieldsCount; c++)
+            {
+               char order[1024];
+               FieldIndex * fIndex = &indexFields[c];
+               order[0] = 0;
+               if(c) strcat(order, ", ");
+               strcat(order, "`");
+               strcat(order, fIndex->field.name);
+               strcat(order, "`");
+               if(fIndex->order == descending) strcat(command, " DESC");
+               strcat(command, order);
+            }
+            strcat(command, ";");
+         }
+      }
+      sqlite3_prepare_v2(db.db, command, -1, &statement, null);
+
+      sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
+      sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
+
+      sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
+      sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
+
+      return SQLiteRow
+         { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt, 
+           insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt };
+   }
+
+   ~SQLiteTable()
+   {
+      delete name;
+      delete specialStatement;
+      delete indexFields;
+      fields.Free();
+   }
+}
+
+class SQLiteRow : DriverRow
+{
+   SQLiteTable tbl;
+   sqlite3_stmt * curStatement;
+
+   sqlite3_stmt * defaultStatement;
+   sqlite3_stmt * findStatement;
+   sqlite3_stmt * sysIDStatement;
+   sqlite3_stmt * queryStatement;
+   sqlite3_stmt * findMultipleStatement;
+   sqlite3_stmt * selectRowIDsStmt;
+   sqlite3_stmt * setRowIDStmt;
+
+   sqlite3_stmt * insertStatement;
+   sqlite3_stmt * deleteStatement;
+   sqlite3_stmt * updateStatement;
+   bool done;
+   done = true;
+   int64 rowID;
+   
+   bool Nil()
+   {
+      return done;
+   }
+
+   ~SQLiteRow()
+   {
+      if(defaultStatement) sqlite3_finalize(defaultStatement);
+      if(findStatement)    sqlite3_finalize(findStatement);
+      if(findMultipleStatement)    sqlite3_finalize(findMultipleStatement);
+      if(sysIDStatement)   sqlite3_finalize(sysIDStatement);
+      if(insertStatement)  sqlite3_finalize(insertStatement);
+      if(deleteStatement)  sqlite3_finalize(deleteStatement);
+      if(updateStatement)  sqlite3_finalize(updateStatement);
+      if(queryStatement)   sqlite3_finalize(queryStatement);
+      if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
+      if(setRowIDStmt)     sqlite3_finalize(setRowIDStmt);
+   }
+
+   bool Select(MoveOptions move)
+   {
+      int result;
+      if(!curStatement)
+         curStatement = defaultStatement;
+      switch(move)
+      {
+         case first:
+         {
+            sqlite3_reset(curStatement);
+            result = sqlite3_step(curStatement);
+            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+            if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
+            rowID = sqlite3_column_int64(curStatement, 0);
+            break;
+         }
+         case last:
+         {
+            sqlite3_stmt * statement;
+            char command[1024];
+            sprintf(command, "SELECT MAX(ROWID) FROM `%s`", tbl.name);
+            result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
+            result = sqlite3_step(statement);
+            rowID = sqlite3_column_int64(statement, 0);
+            sqlite3_finalize(statement);
+            break;
+         }
+         case middle:
+            break;
+         case next:
+         {
+            result = sqlite3_step(curStatement);
+            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+            if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
+            rowID = sqlite3_column_int64(curStatement, 0);
+            break;
+         }
+         case previous:
+            break;
+         case nil:
+            sqlite3_reset(curStatement);
+            rowID = 0;
+            done = true;
+            break;
+         case here:
+            break;
+      }
+      return true;
+   }
+
+   bool Query(char * queryString)
+   {
+      bool status = true;
+      int result;
+
+      if(curStatement)
+         sqlite3_reset(curStatement);
+      if(queryStatement)
+      {
+         sqlite3_finalize(queryStatement);
+         queryStatement = null;
+      }
+
+      if(queryString)
+      {
+         result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
+         curStatement = queryStatement;
+         if(!strchr(queryString, '?'))
+         {
+            result = sqlite3_step(queryStatement);
+
+            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+            if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
+
+            rowID = sqlite3_column_int64(queryStatement, 0);
+         }
+      }
+      else
+         curStatement = null;
+      return status;
+   }
+
+   bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
+   {
+      char command[1024];
+      int result;
+      SQLiteField sqlFld = (SQLiteField)fld;
+      Class dataType = sqlFld.type;
+
+      if(fld == tbl.primaryKey)
+      {
+         return GoToSysID(*(int *)data);
+      }
+      
+      if(curStatement)
+         sqlite3_reset(curStatement);
+      if(findStatement)
+         sqlite3_finalize(findStatement);
+
+      sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?;", tbl.name, fld.name);
+      result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findStatement, null);
+
+      // result = sqlite3_bind_text(findStatement, 1, fld.name, strlen(fld.name), SQLITE_STATIC);
+
+      curStatement = findStatement;
+      switch(sqlFld.sqliteType)
+      {
+         case SQLITE_INTEGER: 
+         {
+            switch(dataType.typeSize)
+            {
+               case 8:
+                  sqlite3_bind_int64(findStatement, 1, (sqlite3_int64)*(int64 *)data);
+                  break;
+               case 4:
+                  sqlite3_bind_int(findStatement, 1, *(int *)data);
+                  break;
+               case 2:
+               {
+                  int value;
+                  if(value < 0)
+                     value = (int)*(short *)data;
+                  else
+                     value = (int)*(uint16 *)data;
+                  sqlite3_bind_int(findStatement, 1, value);
+                  break;
+               }
+               case 1:
+               {
+                  int value;
+                  if(value < 0)
+                     value = (int)*(char *)data;
+                  else
+                     value = (int)*(byte *)data;
+                  sqlite3_bind_int(findStatement, 1, value);
+                  break;
+               }
+            }
+            break;
+         }
+         case SQLITE_FLOAT:
+         {
+            if(dataType.typeSize == 8)
+               sqlite3_bind_double(findStatement, 1, *(double *)data);
+            else
+               sqlite3_bind_double(findStatement, 1, (double)*(float *)data);
+            break;
+         }
+         case SQLITE_TEXT:
+         {
+            if(data)
+               sqlite3_bind_text(findStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
+            else
+               sqlite3_bind_text(findStatement, 1, null, 0, SQLITE_STATIC);
+            break;
+         }
+         case SQLITE_BLOB:
+         case SQLITE_NULL:
+         {
+            SerialBuffer buffer { };
+
+            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
+            //sqlite3_bind_blob(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
+            sqlite3_bind_text(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
+            result = sqlite3_step(findStatement);
+
+            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+            if(done) { rowID = 0; sqlite3_reset(findStatement); delete buffer; return false; }
+
+            rowID = sqlite3_column_int64(findStatement, 0);
+
+            delete buffer;
+            return true;
+            break;
+         } 
+      }
+      result = sqlite3_step(findStatement);
+
+      done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+      if(done) { rowID = 0; sqlite3_reset(findStatement); return false; }
+
+      rowID = sqlite3_column_int64(findStatement, 0);
+      return true;
+   }
+
+   bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
+   {
+      if(numFields)
+      {
+         char command[4096];
+         int result;
+         int c;
+         Array<SerialBuffer> serialBuffers { };
+
+         if(curStatement)
+            sqlite3_reset(curStatement);
+         if(findMultipleStatement)
+            sqlite3_finalize(findMultipleStatement);
+
+         sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
+         for(c = 0; c < numFields; c++)
+         {
+            FieldFindData * fieldFind = &findData[c];
+
+            if(c) strcat(command, " AND `");
+            strcat(command, fieldFind->field.name);
+            strcat(command, "` = ?");
+         }
+         strcat(command, ";");
+
+         result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findMultipleStatement, null);
+         curStatement = findMultipleStatement;
+
+         for(c = 0; c < numFields; c++)
+         {
+            FieldFindData * fieldFind = &findData[c];
+            SQLiteField sqlFld = (SQLiteField)fieldFind->field;
+            Class dataType = sqlFld.type;
+
+            switch(sqlFld.sqliteType)
+            {
+               case SQLITE_INTEGER: 
+               {
+                  switch(dataType.typeSize)
+                  {
+                     case 8:
+                        sqlite3_bind_int64(findMultipleStatement, 1 + c, (sqlite_int64)fieldFind->value.i64);
+                        break;
+                     case 4:
+                        sqlite3_bind_int(findMultipleStatement, 1 + c, fieldFind->value.i);
+                        break;
+                     case 2:
+                     {
+                        int value;
+                        if(value < 0)
+                           value = (int)fieldFind->value.s;
+                        else
+                           value = (int)fieldFind->value.us;
+                        sqlite3_bind_int(findMultipleStatement, 1 + c, value);
+                        break;
+                     }
+                     case 1:
+                     {
+                        int value;
+                        if(value < 0)
+                           value = (int)fieldFind->value.c;
+                        else
+                           value = (int)fieldFind->value.uc;
+                        sqlite3_bind_int(findMultipleStatement, 1 + c, value);
+                        break;
+                     }
+                  }
+                  break;
+               }
+               case SQLITE_FLOAT:
+               {
+                  if(dataType.typeSize == 8)
+                     sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.d);
+                  else
+                     sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.f);
+                  break;
+               }
+               case SQLITE_TEXT:
+               {
+                  if(fieldFind->value.p)
+                     sqlite3_bind_text(findMultipleStatement, 1 + c, (char *)fieldFind->value.p, strlen(fieldFind->value.p), SQLITE_STATIC);
+                  else
+                     sqlite3_bind_text(findMultipleStatement, 1 + c, null, 0, SQLITE_STATIC);
+                  break;
+               }
+               case SQLITE_BLOB:
+               case SQLITE_NULL:
+               {
+                  SerialBuffer buffer { };
+
+                  dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, fieldFind->value.p, buffer);
+                  //sqlite3_bind_blob(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
+                  sqlite3_bind_text(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
+
+                  serialBuffers.Add(buffer);
+                  break;
+               } 
+            }
+         }
+
+         result = sqlite3_step(findMultipleStatement);
+
+         done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+         if(done)
+         {
+            rowID = 0;
+            sqlite3_reset(findMultipleStatement);
+
+            serialBuffers.Free();
+            delete serialBuffers;
+            return false;
+         }
+         else
+         {
+            rowID = sqlite3_column_int64(findMultipleStatement, 0);
+
+            serialBuffers.Free();
+            delete serialBuffers;
+            return true;
+         }
+      }
+      return false;
+   }
+
+   bool Synch(DriverRow to)
+   {
+      return true;
+   }
+
+   bool Add()
+   {
+      int result;
+      //char command[1024];
+      //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
+      //result = sqlite3_exec(tbl.db.db, command, null, null, null);
+      result = sqlite3_step(insertStatement);
+      if(result == SQLITE_DONE)     // if(result == SQLITE_OK)
+      {
+         rowID = sqlite3_last_insert_rowid(tbl.db.db);
+         if(rowID > MAXDWORD)
+         {
+            int64 lastID = tbl.lastID;
+
+            sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
+            while(true)
+            {
+               int64 id;
+               result = sqlite3_step(selectRowIDsStmt);
+               if(result == SQLITE_DONE || result != SQLITE_ROW) break;
+               id = sqlite3_column_int64(selectRowIDsStmt, 0);
+               if(id - lastID > 1) break;
+               lastID = id;
+            }
+            sqlite3_reset(selectRowIDsStmt);
+
+            sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
+            rowID = lastID + 1;
+            tbl.lastID = rowID;
+            sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
+            result = sqlite3_step(setRowIDStmt);
+            sqlite3_reset(setRowIDStmt);
+         }
+         sqlite3_reset(insertStatement);
+         curStatement = sysIDStatement;
+         sqlite3_reset(curStatement);
+         return true;
+      }
+      sqlite3_reset(insertStatement);
+      return false;
+   }
+
+   bool Delete()
+   {
+      int result;
+      //char command[1024];
+      //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
+      //result = sqlite3_exec(tbl.db.db, command, null, null, null);
+      sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
+      result = sqlite3_step(deleteStatement);
+      sqlite3_reset(deleteStatement);
+      rowID = 0;
+      return result == SQLITE_OK || result == SQLITE_DONE;
+   }
+
+   bool GetData(Field fld, typed_object &data)
+   {
+      SQLiteField sqlFld = (SQLiteField)fld;
+      int num = sqlFld.num + 1;
+      Class dataType = sqlFld.type;
+      switch(sqlFld.sqliteType)
+      {
+         case SQLITE_INTEGER: 
+         {
+            switch(dataType.typeSize)
+            {
+               case 8:
+                  if(fld == tbl.primaryKey)
+                     *(int64 *)data = rowID;
+                  else
+                     *(int64 *)data = sqlite3_column_int64(curStatement, num);
+                  break;
+               case 4:
+                  if(fld == tbl.primaryKey)
+                     *(int *)data = (int)(uint)rowID;
+                  else
+                     *(int *)data = sqlite3_column_int(curStatement, num);
+                  break;
+               case 2:
+               {
+                  int value;
+                  if(fld == tbl.primaryKey)
+                     value = (int)(uint)rowID;
+                  else
+                     value = sqlite3_column_int(curStatement, num);
+                  if(value < 0)
+                     *(short *)data = (short)value;
+                  else
+                     *(uint16 *)data = (uint16)value;
+                  break;
+               }
+               case 1:
+               {
+                  int value;
+                  if(fld == tbl.primaryKey)
+                     value = (int)(uint)rowID;
+                  else
+                     value = sqlite3_column_int(curStatement, num);
+                  if(value < 0)
+                     *(char *)data = (char)value;
+                  else
+                     *(byte *)data = (byte)value;
+                  break;
+               }
+            }
+            break;
+         }
+         case SQLITE_FLOAT:
+         {
+            double d = sqlite3_column_double(curStatement, num);
+            if(dataType.typeSize == 8)
+               *(double *)data = d;
+            else
+               *(float *)data = (float)d;
+            break;
+         }
+         case SQLITE_TEXT:
+         {
+            int numBytes = sqlite3_column_bytes(curStatement, num);
+            char * text = sqlite3_column_text(curStatement, num);
+            *(char **)data = text ? new byte[numBytes+1] : null;
+            if(text)
+               memcpy(*(char **)data, text, numBytes+1);
+            break;
+         }
+         case SQLITE_BLOB:
+         {
+            SerialBuffer buffer { };
+            //buffer._buffer = sqlite3_column_blob(curStatement, num);
+            buffer._size = sqlite3_column_bytes(curStatement, num);
+            buffer._buffer = sqlite3_column_text(curStatement, num);
+            buffer.count = buffer._size;
+
+            dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
+           
+            buffer._buffer = null;
+            delete buffer;
+            break;
+         } 
+      }
+      return true;
+   }
+
+   bool SetData(Field fld, typed_object data)
+   {
+      SQLiteField sqlFld = (SQLiteField)fld;
+      int result;
+
+      int num = sqlFld.num + 1;
+      Class dataType = sqlFld.type;
+      char command[1024];
+      //sqlite3_stmt * setStatement;
+
+      if(updateStatement)
+         sqlite3_finalize(updateStatement);
+
+      // sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = %d;", tbl.name, sqlFld.name, rowID);
+      sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
+
+      result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
+
+      //sqlite3_bind_text(updateStatement, 1, sqlFld.name, strlen(sqlFld.name), SQLITE_STATIC);
+      //sqlite3_bind_int64(updateStatement, 3, (sqlite3_int64)rowID);
+
+      sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
+      switch(sqlFld.sqliteType)
+      {
+         case SQLITE_INTEGER: 
+         {
+            switch(dataType.typeSize)
+            {
+               case 8:
+                  sqlite3_bind_int64(updateStatement, 1, (sqlite3_int64)*(int64 *)data);
+                  break;
+               case 4:
+                  sqlite3_bind_int(updateStatement, 1, *(int *)data);
+                  break;
+               case 2:
+               {
+                  int value;
+                  if(value < 0)
+                     value = (int)*(short *)data;
+                  else
+                     value = (int)*(uint16 *)data;
+                  sqlite3_bind_int(updateStatement, 1, value);
+                  break;
+               }
+               case 1:
+               {
+                  int value;
+                  if(value < 0)
+                     value = (int)*(char *)data;
+                  else
+                     value = (int)*(byte *)data;
+                  sqlite3_bind_int(updateStatement, 1, value);
+                  break;
+               }
+            }
+            break;
+         }
+         case SQLITE_FLOAT:
+         {
+            if(dataType.typeSize == 8)
+               sqlite3_bind_double(updateStatement, 1, *(double *)data);
+            else
+               sqlite3_bind_double(updateStatement, 1, (double)*(float *)data);
+            break;
+         }
+         case SQLITE_TEXT:
+         {
+            if(data)
+               sqlite3_bind_text(updateStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
+            else
+               sqlite3_bind_text(updateStatement, 1, null, 0, SQLITE_STATIC);
+            break;
+         }
+         case SQLITE_BLOB:
+         case SQLITE_NULL:
+         {
+            SerialBuffer buffer { };
+
+            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
+            //sqlite3_bind_blob(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
+            sqlite3_bind_text(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
+            sqlite3_step(updateStatement);
+            sqlite3_reset(updateStatement);
+            delete buffer;
+            return true;
+            break;
+         }
+      }
+      result = sqlite3_step(updateStatement);
+      sqlite3_reset(updateStatement);
+      if(fld == tbl.primaryKey)
+      {
+         rowID = *(uint *)data;
+      }
+      return result == SQLITE_DONE;
+   }
+
+   int GetSysID()
+   {
+      return (int)(uint)rowID;
+   }
+
+   bool GoToSysID(int id)
+   {
+      //char command[1024];
+      int result;
+      rowID = (uint)id;
+      //if(statement)
+         //sqlite3_finalize(statement);
+      //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
+      //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
+
+      if(curStatement)
+         sqlite3_reset(curStatement);
+
+      curStatement = sysIDStatement;
+      sqlite3_reset(sysIDStatement);
+      sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
+      result = sqlite3_step(curStatement);
+      done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
+      if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
+      return !done;
+   }
+
+   bool SetQueryParam(int paramID, int value)
+   {
+      int result;
+      if(curStatement != queryStatement)
+      {
+         if(curStatement) sqlite3_reset(curStatement);
+         curStatement = queryStatement;         
+      }
+      sqlite3_reset(queryStatement);
+      result = sqlite3_bind_int(queryStatement, paramID, value);
+      return !result;
+   }
+
+   bool SetQueryParam64(int paramID, int64 value)
+   {
+      int result;
+      if(curStatement != queryStatement)
+      {
+         if(curStatement) sqlite3_reset(curStatement);
+         curStatement = queryStatement;         
+      }
+      sqlite3_reset(queryStatement);
+      result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
+      return !result;
+   }
+
+   bool SetQueryParamText(int paramID, char * data)
+   {
+      int result;
+      if(curStatement != queryStatement)
+      {
+         if(curStatement) sqlite3_reset(curStatement);
+         curStatement = queryStatement;         
+      }
+      sqlite3_reset(queryStatement);
+      if(data)
+         result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_STATIC);
+      else
+         result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_STATIC);
+      return !result;
+   }
+
+   bool SetQueryParamObject(int paramID, void * data, Class type)
+   {
+      int result;
+      if(curStatement != queryStatement)
+      {
+         if(curStatement) sqlite3_reset(curStatement);
+         curStatement = queryStatement;         
+      }
+      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);
+         delete buffer;
+      }
+      return !result;
+   }
+
+   /*char * GetExtraColumn(int paramID)
+   {
+      SQLiteField lastFld = tbl.fields.last;
+      return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
+   }*/
+   char * GetColumn(int paramID)
+   {
+      return sqlite3_column_text(curStatement, paramID);
+   }
+}
index 8933413..2e8219c 100644 (file)
@@ -11,8 +11,6 @@ OBJ = obj/$(CONFIG).$(PLATFORM)/
 
 RES = 
 
-TARGET_TYPE = sharedlib
-
 # CROSS-PLATFORM MAGIC
 
 include ../../../include.mk
@@ -25,15 +23,16 @@ TARGET = obj/$(CONFIG).$(PLATFORM)/$(LP)EDASQLite$(SO)
 SONAME =
 endif
 
-OBJECTS = $(OBJ)sqlite3.o $(OBJ)EDASQLite.o $(OBJ)$(MODULE).main$(O)
+OBJECTS = $(OBJ)sqlite3.o $(OBJ)EDASQLite.o $(OBJ)EDASQLiteCommon.o \
+       $(OBJ)$(MODULE).main$(O)
 
-COBJECTS = $(OBJ)EDASQLite.c
+COBJECTS = $(OBJ)EDASQLite.c $(OBJ)EDASQLiteCommon.c
 
-SYMBOLS = $(OBJ)EDASQLite.sym
+SYMBOLS = $(OBJ)EDASQLite.sym $(OBJ)EDASQLiteCommon.sym
 
-IMPORTS = $(OBJ)EDASQLite.imp
+IMPORTS = $(OBJ)EDASQLite.imp $(OBJ)EDASQLiteCommon.imp
 
-SOURCES = sqlite3.c EDASQLite.ec
+SOURCES = sqlite3.c EDASQLite.ec EDASQLiteCommon.ec
 
 RESOURCES =
 
@@ -114,11 +113,17 @@ endif
 $(OBJ)EDASQLite.sym: EDASQLite.ec
        $(ECP) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) -c EDASQLite.ec -o $(OBJ)EDASQLite.sym
 
+$(OBJ)EDASQLiteCommon.sym: EDASQLiteCommon.ec
+       $(ECP) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) -c EDASQLiteCommon.ec -o $(OBJ)EDASQLiteCommon.sym
+
 # C OBJECT RULES
 
 $(OBJ)EDASQLite.c: EDASQLite.ec $(OBJ)EDASQLite.sym | $(SYMBOLS)
        $(ECC) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) $(FVISIBILITY) -c EDASQLite.ec -o $(OBJ)EDASQLite.c -symbols $(OBJ)
 
+$(OBJ)EDASQLiteCommon.c: EDASQLiteCommon.ec $(OBJ)EDASQLiteCommon.sym | $(SYMBOLS)
+       $(ECC) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) $(FVISIBILITY) -c EDASQLiteCommon.ec -o $(OBJ)EDASQLiteCommon.c -symbols $(OBJ)
+
 # IMPLICIT OBJECT RULE
 
 $(OBJ)%$(O) : $(OBJ)%.c
index 4cdb5dc..def7b5c 100644 (file)
@@ -8,112 +8,9 @@ public import "EDA"
 
 #include "sqlite3.h"
 
-static void UnusedFunction()
-{
-   int a;
-   a.OnGetString(0,0,0);
-   a.OnFree();
-   a.OnCopy(null);
-   a.OnCompare(null);
-   a.OnSaveEdit(null,0);
-   a.OnEdit(null,null,0,0,0,0,0);
-   a.OnDisplay(null,0,0,0,0,0,0);
-   a.OnGetDataFromString(null);
-   a.OnUnserialize(null);
-   a.OnSerialize(null);
-}
-
-default:
-extern int __ecereVMethodID_class_OnGetString;
-extern int __ecereVMethodID_class_OnGetDataFromString;
-extern int __ecereVMethodID_class_OnCompare;
-extern int __ecereVMethodID_class_OnSerialize;
-extern int __ecereVMethodID_class_OnUnserialize;
-extern int __ecereVMethodID_class_OnFree;
-private:
-
-static int CollationCompare(Class type, int count1, void * data1, int count2, 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 };
-
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
-
-      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
-     
-      buffer1.buffer = null;
-      buffer2.buffer = null;
-      delete buffer1;
-      delete buffer2;
-      inst1.OnFree();
-      inst2.OnFree();
-      return result;
-   }
-   else if(type.type == structClass)
-   {
-      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];
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
-      type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
-
-      result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
-     
-      buffer1.buffer = null;
-      buffer2.buffer = null;
-      delete buffer1;
-      delete buffer2;
-      delete inst1;
-      delete inst2;
-      return result;
-   }
-   else
-      return type._vTbl[__ecereVMethodID_class_OnCompare](type, data1, data2);
-}
+import "EDASQLiteCommon"
 
-class SQLiteField : Field
-{
-   char * name;
-   Class type;
-   int length;
-   public LinkElement<SQLiteField> link;
-   int num;
-   int sqliteType;
-
-   ~SQLiteField()
-   {
-      delete name;
-   }
-
-   String GetName()
-   {
-      return name;
-   }
-   Class GetType()
-   {
-      return type;
-   }
-   int GetLength() { return length; }
-   Field GetPrev()
-   {
-      return link.prev;
-   }
-   Field GetNext()
-   {
-      return link.next;
-   }
-}
-
-static class SQLiteDataSource : DataSourceDriver
+static class SQLiteCipherDataSource : DataSourceDriver
 {
    class_property(name) = "SQLiteCipher";
    String path;
@@ -130,7 +27,7 @@ static class SQLiteDataSource : DataSourceDriver
       return databasesCount;
    }
 
-   ~SQLiteDataSource()
+   ~SQLiteCipherDataSource()
    {
       delete path;
    }
@@ -228,11 +125,11 @@ static class SQLiteDataSource : DataSourceDriver
                sqlite3_exec(db, command, null, null, null);
                if(sqlite3_exec(db, "SELECT count(*) FROM sqlite_master;", null, null, null) == SQLITE_OK)
                {
-                  PrintLn("password is correct, or, database has been initialized");
+                  PrintLn("EDASQLiteCipher: password is correct, database has been initialized");
                }
                else
                {
-                  PrintLn("incorrect password!");
+                  PrintLn("EDASQLiteCipher: incorrect password!");
                }
             }
             sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
@@ -245,1239 +142,3 @@ static class SQLiteDataSource : DataSourceDriver
       return result;
    }
 }
-
-class SQLiteDatabase : Database
-{
-   sqlite3 * db;
-   AVLTree<String> collations { };
-   
-   ~SQLiteDatabase()
-   {
-      sqlite3_close(db);
-   }
-
-   uint ObjectsCount(ObjectType type)
-   {
-      // TODO
-      return 0;
-   }
-
-   bool RenameObject(ObjectType type, const String name, const String rename)
-   {
-      // TODO
-      return false;
-   }
-
-   bool DeleteObject(ObjectType type, const String name)
-   {
-      // TODO
-      return false;
-   }
-
-   Table OpenTable(const String name, OpenOptions options)
-   {
-      char command[1024];
-      int result;
-      int nRows = 0, nCols = 0;
-      char ** t;
-      SQLiteTable table = null;
-      if(options.type == tablesList)
-      {
-         SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
-         strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
-         table = SQLiteTable { db = this, specialStatement = CopyString(command) };
-         LinkTable(table);
-         incref field;
-         table.fields.Add(field);
-      }
-      else if(options.type == fieldsList)
-      {
-         SQLiteField field;
-
-         sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
-         table = SQLiteTable { db = this, specialStatement = CopyString(command) };
-         LinkTable(table);
-         field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
-         incref field;
-         table.fields.Add(field);
-         field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
-         incref field;
-         table.fields.Add(field);
-         field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
-         incref 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);
-         if(!nRows && !nCols)
-            addFields = true;
-
-         sqlite3_free_table(t);
-
-         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);
-         
-         if((nCols || nRows) || options.create)
-         {
-            table = SQLiteTable { db = this, name = CopyString(name) };
-            LinkTable(table);
-            if(!nCols && !nRows)
-               table.mustCreate = true;
-            else
-            {
-               if(addFields)
-               {
-                  int r;
-                  for(r = 1; r <= nRows; r++)      // There should be only 1 row here
-                  {
-                     char * sql = t[nCols * r];
-                     char * bracket = strchr(sql, '(');
-                     if(bracket) 
-                     {
-                        int c = 0;
-                        bracket++;
-                        while(true)
-                        {
-                           char ch;
-                           char fieldName[256];
-                           char dataType[256];
-                           int d;
-                           int start = c;
-                           int sqliteType;
-                           Class type = class(int);
-                           fieldName[0] = 0;
-                           dataType[0] = 0;
-
-                           while((ch = bracket[c++]))
-                           {
-                              if(ch == ',' || ch == ')')
-                                 break;
-                           }
-                           for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
-
-                           memcpy(fieldName, bracket + start, d - start);
-                           fieldName[d - start] = 0;
-
-                           memcpy(dataType, bracket + d + 1, c - d - 2);
-                           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); }
-                           else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
-
-                           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);
-
-                           {
-                              SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
-                              incref field;
-                              table.fields.Add(field);
-                           }
-
-                           if(!ch || ch == ')') break;
-                        }
-                     }
-                  }
-               }
-               else
-               {
-                  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);
-
-                  while(sqlite3_step(statement) != SQLITE_DONE)
-                  {
-                     char * fieldName = sqlite3_column_text(statement, 0);
-                     char * typeName = sqlite3_column_text(statement, 1);
-                     int length = sqlite3_column_int(statement, 2);
-                     Class type = null;
-                     int sqliteType;
-
-                     ((Class)(&type)).OnGetDataFromString(typeName);    // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
-
-                     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") || 
-                           !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;
-                        else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
-                           sqliteType = SQLITE_FLOAT;
-                        else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
-                           sqliteType = SQLITE_TEXT;
-                        else
-                        {
-                           if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
-                           {
-                              collations.Add(type.fullName);
-                              sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
-                           }
-                           sqliteType = SQLITE_BLOB;
-                        }
-                     }
-
-                     {
-                        SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
-                        incref field;
-                        table.fields.Add(field);
-                     }
-                  }
-                  sqlite3_finalize(statement);
-               }
-            }
-         }
-         sqlite3_free_table(t);
-      }
-      return (Table)table;
-   }
-
-   bool Begin()
-   {
-      char command[1024];
-      int result;
-      sprintf(command, "BEGIN;");
-      result = sqlite3_exec(db, command, null, null, null);
-      if(result)
-         PrintLn("BEGIN FAILED!");
-      return result == SQLITE_OK;
-   }
-
-   bool Commit()
-   {
-      char command[1024];
-      int result;
-      sprintf(command, "COMMIT;");
-      result = sqlite3_exec(db, command, null, null, null);
-      if(result)
-         PrintLn("COMMIT FAILED!");
-      return result == SQLITE_OK;
-   }
-
-   bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
-   {
-      int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
-      return result == SQLITE_OK;
-   }
-}
-
-static void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
-{
-   SQLCustomFunction sqlFunction = sqlite3_user_data(context);
-   char * text = sqlite3_value_text(*value);
-   sqlFunction.array.size = 1;
-   sqlFunction.array[0] = 0;
-   sqlFunction.Process(text);
-   sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
-}
-
-class SQLiteTable : Table
-{
-   char * name;
-   bool mustCreate;
-   SQLiteDatabase db;
-   LinkList<SQLiteField> fields { };
-   char * specialStatement;
-   SQLiteField primaryKey;
-   FieldIndex * indexFields;
-   int indexFieldsCount;
-   int64 lastID;
-
-   Field AddField(const String fieldName, Class type, int length)
-   {
-      SQLiteField field;
-      char command[1024];
-      char dataType[256];
-      int sqliteType;
-      int result;
-      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") || 
-         !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"))
-      {
-         strcpy(dataType, "INTEGER");
-         sqliteType = SQLITE_INTEGER;
-      }
-      else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
-      {
-         strcpy(dataType, "REAL");
-         sqliteType = SQLITE_FLOAT;
-      }
-      else if(!strcmp(type.name, "CIString"))
-      {
-         strcpy(dataType, "TEXT");
-         sqliteType = SQLITE_BLOB;
-      }
-      else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
-      {
-         strcpy(dataType, "TEXT");
-         sqliteType = SQLITE_TEXT;
-      }
-      else
-      {
-         //strcpy(dataType, "BLOB");
-         strcpy(dataType, "TEXT");
-         sqliteType = SQLITE_BLOB;
-
-         if(!db.collations.Find(type.fullName))
-         {
-            db.collations.Add(type.fullName);
-            result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
-         }
-      }
-      if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
-      {
-         Table * table = (Table *)eClass_GetProperty(type, "table");
-         if(table) refTable = *table;
-         if(refTable)
-         {
-            if(primaryKey || refTable != this)
-            {
-               for(idField = refTable.firstField; idField; idField = idField.next)
-                  if(eClass_IsDerived(type, idField.type)) break;
-
-               if(!idField)
-                  PrintLn("WARNING: field not yet created for class ", (String)type.name);
-            }
-            else
-               idField = primaryKey;
-         }
-         else
-         {
-            PrintLn("WARNING: Table not yet created for class ", (String)type.name);
-         }
-      }
-      
-      if(mustCreate)
-      {
-         if(sqliteType == SQLITE_BLOB)
-         {
-            if(!strcmp(type.name, "CIString"))
-               sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
-            else
-               sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
-         }
-         else if(refTable)
-         {
-            if(!idField && refTable == this)
-               sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
-            else if(idField)
-               sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
-         }
-         else
-            sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
-         result = sqlite3_exec(db.db, command, null, null, null);
-         if(result) return null;
-         mustCreate = false;
-      }
-      else
-      {
-         if(sqliteType == SQLITE_BLOB)
-         {
-            if(!strcmp(type.name, "CIString"))
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
-            else
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
-         }
-         else if(refTable)
-         {
-            if(!idField && refTable == this)
-            {
-               PrintLn("WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
-            }
-            else if(idField)
-               sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
-         }
-         else
-            sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
-         result = sqlite3_exec(db.db, command, null, null, null);
-         if(result) return null;
-      }
-
-      sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
-         fieldName, type.name, length);
-      result = sqlite3_exec(db.db, command, null, null, null);
-
-      field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
-      incref field;
-      fields.Add(field);
-      if(!primaryKey && refTable == this)
-         primaryKey = field;
-      return (Field)field;
-   }
-
-   Field FindField(const String 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");
-               if(tablePtr && *tablePtr == this)
-                  primaryKey = f;
-            }
-         }
-         return (Field)f;
-      }
-      return null;
-   }
-
-   bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
-   {
-      char command[1024];
-      int c;
-      int result;
-      char indexName[4096];
-
-      delete indexFields;
-      indexFieldsCount = count;
-      indexFields = new FieldIndex[count];
-      memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
-
-      // TODO: USE CODED INDEX NAME INSTEAD?
-      strcpy(indexName, "index_");
-      strcat(indexName, name);
-      strcat(indexName, "_");
-      for(c = 0; c<count; c++)
-      {
-         if(fieldIndexes[c].field)
-         {
-            if(count == 1 && fieldIndexes[c].field == primaryKey)
-               return true;
-            strcat(indexName, fieldIndexes[c].field.name);
-            if(fieldIndexes[c].memberField)
-            {
-               strcat(indexName, ".");
-               strcat(indexName, fieldIndexes[c].memberField.name);
-            }
-            strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
-         }
-         else
-            return false;
-      }
-
-      sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
-      for(c = 0; c<count; c++)
-      {
-         char columnName[1024];
-         sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
-         if(c > 0) strcat(command, ", ");
-         strcat(command, columnName);
-      }
-      strcat(command, ");");
-      result = sqlite3_exec(db.db, command, null, null, null);
-
-      return result == SQLITE_OK;
-   }
-
-   String GetName()
-   {
-      return name;
-   }
-
-   Field GetFirstField()
-   {
-      return fields.first;
-   }
-
-   uint GetFieldsCount()
-   {
-      return fields.count;
-   }
-
-   uint GetRowsCount()
-   {
-      char command[1024];
-      char **t;
-      int nCols, nRows;
-      int result;
-      uint rowCount = 0;
-      sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
-      result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
-      if(result == SQLITE_OK)
-      {
-         rowCount = atoi(t[1]);
-         sqlite3_free_table(t);
-      }
-      return rowCount;
-   }
-
-   DriverRow CreateRow()
-   {
-      char command[1024];
-      sqlite3_stmt * statement;
-      sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
-
-      if(specialStatement)
-         strcpy(command, specialStatement);
-      else
-      {
-         /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
-         sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
-
-         sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
-         sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
-         /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
-         sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
-
-         if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
-            sprintf(command, "SELECT ROWID, * FROM `%s`;", name);
-         else
-         {
-            int c;
-            sprintf(command, "SELECT ROWID, * FROM `%s` ORDER BY ", name);
-            for(c = 0; c < indexFieldsCount; c++)
-            {
-               char order[1024];
-               FieldIndex * fIndex = &indexFields[c];
-               order[0] = 0;
-               if(c) strcat(order, ", ");
-               strcat(order, "`");
-               strcat(order, fIndex->field.name);
-               strcat(order, "`");
-               if(fIndex->order == descending) strcat(command, " DESC");
-               strcat(command, order);
-            }
-            strcat(command, ";");
-         }
-      }
-      sqlite3_prepare_v2(db.db, command, -1, &statement, null);
-
-      sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
-      sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
-
-      sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
-      sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
-
-      return SQLiteRow
-         { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt, 
-           insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt };
-   }
-
-   ~SQLiteTable()
-   {
-      delete name;
-      delete specialStatement;
-      delete indexFields;
-      fields.Free();
-   }
-}
-
-class SQLiteRow : DriverRow
-{
-   SQLiteTable tbl;
-   sqlite3_stmt * curStatement;
-
-   sqlite3_stmt * defaultStatement;
-   sqlite3_stmt * findStatement;
-   sqlite3_stmt * sysIDStatement;
-   sqlite3_stmt * queryStatement;
-   sqlite3_stmt * findMultipleStatement;
-   sqlite3_stmt * selectRowIDsStmt;
-   sqlite3_stmt * setRowIDStmt;
-
-   sqlite3_stmt * insertStatement;
-   sqlite3_stmt * deleteStatement;
-   sqlite3_stmt * updateStatement;
-   bool done;
-   done = true;
-   int64 rowID;
-   
-   bool Nil()
-   {
-      return done;
-   }
-
-   ~SQLiteRow()
-   {
-      if(defaultStatement) sqlite3_finalize(defaultStatement);
-      if(findStatement)    sqlite3_finalize(findStatement);
-      if(findMultipleStatement)    sqlite3_finalize(findMultipleStatement);
-      if(sysIDStatement)   sqlite3_finalize(sysIDStatement);
-      if(insertStatement)  sqlite3_finalize(insertStatement);
-      if(deleteStatement)  sqlite3_finalize(deleteStatement);
-      if(updateStatement)  sqlite3_finalize(updateStatement);
-      if(queryStatement)   sqlite3_finalize(queryStatement);
-      if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
-      if(setRowIDStmt)     sqlite3_finalize(setRowIDStmt);
-   }
-
-   bool Select(MoveOptions move)
-   {
-      int result;
-      if(!curStatement)
-         curStatement = defaultStatement;
-      switch(move)
-      {
-         case first:
-         {
-            sqlite3_reset(curStatement);
-            result = sqlite3_step(curStatement);
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
-            rowID = sqlite3_column_int64(curStatement, 0);
-            break;
-         }
-         case last:
-         {
-            sqlite3_stmt * statement;
-            char command[1024];
-            sprintf(command, "SELECT MAX(ROWID) FROM `%s`", tbl.name);
-            result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
-            result = sqlite3_step(statement);
-            rowID = sqlite3_column_int64(statement, 0);
-            sqlite3_finalize(statement);
-            break;
-         }
-         case middle:
-            break;
-         case next:
-         {
-            result = sqlite3_step(curStatement);
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
-            rowID = sqlite3_column_int64(curStatement, 0);
-            break;
-         }
-         case previous:
-            break;
-         case nil:
-            sqlite3_reset(curStatement);
-            rowID = 0;
-            done = true;
-            break;
-         case here:
-            break;
-      }
-      return true;
-   }
-
-   bool Query(char * queryString)
-   {
-      bool status = true;
-      int result;
-
-      if(curStatement)
-         sqlite3_reset(curStatement);
-      if(queryStatement)
-      {
-         sqlite3_finalize(queryStatement);
-         queryStatement = null;
-      }
-
-      if(queryString)
-      {
-         result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
-         curStatement = queryStatement;
-         if(!strchr(queryString, '?'))
-         {
-            result = sqlite3_step(queryStatement);
-
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
-
-            rowID = sqlite3_column_int64(queryStatement, 0);
-         }
-      }
-      else
-         curStatement = null;
-      return status;
-   }
-
-   bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
-   {
-      char command[1024];
-      int result;
-      SQLiteField sqlFld = (SQLiteField)fld;
-      Class dataType = sqlFld.type;
-
-      if(fld == tbl.primaryKey)
-      {
-         return GoToSysID(*(int *)data);
-      }
-      
-      if(curStatement)
-         sqlite3_reset(curStatement);
-      if(findStatement)
-         sqlite3_finalize(findStatement);
-
-      sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?;", tbl.name, fld.name);
-      result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findStatement, null);
-
-      // result = sqlite3_bind_text(findStatement, 1, fld.name, strlen(fld.name), SQLITE_STATIC);
-
-      curStatement = findStatement;
-      switch(sqlFld.sqliteType)
-      {
-         case SQLITE_INTEGER: 
-         {
-            switch(dataType.typeSize)
-            {
-               case 8:
-                  sqlite3_bind_int64(findStatement, 1, (sqlite3_int64)*(int64 *)data);
-                  break;
-               case 4:
-                  sqlite3_bind_int(findStatement, 1, *(int *)data);
-                  break;
-               case 2:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(short *)data;
-                  else
-                     value = (int)*(uint16 *)data;
-                  sqlite3_bind_int(findStatement, 1, value);
-                  break;
-               }
-               case 1:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(char *)data;
-                  else
-                     value = (int)*(byte *)data;
-                  sqlite3_bind_int(findStatement, 1, value);
-                  break;
-               }
-            }
-            break;
-         }
-         case SQLITE_FLOAT:
-         {
-            if(dataType.typeSize == 8)
-               sqlite3_bind_double(findStatement, 1, *(double *)data);
-            else
-               sqlite3_bind_double(findStatement, 1, (double)*(float *)data);
-            break;
-         }
-         case SQLITE_TEXT:
-         {
-            if(data)
-               sqlite3_bind_text(findStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
-            else
-               sqlite3_bind_text(findStatement, 1, null, 0, SQLITE_STATIC);
-            break;
-         }
-         case SQLITE_BLOB:
-         case SQLITE_NULL:
-         {
-            SerialBuffer buffer { };
-
-            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
-            //sqlite3_bind_blob(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            sqlite3_bind_text(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            result = sqlite3_step(findStatement);
-
-            done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-            if(done) { rowID = 0; sqlite3_reset(findStatement); delete buffer; return false; }
-
-            rowID = sqlite3_column_int64(findStatement, 0);
-
-            delete buffer;
-            return true;
-            break;
-         } 
-      }
-      result = sqlite3_step(findStatement);
-
-      done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-      if(done) { rowID = 0; sqlite3_reset(findStatement); return false; }
-
-      rowID = sqlite3_column_int64(findStatement, 0);
-      return true;
-   }
-
-   bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
-   {
-      if(numFields)
-      {
-         char command[4096];
-         int result;
-         int c;
-         Array<SerialBuffer> serialBuffers { };
-
-         if(curStatement)
-            sqlite3_reset(curStatement);
-         if(findMultipleStatement)
-            sqlite3_finalize(findMultipleStatement);
-
-         sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
-         for(c = 0; c < numFields; c++)
-         {
-            FieldFindData * fieldFind = &findData[c];
-
-            if(c) strcat(command, " AND `");
-            strcat(command, fieldFind->field.name);
-            strcat(command, "` = ?");
-         }
-         strcat(command, ";");
-
-         result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findMultipleStatement, null);
-         curStatement = findMultipleStatement;
-
-         for(c = 0; c < numFields; c++)
-         {
-            FieldFindData * fieldFind = &findData[c];
-            SQLiteField sqlFld = (SQLiteField)fieldFind->field;
-            Class dataType = sqlFld.type;
-
-            switch(sqlFld.sqliteType)
-            {
-               case SQLITE_INTEGER: 
-               {
-                  switch(dataType.typeSize)
-                  {
-                     case 8:
-                        sqlite3_bind_int64(findMultipleStatement, 1 + c, (sqlite_int64)fieldFind->value.i64);
-                        break;
-                     case 4:
-                        sqlite3_bind_int(findMultipleStatement, 1 + c, fieldFind->value.i);
-                        break;
-                     case 2:
-                     {
-                        int value;
-                        if(value < 0)
-                           value = (int)fieldFind->value.s;
-                        else
-                           value = (int)fieldFind->value.us;
-                        sqlite3_bind_int(findMultipleStatement, 1 + c, value);
-                        break;
-                     }
-                     case 1:
-                     {
-                        int value;
-                        if(value < 0)
-                           value = (int)fieldFind->value.c;
-                        else
-                           value = (int)fieldFind->value.uc;
-                        sqlite3_bind_int(findMultipleStatement, 1 + c, value);
-                        break;
-                     }
-                  }
-                  break;
-               }
-               case SQLITE_FLOAT:
-               {
-                  if(dataType.typeSize == 8)
-                     sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.d);
-                  else
-                     sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.f);
-                  break;
-               }
-               case SQLITE_TEXT:
-               {
-                  if(fieldFind->value.p)
-                     sqlite3_bind_text(findMultipleStatement, 1 + c, (char *)fieldFind->value.p, strlen(fieldFind->value.p), SQLITE_STATIC);
-                  else
-                     sqlite3_bind_text(findMultipleStatement, 1 + c, null, 0, SQLITE_STATIC);
-                  break;
-               }
-               case SQLITE_BLOB:
-               case SQLITE_NULL:
-               {
-                  SerialBuffer buffer { };
-
-                  dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, fieldFind->value.p, buffer);
-                  //sqlite3_bind_blob(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
-                  sqlite3_bind_text(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
-
-                  serialBuffers.Add(buffer);
-                  break;
-               } 
-            }
-         }
-
-         result = sqlite3_step(findMultipleStatement);
-
-         done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-         if(done)
-         {
-            rowID = 0;
-            sqlite3_reset(findMultipleStatement);
-
-            serialBuffers.Free();
-            delete serialBuffers;
-            return false;
-         }
-         else
-         {
-            rowID = sqlite3_column_int64(findMultipleStatement, 0);
-
-            serialBuffers.Free();
-            delete serialBuffers;
-            return true;
-         }
-      }
-      return false;
-   }
-
-   bool Synch(DriverRow to)
-   {
-      return true;
-   }
-
-   bool Add()
-   {
-      int result;
-      //char command[1024];
-      //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
-      //result = sqlite3_exec(tbl.db.db, command, null, null, null);
-      result = sqlite3_step(insertStatement);
-      if(result == SQLITE_DONE)     // if(result == SQLITE_OK)
-      {
-         rowID = sqlite3_last_insert_rowid(tbl.db.db);
-         if(rowID > MAXDWORD)
-         {
-            int64 lastID = tbl.lastID;
-
-            sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
-            while(true)
-            {
-               int64 id;
-               result = sqlite3_step(selectRowIDsStmt);
-               if(result == SQLITE_DONE || result != SQLITE_ROW) break;
-               id = sqlite3_column_int64(selectRowIDsStmt, 0);
-               if(id - lastID > 1) break;
-               lastID = id;
-            }
-            sqlite3_reset(selectRowIDsStmt);
-
-            sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
-            rowID = lastID + 1;
-            tbl.lastID = rowID;
-            sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
-            result = sqlite3_step(setRowIDStmt);
-            sqlite3_reset(setRowIDStmt);
-         }
-         sqlite3_reset(insertStatement);
-         curStatement = sysIDStatement;
-         sqlite3_reset(curStatement);
-         return true;
-      }
-      sqlite3_reset(insertStatement);
-      return false;
-   }
-
-   bool Delete()
-   {
-      int result;
-      //char command[1024];
-      //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
-      //result = sqlite3_exec(tbl.db.db, command, null, null, null);
-      sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
-      result = sqlite3_step(deleteStatement);
-      sqlite3_reset(deleteStatement);
-      rowID = 0;
-      return result == SQLITE_OK || result == SQLITE_DONE;
-   }
-
-   bool GetData(Field fld, typed_object &data)
-   {
-      SQLiteField sqlFld = (SQLiteField)fld;
-      int num = sqlFld.num + 1;
-      Class dataType = sqlFld.type;
-      switch(sqlFld.sqliteType)
-      {
-         case SQLITE_INTEGER: 
-         {
-            switch(dataType.typeSize)
-            {
-               case 8:
-                  if(fld == tbl.primaryKey)
-                     *(int64 *)data = rowID;
-                  else
-                     *(int64 *)data = sqlite3_column_int64(curStatement, num);
-                  break;
-               case 4:
-                  if(fld == tbl.primaryKey)
-                     *(int *)data = (int)(uint)rowID;
-                  else
-                     *(int *)data = sqlite3_column_int(curStatement, num);
-                  break;
-               case 2:
-               {
-                  int value;
-                  if(fld == tbl.primaryKey)
-                     value = (int)(uint)rowID;
-                  else
-                     value = sqlite3_column_int(curStatement, num);
-                  if(value < 0)
-                     *(short *)data = (short)value;
-                  else
-                     *(uint16 *)data = (uint16)value;
-                  break;
-               }
-               case 1:
-               {
-                  int value;
-                  if(fld == tbl.primaryKey)
-                     value = (int)(uint)rowID;
-                  else
-                     value = sqlite3_column_int(curStatement, num);
-                  if(value < 0)
-                     *(char *)data = (char)value;
-                  else
-                     *(byte *)data = (byte)value;
-                  break;
-               }
-            }
-            break;
-         }
-         case SQLITE_FLOAT:
-         {
-            double d = sqlite3_column_double(curStatement, num);
-            if(dataType.typeSize == 8)
-               *(double *)data = d;
-            else
-               *(float *)data = (float)d;
-            break;
-         }
-         case SQLITE_TEXT:
-         {
-            int numBytes = sqlite3_column_bytes(curStatement, num);
-            char * text = sqlite3_column_text(curStatement, num);
-            *(char **)data = text ? new byte[numBytes+1] : null;
-            if(text)
-               memcpy(*(char **)data, text, numBytes+1);
-            break;
-         }
-         case SQLITE_BLOB:
-         {
-            SerialBuffer buffer { };
-            //buffer._buffer = sqlite3_column_blob(curStatement, num);
-            buffer._size = sqlite3_column_bytes(curStatement, num);
-            buffer._buffer = sqlite3_column_text(curStatement, num);
-            buffer.count = buffer._size;
-
-            dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
-           
-            buffer._buffer = null;
-            delete buffer;
-            break;
-         } 
-      }
-      return true;
-   }
-
-   bool SetData(Field fld, typed_object data)
-   {
-      SQLiteField sqlFld = (SQLiteField)fld;
-      int result;
-
-      int num = sqlFld.num + 1;
-      Class dataType = sqlFld.type;
-      char command[1024];
-      //sqlite3_stmt * setStatement;
-
-      if(updateStatement)
-         sqlite3_finalize(updateStatement);
-
-      // sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = %d;", tbl.name, sqlFld.name, rowID);
-      sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
-
-      result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
-
-      //sqlite3_bind_text(updateStatement, 1, sqlFld.name, strlen(sqlFld.name), SQLITE_STATIC);
-      //sqlite3_bind_int64(updateStatement, 3, (sqlite3_int64)rowID);
-
-      sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
-      switch(sqlFld.sqliteType)
-      {
-         case SQLITE_INTEGER: 
-         {
-            switch(dataType.typeSize)
-            {
-               case 8:
-                  sqlite3_bind_int64(updateStatement, 1, (sqlite3_int64)*(int64 *)data);
-                  break;
-               case 4:
-                  sqlite3_bind_int(updateStatement, 1, *(int *)data);
-                  break;
-               case 2:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(short *)data;
-                  else
-                     value = (int)*(uint16 *)data;
-                  sqlite3_bind_int(updateStatement, 1, value);
-                  break;
-               }
-               case 1:
-               {
-                  int value;
-                  if(value < 0)
-                     value = (int)*(char *)data;
-                  else
-                     value = (int)*(byte *)data;
-                  sqlite3_bind_int(updateStatement, 1, value);
-                  break;
-               }
-            }
-            break;
-         }
-         case SQLITE_FLOAT:
-         {
-            if(dataType.typeSize == 8)
-               sqlite3_bind_double(updateStatement, 1, *(double *)data);
-            else
-               sqlite3_bind_double(updateStatement, 1, (double)*(float *)data);
-            break;
-         }
-         case SQLITE_TEXT:
-         {
-            if(data)
-               sqlite3_bind_text(updateStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
-            else
-               sqlite3_bind_text(updateStatement, 1, null, 0, SQLITE_STATIC);
-            break;
-         }
-         case SQLITE_BLOB:
-         case SQLITE_NULL:
-         {
-            SerialBuffer buffer { };
-
-            dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
-            //sqlite3_bind_blob(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            sqlite3_bind_text(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
-            sqlite3_step(updateStatement);
-            sqlite3_reset(updateStatement);
-            delete buffer;
-            return true;
-            break;
-         }
-      }
-      result = sqlite3_step(updateStatement);
-      sqlite3_reset(updateStatement);
-      if(fld == tbl.primaryKey)
-      {
-         rowID = *(uint *)data;
-      }
-      return result == SQLITE_DONE;
-   }
-
-   int GetSysID()
-   {
-      return (int)(uint)rowID;
-   }
-
-   bool GoToSysID(int id)
-   {
-      //char command[1024];
-      int result;
-      rowID = (uint)id;
-      //if(statement)
-         //sqlite3_finalize(statement);
-      //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
-      //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
-
-      if(curStatement)
-         sqlite3_reset(curStatement);
-
-      curStatement = sysIDStatement;
-      sqlite3_reset(sysIDStatement);
-      sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
-      result = sqlite3_step(curStatement);
-      done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
-      if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
-      return !done;
-   }
-
-   bool SetQueryParam(int paramID, int value)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      sqlite3_reset(queryStatement);
-      result = sqlite3_bind_int(queryStatement, paramID, value);
-      return !result;
-   }
-
-   bool SetQueryParam64(int paramID, int64 value)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      sqlite3_reset(queryStatement);
-      result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
-      return !result;
-   }
-
-   bool SetQueryParamText(int paramID, char * data)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      sqlite3_reset(queryStatement);
-      if(data)
-         result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_STATIC);
-      else
-         result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_STATIC);
-      return !result;
-   }
-
-   bool SetQueryParamObject(int paramID, void * data, Class type)
-   {
-      int result;
-      if(curStatement != queryStatement)
-      {
-         if(curStatement) sqlite3_reset(curStatement);
-         curStatement = queryStatement;         
-      }
-      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);
-         delete buffer;
-      }
-      return !result;
-   }
-
-   /*char * GetExtraColumn(int paramID)
-   {
-      SQLiteField lastFld = tbl.fields.last;
-      return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
-   }*/
-   char * GetColumn(int paramID)
-   {
-      return sqlite3_column_text(curStatement, paramID);
-   }
-}
index d709f96..73617ea 100644 (file)
@@ -58,8 +58,8 @@
       {
          "Name" : "Release",
          "Options" : {
-            "Warnings" : "None",
             "NoLineNumbers" : true,
+            "Optimization" : "Speed",
             "LibraryDirs" : [
                "../../../obj/$(PLATFORM)/bin",
                "../../../obj/$(PLATFORM)/lib"
                "_DEBUG"
             ]
          }
-      },
-      {
-         "Name" : "Static",
-         "Options" : {
-            "TargetType" : "StaticLibrary"
-         }
       }
    ],
    "Files" : [
       "sqlite3.c",
       "sqlite3.h",
-      "EDASQLiteCipher.ec"
+      "EDASQLiteCipher.ec",
+      "../sqlite/EDASQLiteCommon.ec"
    ],
    "ResourcesPath" : "",
    "Resources" : [
index 19a44c9..6cea657 100644 (file)
@@ -23,15 +23,16 @@ TARGET = obj/$(CONFIG).$(PLATFORM)/$(LP)EDASQLiteCipher$(SO)
 SONAME =
 endif
 
-OBJECTS = $(OBJ)sqlite3.o $(OBJ)EDASQLiteCipher.o $(OBJ)$(MODULE).main$(O)
+OBJECTS = $(OBJ)sqlite3.o $(OBJ)EDASQLiteCipher.o $(OBJ)EDASQLiteCommon.o \
+       $(OBJ)$(MODULE).main$(O)
 
-COBJECTS = $(OBJ)EDASQLiteCipher.c
+COBJECTS = $(OBJ)EDASQLiteCipher.c $(OBJ)EDASQLiteCommon.c
 
-SYMBOLS = $(OBJ)EDASQLiteCipher.sym
+SYMBOLS = $(OBJ)EDASQLiteCipher.sym $(OBJ)EDASQLiteCommon.sym
 
-IMPORTS = $(OBJ)EDASQLiteCipher.imp
+IMPORTS = $(OBJ)EDASQLiteCipher.imp $(OBJ)EDASQLiteCommon.imp
 
-SOURCES = sqlite3.c EDASQLiteCipher.ec
+SOURCES = sqlite3.c EDASQLiteCipher.ec ../sqlite/EDASQLiteCommon.ec
 
 RESOURCES =
 
@@ -51,7 +52,7 @@ UPX := upx
 
 # FLAGS
 
-CFLAGS = -fmessage-length=0 -m32 $(FPIC) -w \
+CFLAGS = -fmessage-length=0 -O2 -m32 $(FPIC) -w \
         -DSQLITE_HAS_CODEC
 
 CECFLAGS =
@@ -137,11 +138,17 @@ endif
 $(OBJ)EDASQLiteCipher.sym: EDASQLiteCipher.ec
        $(ECP) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) -c EDASQLiteCipher.ec -o $(OBJ)EDASQLiteCipher.sym
 
+$(OBJ)EDASQLiteCommon.sym: ../sqlite/EDASQLiteCommon.ec
+       $(ECP) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) -c ../sqlite/EDASQLiteCommon.ec -o $(OBJ)EDASQLiteCommon.sym
+
 # C OBJECT RULES
 
 $(OBJ)EDASQLiteCipher.c: EDASQLiteCipher.ec $(OBJ)EDASQLiteCipher.sym | $(SYMBOLS)
        $(ECC) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) $(FVISIBILITY) -c EDASQLiteCipher.ec -o $(OBJ)EDASQLiteCipher.c -symbols $(OBJ)
 
+$(OBJ)EDASQLiteCommon.c: ../sqlite/EDASQLiteCommon.ec $(OBJ)EDASQLiteCommon.sym | $(SYMBOLS)
+       $(ECC) $(CECFLAGS) $(ECFLAGS) $(CFLAGS) $(FVISIBILITY) -c ../sqlite/EDASQLiteCommon.ec -o $(OBJ)EDASQLiteCommon.c -symbols $(OBJ)
+
 # IMPLICIT OBJECT RULE
 
 $(OBJ)%$(O) : $(OBJ)%.c