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