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