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 int CollationCompare(Class type, int count1, const void * data1, int count2, const void * data2)
45 if(type.type == normalClass || type.type == noHeadClass)
47 Instance inst1, inst2;
49 SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
50 SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
52 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst1, buffer1);
53 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst2, buffer2);
55 result = ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
57 buffer1.buffer = null;
58 buffer2.buffer = null;
65 else if(type.type == structClass)
67 void * inst1, * inst2;
69 SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
70 SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
72 inst1 = new0 byte[type.structSize];
73 inst2 = new0 byte[type.structSize];
74 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst1, buffer1);
75 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst2, buffer2);
77 result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
79 buffer1.buffer = null;
80 buffer2.buffer = null;
88 return ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, data1, data2);
91 public class SQLiteStaticLink { } // Until .imp generation is fixed
93 class SQLiteDataSource : DirFilesDataSourceDriver
95 class_property(name) = "SQLite";
96 class_property(databaseFileExtension) = "sqlite";
98 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
100 Database result = null;
103 String path = MakeDatabasePath(name);
106 // sqlite3_open(path, &db);
107 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
109 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
110 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
112 // fprintf(stderr, "%s\n", s); // interesting
113 printf($"EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
121 sqlite3_exec(db, "PRAGMA page_size=4096;", null, null, null);
123 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
124 sqlite3_exec(db, command, null, null, null);
126 if(createOptions != readOnly)
128 sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
129 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
130 if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
133 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
137 result = SQLiteDatabase { db = db };
145 class SQLiteField : Field
150 public LinkElement<SQLiteField> link;
160 const String GetName()
168 int GetLength() { return length; }
183 class SQLiteDatabase : Database
186 AVLTree<const String> collations { };
190 sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
191 // "Simply setting the locking-mode to NORMAL is not enough - locks are not released until the next time the database file is accessed."
192 sqlite3_exec(db, "SELECT COUNT(*) from eda_table_fields", null, null, null);
196 uint ObjectsCount(ObjectType type)
202 bool RenameObject(ObjectType type, const String name, const String rename)
208 bool DeleteObject(ObjectType type, const String name)
214 Table OpenTable(const String name, OpenOptions options)
218 int nRows = 0, nCols = 0;
220 SQLiteTable table = null;
221 if(options.type == tablesList)
224 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
225 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
226 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
229 table._fields.Add(field);
231 else if(options.type == fieldsList)
235 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
236 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
238 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
240 table._fields.Add(field);
241 field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
243 table._fields.Add(field);
244 field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
246 table._fields.Add(field);
248 else if(options.type == tableRows)
250 bool addFields = false;
252 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
253 /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
257 sqlite3_free_table(t);
259 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
260 nCols = 0, nRows = 0;
261 /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
263 if((nCols || nRows) || options.create)
265 table = SQLiteTable { db = this, name = CopyString(name) };
268 table.mustCreate = true;
274 for(r = 1; r <= nRows; r++) // There should be only 1 row here
276 char * sql = t[nCols * r];
277 char * bracket = strchr(sql, '(');
289 int sqliteType = SQLITE_BLOB;
290 Class type = class(int);
294 while((ch = bracket[c++]))
296 if(ch == ',' || ch == ')')
299 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
301 memcpy(fieldName, bracket + start, d - start);
302 fieldName[d - start] = 0;
304 memcpy(dataType, bracket + d + 1, c - d - 2);
305 dataType[c - d - 2] = 0;
307 while(ch && bracket[c] == ' ') c++;
309 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
310 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
311 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
312 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
314 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
315 fieldName, type.name, 0);
316 /*result = */sqlite3_exec(db, command, null, null, null);
319 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table._fields.count, sqliteType = sqliteType };
321 table._fields.Add(field);
324 if(!ch || ch == ')') break;
331 Table refTable = null;
332 sqlite3_stmt * statement;
334 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
335 /*result = */sqlite3_prepare_v2(db, command, -1, &statement, null);
337 while(sqlite3_step(statement) != SQLITE_DONE)
339 const char * fieldName = (const char *)sqlite3_column_text(statement, 0);
340 const char * typeName = (const char *)sqlite3_column_text(statement, 1);
341 int length = sqlite3_column_int(statement, 2);
343 int sqliteType = SQLITE_BLOB;
345 type.OnGetDataFromString(typeName);
349 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
350 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
351 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
352 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
353 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
354 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
355 sqliteType = SQLITE_INTEGER;
356 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
357 sqliteType = SQLITE_FLOAT;
358 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
359 sqliteType = SQLITE_TEXT;
362 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
364 collations.Add(type.fullName);
365 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
367 sqliteType = SQLITE_BLOB;
372 Table * fTable = (Table *)(intptr)eClass_GetProperty(type, "table");
373 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table._fields.count, sqliteType = sqliteType };
375 if(fTable) refTable = *fTable;
376 if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
377 table.primaryKey = field;
379 table._fields.Add(field);
382 sqlite3_finalize(statement);
386 sqlite3_free_table(t);
395 sprintf(command, "BEGIN;");
396 result = sqlite3_exec(db, command, null, null, null);
398 PrintLn($"BEGIN FAILED!");
399 return result == SQLITE_OK;
406 sprintf(command, "COMMIT;");
407 result = sqlite3_exec(db, command, null, null, null);
409 PrintLn($"COMMIT FAILED!");
410 return result == SQLITE_OK;
413 bool CreateCustomFunction(const char * name, SQLCustomFunction customFunction)
416 Class cfClass = customFunction._class;
417 customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
418 if(customFunction.method)
420 String typeString = CopyString(customFunction.method.dataTypeString);
422 int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
424 bool variadic = false;
426 for(c = 0; c < count; c++)
429 bool pointer = false;
430 const String arg = tokens[c];
432 TrimLSpaces(tokens[c], tokens[c]);
433 if(strchr(arg, '*')) pointer = true;
435 // Using String for generic pointer...
436 type = class(String);
439 if((space = strchr(arg, ' '))) *space = 0;
440 if(!strcmp(arg, "void"))
442 else if(!strcmp(arg, "..."))
446 if(cfClass.templateParams.count)
448 ClassTemplateParameter p;
450 for(p = cfClass.templateParams.first; p; p = p.next, id++)
452 if(!strcmp(p.name, arg))
455 if(p && cfClass.templateArgs)
456 arg = cfClass.templateArgs[id].dataTypeString;
458 type = eSystem_FindClass(customFunction._class.module, arg);
460 type = eSystem_FindClass(customFunction._class.module.application, arg);
464 customFunction.returnType = type;
466 customFunction.args.Add(type);
472 // Variadic args don't make sense for SQL custom functions
473 // Note that different CIF must be prepared for different set of arguments
474 // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
478 customFunction.rType = FFIGetType(customFunction.returnType, true);
479 customFunction.argTypes.Add((void *)&ffi_type_pointer); // This pointer for SQLCustomFunction object
480 for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
481 ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
482 result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
489 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
490 FFITypesHolder structFFITypes { };
491 __attribute__((unused)) static Iterator dummy; // TOFIX: forward struct declaration issues on Clang
493 public ffi_type * FFIGetType(Class type, bool structByValue)
502 MapIterator<Class, String> it { map = structFFITypes };
503 ffi_type * ffiType = null;
504 if(it.Index(type, false))
505 ffiType = (void *)it.data;
510 Array<String> memberTypes { };
511 for(member = type.membersAndProperties.first; member; member = member.next)
513 if(!member.isProperty)
515 memberTypes.Add(FFIGetType(member.dataType
519 ffiType = new0 ffi_type[1];
520 ffiType->size = type.structSize;
521 ffiType->type = FFI_TYPE_STRUCT;
522 structFFITypes[type] = (void *)ffiType;
529 return &ffi_type_pointer;
535 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
536 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
538 switch(type.typeSize)
540 case 1: return &ffi_type_uint8;
541 case 2: return &ffi_type_uint16;
542 case 4: return &ffi_type_uint32;
543 case 8: return &ffi_type_uint64;
547 return &ffi_type_void;
551 static SerialBuffer staticBuffer { };
552 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
554 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
556 /* // Simple 1 pointer param returning a string
557 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
558 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
561 void * ret = &retData;
562 Array<String> args { size = sqlFunction.args.count + 1 };
563 Iterator<String> ffiArg { sqlFunction.argTypes };
564 Iterator<String> arg { args };
567 // this * for the SQLCustomFunction
568 args[0] = (void *)&sqlFunction;
570 // Get the arguments from SQLite
571 for(a : sqlFunction.args)
573 ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
582 void ** data = new void *[1];
583 args[i+1] = (void *)data;
584 if(a == class(String))
586 int numBytes = sqlite3_value_bytes(values[i]);
587 const char * text = (const char *)sqlite3_value_text(values[i]);
588 *(char **)data = text ? new byte[numBytes+1] : null;
590 memcpy(*(char **)data, text, numBytes+1);
594 SerialBuffer buffer = staticBuffer; //{ };
596 buffer._size = sqlite3_value_bytes(values[i]);
597 buffer._buffer = (byte *)sqlite3_value_text(values[i]);
598 //buffer._buffer = sqlite3_value_blob(curStatement);
599 buffer.count = buffer._size;
600 if(a.type == structClass)
601 *data = new byte[a.structSize];
602 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
603 buffer._buffer = null;
612 if(type == &ffi_type_double || type == &ffi_type_float)
614 double d = sqlite3_value_double(values[i]);
617 double * data = new double[1];
618 args[i+1] = (void *)data;
623 float * data = new float[1];
624 args[i+1] = (void *)data;
634 int64 * data = new int64[1];
635 args[i+1] = (void *)data;
636 *data = sqlite3_value_int64(values[i]);
641 int * data = new int[1];
642 args[i+1] = (void *)data;
643 *data = sqlite3_value_int(values[i]);
648 short * data = new short[1];
650 args[i+1] = (void *)data;
651 value = sqlite3_value_int(values[i]);
653 *data = (short)value;
655 *(uint16 *)data = (uint16)value;
660 char * data = new char[1];
663 value = sqlite3_value_int(values[i]);
667 *(byte *)data = (byte)value;
677 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
678 ret = new byte[sqlFunction.returnType.typeSize];
679 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
680 // Give SQLite the return value
681 if(sqlFunction.returnType)
683 ffi_type * type = sqlFunction.rType;
684 Class r = sqlFunction.returnType;
692 void * data = ret ? *(void **)ret : null;
693 if(r.type == structClass)
695 if(r == class(String))
698 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
700 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
704 SerialBuffer buffer { };
705 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
706 sqlite3_result_text(context, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
709 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
710 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
713 if(r.type == structClass)
721 if(type == &ffi_type_double || type == &ffi_type_float)
724 sqlite3_result_double(context, *(double *)ret);
726 sqlite3_result_double(context, (double)*(float *)ret);
733 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
736 sqlite3_result_int(context, *(int *)ret);
742 value = (int)*(short *)ret;
744 //value = (int)*(uint16 *)ret;
745 sqlite3_result_int(context, value);
752 value = (int)*(char *)ret;
754 //value = (int)*(byte *)ret;
755 sqlite3_result_int(context, value);
766 for(type : sqlFunction.args; arg.Next())
769 void * data = *(void **)arg.data;
770 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
771 if(type.type == structClass)
780 class SQLiteTable : Table
785 LinkList<SQLiteField> _fields { };
786 char * specialStatement;
787 SQLiteField primaryKey;
788 FieldIndex * indexFields;
789 int indexFieldsCount;
792 Field AddField(const String fieldName, Class type, int length)
799 Table refTable = null;
800 Field idField = null;
803 if(FindField(fieldName)) return null;
805 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
806 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
807 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
808 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
809 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
810 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
812 strcpy(dataType, "INTEGER");
813 sqliteType = SQLITE_INTEGER;
815 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
817 strcpy(dataType, "REAL");
818 sqliteType = SQLITE_FLOAT;
820 else if(!strcmp(type.name, "CIString"))
822 strcpy(dataType, "TEXT");
823 sqliteType = SQLITE_BLOB;
825 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
827 strcpy(dataType, "TEXT");
828 sqliteType = SQLITE_TEXT;
832 //strcpy(dataType, "BLOB");
833 strcpy(dataType, "TEXT");
834 sqliteType = SQLITE_BLOB;
836 if(!db.collations.Find(type.fullName))
838 db.collations.Add(type.fullName);
839 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
842 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)) && type != class(eda::Id))
844 Table * table = (Table *)(intptr)eClass_GetProperty(type, "table");
845 if(table) refTable = *table;
848 if(primaryKey || refTable != this)
850 for(idField = refTable.firstField; idField; idField = idField.next)
851 if(eClass_IsDerived(type, idField.type)) break;
854 PrintLn("WARNING: field not yet created for class ", (String)type.name);
857 idField = primaryKey;
861 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
867 if(sqliteType == SQLITE_BLOB)
869 if(!strcmp(type.name, "CIString"))
870 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
872 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
876 if(!idField && refTable == this)
877 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
879 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
882 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
883 result = sqlite3_exec(db.db, command, null, null, null);
884 if(result) return null;
889 if(sqliteType == SQLITE_BLOB)
891 if(!strcmp(type.name, "CIString"))
892 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
894 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
898 if(!idField && refTable == this)
900 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
901 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
904 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
907 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
908 result = sqlite3_exec(db.db, command, null, null, null);
909 if(result) return null;
912 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
913 fieldName, type.name, length);
914 result = sqlite3_exec(db.db, command, null, null, null);
916 field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
919 if(!primaryKey && refTable == this)
924 Field FindField(const String name)
926 for(f : _fields; !strcmp(f.name, name))
930 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
933 Table * tablePtr = (Table *)(intptr)eClass_GetProperty(f.type, "table");
934 if(tablePtr && *tablePtr == this)
943 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
948 char indexName[4096];
951 indexFieldsCount = count;
952 indexFields = new FieldIndex[count];
953 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
955 // TODO: USE CODED INDEX NAME INSTEAD?
956 strcpy(indexName, "index_");
957 strcat(indexName, name);
958 strcat(indexName, "_");
959 for(c = 0; c<count; c++)
961 if(fieldIndexes[c].field)
963 if(count == 1 && fieldIndexes[c].field == primaryKey)
965 strcat(indexName, fieldIndexes[c].field.name);
966 if(fieldIndexes[c].memberField)
968 strcat(indexName, ".");
969 strcat(indexName, fieldIndexes[c].memberField.name);
971 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
977 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
978 for(c = 0; c<count; c++)
980 char columnName[1024];
981 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
982 if(c > 0) strcat(command, ", ");
983 strcat(command, columnName);
985 strcat(command, ");");
986 result = sqlite3_exec(db.db, command, null, null, null);
988 return result == SQLITE_OK;
991 const String GetName()
996 Field GetFirstField()
998 return _fields.first;
1001 Field GetPrimaryKey()
1006 uint GetFieldsCount()
1008 return _fields.count;
1018 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1019 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1020 if(result == SQLITE_OK)
1022 rowCount = atoi(t[1]);
1023 sqlite3_free_table(t);
1028 // Returns true if not ordered by row ID
1029 bool GetIndexOrder(char * fullOrder, bool flip)
1031 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1033 strcpy(fullOrder, " ORDER BY ROWID");
1039 strcpy(fullOrder, " ORDER BY ");
1040 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1043 FieldIndex * fIndex = &indexFields[c];
1045 if(c) strcat(order, ", ");
1047 strcat(order, fIndex->field.name);
1049 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1050 strcat(fullOrder, order);
1056 Container<Field> GetFields()
1058 return (Container<Field>)_fields;
1061 DriverRow CreateRow()
1064 sqlite3_stmt * statement;
1065 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1066 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1068 if(specialStatement)
1069 strcpy(command, specialStatement);
1073 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1074 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1075 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1076 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1078 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1079 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1081 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1082 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1084 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1085 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1087 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1088 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1090 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1091 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1093 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1094 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1096 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1098 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1100 GetIndexOrder(order, false);
1101 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1103 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1105 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1106 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1108 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1109 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1112 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1113 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1114 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1120 delete specialStatement;
1126 class SQLiteRow : DriverRow
1129 sqlite3_stmt * curStatement;
1131 sqlite3_stmt * defaultStatement;
1132 sqlite3_stmt * findStatement;
1133 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1134 sqlite3_stmt * nextFindStatement;
1135 sqlite3_stmt * sysIDStatement;
1136 sqlite3_stmt * queryStatement;
1137 sqlite3_stmt * selectRowIDsStmt;
1138 sqlite3_stmt * setRowIDStmt;
1139 sqlite3_stmt * lastStatement;
1140 sqlite3_stmt * previousStatement;
1141 sqlite3_stmt * nextStatement;
1143 sqlite3_stmt * insertStatement;
1144 sqlite3_stmt * deleteStatement;
1145 sqlite3_stmt * updateStatement;
1146 sqlite3_stmt * insertIDStatement;
1150 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1151 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1162 if(defaultStatement) sqlite3_finalize(defaultStatement);
1163 if(findStatement) sqlite3_finalize(findStatement);
1164 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1165 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1166 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1167 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1168 if(insertStatement) sqlite3_finalize(insertStatement);
1169 if(deleteStatement) sqlite3_finalize(deleteStatement);
1170 if(updateStatement) sqlite3_finalize(updateStatement);
1171 if(queryStatement) sqlite3_finalize(queryStatement);
1172 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1173 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1174 if(previousStatement)sqlite3_finalize(previousStatement);
1175 if(nextStatement) sqlite3_finalize(nextStatement);
1176 if(lastStatement) sqlite3_finalize(lastStatement);
1177 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1180 bool Select(MoveOptions move)
1183 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1185 curStatement = defaultStatement;
1190 sqlite3_reset(curStatement);
1191 result = sqlite3_step(curStatement);
1192 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1193 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1194 rowID = sqlite3_column_int64(curStatement, 0);
1199 sqlite3_reset(curStatement);
1200 curStatement = lastStatement;
1201 result = sqlite3_step(curStatement);
1202 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1203 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1204 rowID = sqlite3_column_int64(curStatement, 0);
1212 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1213 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1214 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1216 result = sqlite3_step(curStatement);
1217 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1218 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1219 rowID = sqlite3_column_int64(curStatement, 0);
1221 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1225 int bindId = findBindId;
1226 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1227 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1228 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1229 sqlite3_reset(curStatement);
1230 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1231 result = sqlite3_step(curStatement);
1232 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1233 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1234 rowID = sqlite3_column_int64(curStatement, 0);
1238 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1239 sqlite3_reset(curStatement);
1240 curStatement = (move == next) ? findStatement : lastFindStatement;
1241 result = sqlite3_step(curStatement);
1242 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1243 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1244 rowID = sqlite3_column_int64(curStatement, 0);
1249 sqlite3_reset(curStatement);
1250 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1251 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1252 result = sqlite3_step(curStatement);
1253 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1254 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1255 rowID = sqlite3_column_int64(curStatement, 0);
1260 sqlite3_reset(curStatement);
1270 bool Query(const char * queryString)
1276 sqlite3_reset(curStatement);
1279 sqlite3_finalize(queryStatement);
1280 queryStatement = null;
1285 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1288 curStatement = queryStatement;
1289 if(!strchr(queryString, '?'))
1291 result = sqlite3_step(queryStatement);
1293 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1294 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1296 rowID = sqlite3_column_int64(queryStatement, 0);
1301 printf("SQLite Query Error: %s\n", queryString);
1306 curStatement = null;
1310 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1313 Class dataType = fld.type;
1314 SerialBuffer buffer = null;
1315 switch(fld.sqliteType)
1317 case SQLITE_INTEGER:
1319 switch(dataType.typeSize)
1322 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1325 result = sqlite3_bind_int(statement, pos, *(int *)data);
1331 value = (int)*(short *)data;
1333 value = (int)*(uint16 *)data;
1334 result = sqlite3_bind_int(statement, pos, value);
1341 value = (int)*(char *)data;
1343 value = (int)*(byte *)data;
1344 result = sqlite3_bind_int(statement, pos, value);
1352 if(dataType.typeSize == 8)
1353 result = sqlite3_bind_double(statement, pos, *(double *)data);
1355 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1361 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1363 result = sqlite3_bind_null(statement, pos);
1369 if((void *)data && dataType)
1371 buffer = SerialBuffer { };
1372 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1373 result = sqlite3_bind_text(statement, pos, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1376 result = sqlite3_bind_null(statement, pos);
1381 *bufferOut = buffer;
1387 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1389 if(move == next || move == previous)
1391 // Where clauses for index
1395 bool gotPrimaryKey = false;
1397 strcatf(command, " AND (");
1398 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1401 FieldIndex * fIndex = &tbl.indexFields[c];
1405 strcat(where, fIndex->field.name);
1406 strcat(where, "` ");
1407 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1408 strcat(where, " ? OR (");
1409 strcat(where, fIndex->field.name);
1410 if(fIndex->field == tbl.primaryKey)
1411 gotPrimaryKey = true;
1412 strcat(where, " = ? AND (");
1413 strcat(command, where);
1415 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1416 for(c = 0; c < tbl.indexFieldsCount; c++)
1417 strcat(command, "))");
1420 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1424 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1426 if(move == next || move == previous)
1428 // The binds for the Extra ordering Where clauses
1432 /* // Code to not rely on curStatement being set up
1433 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1434 dataRow.GoToSysID((uint)rowID);
1436 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1438 FieldIndex * fIndex = &tbl.indexFields[c];
1440 SQLiteField fld = (SQLiteField)fIndex->field;
1441 Class type = fld.type;
1443 SerialBuffer buffer;
1445 if(type.type == unitClass && !type.typeSize)
1447 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1451 if(type.type == structClass)
1453 data = (int64)(intptr)new0 byte[type.structSize];
1454 dataPtr = (void *)(intptr)data;
1456 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1457 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)(intptr)data : &data);
1458 if(type.type == normalClass || type.type == noHeadClass)
1459 dataPtr = (void *)(intptr)data;
1462 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1463 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1464 // Reuse the buffer for Blobs...
1465 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1467 sqlite3_bind_text(stmt, (*bindId)++, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1471 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1473 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1478 // Bind for the rowid
1479 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1483 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1485 char order[1024], command[2048];
1488 sqlite3_stmt * stmt = null;
1491 if(fld == tbl.primaryKey)
1493 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1494 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1495 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1496 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1497 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1498 result = GoToSysID(*(int *)data);
1504 useIndex = tbl.GetIndexOrder(order, false);
1506 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1507 AddCursorWhereClauses(command, move, useIndex);
1508 strcat(command, order);
1509 strcat(command, ";");
1510 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1511 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1512 BindCursorData(stmt, move, useIndex, &bindId);
1514 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1515 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1516 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1517 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1518 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1519 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1521 curStatement = findStatement = stmt;
1522 findBindId = bindId;
1524 // For going back to forward find
1526 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1527 AddCursorWhereClauses(command, next, useIndex);
1528 strcat(command, order);
1529 strcat(command, ";");
1530 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1531 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1532 nextFindStatement = stmt;
1535 tbl.GetIndexOrder(order, true);
1536 // For tracing back finds
1538 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1539 AddCursorWhereClauses(command, previous, true);
1540 strcat(command, order);
1541 strcat(command, ";");
1542 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1543 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1544 prevFindStatement = stmt;
1546 // For tracing back from last
1548 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1549 strcat(command, order);
1550 strcat(command, ";");
1551 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1552 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1553 lastFindStatement = stmt;
1555 result = sqlite3_step(findStatement);
1557 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1561 sqlite3_reset(findStatement);
1564 rowID = sqlite3_column_int64(findStatement, 0);
1568 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1571 for(c = 0; c < numFields; c++) \
1573 FieldFindData * fieldFind = &findData[c]; \
1574 SQLiteField sqlFld = (SQLiteField)findData->field; \
1575 Class dataType = sqlFld.type; \
1576 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i64, null); \
1581 char criterias[4096], command[4096], order[1024];
1585 sqlite3_stmt * stmt = null;
1589 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1590 for(c = 0; c < numFields; c++)
1592 FieldFindData * fieldFind = &findData[c];
1594 if(c) strcat(criterias, " AND `");
1595 strcat(criterias, fieldFind->field.name);
1596 strcat(criterias, "` = ?");
1599 useIndex = tbl.GetIndexOrder(order, false);
1600 // Basic Find (multiple)
1601 strcpy(command, criterias);
1602 AddCursorWhereClauses(command, move, useIndex);
1603 strcat(command, order);
1604 strcat(command, ";");
1605 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1607 BindCursorData(stmt, move, useIndex, &bindId);
1609 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1610 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1611 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1612 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1613 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1614 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1616 curStatement = findStatement = stmt;
1617 findBindId = bindId;
1619 // For tracing back forward finds
1621 strcpy(command, criterias);
1622 AddCursorWhereClauses(command, previous, true);
1623 strcat(command, order);
1624 strcat(command, ";");
1625 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1627 nextFindStatement = stmt;
1630 tbl.GetIndexOrder(order, true);
1631 // For tracing back finds
1633 strcpy(command, criterias);
1634 AddCursorWhereClauses(command, next, useIndex);
1635 strcat(command, order);
1636 strcat(command, ";");
1637 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1639 prevFindStatement = stmt;
1641 // For tracing back from last
1643 strcpy(command, criterias);
1644 strcat(command, order);
1645 strcat(command, ";");
1646 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1648 lastFindStatement = stmt;
1650 result = sqlite3_step(findStatement);
1651 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1655 sqlite3_reset(findStatement);
1658 rowID = sqlite3_column_int64(findStatement, 0);
1664 bool Synch(DriverRow to)
1666 SQLiteRow rowTo = (SQLiteRow)to;
1667 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1668 return GoToSysID((uint)rowTo.rowID);
1675 //char command[1024];
1676 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1677 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1680 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1681 result = sqlite3_step(insertIDStatement);
1684 result = sqlite3_step(insertStatement);
1685 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1687 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1688 if(rowID > MAXDWORD)
1690 int64 lastID = tbl.lastID;
1692 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1696 result = sqlite3_step(selectRowIDsStmt);
1697 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1698 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1699 if(id - lastID > 1) break;
1702 sqlite3_reset(selectRowIDsStmt);
1704 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1707 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1708 result = sqlite3_step(setRowIDStmt);
1709 sqlite3_reset(setRowIDStmt);
1711 sqlite3_reset(id ? insertIDStatement : insertStatement);
1712 curStatement = sysIDStatement;
1714 sqlite3_reset(curStatement);
1715 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1716 result = sqlite3_step(curStatement);
1717 done = false; // Make sure 'nil' is false
1720 sqlite3_reset(insertStatement);
1727 //char command[1024];
1728 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1729 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1730 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1731 result = sqlite3_step(deleteStatement);
1732 sqlite3_reset(deleteStatement);
1734 return result == SQLITE_OK || result == SQLITE_DONE;
1737 bool GetData(Field fld, typed_object &data)
1739 SQLiteField sqlFld = (SQLiteField)fld;
1740 int num = sqlFld.num + 1;
1741 Class dataType = *&sqlFld.type;
1744 switch(sqlFld.sqliteType)
1746 case SQLITE_INTEGER:
1748 switch(dataType.typeSize)
1751 if(fld == tbl.primaryKey)
1752 *(int64 *)data = rowID;
1754 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1757 if(fld == tbl.primaryKey)
1758 *(int *)data = (int)(uint)rowID;
1760 *(int *)data = sqlite3_column_int(curStatement, num);
1765 if(fld == tbl.primaryKey)
1766 value = (int)(uint)rowID;
1768 value = sqlite3_column_int(curStatement, num);
1770 *(short *)data = (short)value;
1772 *(uint16 *)data = (uint16)value;
1778 if(fld == tbl.primaryKey)
1779 value = (int)(uint)rowID;
1781 value = sqlite3_column_int(curStatement, num);
1783 *(char *)data = (char)value;
1785 *(byte *)data = (byte)value;
1793 double d = sqlite3_column_double(curStatement, num);
1794 if(dataType.typeSize == 8)
1795 *(double *)data = d;
1797 *(float *)data = (float)d;
1802 int numBytes = sqlite3_column_bytes(curStatement, num);
1803 const char * text = (const char *)sqlite3_column_text(curStatement, num);
1804 *(char **)data = text ? new byte[numBytes+1] : null;
1806 memcpy(*(char **)data, text, numBytes+1);
1811 SerialBuffer buffer { };
1812 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1813 buffer._size = sqlite3_column_bytes(curStatement, num);
1814 buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
1815 buffer.count = buffer._size;
1817 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1819 buffer._buffer = null;
1827 bool SetData(Field fld, typed_object data)
1829 SQLiteField sqlFld = (SQLiteField)fld;
1834 sqlite3_finalize(updateStatement);
1835 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1836 // TODO: Shouldn't we cache those update statements per field?
1837 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1838 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1839 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1840 result = sqlite3_step(updateStatement);
1841 sqlite3_reset(updateStatement);
1842 if(fld == tbl.primaryKey)
1843 rowID = *(uint64 *)data;
1844 return result == SQLITE_DONE;
1849 return (int64)rowID;
1852 bool GoToSysID(uint64 id)
1854 //char command[1024];
1858 //sqlite3_finalize(statement);
1859 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1860 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1864 sqlite3_reset(curStatement);
1866 curStatement = sysIDStatement;
1867 sqlite3_reset(sysIDStatement);
1868 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1869 result = sqlite3_step(curStatement);
1870 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1871 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1875 bool SetQueryParam(int paramID, int value)
1878 if(curStatement != queryStatement)
1880 if(curStatement) sqlite3_reset(curStatement);
1881 curStatement = queryStatement;
1883 sqlite3_reset(queryStatement);
1884 result = sqlite3_bind_int(queryStatement, paramID, value);
1888 bool SetQueryParam64(int paramID, int64 value)
1891 if(curStatement != queryStatement)
1893 if(curStatement) sqlite3_reset(curStatement);
1894 curStatement = queryStatement;
1896 sqlite3_reset(queryStatement);
1897 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1901 bool SetQueryParamText(int paramID, const char * data)
1904 if(curStatement != queryStatement)
1906 if(curStatement) sqlite3_reset(curStatement);
1907 curStatement = queryStatement;
1909 sqlite3_reset(queryStatement);
1911 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1913 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1917 bool SetQueryParamObject(int paramID, const void * data, Class type)
1920 if(curStatement != queryStatement)
1922 if(curStatement) sqlite3_reset(curStatement);
1923 curStatement = queryStatement;
1925 sqlite3_reset(queryStatement);
1927 SerialBuffer buffer { };
1928 ((void (*)(void *, const void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1929 result = sqlite3_bind_text(queryStatement, paramID, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1935 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
1937 if(curStatement != queryStatement)
1939 if(curStatement) sqlite3_reset(curStatement);
1940 curStatement = queryStatement;
1942 sqlite3_reset(queryStatement);
1943 return BindData(queryStatement, pos, fld, data, null);
1946 bool GetQueryData(int num, SQLiteField fld, typed_object & data)
1948 SQLiteField sqlFld = (SQLiteField)fld;
1949 Class dataType = *&sqlFld.type;
1951 switch(sqlFld.sqliteType)
1953 case SQLITE_INTEGER:
1955 switch(dataType.typeSize)
1958 if(fld == tbl.primaryKey)
1959 *(int64 *)data = rowID;
1961 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1964 if(fld == tbl.primaryKey)
1965 *(int *)data = (int)(uint)rowID;
1967 *(int *)data = sqlite3_column_int(curStatement, num);
1972 if(fld == tbl.primaryKey)
1973 value = (int)(uint)rowID;
1975 value = sqlite3_column_int(curStatement, num);
1977 *(short *)data = (short)value;
1979 *(uint16 *)data = (uint16)value;
1985 if(fld == tbl.primaryKey)
1986 value = (int)(uint)rowID;
1988 value = sqlite3_column_int(curStatement, num);
1990 *(char *)data = (char)value;
1992 *(byte *)data = (byte)value;
2000 double d = sqlite3_column_double(curStatement, num);
2001 if(dataType.typeSize == 8)
2002 *(double *)data = d;
2004 *(float *)data = (float)d;
2009 int numBytes = sqlite3_column_bytes(curStatement, num);
2010 const char * text = (const char *)sqlite3_column_text(curStatement, num);
2011 *(char **)data = text ? new byte[numBytes+1] : null;
2013 memcpy(*(char **)data, text, numBytes+1);
2018 SerialBuffer buffer { };
2019 //buffer._buffer = sqlite3_column_blob(curStatement, num);
2020 buffer._size = sqlite3_column_bytes(curStatement, num);
2021 buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
2022 buffer.count = buffer._size;
2024 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
2026 buffer._buffer = null;
2034 /*char * GetExtraColumn(int paramID)
2036 SQLiteField lastFld = tbl._fields.last;
2037 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
2039 const char * GetColumn(int paramID)
2041 return (const char *)sqlite3_column_text(curStatement, paramID);