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