EDA:SQLite:SQLiteCipher: moved code common to both drivers into EDASQLiteCommon.ec...
[sdk] / eda / drivers / sqlite / EDASQLiteCommon.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 #include "sqlite3.h"
10
11 static void UnusedFunction()
12 {
13    int a;
14    a.OnGetString(0,0,0);
15    a.OnFree();
16    a.OnCopy(null);
17    a.OnCompare(null);
18    a.OnSaveEdit(null,0);
19    a.OnEdit(null,null,0,0,0,0,0);
20    a.OnDisplay(null,0,0,0,0,0,0);
21    a.OnGetDataFromString(null);
22    a.OnUnserialize(null);
23    a.OnSerialize(null);
24 }
25
26 default:
27 extern int __ecereVMethodID_class_OnGetString;
28 extern int __ecereVMethodID_class_OnGetDataFromString;
29 extern int __ecereVMethodID_class_OnCompare;
30 extern int __ecereVMethodID_class_OnSerialize;
31 extern int __ecereVMethodID_class_OnUnserialize;
32 extern int __ecereVMethodID_class_OnFree;
33 private:
34
35 static int CollationCompare(Class type, int count1, void * data1, int count2, void * data2)
36 {
37    if(type.type == normalClass || type.type ==  noHeadClass)
38    {
39       Instance inst1, inst2;
40       int result;
41       SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
42       SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
43
44       type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
45       type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
46
47       result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
48      
49       buffer1.buffer = null;
50       buffer2.buffer = null;
51       delete buffer1;
52       delete buffer2;
53       inst1.OnFree();
54       inst2.OnFree();
55       return result;
56    }
57    else if(type.type == structClass)
58    {
59       void * inst1, * inst2;
60       int result;
61       SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
62       SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
63
64       inst1 = new0 byte[type.structSize];
65       inst2 = new0 byte[type.structSize];
66       type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
67       type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
68
69       result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
70      
71       buffer1.buffer = null;
72       buffer2.buffer = null;
73       delete buffer1;
74       delete buffer2;
75       delete inst1;
76       delete inst2;
77       return result;
78    }
79    else
80       return type._vTbl[__ecereVMethodID_class_OnCompare](type, data1, data2);
81 }
82
83 class SQLiteField : Field
84 {
85    char * name;
86    Class type;
87    int length;
88    public LinkElement<SQLiteField> link;
89    int num;
90    int sqliteType;
91
92    ~SQLiteField()
93    {
94       delete name;
95    }
96
97    String GetName()
98    {
99       return name;
100    }
101    Class GetType()
102    {
103       return type;
104    }
105    int GetLength() { return length; }
106    Field GetPrev()
107    {
108       return link.prev;
109    }
110    Field GetNext()
111    {
112       return link.next;
113    }
114 }
115
116 class SQLiteDatabase : Database
117 {
118    sqlite3 * db;
119    AVLTree<String> collations { };
120    
121    ~SQLiteDatabase()
122    {
123       sqlite3_close(db);
124    }
125
126    uint ObjectsCount(ObjectType type)
127    {
128       // TODO
129       return 0;
130    }
131
132    bool RenameObject(ObjectType type, const String name, const String rename)
133    {
134       // TODO
135       return false;
136    }
137
138    bool DeleteObject(ObjectType type, const String name)
139    {
140       // TODO
141       return false;
142    }
143
144    Table OpenTable(const String name, OpenOptions options)
145    {
146       char command[1024];
147       int result;
148       int nRows = 0, nCols = 0;
149       char ** t;
150       SQLiteTable table = null;
151       if(options.type == tablesList)
152       {
153          SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
154          strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
155          table = SQLiteTable { db = this, specialStatement = CopyString(command) };
156          LinkTable(table);
157          incref field;
158          table.fields.Add(field);
159       }
160       else if(options.type == fieldsList)
161       {
162          SQLiteField field;
163
164          sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
165          table = SQLiteTable { db = this, specialStatement = CopyString(command) };
166          LinkTable(table);
167          field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
168          incref field;
169          table.fields.Add(field);
170          field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
171          incref field;
172          table.fields.Add(field);
173          field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
174          incref field;
175          table.fields.Add(field);
176       }
177       else if(options.type == tableRows)
178       {
179          bool addFields = false;
180
181          sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
182          result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
183          if(!nRows && !nCols)
184             addFields = true;
185
186          sqlite3_free_table(t);
187
188          sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
189          nCols = 0, nRows = 0;
190          result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
191          
192          if((nCols || nRows) || options.create)
193          {
194             table = SQLiteTable { db = this, name = CopyString(name) };
195             LinkTable(table);
196             if(!nCols && !nRows)
197                table.mustCreate = true;
198             else
199             {
200                if(addFields)
201                {
202                   int r;
203                   for(r = 1; r <= nRows; r++)      // There should be only 1 row here
204                   {
205                      char * sql = t[nCols * r];
206                      char * bracket = strchr(sql, '(');
207                      if(bracket) 
208                      {
209                         int c = 0;
210                         bracket++;
211                         while(true)
212                         {
213                            char ch;
214                            char fieldName[256];
215                            char dataType[256];
216                            int d;
217                            int start = c;
218                            int sqliteType;
219                            Class type = class(int);
220                            fieldName[0] = 0;
221                            dataType[0] = 0;
222
223                            while((ch = bracket[c++]))
224                            {
225                               if(ch == ',' || ch == ')')
226                                  break;
227                            }
228                            for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
229
230                            memcpy(fieldName, bracket + start, d - start);
231                            fieldName[d - start] = 0;
232
233                            memcpy(dataType, bracket + d + 1, c - d - 2);
234                            dataType[c - d - 2] = 0;
235
236                            while(ch && bracket[c] == ' ') c++;
237                            
238                            if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
239                            else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
240                            else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
241                            else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
242
243                            sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
244                               fieldName, type.name, 0);
245                            result = sqlite3_exec(db, command, null, null, null);
246
247                            {
248                               SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
249                               incref field;
250                               table.fields.Add(field);
251                            }
252
253                            if(!ch || ch == ')') break;
254                         }
255                      }
256                   }
257                }
258                else
259                {
260                   sqlite3_stmt * statement;
261                   
262                   sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
263                   result = sqlite3_prepare_v2(db, command, -1, &statement, null);
264
265                   while(sqlite3_step(statement) != SQLITE_DONE)
266                   {
267                      char * fieldName = sqlite3_column_text(statement, 0);
268                      char * typeName = sqlite3_column_text(statement, 1);
269                      int length = sqlite3_column_int(statement, 2);
270                      Class type = null;
271                      int sqliteType;
272
273                      ((Class)(&type)).OnGetDataFromString(typeName);    // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
274
275                      if(type)
276                      {
277                         if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || 
278                            !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") || 
279                            !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") || 
280                            !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") || 
281                            !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
282                            !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
283                            sqliteType = SQLITE_INTEGER;
284                         else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
285                            sqliteType = SQLITE_FLOAT;
286                         else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
287                            sqliteType = SQLITE_TEXT;
288                         else
289                         {
290                            if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
291                            {
292                               collations.Add(type.fullName);
293                               sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
294                            }
295                            sqliteType = SQLITE_BLOB;
296                         }
297                      }
298
299                      {
300                         SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
301                         incref field;
302                         table.fields.Add(field);
303                      }
304                   }
305                   sqlite3_finalize(statement);
306                }
307             }
308          }
309          sqlite3_free_table(t);
310       }
311       return (Table)table;
312    }
313
314    bool Begin()
315    {
316       char command[1024];
317       int result;
318       sprintf(command, "BEGIN;");
319       result = sqlite3_exec(db, command, null, null, null);
320       if(result)
321          PrintLn("BEGIN FAILED!");
322       return result == SQLITE_OK;
323    }
324
325    bool Commit()
326    {
327       char command[1024];
328       int result;
329       sprintf(command, "COMMIT;");
330       result = sqlite3_exec(db, command, null, null, null);
331       if(result)
332          PrintLn("COMMIT FAILED!");
333       return result == SQLITE_OK;
334    }
335
336    bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
337    {
338       int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
339       return result == SQLITE_OK;
340    }
341 }
342
343 static void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
344 {
345    SQLCustomFunction sqlFunction = sqlite3_user_data(context);
346    char * text = sqlite3_value_text(*value);
347    sqlFunction.array.size = 1;
348    sqlFunction.array[0] = 0;
349    sqlFunction.Process(text);
350    sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
351 }
352
353 class SQLiteTable : Table
354 {
355    char * name;
356    bool mustCreate;
357    SQLiteDatabase db;
358    LinkList<SQLiteField> fields { };
359    char * specialStatement;
360    SQLiteField primaryKey;
361    FieldIndex * indexFields;
362    int indexFieldsCount;
363    int64 lastID;
364
365    Field AddField(const String fieldName, Class type, int length)
366    {
367       SQLiteField field;
368       char command[1024];
369       char dataType[256];
370       int sqliteType;
371       int result;
372       Table refTable = null;
373       Field idField = null;
374       command[0] = 0;
375       
376       if(FindField(fieldName)) return null;
377
378       if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") || 
379          !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") || 
380          !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") || 
381          !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") || 
382          !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
383          !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
384       {
385          strcpy(dataType, "INTEGER");
386          sqliteType = SQLITE_INTEGER;
387       }
388       else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
389       {
390          strcpy(dataType, "REAL");
391          sqliteType = SQLITE_FLOAT;
392       }
393       else if(!strcmp(type.name, "CIString"))
394       {
395          strcpy(dataType, "TEXT");
396          sqliteType = SQLITE_BLOB;
397       }
398       else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
399       {
400          strcpy(dataType, "TEXT");
401          sqliteType = SQLITE_TEXT;
402       }
403       else
404       {
405          //strcpy(dataType, "BLOB");
406          strcpy(dataType, "TEXT");
407          sqliteType = SQLITE_BLOB;
408
409          if(!db.collations.Find(type.fullName))
410          {
411             db.collations.Add(type.fullName);
412             result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
413          }
414       }
415       if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
416       {
417          Table * table = (Table *)eClass_GetProperty(type, "table");
418          if(table) refTable = *table;
419          if(refTable)
420          {
421             if(primaryKey || refTable != this)
422             {
423                for(idField = refTable.firstField; idField; idField = idField.next)
424                   if(eClass_IsDerived(type, idField.type)) break;
425
426                if(!idField)
427                   PrintLn("WARNING: field not yet created for class ", (String)type.name);
428             }
429             else
430                idField = primaryKey;
431          }
432          else
433          {
434             PrintLn("WARNING: Table not yet created for class ", (String)type.name);
435          }
436       }
437       
438       if(mustCreate)
439       {
440          if(sqliteType == SQLITE_BLOB)
441          {
442             if(!strcmp(type.name, "CIString"))
443                sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
444             else
445                sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
446          }
447          else if(refTable)
448          {
449             if(!idField && refTable == this)
450                sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
451             else if(idField)
452                sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
453          }
454          else
455             sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
456          result = sqlite3_exec(db.db, command, null, null, null);
457          if(result) return null;
458          mustCreate = false;
459       }
460       else
461       {
462          if(sqliteType == SQLITE_BLOB)
463          {
464             if(!strcmp(type.name, "CIString"))
465                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
466             else
467                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
468          }
469          else if(refTable)
470          {
471             if(!idField && refTable == this)
472             {
473                PrintLn("WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
474                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
475             }
476             else if(idField)
477                sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
478          }
479          else
480             sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
481          result = sqlite3_exec(db.db, command, null, null, null);
482          if(result) return null;
483       }
484
485       sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
486          fieldName, type.name, length);
487       result = sqlite3_exec(db.db, command, null, null, null);
488
489       field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
490       incref field;
491       fields.Add(field);
492       if(!primaryKey && refTable == this)
493          primaryKey = field;
494       return (Field)field;
495    }
496
497    Field FindField(const String name)
498    {
499       for(f : fields; !strcmp(f.name, name))
500       {
501          if(!primaryKey)
502          {
503             if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
504             {
505
506                Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
507                if(tablePtr && *tablePtr == this)
508                   primaryKey = f;
509             }
510          }
511          return (Field)f;
512       }
513       return null;
514    }
515
516    bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
517    {
518       char command[1024];
519       int c;
520       int result;
521       char indexName[4096];
522
523       delete indexFields;
524       indexFieldsCount = count;
525       indexFields = new FieldIndex[count];
526       memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
527
528       // TODO: USE CODED INDEX NAME INSTEAD?
529       strcpy(indexName, "index_");
530       strcat(indexName, name);
531       strcat(indexName, "_");
532       for(c = 0; c<count; c++)
533       {
534          if(fieldIndexes[c].field)
535          {
536             if(count == 1 && fieldIndexes[c].field == primaryKey)
537                return true;
538             strcat(indexName, fieldIndexes[c].field.name);
539             if(fieldIndexes[c].memberField)
540             {
541                strcat(indexName, ".");
542                strcat(indexName, fieldIndexes[c].memberField.name);
543             }
544             strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
545          }
546          else
547             return false;
548       }
549
550       sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
551       for(c = 0; c<count; c++)
552       {
553          char columnName[1024];
554          sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
555          if(c > 0) strcat(command, ", ");
556          strcat(command, columnName);
557       }
558       strcat(command, ");");
559       result = sqlite3_exec(db.db, command, null, null, null);
560
561       return result == SQLITE_OK;
562    }
563
564    String GetName()
565    {
566       return name;
567    }
568
569    Field GetFirstField()
570    {
571       return fields.first;
572    }
573
574    uint GetFieldsCount()
575    {
576       return fields.count;
577    }
578
579    uint GetRowsCount()
580    {
581       char command[1024];
582       char **t;
583       int nCols, nRows;
584       int result;
585       uint rowCount = 0;
586       sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
587       result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
588       if(result == SQLITE_OK)
589       {
590          rowCount = atoi(t[1]);
591          sqlite3_free_table(t);
592       }
593       return rowCount;
594    }
595
596    DriverRow CreateRow()
597    {
598       char command[1024];
599       sqlite3_stmt * statement;
600       sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
601
602       if(specialStatement)
603          strcpy(command, specialStatement);
604       else
605       {
606          /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
607          sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
608          sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
609          sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
610
611          sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
612          sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
613          sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
614          sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
615          /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
616          sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
617
618          if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
619             sprintf(command, "SELECT ROWID, * FROM `%s`;", name);
620          else
621          {
622             int c;
623             sprintf(command, "SELECT ROWID, * FROM `%s` ORDER BY ", name);
624             for(c = 0; c < indexFieldsCount; c++)
625             {
626                char order[1024];
627                FieldIndex * fIndex = &indexFields[c];
628                order[0] = 0;
629                if(c) strcat(order, ", ");
630                strcat(order, "`");
631                strcat(order, fIndex->field.name);
632                strcat(order, "`");
633                if(fIndex->order == descending) strcat(command, " DESC");
634                strcat(command, order);
635             }
636             strcat(command, ";");
637          }
638       }
639       sqlite3_prepare_v2(db.db, command, -1, &statement, null);
640
641       sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
642       sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
643
644       sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
645       sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
646
647       return SQLiteRow
648          { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt, 
649            insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt };
650    }
651
652    ~SQLiteTable()
653    {
654       delete name;
655       delete specialStatement;
656       delete indexFields;
657       fields.Free();
658    }
659 }
660
661 class SQLiteRow : DriverRow
662 {
663    SQLiteTable tbl;
664    sqlite3_stmt * curStatement;
665
666    sqlite3_stmt * defaultStatement;
667    sqlite3_stmt * findStatement;
668    sqlite3_stmt * sysIDStatement;
669    sqlite3_stmt * queryStatement;
670    sqlite3_stmt * findMultipleStatement;
671    sqlite3_stmt * selectRowIDsStmt;
672    sqlite3_stmt * setRowIDStmt;
673
674    sqlite3_stmt * insertStatement;
675    sqlite3_stmt * deleteStatement;
676    sqlite3_stmt * updateStatement;
677    bool done;
678    done = true;
679    int64 rowID;
680    
681    bool Nil()
682    {
683       return done;
684    }
685
686    ~SQLiteRow()
687    {
688       if(defaultStatement) sqlite3_finalize(defaultStatement);
689       if(findStatement)    sqlite3_finalize(findStatement);
690       if(findMultipleStatement)    sqlite3_finalize(findMultipleStatement);
691       if(sysIDStatement)   sqlite3_finalize(sysIDStatement);
692       if(insertStatement)  sqlite3_finalize(insertStatement);
693       if(deleteStatement)  sqlite3_finalize(deleteStatement);
694       if(updateStatement)  sqlite3_finalize(updateStatement);
695       if(queryStatement)   sqlite3_finalize(queryStatement);
696       if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
697       if(setRowIDStmt)     sqlite3_finalize(setRowIDStmt);
698    }
699
700    bool Select(MoveOptions move)
701    {
702       int result;
703       if(!curStatement)
704          curStatement = defaultStatement;
705       switch(move)
706       {
707          case first:
708          {
709             sqlite3_reset(curStatement);
710             result = sqlite3_step(curStatement);
711             done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
712             if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
713             rowID = sqlite3_column_int64(curStatement, 0);
714             break;
715          }
716          case last:
717          {
718             sqlite3_stmt * statement;
719             char command[1024];
720             sprintf(command, "SELECT MAX(ROWID) FROM `%s`", tbl.name);
721             result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
722             result = sqlite3_step(statement);
723             rowID = sqlite3_column_int64(statement, 0);
724             sqlite3_finalize(statement);
725             break;
726          }
727          case middle:
728             break;
729          case next:
730          {
731             result = sqlite3_step(curStatement);
732             done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
733             if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
734             rowID = sqlite3_column_int64(curStatement, 0);
735             break;
736          }
737          case previous:
738             break;
739          case nil:
740             sqlite3_reset(curStatement);
741             rowID = 0;
742             done = true;
743             break;
744          case here:
745             break;
746       }
747       return true;
748    }
749
750    bool Query(char * queryString)
751    {
752       bool status = true;
753       int result;
754
755       if(curStatement)
756          sqlite3_reset(curStatement);
757       if(queryStatement)
758       {
759          sqlite3_finalize(queryStatement);
760          queryStatement = null;
761       }
762
763       if(queryString)
764       {
765          result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
766          curStatement = queryStatement;
767          if(!strchr(queryString, '?'))
768          {
769             result = sqlite3_step(queryStatement);
770
771             done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
772             if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
773
774             rowID = sqlite3_column_int64(queryStatement, 0);
775          }
776       }
777       else
778          curStatement = null;
779       return status;
780    }
781
782    bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
783    {
784       char command[1024];
785       int result;
786       SQLiteField sqlFld = (SQLiteField)fld;
787       Class dataType = sqlFld.type;
788
789       if(fld == tbl.primaryKey)
790       {
791          return GoToSysID(*(int *)data);
792       }
793       
794       if(curStatement)
795          sqlite3_reset(curStatement);
796       if(findStatement)
797          sqlite3_finalize(findStatement);
798
799       sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?;", tbl.name, fld.name);
800       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findStatement, null);
801
802       // result = sqlite3_bind_text(findStatement, 1, fld.name, strlen(fld.name), SQLITE_STATIC);
803
804       curStatement = findStatement;
805       switch(sqlFld.sqliteType)
806       {
807          case SQLITE_INTEGER: 
808          {
809             switch(dataType.typeSize)
810             {
811                case 8:
812                   sqlite3_bind_int64(findStatement, 1, (sqlite3_int64)*(int64 *)data);
813                   break;
814                case 4:
815                   sqlite3_bind_int(findStatement, 1, *(int *)data);
816                   break;
817                case 2:
818                {
819                   int value;
820                   if(value < 0)
821                      value = (int)*(short *)data;
822                   else
823                      value = (int)*(uint16 *)data;
824                   sqlite3_bind_int(findStatement, 1, value);
825                   break;
826                }
827                case 1:
828                {
829                   int value;
830                   if(value < 0)
831                      value = (int)*(char *)data;
832                   else
833                      value = (int)*(byte *)data;
834                   sqlite3_bind_int(findStatement, 1, value);
835                   break;
836                }
837             }
838             break;
839          }
840          case SQLITE_FLOAT:
841          {
842             if(dataType.typeSize == 8)
843                sqlite3_bind_double(findStatement, 1, *(double *)data);
844             else
845                sqlite3_bind_double(findStatement, 1, (double)*(float *)data);
846             break;
847          }
848          case SQLITE_TEXT:
849          {
850             if(data)
851                sqlite3_bind_text(findStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
852             else
853                sqlite3_bind_text(findStatement, 1, null, 0, SQLITE_STATIC);
854             break;
855          }
856          case SQLITE_BLOB:
857          case SQLITE_NULL:
858          {
859             SerialBuffer buffer { };
860
861             dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
862             //sqlite3_bind_blob(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
863             sqlite3_bind_text(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
864             result = sqlite3_step(findStatement);
865
866             done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
867             if(done) { rowID = 0; sqlite3_reset(findStatement); delete buffer; return false; }
868
869             rowID = sqlite3_column_int64(findStatement, 0);
870
871             delete buffer;
872             return true;
873             break;
874          } 
875       }
876       result = sqlite3_step(findStatement);
877
878       done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
879       if(done) { rowID = 0; sqlite3_reset(findStatement); return false; }
880
881       rowID = sqlite3_column_int64(findStatement, 0);
882       return true;
883    }
884
885    bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
886    {
887       if(numFields)
888       {
889          char command[4096];
890          int result;
891          int c;
892          Array<SerialBuffer> serialBuffers { };
893
894          if(curStatement)
895             sqlite3_reset(curStatement);
896          if(findMultipleStatement)
897             sqlite3_finalize(findMultipleStatement);
898
899          sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
900          for(c = 0; c < numFields; c++)
901          {
902             FieldFindData * fieldFind = &findData[c];
903
904             if(c) strcat(command, " AND `");
905             strcat(command, fieldFind->field.name);
906             strcat(command, "` = ?");
907          }
908          strcat(command, ";");
909
910          result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findMultipleStatement, null);
911          curStatement = findMultipleStatement;
912
913          for(c = 0; c < numFields; c++)
914          {
915             FieldFindData * fieldFind = &findData[c];
916             SQLiteField sqlFld = (SQLiteField)fieldFind->field;
917             Class dataType = sqlFld.type;
918
919             switch(sqlFld.sqliteType)
920             {
921                case SQLITE_INTEGER: 
922                {
923                   switch(dataType.typeSize)
924                   {
925                      case 8:
926                         sqlite3_bind_int64(findMultipleStatement, 1 + c, (sqlite_int64)fieldFind->value.i64);
927                         break;
928                      case 4:
929                         sqlite3_bind_int(findMultipleStatement, 1 + c, fieldFind->value.i);
930                         break;
931                      case 2:
932                      {
933                         int value;
934                         if(value < 0)
935                            value = (int)fieldFind->value.s;
936                         else
937                            value = (int)fieldFind->value.us;
938                         sqlite3_bind_int(findMultipleStatement, 1 + c, value);
939                         break;
940                      }
941                      case 1:
942                      {
943                         int value;
944                         if(value < 0)
945                            value = (int)fieldFind->value.c;
946                         else
947                            value = (int)fieldFind->value.uc;
948                         sqlite3_bind_int(findMultipleStatement, 1 + c, value);
949                         break;
950                      }
951                   }
952                   break;
953                }
954                case SQLITE_FLOAT:
955                {
956                   if(dataType.typeSize == 8)
957                      sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.d);
958                   else
959                      sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.f);
960                   break;
961                }
962                case SQLITE_TEXT:
963                {
964                   if(fieldFind->value.p)
965                      sqlite3_bind_text(findMultipleStatement, 1 + c, (char *)fieldFind->value.p, strlen(fieldFind->value.p), SQLITE_STATIC);
966                   else
967                      sqlite3_bind_text(findMultipleStatement, 1 + c, null, 0, SQLITE_STATIC);
968                   break;
969                }
970                case SQLITE_BLOB:
971                case SQLITE_NULL:
972                {
973                   SerialBuffer buffer { };
974
975                   dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, fieldFind->value.p, buffer);
976                   //sqlite3_bind_blob(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
977                   sqlite3_bind_text(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
978
979                   serialBuffers.Add(buffer);
980                   break;
981                } 
982             }
983          }
984
985          result = sqlite3_step(findMultipleStatement);
986
987          done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
988          if(done)
989          {
990             rowID = 0;
991             sqlite3_reset(findMultipleStatement);
992
993             serialBuffers.Free();
994             delete serialBuffers;
995             return false;
996          }
997          else
998          {
999             rowID = sqlite3_column_int64(findMultipleStatement, 0);
1000
1001             serialBuffers.Free();
1002             delete serialBuffers;
1003             return true;
1004          }
1005       }
1006       return false;
1007    }
1008
1009    bool Synch(DriverRow to)
1010    {
1011       return true;
1012    }
1013
1014    bool Add()
1015    {
1016       int result;
1017       //char command[1024];
1018       //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1019       //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1020       result = sqlite3_step(insertStatement);
1021       if(result == SQLITE_DONE)     // if(result == SQLITE_OK)
1022       {
1023          rowID = sqlite3_last_insert_rowid(tbl.db.db);
1024          if(rowID > MAXDWORD)
1025          {
1026             int64 lastID = tbl.lastID;
1027
1028             sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1029             while(true)
1030             {
1031                int64 id;
1032                result = sqlite3_step(selectRowIDsStmt);
1033                if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1034                id = sqlite3_column_int64(selectRowIDsStmt, 0);
1035                if(id - lastID > 1) break;
1036                lastID = id;
1037             }
1038             sqlite3_reset(selectRowIDsStmt);
1039
1040             sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1041             rowID = lastID + 1;
1042             tbl.lastID = rowID;
1043             sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1044             result = sqlite3_step(setRowIDStmt);
1045             sqlite3_reset(setRowIDStmt);
1046          }
1047          sqlite3_reset(insertStatement);
1048          curStatement = sysIDStatement;
1049          sqlite3_reset(curStatement);
1050          return true;
1051       }
1052       sqlite3_reset(insertStatement);
1053       return false;
1054    }
1055
1056    bool Delete()
1057    {
1058       int result;
1059       //char command[1024];
1060       //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1061       //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1062       sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1063       result = sqlite3_step(deleteStatement);
1064       sqlite3_reset(deleteStatement);
1065       rowID = 0;
1066       return result == SQLITE_OK || result == SQLITE_DONE;
1067    }
1068
1069    bool GetData(Field fld, typed_object &data)
1070    {
1071       SQLiteField sqlFld = (SQLiteField)fld;
1072       int num = sqlFld.num + 1;
1073       Class dataType = sqlFld.type;
1074       switch(sqlFld.sqliteType)
1075       {
1076          case SQLITE_INTEGER: 
1077          {
1078             switch(dataType.typeSize)
1079             {
1080                case 8:
1081                   if(fld == tbl.primaryKey)
1082                      *(int64 *)data = rowID;
1083                   else
1084                      *(int64 *)data = sqlite3_column_int64(curStatement, num);
1085                   break;
1086                case 4:
1087                   if(fld == tbl.primaryKey)
1088                      *(int *)data = (int)(uint)rowID;
1089                   else
1090                      *(int *)data = sqlite3_column_int(curStatement, num);
1091                   break;
1092                case 2:
1093                {
1094                   int value;
1095                   if(fld == tbl.primaryKey)
1096                      value = (int)(uint)rowID;
1097                   else
1098                      value = sqlite3_column_int(curStatement, num);
1099                   if(value < 0)
1100                      *(short *)data = (short)value;
1101                   else
1102                      *(uint16 *)data = (uint16)value;
1103                   break;
1104                }
1105                case 1:
1106                {
1107                   int value;
1108                   if(fld == tbl.primaryKey)
1109                      value = (int)(uint)rowID;
1110                   else
1111                      value = sqlite3_column_int(curStatement, num);
1112                   if(value < 0)
1113                      *(char *)data = (char)value;
1114                   else
1115                      *(byte *)data = (byte)value;
1116                   break;
1117                }
1118             }
1119             break;
1120          }
1121          case SQLITE_FLOAT:
1122          {
1123             double d = sqlite3_column_double(curStatement, num);
1124             if(dataType.typeSize == 8)
1125                *(double *)data = d;
1126             else
1127                *(float *)data = (float)d;
1128             break;
1129          }
1130          case SQLITE_TEXT:
1131          {
1132             int numBytes = sqlite3_column_bytes(curStatement, num);
1133             char * text = sqlite3_column_text(curStatement, num);
1134             *(char **)data = text ? new byte[numBytes+1] : null;
1135             if(text)
1136                memcpy(*(char **)data, text, numBytes+1);
1137             break;
1138          }
1139          case SQLITE_BLOB:
1140          {
1141             SerialBuffer buffer { };
1142             //buffer._buffer = sqlite3_column_blob(curStatement, num);
1143             buffer._size = sqlite3_column_bytes(curStatement, num);
1144             buffer._buffer = sqlite3_column_text(curStatement, num);
1145             buffer.count = buffer._size;
1146
1147             dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
1148            
1149             buffer._buffer = null;
1150             delete buffer;
1151             break;
1152          } 
1153       }
1154       return true;
1155    }
1156
1157    bool SetData(Field fld, typed_object data)
1158    {
1159       SQLiteField sqlFld = (SQLiteField)fld;
1160       int result;
1161
1162       int num = sqlFld.num + 1;
1163       Class dataType = sqlFld.type;
1164       char command[1024];
1165       //sqlite3_stmt * setStatement;
1166
1167       if(updateStatement)
1168          sqlite3_finalize(updateStatement);
1169
1170       // sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = %d;", tbl.name, sqlFld.name, rowID);
1171       sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1172
1173       result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1174
1175       //sqlite3_bind_text(updateStatement, 1, sqlFld.name, strlen(sqlFld.name), SQLITE_STATIC);
1176       //sqlite3_bind_int64(updateStatement, 3, (sqlite3_int64)rowID);
1177
1178       sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1179       switch(sqlFld.sqliteType)
1180       {
1181          case SQLITE_INTEGER: 
1182          {
1183             switch(dataType.typeSize)
1184             {
1185                case 8:
1186                   sqlite3_bind_int64(updateStatement, 1, (sqlite3_int64)*(int64 *)data);
1187                   break;
1188                case 4:
1189                   sqlite3_bind_int(updateStatement, 1, *(int *)data);
1190                   break;
1191                case 2:
1192                {
1193                   int value;
1194                   if(value < 0)
1195                      value = (int)*(short *)data;
1196                   else
1197                      value = (int)*(uint16 *)data;
1198                   sqlite3_bind_int(updateStatement, 1, value);
1199                   break;
1200                }
1201                case 1:
1202                {
1203                   int value;
1204                   if(value < 0)
1205                      value = (int)*(char *)data;
1206                   else
1207                      value = (int)*(byte *)data;
1208                   sqlite3_bind_int(updateStatement, 1, value);
1209                   break;
1210                }
1211             }
1212             break;
1213          }
1214          case SQLITE_FLOAT:
1215          {
1216             if(dataType.typeSize == 8)
1217                sqlite3_bind_double(updateStatement, 1, *(double *)data);
1218             else
1219                sqlite3_bind_double(updateStatement, 1, (double)*(float *)data);
1220             break;
1221          }
1222          case SQLITE_TEXT:
1223          {
1224             if(data)
1225                sqlite3_bind_text(updateStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
1226             else
1227                sqlite3_bind_text(updateStatement, 1, null, 0, SQLITE_STATIC);
1228             break;
1229          }
1230          case SQLITE_BLOB:
1231          case SQLITE_NULL:
1232          {
1233             SerialBuffer buffer { };
1234
1235             dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
1236             //sqlite3_bind_blob(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
1237             sqlite3_bind_text(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
1238             sqlite3_step(updateStatement);
1239             sqlite3_reset(updateStatement);
1240             delete buffer;
1241             return true;
1242             break;
1243          }
1244       }
1245       result = sqlite3_step(updateStatement);
1246       sqlite3_reset(updateStatement);
1247       if(fld == tbl.primaryKey)
1248       {
1249          rowID = *(uint *)data;
1250       }
1251       return result == SQLITE_DONE;
1252    }
1253
1254    int GetSysID()
1255    {
1256       return (int)(uint)rowID;
1257    }
1258
1259    bool GoToSysID(int id)
1260    {
1261       //char command[1024];
1262       int result;
1263       rowID = (uint)id;
1264       //if(statement)
1265          //sqlite3_finalize(statement);
1266       //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1267       //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1268
1269       if(curStatement)
1270          sqlite3_reset(curStatement);
1271
1272       curStatement = sysIDStatement;
1273       sqlite3_reset(sysIDStatement);
1274       sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1275       result = sqlite3_step(curStatement);
1276       done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1277       if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1278       return !done;
1279    }
1280
1281    bool SetQueryParam(int paramID, int value)
1282    {
1283       int result;
1284       if(curStatement != queryStatement)
1285       {
1286          if(curStatement) sqlite3_reset(curStatement);
1287          curStatement = queryStatement;         
1288       }
1289       sqlite3_reset(queryStatement);
1290       result = sqlite3_bind_int(queryStatement, paramID, value);
1291       return !result;
1292    }
1293
1294    bool SetQueryParam64(int paramID, int64 value)
1295    {
1296       int result;
1297       if(curStatement != queryStatement)
1298       {
1299          if(curStatement) sqlite3_reset(curStatement);
1300          curStatement = queryStatement;         
1301       }
1302       sqlite3_reset(queryStatement);
1303       result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1304       return !result;
1305    }
1306
1307    bool SetQueryParamText(int paramID, char * data)
1308    {
1309       int result;
1310       if(curStatement != queryStatement)
1311       {
1312          if(curStatement) sqlite3_reset(curStatement);
1313          curStatement = queryStatement;         
1314       }
1315       sqlite3_reset(queryStatement);
1316       if(data)
1317          result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_STATIC);
1318       else
1319          result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_STATIC);
1320       return !result;
1321    }
1322
1323    bool SetQueryParamObject(int paramID, void * data, Class type)
1324    {
1325       int result;
1326       if(curStatement != queryStatement)
1327       {
1328          if(curStatement) sqlite3_reset(curStatement);
1329          curStatement = queryStatement;         
1330       }
1331       sqlite3_reset(queryStatement);
1332       {
1333          SerialBuffer buffer { };
1334          type._vTbl[__ecereVMethodID_class_OnSerialize](type, data, buffer);
1335          result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1336          delete buffer;
1337       }
1338       return !result;
1339    }
1340
1341    /*char * GetExtraColumn(int paramID)
1342    {
1343       SQLiteField lastFld = tbl.fields.last;
1344       return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1345    }*/
1346    char * GetColumn(int paramID)
1347    {
1348       return sqlite3_column_text(curStatement, paramID);
1349    }
1350 }