EDA/SQLite: Collation comparison optimization
[sdk] / eda / drivers / sqlite / EDASQLite.ec
1 #ifdef ECERE_STATIC
2 public import static "ecere"
3 public import static "EDA"
4 #else
5 public import "ecere"
6 public import "EDA"
7 #endif
8
9 #ifdef __linux__
10 #include <sqlite3.h>
11 #else
12 #include "sqlite3.h"
13 #endif
14
15 #define uint _uint
16 #include "ffi.h"
17 #undef uint
18
19 __attribute__((unused)) static void UnusedFunction()
20 {
21    int a;
22    a.OnGetString(0,0,0);
23    a.OnFree();
24    a.OnCopy(null);
25    a.OnCompare(null);
26    a.OnSaveEdit(null,0);
27    a.OnEdit(null,null,0,0,0,0,0);
28    a.OnDisplay(null,0,0,0,0,0,0);
29    a.OnGetDataFromString(null);
30    a.OnUnserialize(null);
31    a.OnSerialize(null);
32 }
33
34 default:
35 extern int __ecereVMethodID_class_OnGetString;
36 extern int __ecereVMethodID_class_OnGetDataFromString;
37 extern int __ecereVMethodID_class_OnCompare;
38 extern int __ecereVMethodID_class_OnSerialize;
39 extern int __ecereVMethodID_class_OnUnserialize;
40 extern int __ecereVMethodID_class_OnFree;
41 private:
42
43 static SerialBuffer collationBuffer1 { };
44 static SerialBuffer collationBuffer2 { };
45 static char storage1[512];
46 static char storage2[512];
47
48 int CollationCompare(Class type, int count1, const void * data1, int count2, const void * data2)
49 {
50    if(type.type == normalClass || type.type ==  noHeadClass)
51    {
52       Instance inst1, inst2;
53       int result;
54       SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
55       SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
56
57       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst1, buffer1);
58       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst2, buffer2);
59
60       result = ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
61
62       buffer1.buffer = null;
63       buffer2.buffer = null;
64       delete buffer1;
65       delete buffer2;
66       inst1.OnFree();
67       inst2.OnFree();
68       return result;
69    }
70    else if(type.type == structClass)
71    {
72       void * inst1, * inst2;
73       int result;
74       //SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
75       //SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
76
77       SerialBuffer buffer1 = collationBuffer1;
78       SerialBuffer buffer2 = collationBuffer2;
79       buffer1.buffer = (byte*)data1;
80       buffer1.size = count1;
81       buffer1.count = count1;
82       buffer1.pos = 0;
83       buffer2.buffer = (byte*)data2;
84       buffer2.size = count2;
85       buffer2.count = count2;
86       buffer2.pos = 0;
87
88       if(type.structSize > 512)
89       {
90          inst1 = new0 byte[type.structSize];
91          inst2 = new0 byte[type.structSize];
92       }
93       else
94       {
95          inst1 = storage1;
96          inst2 = storage2;
97       }
98       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst1, buffer1);
99       ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst2, buffer2);
100
101       result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
102
103       buffer1.buffer = null;
104       buffer2.buffer = null;
105       //delete buffer1;
106       //delete buffer2;
107       if(type.structSize > 512)
108       {
109          delete inst1;
110          delete inst2;
111       }
112       return result;
113    }
114    else
115       return ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, data1, data2);
116 }
117
118 public class SQLiteStaticLink { }   // Until .imp generation is fixed
119
120 class SQLiteDataSource : DirFilesDataSourceDriver
121 {
122    class_property(name) = "SQLite";
123    class_property(databaseFileExtension) = "sqlite";
124
125    Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
126    {
127       Database result = null;
128       if(name && name[0])
129       {
130          String path = MakeDatabasePath(name);
131          sqlite3 * db;
132
133          // sqlite3_open(path, &db);
134          // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
135
136          if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
137             (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
138          {
139             // fprintf(stderr, "%s\n", s); // interesting
140             printf($"EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
141             sqlite3_close(db);
142          }
143          else
144          {
145             bool success = true;
146             char command[1024];
147
148             sqlite3_exec(db, "PRAGMA page_size=4096;", null, null, null);
149
150             sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
151             sqlite3_exec(db, command, null, null, null);
152
153             if(createOptions != readOnly)
154             {
155                sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
156                sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
157                if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
158                   success = false;
159                else
160                   sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
161             }
162
163             if(success)
164                result = SQLiteDatabase { db = db };
165          }
166          delete path;
167       }
168       return result;
169    }
170 }
171
172 class SQLiteField : Field
173 {
174    char * name;
175    Class type;
176    int length;
177    public LinkElement<SQLiteField> link;
178    int num;
179    int sqliteType;
180    SQLiteTable tbl;
181
182    ~SQLiteField()
183    {
184       delete name;
185    }
186
187    const String GetName()
188    {
189       return name;
190    }
191    Class GetType()
192    {
193       return type;
194    }
195    int GetLength() { return length; }
196    Field GetPrev()
197    {
198       return link.prev;
199    }
200    Field GetNext()
201    {
202       return link.next;
203    }
204    Table GetTable()
205    {
206       return tbl;
207    }
208 }
209
210 class SQLiteDatabase : Database
211 {
212    sqlite3 * db;
213    AVLTree<const String> collations { };
214
215    ~SQLiteDatabase()
216    {
217       sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
218       // "Simply setting the locking-mode to NORMAL is not enough - locks are not released until the next time the database file is accessed."
219       sqlite3_exec(db, "SELECT COUNT(*) from eda_table_fields", null, null, null);
220       sqlite3_close(db);
221    }
222
223    uint ObjectsCount(ObjectType type)
224    {
225       // TODO
226       return 0;
227    }
228
229    bool RenameObject(ObjectType type, const String name, const String rename)
230    {
231       // TODO
232       return false;
233    }
234
235    bool DeleteObject(ObjectType type, const String name)
236    {
237       // TODO
238       return false;
239    }
240
241    Table OpenTable(const String name, OpenOptions options)
242    {
243       char command[1024];
244       //int result;
245       int nRows = 0, nCols = 0;
246       char ** t;
247       SQLiteTable table = null;
248       if(options.type == tablesList)
249       {
250          SQLiteField field;
251          strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
252          table = SQLiteTable { db = this, specialStatement = CopyString(command) };
253          field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
254          LinkTable(table);
255          incref field;
256          table._fields.Add(field);
257       }
258       else if(options.type == fieldsList)
259       {
260          SQLiteField field;
261
262          sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
263          table = SQLiteTable { db = this, specialStatement = CopyString(command) };
264          LinkTable(table);
265          field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
266          incref field;
267          table._fields.Add(field);
268          field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
269          incref field;
270          table._fields.Add(field);
271          field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
272          incref field;
273          table._fields.Add(field);
274       }
275       else if(options.type == tableRows)
276       {
277          bool addFields = false;
278
279          sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
280          /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
281          if(!nRows && !nCols)
282             addFields = true;
283
284          sqlite3_free_table(t);
285
286          sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
287          nCols = 0, nRows = 0;
288          /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
289
290          if((nCols || nRows) || options.create)
291          {
292             table = SQLiteTable { db = this, name = CopyString(name) };
293             LinkTable(table);
294             if(!nCols && !nRows)
295                table.mustCreate = true;
296             else
297             {
298                if(addFields)
299                {
300                   int r;
301                   for(r = 1; r <= nRows; r++)      // There should be only 1 row here
302                   {
303                      char * sql = t[nCols * r];
304                      char * bracket = strchr(sql, '(');
305                      if(bracket)
306                      {
307                         int c = 0;
308                         bracket++;
309                         while(true)
310                         {
311                            char ch;
312                            char fieldName[256];
313                            char dataType[256];
314                            int d;
315                            int start = c;
316                            int sqliteType = SQLITE_BLOB;
317                            Class type = class(int);
318                            fieldName[0] = 0;
319                            dataType[0] = 0;
320
321                            while((ch = bracket[c++]))
322                            {
323                               if(ch == ',' || ch == ')')
324                                  break;
325                            }
326                            for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
327
328                            memcpy(fieldName, bracket + start, d - start);
329                            fieldName[d - start] = 0;
330
331                            memcpy(dataType, bracket + d + 1, c - d - 2);
332                            dataType[c - d - 2] = 0;
333
334                            while(ch && bracket[c] == ' ') c++;
335
336                            if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
337                            else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
338                            else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
339                            else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
340
341                            sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
342                               fieldName, type.name, 0);
343                            /*result = */sqlite3_exec(db, command, null, null, null);
344
345                            {
346                               SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table._fields.count, sqliteType = sqliteType };
347                               incref field;
348                               table._fields.Add(field);
349                            }
350
351                            if(!ch || ch == ')') break;
352                         }
353                      }
354                   }
355                }
356                else
357                {
358                   Table refTable = null;
359                   sqlite3_stmt * statement;
360
361                   sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
362                   /*result = */sqlite3_prepare_v2(db, command, -1, &statement, null);
363
364                   while(sqlite3_step(statement) != SQLITE_DONE)
365                   {
366                      const char * fieldName = (const char *)sqlite3_column_text(statement, 0);
367                      const char * typeName = (const char *)sqlite3_column_text(statement, 1);
368                      int length = sqlite3_column_int(statement, 2);
369                      Class type = null;
370                      int sqliteType = SQLITE_BLOB;
371
372                      type.OnGetDataFromString(typeName);
373
374                      if(type)
375                      {
376                         if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
377                            !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
378                            !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
379                            !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
380                            !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
381                            !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
382                            sqliteType = SQLITE_INTEGER;
383                         else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
384                            sqliteType = SQLITE_FLOAT;
385                         else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
386                            sqliteType = SQLITE_TEXT;
387                         else
388                         {
389                            if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
390                            {
391                               collations.Add(type.fullName);
392                               sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
393                            }
394                            sqliteType = SQLITE_BLOB;
395                         }
396                      }
397
398                      {
399                         Table * fTable = (Table *)(intptr)eClass_GetProperty(type, "table");
400                         SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table._fields.count, sqliteType = sqliteType };
401                         incref field;
402                         if(fTable) refTable = *fTable;
403                         if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
404                            table.primaryKey = field;
405
406                         table._fields.Add(field);
407                      }
408                   }
409                   sqlite3_finalize(statement);
410                }
411             }
412          }
413          sqlite3_free_table(t);
414       }
415       return (Table)table;
416    }
417
418    bool Begin()
419    {
420       char command[1024];
421       int result;
422       sprintf(command, "BEGIN;");
423       result = sqlite3_exec(db, command, null, null, null);
424       if(result)
425          PrintLn($"BEGIN FAILED!");
426       return result == SQLITE_OK;
427    }
428
429    bool Commit()
430    {
431       char command[1024];
432       int result;
433       sprintf(command, "COMMIT;");
434       result = sqlite3_exec(db, command, null, null, null);
435       if(result)
436          PrintLn($"COMMIT FAILED!");
437       return result == SQLITE_OK;
438    }
439
440    bool CreateCustomFunction(const char * name, SQLCustomFunction customFunction)
441    {
442       bool result = false;
443       Class cfClass = customFunction._class;
444       customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
445       if(customFunction.method)
446       {
447          String typeString = CopyString(customFunction.method.dataTypeString);
448          char * tokens[256];
449          int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
450          int c;
451          bool variadic = false;
452
453          for(c = 0; c < count; c++)
454          {
455             Class type = null;
456             bool pointer = false;
457             const String arg = tokens[c];
458             char * space;
459             TrimLSpaces(tokens[c], tokens[c]);
460             if(strchr(arg, '*')) pointer = true;
461             if(pointer)
462                // Using String for generic pointer...
463                type = class(String);
464             else
465             {
466                if((space = strchr(arg, ' '))) *space = 0;
467                if(!strcmp(arg, "void"))
468                   type = null;
469                else if(!strcmp(arg, "..."))
470                   variadic = true;
471                else
472                {
473                   if(cfClass.templateParams.count)
474                   {
475                      ClassTemplateParameter p;
476                      int id = 0;
477                      for(p = cfClass.templateParams.first; p; p = p.next, id++)
478                      {
479                         if(!strcmp(p.name, arg))
480                            break;
481                      }
482                      if(p && cfClass.templateArgs)
483                         arg = cfClass.templateArgs[id].dataTypeString;
484                   }
485                   type = eSystem_FindClass(customFunction._class.module, arg);
486                   if(!type)
487                      type = eSystem_FindClass(customFunction._class.module.application, arg);
488                }
489             }
490             if(c == 0)
491                customFunction.returnType = type;
492             else
493                customFunction.args.Add(type);
494          }
495          delete typeString;
496          if(variadic)
497          {
498             result = false;
499             // Variadic args don't make sense for SQL custom functions
500             // Note that different CIF must be prepared for different set of arguments
501             // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
502          }
503          else
504          {
505             customFunction.rType = FFIGetType(customFunction.returnType, true);
506             customFunction.argTypes.Add((void *)&ffi_type_pointer);    // This pointer for SQLCustomFunction object
507             for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
508             ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
509             result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
510          }
511       }
512       return result;
513    }
514 }
515
516 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
517 FFITypesHolder structFFITypes { };
518 __attribute__((unused)) static Iterator dummy; // TOFIX: forward struct declaration issues on Clang
519
520 public ffi_type * FFIGetType(Class type, bool structByValue)
521 {
522    if(type)
523       switch(type.type)
524       {
525          // Pointer Types
526          case structClass:
527             if(structByValue)
528             {
529                MapIterator<Class, String> it { map = structFFITypes };
530                ffi_type * ffiType = null;
531                if(it.Index(type, false))
532                   ffiType = (void *)it.data;
533                else
534                {
535                   /*
536                   DataMember member;
537                   Array<String> memberTypes { };
538                   for(member = type.membersAndProperties.first; member; member = member.next)
539                   {
540                      if(!member.isProperty)
541                      {
542                         memberTypes.Add(FFIGetType(member.dataType
543                      }
544                   }
545                   */
546                   ffiType = new0 ffi_type[1];
547                   ffiType->size = type.structSize;
548                   ffiType->type = FFI_TYPE_STRUCT;
549                   structFFITypes[type] = (void *)ffiType;
550                }
551                return ffiType;
552             }
553          case normalClass:
554          case noHeadClass:
555          case unionClass:
556             return &ffi_type_pointer;
557          // Scalar Types
558          case bitClass:
559          case enumClass:
560          case systemClass:
561          case unitClass:
562                  if(!strcmp(type.dataTypeString, "float"))  return &ffi_type_float;
563             else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
564             else
565                switch(type.typeSize)
566                {
567                   case 1: return &ffi_type_uint8;
568                   case 2: return &ffi_type_uint16;
569                   case 4: return &ffi_type_uint32;
570                   case 8: return &ffi_type_uint64;
571                }
572       }
573    else
574       return &ffi_type_void;
575    return null;
576 }
577
578 static SerialBuffer staticBuffer { };
579 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
580 {
581    SQLCustomFunction sqlFunction = sqlite3_user_data(context);
582
583    /*  // Simple 1 pointer param returning a string
584    void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
585    sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
586    */
587    int64 retData = 0;
588    void * ret = &retData;
589    Array<String> args { size = sqlFunction.args.count + 1 };
590    Iterator<String> ffiArg { sqlFunction.argTypes };
591    Iterator<String> arg { args };
592    int i = 0;
593
594    // this * for the SQLCustomFunction
595    args[0] = (void *)&sqlFunction;
596    ffiArg.Next();
597    // Get the arguments from SQLite
598    for(a : sqlFunction.args)
599    {
600       ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
601       if(i >= n) break;
602       switch(a.type)
603       {
604          case normalClass:
605          case noHeadClass:
606          case structClass:
607          case unionClass:
608          {
609             void ** data = new void *[1];
610             args[i+1] = (void *)data;
611             if(a == class(String))
612             {
613                int numBytes = sqlite3_value_bytes(values[i]);
614                const char * text = (const char *)sqlite3_value_text(values[i]);
615                *(char **)data = text ? new byte[numBytes+1] : null;
616                if(text)
617                   memcpy(*(char **)data, text, numBytes+1);
618             }
619             else
620             {
621                SerialBuffer buffer = staticBuffer; //{ };
622                buffer.pos = 0;
623                buffer._size = sqlite3_value_bytes(values[i]);
624                buffer._buffer = (byte *)sqlite3_value_text(values[i]);
625                //buffer._buffer = sqlite3_value_blob(curStatement);
626                buffer.count = buffer._size;
627                if(a.type == structClass)
628                   *data = new byte[a.structSize];
629                ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
630                buffer._buffer = null;
631                //delete buffer;
632             }
633             break;
634          }
635          case bitClass:
636          case enumClass:
637          case systemClass:
638          case unitClass:
639             if(type == &ffi_type_double || type == &ffi_type_float)
640             {
641                double d = sqlite3_value_double(values[i]);
642                if(a.typeSize == 8)
643                {
644                   double * data = new double[1];
645                   args[i+1] = (void *)data;
646                   *data = d;
647                }
648                else
649                {
650                   float * data = new float[1];
651                   args[i+1] = (void *)data;
652                   *data = (float)d;
653                }
654             }
655             else
656             {
657                switch(a.typeSize)
658                {
659                   case 8:
660                   {
661                      int64 * data = new int64[1];
662                      args[i+1] = (void *)data;
663                      *data = sqlite3_value_int64(values[i]);
664                      break;
665                   }
666                   case 4:
667                   {
668                      int * data = new int[1];
669                      args[i+1] = (void *)data;
670                      *data = sqlite3_value_int(values[i]);
671                      break;
672                   }
673                   case 2:
674                   {
675                      short * data = new short[1];
676                      int value;
677                      args[i+1] = (void *)data;
678                      value = sqlite3_value_int(values[i]);
679                      if(value < 0)
680                         *data = (short)value;
681                      else
682                         *(uint16 *)data = (uint16)value;
683                      break;
684                   }
685                   case 1:
686                   {
687                      char * data = new char[1];
688                      int value;
689                      args[i+1] = data;
690                      value = sqlite3_value_int(values[i]);
691                      if(value < 0)
692                         *data = (char)value;
693                      else
694                         *(byte *)data = (byte)value;
695                      break;
696                   }
697                }
698             }
699             break;
700       }
701       i++;
702       ffiArg.Next();
703    }
704    if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
705       ret = new byte[sqlFunction.returnType.typeSize];
706    ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
707    // Give SQLite the return value
708    if(sqlFunction.returnType)
709    {
710       ffi_type * type = sqlFunction.rType;
711       Class r = sqlFunction.returnType;
712       switch(r.type)
713       {
714          case normalClass:
715          case noHeadClass:
716          case structClass:
717          case unionClass:
718          {
719             void * data = ret ? *(void **)ret : null;
720             if(r.type == structClass)
721                data = ret;
722             if(r == class(String))
723             {
724                if(data)
725                   sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
726                else
727                   sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
728             }
729             else
730             {
731                SerialBuffer buffer { };
732                ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
733                sqlite3_result_text(context, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
734                delete buffer;
735
736                // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
737                ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
738             }
739
740             if(r.type == structClass)
741                delete ret;
742             break;
743          }
744          case bitClass:
745          case enumClass:
746          case systemClass:
747          case unitClass:
748             if(type == &ffi_type_double || type == &ffi_type_float)
749             {
750                if(r.typeSize == 8)
751                   sqlite3_result_double(context, *(double *)ret);
752                else
753                   sqlite3_result_double(context, (double)*(float *)ret);
754             }
755             else
756             {
757                switch(r.typeSize)
758                {
759                   case 8:
760                      sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
761                      break;
762                   case 4:
763                      sqlite3_result_int(context, *(int *)ret);
764                      break;
765                   case 2:
766                   {
767                      int value;
768                      //if((int)data < 0)
769                         value = (int)*(short *)ret;
770                      //else
771                         //value = (int)*(uint16 *)ret;
772                      sqlite3_result_int(context, value);
773                      break;
774                   }
775                   case 1:
776                   {
777                      int value;
778                      //if((int)data < 0)
779                         value = (int)*(char *)ret;
780                      //else
781                         //value = (int)*(byte *)ret;
782                      sqlite3_result_int(context, value);
783                      break;
784                   }
785                }
786             }
787             break;
788       }
789    }
790
791    // Free Stuff up
792    arg.Next();
793    for(type : sqlFunction.args; arg.Next())
794    {
795       // Free instance
796       void * data = *(void **)arg.data;
797       ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
798       if(type.type == structClass)
799          delete data;
800       // Free arg holder
801       data = arg.data;
802       delete data;
803    }
804    delete args;
805 }
806
807 class SQLiteTable : Table
808 {
809    char * name;
810    bool mustCreate;
811    SQLiteDatabase db;
812    LinkList<SQLiteField> _fields { };
813    char * specialStatement;
814    SQLiteField primaryKey;
815    FieldIndex * indexFields;
816    int indexFieldsCount;
817    int64 lastID;
818
819    Field AddField(const String fieldName, Class type, int length)
820    {
821       SQLiteField field;
822       char command[1024];
823       char dataType[256];
824       int sqliteType;
825       int result;
826       Table refTable = null;
827       Field idField = null;
828       command[0] = 0;
829
830       if(FindField(fieldName)) return null;
831
832       if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
833          !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
834          !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
835          !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
836          !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
837          !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
838       {
839          strcpy(dataType, "INTEGER");
840          sqliteType = SQLITE_INTEGER;
841       }
842       else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
843       {
844          strcpy(dataType, "REAL");
845          sqliteType = SQLITE_FLOAT;
846       }
847       else if(!strcmp(type.name, "CIString"))
848       {
849          strcpy(dataType, "TEXT");
850          sqliteType = SQLITE_BLOB;
851       }
852       else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
853       {
854          strcpy(dataType, "TEXT");
855          sqliteType = SQLITE_TEXT;
856       }
857       else
858       {
859          //strcpy(dataType, "BLOB");
860          strcpy(dataType, "TEXT");
861          sqliteType = SQLITE_BLOB;
862
863          if(!db.collations.Find(type.fullName))
864          {
865             db.collations.Add(type.fullName);
866             result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
867          }
868       }
869       if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)) && type != class(eda::Id))
870       {
871          Table * table = (Table *)(intptr)eClass_GetProperty(type, "table");
872          if(table) refTable = *table;
873          if(refTable)
874          {
875             if(primaryKey || refTable != this)
876             {
877                for(idField = refTable.firstField; idField; idField = idField.next)
878                   if(eClass_IsDerived(type, idField.type)) break;
879
880                if(!idField)
881                   PrintLn("WARNING: field not yet created for class ", (String)type.name);
882             }
883             else
884                idField = primaryKey;
885          }
886          else
887          {
888             PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
889          }
890       }
891
892       if(mustCreate)
893       {
894          if(sqliteType == SQLITE_BLOB)
895          {
896             if(!strcmp(type.name, "CIString"))
897                sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
898             else
899                sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
900          }
901          else if(refTable)
902          {
903             if(!idField && refTable == this)
904                sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
905             else if(idField)
906                sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
907          }
908          else
909             sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
910          result = sqlite3_exec(db.db, command, null, null, null);
911          if(result) return null;
912          mustCreate = false;
913       }
914       else
915       {
916          if(sqliteType == SQLITE_BLOB)
917          {
918             if(!strcmp(type.name, "CIString"))
919                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
920             else
921                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
922          }
923          else if(refTable)
924          {
925             if(!idField && refTable == this)
926             {
927                PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
928                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
929             }
930             else if(idField)
931                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
932          }
933          else
934             sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
935          result = sqlite3_exec(db.db, command, null, null, null);
936          if(result) return null;
937       }
938
939       sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
940          fieldName, type.name, length);
941       result = sqlite3_exec(db.db, command, null, null, null);
942
943       field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
944       incref field;
945       _fields.Add(field);
946       if(!primaryKey && refTable == this)
947          primaryKey = field;
948       return (Field)field;
949    }
950
951    Field FindField(const String name)
952    {
953       for(f : _fields; !strcmp(f.name, name))
954       {
955          if(!primaryKey)
956          {
957             if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
958             {
959
960                Table * tablePtr = (Table *)(intptr)eClass_GetProperty(f.type, "table");
961                if(tablePtr && *tablePtr == this)
962                   primaryKey = f;
963             }
964          }
965          return (Field)f;
966       }
967       return null;
968    }
969
970    bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
971    {
972       char command[1024];
973       int c;
974       int result;
975       char indexName[4096];
976
977       delete indexFields;
978       indexFieldsCount = count;
979       indexFields = new FieldIndex[count];
980       memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
981
982       // TODO: USE CODED INDEX NAME INSTEAD?
983       strcpy(indexName, "index_");
984       strcat(indexName, name);
985       strcat(indexName, "_");
986       for(c = 0; c<count; c++)
987       {
988          if(fieldIndexes[c].field)
989          {
990             if(count == 1 && fieldIndexes[c].field == primaryKey)
991                return true;
992             strcat(indexName, fieldIndexes[c].field.name);
993             if(fieldIndexes[c].memberField)
994             {
995                strcat(indexName, ".");
996                strcat(indexName, fieldIndexes[c].memberField.name);
997             }
998             strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
999          }
1000          else
1001             return false;
1002       }
1003
1004       sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
1005       for(c = 0; c<count; c++)
1006       {
1007          char columnName[1024];
1008          sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
1009          if(c > 0) strcat(command, ", ");
1010          strcat(command, columnName);
1011       }
1012       strcat(command, ");");
1013       result = sqlite3_exec(db.db, command, null, null, null);
1014
1015       return result == SQLITE_OK;
1016    }
1017
1018    const String GetName()
1019    {
1020       return name;
1021    }
1022
1023    Field GetFirstField()
1024    {
1025       return _fields.first;
1026    }
1027
1028    Field GetPrimaryKey()
1029    {
1030       return primaryKey;
1031    }
1032
1033    uint GetFieldsCount()
1034    {
1035       return _fields.count;
1036    }
1037
1038    uint GetRowsCount()
1039    {
1040       char command[1024];
1041       char **t;
1042       int nCols, nRows;
1043       int result;
1044       uint rowCount = 0;
1045       sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1046       result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1047       if(result == SQLITE_OK)
1048       {
1049          rowCount = atoi(t[1]);
1050          sqlite3_free_table(t);
1051       }
1052       return rowCount;
1053    }
1054
1055    // Returns true if not ordered by row ID
1056    bool GetIndexOrder(char * fullOrder, bool flip)
1057    {
1058       if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1059       {
1060          strcpy(fullOrder, " ORDER BY ROWID");
1061          return false;
1062       }
1063       else
1064       {
1065          int c;
1066          strcpy(fullOrder, " ORDER BY ");
1067          for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1068          {
1069             char order[1024];
1070             FieldIndex * fIndex = &indexFields[c];
1071             order[0] = 0;
1072             if(c) strcat(order, ", ");
1073             strcat(order, "`");
1074             strcat(order, fIndex->field.name);
1075             strcat(order, "`");
1076             if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1077             strcat(fullOrder, order);
1078          }
1079          return true;
1080       }
1081    }
1082
1083    Container<Field> GetFields()
1084    {
1085       return (Container<Field>)_fields;
1086    }
1087
1088    DriverRow CreateRow()
1089    {
1090       char command[1024];
1091       sqlite3_stmt * statement;
1092       sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1093       sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1094
1095       if(specialStatement)
1096          strcpy(command, specialStatement);
1097       else
1098       {
1099          char order[1024];
1100          /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1101          sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1102          sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1103          sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1104
1105          sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1106          sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1107
1108          sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1109          sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1110
1111          sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1112          sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1113
1114          sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1115          sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1116
1117          sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1118          sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1119
1120          sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1121          sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1122
1123          /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1124
1125          sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1126
1127          GetIndexOrder(order, false);
1128          sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1129       }
1130       sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1131
1132       sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1133       sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1134
1135       sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1136       sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1137
1138       return SQLiteRow
1139          { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1140            insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1141            previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1142    }
1143
1144    ~SQLiteTable()
1145    {
1146       delete name;
1147       delete specialStatement;
1148       delete indexFields;
1149       _fields.Free();
1150    }
1151 }
1152
1153 class SQLiteRow : DriverRow
1154 {
1155    SQLiteTable tbl;
1156    sqlite3_stmt * curStatement;
1157
1158    sqlite3_stmt * defaultStatement;
1159    sqlite3_stmt * findStatement;
1160    sqlite3_stmt * prevFindStatement, * lastFindStatement;
1161    sqlite3_stmt * nextFindStatement;
1162    sqlite3_stmt * sysIDStatement;
1163    sqlite3_stmt * queryStatement;
1164    sqlite3_stmt * selectRowIDsStmt;
1165    sqlite3_stmt * setRowIDStmt;
1166    sqlite3_stmt * lastStatement;
1167    sqlite3_stmt * previousStatement;
1168    sqlite3_stmt * nextStatement;
1169
1170    sqlite3_stmt * insertStatement;
1171    sqlite3_stmt * deleteStatement;
1172    sqlite3_stmt * updateStatement;
1173    sqlite3_stmt * insertIDStatement;
1174    bool done;
1175    done = true;
1176    int64 rowID;
1177    // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1178    // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1179    bool findSysID;
1180    int findBindId;
1181
1182    bool Nil()
1183    {
1184       return done;
1185    }
1186
1187    ~SQLiteRow()
1188    {
1189       if(defaultStatement) sqlite3_finalize(defaultStatement);
1190       if(findStatement)    sqlite3_finalize(findStatement);
1191       if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1192       if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1193       if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1194       if(sysIDStatement)   sqlite3_finalize(sysIDStatement);
1195       if(insertStatement)  sqlite3_finalize(insertStatement);
1196       if(deleteStatement)  sqlite3_finalize(deleteStatement);
1197       if(updateStatement)  sqlite3_finalize(updateStatement);
1198       if(queryStatement)   sqlite3_finalize(queryStatement);
1199       if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1200       if(setRowIDStmt)     sqlite3_finalize(setRowIDStmt);
1201       if(previousStatement)sqlite3_finalize(previousStatement);
1202       if(nextStatement)    sqlite3_finalize(nextStatement);
1203       if(lastStatement)    sqlite3_finalize(lastStatement);
1204       if(insertIDStatement)    sqlite3_finalize(insertIDStatement);
1205    }
1206
1207    bool Select(MoveOptions move)
1208    {
1209       int result;
1210       bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1211       if(!curStatement)
1212          curStatement = defaultStatement;
1213       switch(move)
1214       {
1215          case first:
1216          {
1217             sqlite3_reset(curStatement);
1218             result = sqlite3_step(curStatement);
1219             done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1220             if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1221             rowID = sqlite3_column_int64(curStatement, 0);
1222             break;
1223          }
1224          case last:
1225          {
1226             sqlite3_reset(curStatement);
1227             curStatement = lastStatement;
1228             result = sqlite3_step(curStatement);
1229             done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1230             if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1231             rowID = sqlite3_column_int64(curStatement, 0);
1232             break;
1233          }
1234          case middle:
1235             break;
1236          case next:
1237          case previous:
1238          {
1239             // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1240             if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1241                (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1242             {
1243                result = sqlite3_step(curStatement);
1244                done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1245                if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1246                rowID = sqlite3_column_int64(curStatement, 0);
1247             }
1248             else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1249             {
1250                if(rowID)
1251                {
1252                   int bindId = findBindId;
1253                   sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1254                   BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1255                      (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1256                   sqlite3_reset(curStatement);
1257                   curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1258                   result = sqlite3_step(curStatement);
1259                   done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1260                   if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1261                   rowID = sqlite3_column_int64(curStatement, 0);
1262                }
1263                else
1264                {
1265                   sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1266                   sqlite3_reset(curStatement);
1267                   curStatement = (move == next) ? findStatement : lastFindStatement;
1268                   result = sqlite3_step(curStatement);
1269                   done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1270                   if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1271                   rowID = sqlite3_column_int64(curStatement, 0);
1272                }
1273             }
1274             else
1275             {
1276                sqlite3_reset(curStatement);
1277                curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1278                sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1279                result = sqlite3_step(curStatement);
1280                done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1281                if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1282                rowID = sqlite3_column_int64(curStatement, 0);
1283             }
1284             break;
1285          }
1286          case nil:
1287             sqlite3_reset(curStatement);
1288             rowID = 0;
1289             done = true;
1290             break;
1291          case here:
1292             break;
1293       }
1294       return true;
1295    }
1296
1297    bool Query(const char * queryString)
1298    {
1299       bool status = true;
1300       int result;
1301
1302       if(curStatement)
1303          sqlite3_reset(curStatement);
1304       if(queryStatement)
1305       {
1306          sqlite3_finalize(queryStatement);
1307          queryStatement = null;
1308       }
1309
1310       if(queryString)
1311       {
1312          result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1313          if(!result)
1314          {
1315             curStatement = queryStatement;
1316             if(!strchr(queryString, '?'))
1317             {
1318                result = sqlite3_step(queryStatement);
1319
1320                done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1321                if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1322
1323                rowID = sqlite3_column_int64(queryStatement, 0);
1324             }
1325          }
1326          else
1327          {
1328             printf("SQLite Query Error: %s\n", queryString);
1329             status = false;
1330          }
1331       }
1332       else
1333          curStatement = null;
1334       return status;
1335    }
1336
1337    bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1338    {
1339       int result = 1;
1340       Class dataType = fld.type;
1341       SerialBuffer buffer = null;
1342       switch(fld.sqliteType)
1343       {
1344          case SQLITE_INTEGER:
1345          {
1346             switch(dataType.typeSize)
1347             {
1348                case 8:
1349                   result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1350                   break;
1351                case 4:
1352                   result = sqlite3_bind_int(statement, pos, *(int *)data);
1353                   break;
1354                case 2:
1355                {
1356                   int value;
1357                   if((int)data < 0)
1358                      value = (int)*(short *)data;
1359                   else
1360                      value = (int)*(uint16 *)data;
1361                   result = sqlite3_bind_int(statement, pos, value);
1362                   break;
1363                }
1364                case 1:
1365                {
1366                   int value;
1367                   if((int)data < 0)
1368                      value = (int)*(char *)data;
1369                   else
1370                      value = (int)*(byte *)data;
1371                   result = sqlite3_bind_int(statement, pos, value);
1372                   break;
1373                }
1374             }
1375             break;
1376          }
1377          case SQLITE_FLOAT:
1378          {
1379             if(dataType.typeSize == 8)
1380                result = sqlite3_bind_double(statement, pos, *(double *)data);
1381             else
1382                result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1383             break;
1384          }
1385          case SQLITE_TEXT:
1386          {
1387             if((char *)data)
1388                result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1389             else
1390                result = sqlite3_bind_null(statement, pos);
1391             break;
1392          }
1393          case SQLITE_BLOB:
1394          case SQLITE_NULL:
1395          {
1396             if((void *)data && dataType)
1397             {
1398                buffer = SerialBuffer { };
1399                ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1400                result = sqlite3_bind_text(statement, pos, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1401             }
1402             else
1403                result = sqlite3_bind_null(statement, pos);
1404             break;
1405          }
1406       }
1407       if(bufferOut)
1408          *bufferOut = buffer;
1409       else
1410          delete buffer;
1411       return !result;
1412    }
1413
1414    void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1415    {
1416       if(move == next || move == previous)
1417       {
1418          // Where clauses for index
1419          if(useIndex)
1420          {
1421             int c;
1422             bool gotPrimaryKey = false;
1423
1424             strcatf(command, " AND (");
1425             for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1426             {
1427                char where[1024];
1428                FieldIndex * fIndex = &tbl.indexFields[c];
1429                where[0] = 0;
1430
1431                strcat(where, "`");
1432                strcat(where, fIndex->field.name);
1433                strcat(where, "` ");
1434                strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1435                strcat(where, " ? OR (");
1436                strcat(where, fIndex->field.name);
1437                if(fIndex->field == tbl.primaryKey)
1438                   gotPrimaryKey = true;
1439                strcat(where, " = ? AND (");
1440                strcat(command, where);
1441             }
1442             strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1443             for(c = 0; c < tbl.indexFieldsCount; c++)
1444                strcat(command, "))");
1445          }
1446          else
1447             strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1448       }
1449    }
1450
1451    void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1452    {
1453       if(move == next || move == previous)
1454       {
1455          // The binds for the Extra ordering Where clauses
1456          if(useIndex)
1457          {
1458             int c;
1459             /* // Code to not rely on curStatement being set up
1460             SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1461             dataRow.GoToSysID((uint)rowID);
1462             */
1463             for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1464             {
1465                FieldIndex * fIndex = &tbl.indexFields[c];
1466                int64 data;
1467                SQLiteField fld = (SQLiteField)fIndex->field;
1468                Class type = fld.type;
1469                void * dataPtr;
1470                SerialBuffer buffer;
1471
1472                if(type.type == unitClass && !type.typeSize)
1473                {
1474                   Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1475                   if(dataType)
1476                      type = dataType;
1477                }
1478                if(type.type == structClass)
1479                {
1480                   data = (int64)(intptr)new0 byte[type.structSize];
1481                   dataPtr = (void *)(intptr)data;
1482                }
1483                // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1484                ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)(intptr)data : &data);
1485                if(type.type == normalClass || type.type == noHeadClass)
1486                   dataPtr = (void *)(intptr)data;
1487                else
1488                   dataPtr = &data;
1489                ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1490                // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1491                // Reuse the buffer for Blobs...
1492                if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1493                {
1494                   sqlite3_bind_text(stmt, (*bindId)++, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1495                   delete buffer;
1496                }
1497                else
1498                   ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1499
1500                ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1501             }
1502             // delete dataRow;
1503          }
1504
1505          // Bind for the rowid
1506          sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1507       }
1508    }
1509
1510    bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1511    {
1512       char order[1024], command[2048];
1513       int result;
1514       bool useIndex;
1515       sqlite3_stmt * stmt = null;
1516       int bindId = 1;
1517
1518       if(fld == tbl.primaryKey)
1519       {
1520          if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1521          if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1522          if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1523          if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1524          if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1525          result = GoToSysID(*(int *)data);
1526          if(result)
1527             findSysID = true;
1528          return result != 0;
1529       }
1530
1531       useIndex = tbl.GetIndexOrder(order, false);
1532       // Basic Find
1533       sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1534       AddCursorWhereClauses(command, move, useIndex);
1535       strcat(command, order);
1536       strcat(command, ";");
1537       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1538       BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1539       BindCursorData(stmt, move, useIndex, &bindId);
1540
1541       // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1542       if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1543       if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1544       if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1545       if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1546       if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1547
1548       curStatement = findStatement = stmt;
1549       findBindId = bindId;
1550
1551       // For going back to forward find
1552       bindId = 1;
1553       sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1554       AddCursorWhereClauses(command, next, useIndex);
1555       strcat(command, order);
1556       strcat(command, ";");
1557       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1558       BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1559       nextFindStatement = stmt;
1560
1561       // Backwards
1562       tbl.GetIndexOrder(order, true);
1563       // For tracing back finds
1564       bindId = 1;
1565       sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1566       AddCursorWhereClauses(command, previous, true);
1567       strcat(command, order);
1568       strcat(command, ";");
1569       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1570       BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1571       prevFindStatement = stmt;
1572
1573       // For tracing back from last
1574       bindId = 1;
1575       sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1576       strcat(command, order);
1577       strcat(command, ";");
1578       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1579       BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1580       lastFindStatement = stmt;
1581
1582       result = sqlite3_step(findStatement);
1583
1584       done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1585       if(done)
1586       {
1587          rowID = 0;
1588          sqlite3_reset(findStatement);
1589       }
1590       else
1591          rowID = sqlite3_column_int64(findStatement, 0);
1592       return !done;
1593    }
1594
1595    bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1596    {
1597 #define BINDDATA \
1598          for(c = 0; c < numFields; c++) \
1599          { \
1600             FieldFindData * fieldFind = &findData[c]; \
1601             SQLiteField sqlFld = (SQLiteField)findData->field; \
1602             Class dataType = sqlFld.type; \
1603             BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i64, null); \
1604          }
1605
1606       if(numFields)
1607       {
1608          char criterias[4096], command[4096], order[1024];
1609          int result;
1610          int c;
1611          bool useIndex;
1612          sqlite3_stmt * stmt = null;
1613          int bindId = 1;
1614
1615          // Criterias
1616          sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1617          for(c = 0; c < numFields; c++)
1618          {
1619             FieldFindData * fieldFind = &findData[c];
1620
1621             if(c) strcat(criterias, " AND `");
1622             strcat(criterias, fieldFind->field.name);
1623             strcat(criterias, "` = ?");
1624          }
1625
1626          useIndex = tbl.GetIndexOrder(order, false);
1627          // Basic Find (multiple)
1628          strcpy(command, criterias);
1629          AddCursorWhereClauses(command, move, useIndex);
1630          strcat(command, order);
1631          strcat(command, ";");
1632          result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1633          BINDDATA;
1634          BindCursorData(stmt, move, useIndex, &bindId);
1635
1636          // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1637          if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1638          if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1639          if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1640          if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1641          if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1642
1643          curStatement = findStatement = stmt;
1644          findBindId = bindId;
1645
1646          // For tracing back forward finds
1647          bindId = 1;
1648          strcpy(command, criterias);
1649          AddCursorWhereClauses(command, previous, true);
1650          strcat(command, order);
1651          strcat(command, ";");
1652          result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1653          BINDDATA;
1654          nextFindStatement = stmt;
1655
1656          // Backwards
1657          tbl.GetIndexOrder(order, true);
1658          // For tracing back finds
1659          bindId = 1;
1660          strcpy(command, criterias);
1661          AddCursorWhereClauses(command, next, useIndex);
1662          strcat(command, order);
1663          strcat(command, ";");
1664          result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1665          BINDDATA;
1666          prevFindStatement = stmt;
1667
1668          // For tracing back from last
1669          bindId = 1;
1670          strcpy(command, criterias);
1671          strcat(command, order);
1672          strcat(command, ";");
1673          result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1674          BINDDATA;
1675          lastFindStatement = stmt;
1676
1677          result = sqlite3_step(findStatement);
1678          done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1679          if(done)
1680          {
1681             rowID = 0;
1682             sqlite3_reset(findStatement);
1683          }
1684          else
1685             rowID = sqlite3_column_int64(findStatement, 0);
1686          return !done;
1687       }
1688       return false;
1689    }
1690
1691    bool Synch(DriverRow to)
1692    {
1693       SQLiteRow rowTo = (SQLiteRow)to;
1694       if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1695          return GoToSysID((uint)rowTo.rowID);
1696       return false;
1697    }
1698
1699    bool Add(uint64 id)
1700    {
1701       int result;
1702       //char command[1024];
1703       //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1704       //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1705       if(id)
1706       {
1707          sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1708          result = sqlite3_step(insertIDStatement);
1709       }
1710       else
1711          result = sqlite3_step(insertStatement);
1712       if(result == SQLITE_DONE)     // if(result == SQLITE_OK)
1713       {
1714          rowID = sqlite3_last_insert_rowid(tbl.db.db);
1715          if(rowID > MAXDWORD)
1716          {
1717             int64 lastID = tbl.lastID;
1718
1719             sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1720             while(true)
1721             {
1722                int64 id;
1723                result = sqlite3_step(selectRowIDsStmt);
1724                if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1725                id = sqlite3_column_int64(selectRowIDsStmt, 0);
1726                if(id - lastID > 1) break;
1727                lastID = id;
1728             }
1729             sqlite3_reset(selectRowIDsStmt);
1730
1731             sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1732             rowID = lastID + 1;
1733             tbl.lastID = rowID;
1734             sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1735             result = sqlite3_step(setRowIDStmt);
1736             sqlite3_reset(setRowIDStmt);
1737          }
1738          sqlite3_reset(id ? insertIDStatement : insertStatement);
1739          curStatement = sysIDStatement;
1740          findSysID = false;
1741          sqlite3_reset(curStatement);
1742          sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1743          result = sqlite3_step(curStatement);
1744          done = false; // Make sure 'nil' is false
1745          return true;
1746       }
1747       sqlite3_reset(insertStatement);
1748       return false;
1749    }
1750
1751    bool Delete()
1752    {
1753       int result;
1754       //char command[1024];
1755       //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1756       //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1757       sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1758       result = sqlite3_step(deleteStatement);
1759       sqlite3_reset(deleteStatement);
1760       rowID = 0;
1761       return result == SQLITE_OK || result == SQLITE_DONE;
1762    }
1763
1764    bool GetData(Field fld, typed_object &data)
1765    {
1766       SQLiteField sqlFld = (SQLiteField)fld;
1767       int num = sqlFld.num + 1;
1768       Class dataType = *&sqlFld.type;
1769
1770
1771       switch(sqlFld.sqliteType)
1772       {
1773          case SQLITE_INTEGER:
1774          {
1775             switch(dataType.typeSize)
1776             {
1777                case 8:
1778                   if(fld == tbl.primaryKey)
1779                      *(int64 *)data = rowID;
1780                   else
1781                      *(int64 *)data = sqlite3_column_int64(curStatement, num);
1782                   break;
1783                case 4:
1784                   if(fld == tbl.primaryKey)
1785                      *(int *)data = (int)(uint)rowID;
1786                   else
1787                      *(int *)data = sqlite3_column_int(curStatement, num);
1788                   break;
1789                case 2:
1790                {
1791                   int value;
1792                   if(fld == tbl.primaryKey)
1793                      value = (int)(uint)rowID;
1794                   else
1795                      value = sqlite3_column_int(curStatement, num);
1796                   if(value < 0)
1797                      *(short *)data = (short)value;
1798                   else
1799                      *(uint16 *)data = (uint16)value;
1800                   break;
1801                }
1802                case 1:
1803                {
1804                   int value;
1805                   if(fld == tbl.primaryKey)
1806                      value = (int)(uint)rowID;
1807                   else
1808                      value = sqlite3_column_int(curStatement, num);
1809                   if(value < 0)
1810                      *(char *)data = (char)value;
1811                   else
1812                      *(byte *)data = (byte)value;
1813                   break;
1814                }
1815             }
1816             break;
1817          }
1818          case SQLITE_FLOAT:
1819          {
1820             double d = sqlite3_column_double(curStatement, num);
1821             if(dataType.typeSize == 8)
1822                *(double *)data = d;
1823             else
1824                *(float *)data = (float)d;
1825             break;
1826          }
1827          case SQLITE_TEXT:
1828          {
1829             int numBytes = sqlite3_column_bytes(curStatement, num);
1830             const char * text = (const char *)sqlite3_column_text(curStatement, num);
1831             *(char **)data = text ? new byte[numBytes+1] : null;
1832             if(text)
1833                memcpy(*(char **)data, text, numBytes+1);
1834             break;
1835          }
1836          case SQLITE_BLOB:
1837          {
1838             SerialBuffer buffer { };
1839             //buffer._buffer = sqlite3_column_blob(curStatement, num);
1840             buffer._size = sqlite3_column_bytes(curStatement, num);
1841             buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
1842             buffer.count = buffer._size;
1843
1844             ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1845
1846             buffer._buffer = null;
1847             delete buffer;
1848             break;
1849          }
1850       }
1851       return true;
1852    }
1853
1854    bool SetData(Field fld, typed_object data)
1855    {
1856       SQLiteField sqlFld = (SQLiteField)fld;
1857       int result;
1858       char command[1024];
1859
1860       if(updateStatement)
1861          sqlite3_finalize(updateStatement);
1862       sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1863       // TODO: Shouldn't we cache those update statements per field?
1864       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1865       sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1866       BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1867       result = sqlite3_step(updateStatement);
1868       sqlite3_reset(updateStatement);
1869       if(fld == tbl.primaryKey)
1870          rowID = *(uint64 *)data;
1871       return result == SQLITE_DONE;
1872    }
1873
1874    uint64 GetSysID()
1875    {
1876       return (int64)rowID;
1877    }
1878
1879    bool GoToSysID(uint64 id)
1880    {
1881       //char command[1024];
1882       int result;
1883       rowID = (int64)id;
1884       //if(statement)
1885          //sqlite3_finalize(statement);
1886       //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1887       //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1888
1889       findSysID = false;
1890       if(curStatement)
1891          sqlite3_reset(curStatement);
1892
1893       curStatement = sysIDStatement;
1894       sqlite3_reset(sysIDStatement);
1895       sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1896       result = sqlite3_step(curStatement);
1897       done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1898       if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1899       return !done;
1900    }
1901
1902    bool SetQueryParam(int paramID, int value)
1903    {
1904       int result;
1905       if(curStatement != queryStatement)
1906       {
1907          if(curStatement) sqlite3_reset(curStatement);
1908          curStatement = queryStatement;
1909       }
1910       sqlite3_reset(queryStatement);
1911       result = sqlite3_bind_int(queryStatement, paramID, value);
1912       return !result;
1913    }
1914
1915    bool SetQueryParam64(int paramID, int64 value)
1916    {
1917       int result;
1918       if(curStatement != queryStatement)
1919       {
1920          if(curStatement) sqlite3_reset(curStatement);
1921          curStatement = queryStatement;
1922       }
1923       sqlite3_reset(queryStatement);
1924       result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1925       return !result;
1926    }
1927
1928    bool SetQueryParamText(int paramID, const char * data)
1929    {
1930       int result;
1931       if(curStatement != queryStatement)
1932       {
1933          if(curStatement) sqlite3_reset(curStatement);
1934          curStatement = queryStatement;
1935       }
1936       sqlite3_reset(queryStatement);
1937       if(data)
1938          result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1939       else
1940          result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1941       return !result;
1942    }
1943
1944    bool SetQueryParamObject(int paramID, const void * data, Class type)
1945    {
1946       int result;
1947       if(curStatement != queryStatement)
1948       {
1949          if(curStatement) sqlite3_reset(curStatement);
1950          curStatement = queryStatement;
1951       }
1952       sqlite3_reset(queryStatement);
1953       {
1954          SerialBuffer buffer { };
1955          ((void (*)(void *, const void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1956          result = sqlite3_bind_text(queryStatement, paramID, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1957          delete buffer;
1958       }
1959       return !result;
1960    }
1961
1962    bool BindQueryData(int pos, SQLiteField fld, typed_object data)
1963    {
1964       if(curStatement != queryStatement)
1965       {
1966          if(curStatement) sqlite3_reset(curStatement);
1967          curStatement = queryStatement;
1968       }
1969       sqlite3_reset(queryStatement);
1970       return BindData(queryStatement, pos, fld, data, null);
1971    }
1972
1973    bool GetQueryData(int num, SQLiteField fld, typed_object & data)
1974    {
1975       SQLiteField sqlFld = (SQLiteField)fld;
1976       Class dataType = *&sqlFld.type;
1977
1978       switch(sqlFld.sqliteType)
1979       {
1980          case SQLITE_INTEGER:
1981          {
1982             switch(dataType.typeSize)
1983             {
1984                case 8:
1985                   if(fld == tbl.primaryKey)
1986                      *(int64 *)data = rowID;
1987                   else
1988                      *(int64 *)data = sqlite3_column_int64(curStatement, num);
1989                   break;
1990                case 4:
1991                   if(fld == tbl.primaryKey)
1992                      *(int *)data = (int)(uint)rowID;
1993                   else
1994                      *(int *)data = sqlite3_column_int(curStatement, num);
1995                   break;
1996                case 2:
1997                {
1998                   int value;
1999                   if(fld == tbl.primaryKey)
2000                      value = (int)(uint)rowID;
2001                   else
2002                      value = sqlite3_column_int(curStatement, num);
2003                   if(value < 0)
2004                      *(short *)data = (short)value;
2005                   else
2006                      *(uint16 *)data = (uint16)value;
2007                   break;
2008                }
2009                case 1:
2010                {
2011                   int value;
2012                   if(fld == tbl.primaryKey)
2013                      value = (int)(uint)rowID;
2014                   else
2015                      value = sqlite3_column_int(curStatement, num);
2016                   if(value < 0)
2017                      *(char *)data = (char)value;
2018                   else
2019                      *(byte *)data = (byte)value;
2020                   break;
2021                }
2022             }
2023             break;
2024          }
2025          case SQLITE_FLOAT:
2026          {
2027             double d = sqlite3_column_double(curStatement, num);
2028             if(dataType.typeSize == 8)
2029                *(double *)data = d;
2030             else
2031                *(float *)data = (float)d;
2032             break;
2033          }
2034          case SQLITE_TEXT:
2035          {
2036             int numBytes = sqlite3_column_bytes(curStatement, num);
2037             const char * text = (const char *)sqlite3_column_text(curStatement, num);
2038             *(char **)data = text ? new byte[numBytes+1] : null;
2039             if(text)
2040                memcpy(*(char **)data, text, numBytes+1);
2041             break;
2042          }
2043          case SQLITE_BLOB:
2044          {
2045             SerialBuffer buffer { };
2046             //buffer._buffer = sqlite3_column_blob(curStatement, num);
2047             buffer._size = sqlite3_column_bytes(curStatement, num);
2048             buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
2049             buffer.count = buffer._size;
2050
2051             ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
2052
2053             buffer._buffer = null;
2054             delete buffer;
2055             break;
2056          }
2057       }
2058       return true;
2059    }
2060
2061    /*char * GetExtraColumn(int paramID)
2062    {
2063       SQLiteField lastFld = tbl._fields.last;
2064       return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
2065    }*/
2066    const char * GetColumn(int paramID)
2067    {
2068       return (const char *)sqlite3_column_text(curStatement, paramID);
2069    }
2070 }