2 public import static "ecere"
3 public import static "EDA"
19 __attribute__((unused)) static void UnusedFunction()
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);
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;
43 static SerialBuffer collationBuffer1 { };
44 static SerialBuffer collationBuffer2 { };
45 static char storage1[512];
46 static char storage2[512];
48 int CollationCompare(Class type, int count1, const void * data1, int count2, const void * data2)
50 if(type.type == normalClass || type.type == noHeadClass)
52 Instance inst1, inst2;
54 SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
55 SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
57 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst1, buffer1);
58 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst2, buffer2);
60 result = ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
62 buffer1.buffer = null;
63 buffer2.buffer = null;
70 else if(type.type == structClass)
72 void * inst1, * inst2;
74 //SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
75 //SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
77 SerialBuffer buffer1 = collationBuffer1;
78 SerialBuffer buffer2 = collationBuffer2;
79 buffer1.buffer = (byte*)data1;
80 buffer1.size = count1;
81 buffer1.count = count1;
83 buffer2.buffer = (byte*)data2;
84 buffer2.size = count2;
85 buffer2.count = count2;
88 if(type.structSize > 512)
90 inst1 = new0 byte[type.structSize];
91 inst2 = new0 byte[type.structSize];
98 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst1, buffer1);
99 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst2, buffer2);
101 result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
103 buffer1.buffer = null;
104 buffer2.buffer = null;
107 if(type.structSize > 512)
115 return ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, data1, data2);
118 public class SQLiteStaticLink { } // Until .imp generation is fixed
120 class SQLiteDataSource : DirFilesDataSourceDriver
122 class_property(name) = "SQLite";
123 class_property(databaseFileExtension) = "sqlite";
125 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
127 Database result = null;
130 String path = MakeDatabasePath(name);
133 // sqlite3_open(path, &db);
134 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
136 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
137 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
139 // fprintf(stderr, "%s\n", s); // interesting
140 printf($"EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
148 sqlite3_exec(db, "PRAGMA page_size=4096;", null, null, null);
150 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
151 sqlite3_exec(db, command, null, null, null);
153 if(createOptions != readOnly)
155 sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
156 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
157 if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
160 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
164 result = SQLiteDatabase { db = db };
172 class SQLiteField : Field
177 public LinkElement<SQLiteField> link;
187 const String GetName()
195 int GetLength() { return length; }
210 class SQLiteDatabase : Database
213 AVLTree<const String> collations { };
217 sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
218 // "Simply setting the locking-mode to NORMAL is not enough - locks are not released until the next time the database file is accessed."
219 sqlite3_exec(db, "SELECT COUNT(*) from eda_table_fields", null, null, null);
223 uint ObjectsCount(ObjectType type)
229 bool RenameObject(ObjectType type, const String name, const String rename)
235 bool DeleteObject(ObjectType type, const String name)
241 Table OpenTable(const String name, OpenOptions options)
245 int nRows = 0, nCols = 0;
247 SQLiteTable table = null;
248 if(options.type == tablesList)
251 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
252 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
253 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
256 table._fields.Add(field);
258 else if(options.type == fieldsList)
262 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
263 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
265 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
267 table._fields.Add(field);
268 field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
270 table._fields.Add(field);
271 field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
273 table._fields.Add(field);
275 else if(options.type == tableRows)
277 bool addFields = false;
279 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
280 /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
284 sqlite3_free_table(t);
286 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
287 nCols = 0, nRows = 0;
288 /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
290 if((nCols || nRows) || options.create)
292 table = SQLiteTable { db = this, name = CopyString(name) };
295 table.mustCreate = true;
301 for(r = 1; r <= nRows; r++) // There should be only 1 row here
303 char * sql = t[nCols * r];
304 char * bracket = strchr(sql, '(');
316 int sqliteType = SQLITE_BLOB;
317 Class type = class(int);
321 while((ch = bracket[c++]))
323 if(ch == ',' || ch == ')')
326 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
328 memcpy(fieldName, bracket + start, d - start);
329 fieldName[d - start] = 0;
331 memcpy(dataType, bracket + d + 1, c - d - 2);
332 dataType[c - d - 2] = 0;
334 while(ch && bracket[c] == ' ') c++;
336 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
337 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
338 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
339 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
341 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
342 fieldName, type.name, 0);
343 /*result = */sqlite3_exec(db, command, null, null, null);
346 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table._fields.count, sqliteType = sqliteType };
348 table._fields.Add(field);
351 if(!ch || ch == ')') break;
358 Table refTable = null;
359 sqlite3_stmt * statement;
361 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
362 /*result = */sqlite3_prepare_v2(db, command, -1, &statement, null);
364 while(sqlite3_step(statement) != SQLITE_DONE)
366 const char * fieldName = (const char *)sqlite3_column_text(statement, 0);
367 const char * typeName = (const char *)sqlite3_column_text(statement, 1);
368 int length = sqlite3_column_int(statement, 2);
370 int sqliteType = SQLITE_BLOB;
372 type.OnGetDataFromString(typeName);
376 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
377 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
378 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
379 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
380 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
381 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
382 sqliteType = SQLITE_INTEGER;
383 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
384 sqliteType = SQLITE_FLOAT;
385 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
386 sqliteType = SQLITE_TEXT;
389 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
391 collations.Add(type.fullName);
392 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
394 sqliteType = SQLITE_BLOB;
399 Table * fTable = (Table *)(intptr)eClass_GetProperty(type, "table");
400 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table._fields.count, sqliteType = sqliteType };
402 if(fTable) refTable = *fTable;
403 if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
404 table.primaryKey = field;
406 table._fields.Add(field);
409 sqlite3_finalize(statement);
413 sqlite3_free_table(t);
422 sprintf(command, "BEGIN;");
423 result = sqlite3_exec(db, command, null, null, null);
425 PrintLn($"BEGIN FAILED!");
426 return result == SQLITE_OK;
433 sprintf(command, "COMMIT;");
434 result = sqlite3_exec(db, command, null, null, null);
436 PrintLn($"COMMIT FAILED!");
437 return result == SQLITE_OK;
440 bool CreateCustomFunction(const char * name, SQLCustomFunction customFunction)
443 Class cfClass = customFunction._class;
444 customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
445 if(customFunction.method)
447 String typeString = CopyString(customFunction.method.dataTypeString);
449 int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
451 bool variadic = false;
453 for(c = 0; c < count; c++)
456 bool pointer = false;
457 const String arg = tokens[c];
459 TrimLSpaces(tokens[c], tokens[c]);
460 if(strchr(arg, '*')) pointer = true;
462 // Using String for generic pointer...
463 type = class(String);
466 if((space = strchr(arg, ' '))) *space = 0;
467 if(!strcmp(arg, "void"))
469 else if(!strcmp(arg, "..."))
473 if(cfClass.templateParams.count)
475 ClassTemplateParameter p;
477 for(p = cfClass.templateParams.first; p; p = p.next, id++)
479 if(!strcmp(p.name, arg))
482 if(p && cfClass.templateArgs)
483 arg = cfClass.templateArgs[id].dataTypeString;
485 type = eSystem_FindClass(customFunction._class.module, arg);
487 type = eSystem_FindClass(customFunction._class.module.application, arg);
491 customFunction.returnType = type;
493 customFunction.args.Add(type);
499 // Variadic args don't make sense for SQL custom functions
500 // Note that different CIF must be prepared for different set of arguments
501 // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
505 customFunction.rType = FFIGetType(customFunction.returnType, true);
506 customFunction.argTypes.Add((void *)&ffi_type_pointer); // This pointer for SQLCustomFunction object
507 for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
508 ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
509 result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
516 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
517 FFITypesHolder structFFITypes { };
518 __attribute__((unused)) static Iterator dummy; // TOFIX: forward struct declaration issues on Clang
520 public ffi_type * FFIGetType(Class type, bool structByValue)
529 MapIterator<Class, String> it { map = structFFITypes };
530 ffi_type * ffiType = null;
531 if(it.Index(type, false))
532 ffiType = (void *)it.data;
537 Array<String> memberTypes { };
538 for(member = type.membersAndProperties.first; member; member = member.next)
540 if(!member.isProperty)
542 memberTypes.Add(FFIGetType(member.dataType
546 ffiType = new0 ffi_type[1];
547 ffiType->size = type.structSize;
548 ffiType->type = FFI_TYPE_STRUCT;
549 structFFITypes[type] = (void *)ffiType;
556 return &ffi_type_pointer;
562 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
563 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
565 switch(type.typeSize)
567 case 1: return &ffi_type_uint8;
568 case 2: return &ffi_type_uint16;
569 case 4: return &ffi_type_uint32;
570 case 8: return &ffi_type_uint64;
574 return &ffi_type_void;
578 static SerialBuffer staticBuffer { };
579 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
581 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
583 /* // Simple 1 pointer param returning a string
584 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
585 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
588 void * ret = &retData;
589 Array<String> args { size = sqlFunction.args.count + 1 };
590 Iterator<String> ffiArg { sqlFunction.argTypes };
591 Iterator<String> arg { args };
594 // this * for the SQLCustomFunction
595 args[0] = (void *)&sqlFunction;
597 // Get the arguments from SQLite
598 for(a : sqlFunction.args)
600 ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
609 void ** data = new void *[1];
610 args[i+1] = (void *)data;
611 if(a == class(String))
613 int numBytes = sqlite3_value_bytes(values[i]);
614 const char * text = (const char *)sqlite3_value_text(values[i]);
615 *(char **)data = text ? new byte[numBytes+1] : null;
617 memcpy(*(char **)data, text, numBytes+1);
621 SerialBuffer buffer = staticBuffer; //{ };
623 buffer._size = sqlite3_value_bytes(values[i]);
624 buffer._buffer = (byte *)sqlite3_value_text(values[i]);
625 //buffer._buffer = sqlite3_value_blob(curStatement);
626 buffer.count = buffer._size;
627 if(a.type == structClass)
628 *data = new byte[a.structSize];
629 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
630 buffer._buffer = null;
639 if(type == &ffi_type_double || type == &ffi_type_float)
641 double d = sqlite3_value_double(values[i]);
644 double * data = new double[1];
645 args[i+1] = (void *)data;
650 float * data = new float[1];
651 args[i+1] = (void *)data;
661 int64 * data = new int64[1];
662 args[i+1] = (void *)data;
663 *data = sqlite3_value_int64(values[i]);
668 int * data = new int[1];
669 args[i+1] = (void *)data;
670 *data = sqlite3_value_int(values[i]);
675 short * data = new short[1];
677 args[i+1] = (void *)data;
678 value = sqlite3_value_int(values[i]);
680 *data = (short)value;
682 *(uint16 *)data = (uint16)value;
687 char * data = new char[1];
690 value = sqlite3_value_int(values[i]);
694 *(byte *)data = (byte)value;
704 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
705 ret = new byte[sqlFunction.returnType.typeSize];
706 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
707 // Give SQLite the return value
708 if(sqlFunction.returnType)
710 ffi_type * type = sqlFunction.rType;
711 Class r = sqlFunction.returnType;
719 void * data = ret ? *(void **)ret : null;
720 if(r.type == structClass)
722 if(r == class(String))
725 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
727 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
731 SerialBuffer buffer { };
732 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
733 sqlite3_result_text(context, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
736 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
737 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
740 if(r.type == structClass)
748 if(type == &ffi_type_double || type == &ffi_type_float)
751 sqlite3_result_double(context, *(double *)ret);
753 sqlite3_result_double(context, (double)*(float *)ret);
760 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
763 sqlite3_result_int(context, *(int *)ret);
769 value = (int)*(short *)ret;
771 //value = (int)*(uint16 *)ret;
772 sqlite3_result_int(context, value);
779 value = (int)*(char *)ret;
781 //value = (int)*(byte *)ret;
782 sqlite3_result_int(context, value);
793 for(type : sqlFunction.args; arg.Next())
796 void * data = *(void **)arg.data;
797 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
798 if(type.type == structClass)
807 class SQLiteTable : Table
812 LinkList<SQLiteField> _fields { };
813 char * specialStatement;
814 SQLiteField primaryKey;
815 FieldIndex * indexFields;
816 int indexFieldsCount;
819 Field AddField(const String fieldName, Class type, int length)
826 Table refTable = null;
827 Field idField = null;
830 if(FindField(fieldName)) return null;
832 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
833 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
834 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
835 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
836 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
837 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
839 strcpy(dataType, "INTEGER");
840 sqliteType = SQLITE_INTEGER;
842 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
844 strcpy(dataType, "REAL");
845 sqliteType = SQLITE_FLOAT;
847 else if(!strcmp(type.name, "CIString"))
849 strcpy(dataType, "TEXT");
850 sqliteType = SQLITE_BLOB;
852 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
854 strcpy(dataType, "TEXT");
855 sqliteType = SQLITE_TEXT;
859 //strcpy(dataType, "BLOB");
860 strcpy(dataType, "TEXT");
861 sqliteType = SQLITE_BLOB;
863 if(!db.collations.Find(type.fullName))
865 db.collations.Add(type.fullName);
866 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
869 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)) && type != class(eda::Id))
871 Table * table = (Table *)(intptr)eClass_GetProperty(type, "table");
872 if(table) refTable = *table;
875 if(primaryKey || refTable != this)
877 for(idField = refTable.firstField; idField; idField = idField.next)
878 if(eClass_IsDerived(type, idField.type)) break;
881 PrintLn("WARNING: field not yet created for class ", (String)type.name);
884 idField = primaryKey;
888 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
894 if(sqliteType == SQLITE_BLOB)
896 if(!strcmp(type.name, "CIString"))
897 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
899 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
903 if(!idField && refTable == this)
904 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
906 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
909 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
910 result = sqlite3_exec(db.db, command, null, null, null);
911 if(result) return null;
916 if(sqliteType == SQLITE_BLOB)
918 if(!strcmp(type.name, "CIString"))
919 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
921 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
925 if(!idField && refTable == this)
927 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
928 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
931 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
934 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
935 result = sqlite3_exec(db.db, command, null, null, null);
936 if(result) return null;
939 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
940 fieldName, type.name, length);
941 result = sqlite3_exec(db.db, command, null, null, null);
943 field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
946 if(!primaryKey && refTable == this)
951 Field FindField(const String name)
953 for(f : _fields; !strcmp(f.name, name))
957 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
960 Table * tablePtr = (Table *)(intptr)eClass_GetProperty(f.type, "table");
961 if(tablePtr && *tablePtr == this)
970 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
975 char indexName[4096];
978 indexFieldsCount = count;
979 indexFields = new FieldIndex[count];
980 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
982 // TODO: USE CODED INDEX NAME INSTEAD?
983 strcpy(indexName, "index_");
984 strcat(indexName, name);
985 strcat(indexName, "_");
986 for(c = 0; c<count; c++)
988 if(fieldIndexes[c].field)
990 if(count == 1 && fieldIndexes[c].field == primaryKey)
992 strcat(indexName, fieldIndexes[c].field.name);
993 if(fieldIndexes[c].memberField)
995 strcat(indexName, ".");
996 strcat(indexName, fieldIndexes[c].memberField.name);
998 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
1004 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
1005 for(c = 0; c<count; c++)
1007 char columnName[1024];
1008 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
1009 if(c > 0) strcat(command, ", ");
1010 strcat(command, columnName);
1012 strcat(command, ");");
1013 result = sqlite3_exec(db.db, command, null, null, null);
1015 return result == SQLITE_OK;
1018 const String GetName()
1023 Field GetFirstField()
1025 return _fields.first;
1028 Field GetPrimaryKey()
1033 uint GetFieldsCount()
1035 return _fields.count;
1045 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1046 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1047 if(result == SQLITE_OK)
1049 rowCount = atoi(t[1]);
1050 sqlite3_free_table(t);
1055 // Returns true if not ordered by row ID
1056 bool GetIndexOrder(char * fullOrder, bool flip)
1058 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1060 strcpy(fullOrder, " ORDER BY ROWID");
1066 strcpy(fullOrder, " ORDER BY ");
1067 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1070 FieldIndex * fIndex = &indexFields[c];
1072 if(c) strcat(order, ", ");
1074 strcat(order, fIndex->field.name);
1076 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1077 strcat(fullOrder, order);
1083 Container<Field> GetFields()
1085 return (Container<Field>)_fields;
1088 DriverRow CreateRow()
1091 sqlite3_stmt * statement;
1092 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1093 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1095 if(specialStatement)
1096 strcpy(command, specialStatement);
1100 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1101 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1102 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1103 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1105 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1106 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1108 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1109 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1111 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1112 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1114 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1115 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1117 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1118 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1120 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1121 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1123 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1125 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1127 GetIndexOrder(order, false);
1128 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1130 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1132 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1133 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1135 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1136 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1139 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1140 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1141 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1147 delete specialStatement;
1153 class SQLiteRow : DriverRow
1156 sqlite3_stmt * curStatement;
1158 sqlite3_stmt * defaultStatement;
1159 sqlite3_stmt * findStatement;
1160 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1161 sqlite3_stmt * nextFindStatement;
1162 sqlite3_stmt * sysIDStatement;
1163 sqlite3_stmt * queryStatement;
1164 sqlite3_stmt * selectRowIDsStmt;
1165 sqlite3_stmt * setRowIDStmt;
1166 sqlite3_stmt * lastStatement;
1167 sqlite3_stmt * previousStatement;
1168 sqlite3_stmt * nextStatement;
1170 sqlite3_stmt * insertStatement;
1171 sqlite3_stmt * deleteStatement;
1172 sqlite3_stmt * updateStatement;
1173 sqlite3_stmt * insertIDStatement;
1177 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1178 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1189 if(defaultStatement) sqlite3_finalize(defaultStatement);
1190 if(findStatement) sqlite3_finalize(findStatement);
1191 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1192 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1193 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1194 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1195 if(insertStatement) sqlite3_finalize(insertStatement);
1196 if(deleteStatement) sqlite3_finalize(deleteStatement);
1197 if(updateStatement) sqlite3_finalize(updateStatement);
1198 if(queryStatement) sqlite3_finalize(queryStatement);
1199 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1200 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1201 if(previousStatement)sqlite3_finalize(previousStatement);
1202 if(nextStatement) sqlite3_finalize(nextStatement);
1203 if(lastStatement) sqlite3_finalize(lastStatement);
1204 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1207 bool Select(MoveOptions move)
1210 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1212 curStatement = defaultStatement;
1217 sqlite3_reset(curStatement);
1218 result = sqlite3_step(curStatement);
1219 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1220 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1221 rowID = sqlite3_column_int64(curStatement, 0);
1226 sqlite3_reset(curStatement);
1227 curStatement = lastStatement;
1228 result = sqlite3_step(curStatement);
1229 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1230 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1231 rowID = sqlite3_column_int64(curStatement, 0);
1239 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1240 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1241 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1243 result = sqlite3_step(curStatement);
1244 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1245 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1246 rowID = sqlite3_column_int64(curStatement, 0);
1248 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1252 int bindId = findBindId;
1253 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1254 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1255 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1256 sqlite3_reset(curStatement);
1257 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1258 result = sqlite3_step(curStatement);
1259 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1260 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1261 rowID = sqlite3_column_int64(curStatement, 0);
1265 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1266 sqlite3_reset(curStatement);
1267 curStatement = (move == next) ? findStatement : lastFindStatement;
1268 result = sqlite3_step(curStatement);
1269 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1270 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1271 rowID = sqlite3_column_int64(curStatement, 0);
1276 sqlite3_reset(curStatement);
1277 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1278 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1279 result = sqlite3_step(curStatement);
1280 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1281 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1282 rowID = sqlite3_column_int64(curStatement, 0);
1287 sqlite3_reset(curStatement);
1297 bool Query(const char * queryString)
1303 sqlite3_reset(curStatement);
1306 sqlite3_finalize(queryStatement);
1307 queryStatement = null;
1312 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1315 curStatement = queryStatement;
1316 if(!strchr(queryString, '?'))
1318 result = sqlite3_step(queryStatement);
1320 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1321 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1323 rowID = sqlite3_column_int64(queryStatement, 0);
1328 printf("SQLite Query Error: %s\n", queryString);
1333 curStatement = null;
1337 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1340 Class dataType = fld.type;
1341 SerialBuffer buffer = null;
1342 switch(fld.sqliteType)
1344 case SQLITE_INTEGER:
1346 switch(dataType.typeSize)
1349 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1352 result = sqlite3_bind_int(statement, pos, *(int *)data);
1358 value = (int)*(short *)data;
1360 value = (int)*(uint16 *)data;
1361 result = sqlite3_bind_int(statement, pos, value);
1368 value = (int)*(char *)data;
1370 value = (int)*(byte *)data;
1371 result = sqlite3_bind_int(statement, pos, value);
1379 if(dataType.typeSize == 8)
1380 result = sqlite3_bind_double(statement, pos, *(double *)data);
1382 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1388 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1390 result = sqlite3_bind_null(statement, pos);
1396 if((void *)data && dataType)
1398 buffer = SerialBuffer { };
1399 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1400 result = sqlite3_bind_text(statement, pos, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1403 result = sqlite3_bind_null(statement, pos);
1408 *bufferOut = buffer;
1414 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1416 if(move == next || move == previous)
1418 // Where clauses for index
1422 bool gotPrimaryKey = false;
1424 strcatf(command, " AND (");
1425 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1428 FieldIndex * fIndex = &tbl.indexFields[c];
1432 strcat(where, fIndex->field.name);
1433 strcat(where, "` ");
1434 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1435 strcat(where, " ? OR (");
1436 strcat(where, fIndex->field.name);
1437 if(fIndex->field == tbl.primaryKey)
1438 gotPrimaryKey = true;
1439 strcat(where, " = ? AND (");
1440 strcat(command, where);
1442 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1443 for(c = 0; c < tbl.indexFieldsCount; c++)
1444 strcat(command, "))");
1447 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1451 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1453 if(move == next || move == previous)
1455 // The binds for the Extra ordering Where clauses
1459 /* // Code to not rely on curStatement being set up
1460 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1461 dataRow.GoToSysID((uint)rowID);
1463 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1465 FieldIndex * fIndex = &tbl.indexFields[c];
1467 SQLiteField fld = (SQLiteField)fIndex->field;
1468 Class type = fld.type;
1470 SerialBuffer buffer;
1472 if(type.type == unitClass && !type.typeSize)
1474 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1478 if(type.type == structClass)
1480 data = (int64)(intptr)new0 byte[type.structSize];
1481 dataPtr = (void *)(intptr)data;
1483 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1484 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)(intptr)data : &data);
1485 if(type.type == normalClass || type.type == noHeadClass)
1486 dataPtr = (void *)(intptr)data;
1489 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1490 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1491 // Reuse the buffer for Blobs...
1492 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1494 sqlite3_bind_text(stmt, (*bindId)++, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1498 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1500 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1505 // Bind for the rowid
1506 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1510 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1512 char order[1024], command[2048];
1515 sqlite3_stmt * stmt = null;
1518 if(fld == tbl.primaryKey)
1520 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1521 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1522 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1523 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1524 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1525 result = GoToSysID(*(int *)data);
1531 useIndex = tbl.GetIndexOrder(order, false);
1533 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1534 AddCursorWhereClauses(command, move, useIndex);
1535 strcat(command, order);
1536 strcat(command, ";");
1537 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1538 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1539 BindCursorData(stmt, move, useIndex, &bindId);
1541 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1542 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1543 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1544 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1545 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1546 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1548 curStatement = findStatement = stmt;
1549 findBindId = bindId;
1551 // For going back to forward find
1553 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1554 AddCursorWhereClauses(command, next, useIndex);
1555 strcat(command, order);
1556 strcat(command, ";");
1557 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1558 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1559 nextFindStatement = stmt;
1562 tbl.GetIndexOrder(order, true);
1563 // For tracing back finds
1565 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1566 AddCursorWhereClauses(command, previous, true);
1567 strcat(command, order);
1568 strcat(command, ";");
1569 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1570 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1571 prevFindStatement = stmt;
1573 // For tracing back from last
1575 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1576 strcat(command, order);
1577 strcat(command, ";");
1578 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1579 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1580 lastFindStatement = stmt;
1582 result = sqlite3_step(findStatement);
1584 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1588 sqlite3_reset(findStatement);
1591 rowID = sqlite3_column_int64(findStatement, 0);
1595 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1598 for(c = 0; c < numFields; c++) \
1600 FieldFindData * fieldFind = &findData[c]; \
1601 SQLiteField sqlFld = (SQLiteField)findData->field; \
1602 Class dataType = sqlFld.type; \
1603 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i64, null); \
1608 char criterias[4096], command[4096], order[1024];
1612 sqlite3_stmt * stmt = null;
1616 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1617 for(c = 0; c < numFields; c++)
1619 FieldFindData * fieldFind = &findData[c];
1621 if(c) strcat(criterias, " AND `");
1622 strcat(criterias, fieldFind->field.name);
1623 strcat(criterias, "` = ?");
1626 useIndex = tbl.GetIndexOrder(order, false);
1627 // Basic Find (multiple)
1628 strcpy(command, criterias);
1629 AddCursorWhereClauses(command, move, useIndex);
1630 strcat(command, order);
1631 strcat(command, ";");
1632 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1634 BindCursorData(stmt, move, useIndex, &bindId);
1636 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1637 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1638 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1639 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1640 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1641 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1643 curStatement = findStatement = stmt;
1644 findBindId = bindId;
1646 // For tracing back forward finds
1648 strcpy(command, criterias);
1649 AddCursorWhereClauses(command, previous, true);
1650 strcat(command, order);
1651 strcat(command, ";");
1652 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1654 nextFindStatement = stmt;
1657 tbl.GetIndexOrder(order, true);
1658 // For tracing back finds
1660 strcpy(command, criterias);
1661 AddCursorWhereClauses(command, next, useIndex);
1662 strcat(command, order);
1663 strcat(command, ";");
1664 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1666 prevFindStatement = stmt;
1668 // For tracing back from last
1670 strcpy(command, criterias);
1671 strcat(command, order);
1672 strcat(command, ";");
1673 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1675 lastFindStatement = stmt;
1677 result = sqlite3_step(findStatement);
1678 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1682 sqlite3_reset(findStatement);
1685 rowID = sqlite3_column_int64(findStatement, 0);
1691 bool Synch(DriverRow to)
1693 SQLiteRow rowTo = (SQLiteRow)to;
1694 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1695 return GoToSysID((uint)rowTo.rowID);
1702 //char command[1024];
1703 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1704 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1707 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1708 result = sqlite3_step(insertIDStatement);
1711 result = sqlite3_step(insertStatement);
1712 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1714 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1715 if(rowID > MAXDWORD)
1717 int64 lastID = tbl.lastID;
1719 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1723 result = sqlite3_step(selectRowIDsStmt);
1724 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1725 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1726 if(id - lastID > 1) break;
1729 sqlite3_reset(selectRowIDsStmt);
1731 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1734 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1735 result = sqlite3_step(setRowIDStmt);
1736 sqlite3_reset(setRowIDStmt);
1738 sqlite3_reset(id ? insertIDStatement : insertStatement);
1739 curStatement = sysIDStatement;
1741 sqlite3_reset(curStatement);
1742 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1743 result = sqlite3_step(curStatement);
1744 done = false; // Make sure 'nil' is false
1747 sqlite3_reset(insertStatement);
1754 //char command[1024];
1755 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1756 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1757 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1758 result = sqlite3_step(deleteStatement);
1759 sqlite3_reset(deleteStatement);
1761 return result == SQLITE_OK || result == SQLITE_DONE;
1764 bool GetData(Field fld, typed_object &data)
1766 SQLiteField sqlFld = (SQLiteField)fld;
1767 int num = sqlFld.num + 1;
1768 Class dataType = *&sqlFld.type;
1771 switch(sqlFld.sqliteType)
1773 case SQLITE_INTEGER:
1775 switch(dataType.typeSize)
1778 if(fld == tbl.primaryKey)
1779 *(int64 *)data = rowID;
1781 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1784 if(fld == tbl.primaryKey)
1785 *(int *)data = (int)(uint)rowID;
1787 *(int *)data = sqlite3_column_int(curStatement, num);
1792 if(fld == tbl.primaryKey)
1793 value = (int)(uint)rowID;
1795 value = sqlite3_column_int(curStatement, num);
1797 *(short *)data = (short)value;
1799 *(uint16 *)data = (uint16)value;
1805 if(fld == tbl.primaryKey)
1806 value = (int)(uint)rowID;
1808 value = sqlite3_column_int(curStatement, num);
1810 *(char *)data = (char)value;
1812 *(byte *)data = (byte)value;
1820 double d = sqlite3_column_double(curStatement, num);
1821 if(dataType.typeSize == 8)
1822 *(double *)data = d;
1824 *(float *)data = (float)d;
1829 int numBytes = sqlite3_column_bytes(curStatement, num);
1830 const char * text = (const char *)sqlite3_column_text(curStatement, num);
1831 *(char **)data = text ? new byte[numBytes+1] : null;
1833 memcpy(*(char **)data, text, numBytes+1);
1838 SerialBuffer buffer { };
1839 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1840 buffer._size = sqlite3_column_bytes(curStatement, num);
1841 buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
1842 buffer.count = buffer._size;
1844 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1846 buffer._buffer = null;
1854 bool SetData(Field fld, typed_object data)
1856 SQLiteField sqlFld = (SQLiteField)fld;
1861 sqlite3_finalize(updateStatement);
1862 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1863 // TODO: Shouldn't we cache those update statements per field?
1864 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1865 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1866 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1867 result = sqlite3_step(updateStatement);
1868 sqlite3_reset(updateStatement);
1869 if(fld == tbl.primaryKey)
1870 rowID = *(uint64 *)data;
1871 return result == SQLITE_DONE;
1876 return (int64)rowID;
1879 bool GoToSysID(uint64 id)
1881 //char command[1024];
1885 //sqlite3_finalize(statement);
1886 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1887 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1891 sqlite3_reset(curStatement);
1893 curStatement = sysIDStatement;
1894 sqlite3_reset(sysIDStatement);
1895 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1896 result = sqlite3_step(curStatement);
1897 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1898 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1902 bool SetQueryParam(int paramID, int value)
1905 if(curStatement != queryStatement)
1907 if(curStatement) sqlite3_reset(curStatement);
1908 curStatement = queryStatement;
1910 sqlite3_reset(queryStatement);
1911 result = sqlite3_bind_int(queryStatement, paramID, value);
1915 bool SetQueryParam64(int paramID, int64 value)
1918 if(curStatement != queryStatement)
1920 if(curStatement) sqlite3_reset(curStatement);
1921 curStatement = queryStatement;
1923 sqlite3_reset(queryStatement);
1924 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1928 bool SetQueryParamText(int paramID, const char * data)
1931 if(curStatement != queryStatement)
1933 if(curStatement) sqlite3_reset(curStatement);
1934 curStatement = queryStatement;
1936 sqlite3_reset(queryStatement);
1938 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1940 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1944 bool SetQueryParamObject(int paramID, const void * data, Class type)
1947 if(curStatement != queryStatement)
1949 if(curStatement) sqlite3_reset(curStatement);
1950 curStatement = queryStatement;
1952 sqlite3_reset(queryStatement);
1954 SerialBuffer buffer { };
1955 ((void (*)(void *, const void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1956 result = sqlite3_bind_text(queryStatement, paramID, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1962 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
1964 if(curStatement != queryStatement)
1966 if(curStatement) sqlite3_reset(curStatement);
1967 curStatement = queryStatement;
1969 sqlite3_reset(queryStatement);
1970 return BindData(queryStatement, pos, fld, data, null);
1973 bool GetQueryData(int num, SQLiteField fld, typed_object & data)
1975 SQLiteField sqlFld = (SQLiteField)fld;
1976 Class dataType = *&sqlFld.type;
1978 switch(sqlFld.sqliteType)
1980 case SQLITE_INTEGER:
1982 switch(dataType.typeSize)
1985 if(fld == tbl.primaryKey)
1986 *(int64 *)data = rowID;
1988 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1991 if(fld == tbl.primaryKey)
1992 *(int *)data = (int)(uint)rowID;
1994 *(int *)data = sqlite3_column_int(curStatement, num);
1999 if(fld == tbl.primaryKey)
2000 value = (int)(uint)rowID;
2002 value = sqlite3_column_int(curStatement, num);
2004 *(short *)data = (short)value;
2006 *(uint16 *)data = (uint16)value;
2012 if(fld == tbl.primaryKey)
2013 value = (int)(uint)rowID;
2015 value = sqlite3_column_int(curStatement, num);
2017 *(char *)data = (char)value;
2019 *(byte *)data = (byte)value;
2027 double d = sqlite3_column_double(curStatement, num);
2028 if(dataType.typeSize == 8)
2029 *(double *)data = d;
2031 *(float *)data = (float)d;
2036 int numBytes = sqlite3_column_bytes(curStatement, num);
2037 const char * text = (const char *)sqlite3_column_text(curStatement, num);
2038 *(char **)data = text ? new byte[numBytes+1] : null;
2040 memcpy(*(char **)data, text, numBytes+1);
2045 SerialBuffer buffer { };
2046 //buffer._buffer = sqlite3_column_blob(curStatement, num);
2047 buffer._size = sqlite3_column_bytes(curStatement, num);
2048 buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
2049 buffer.count = buffer._size;
2051 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
2053 buffer._buffer = null;
2061 /*char * GetExtraColumn(int paramID)
2063 SQLiteField lastFld = tbl._fields.last;
2064 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
2066 const char * GetColumn(int paramID)
2068 return (const char *)sqlite3_column_text(curStatement, paramID);