2 public import static "ecere"
3 public import static "EDA"
19 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, void * data1, int count2, void * data2)
45 if(type.type == normalClass || type.type == noHeadClass)
47 Instance inst1, inst2;
49 SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
50 SerialBuffer buffer2 { size = count2, count = count2, buffer = 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 *, void *, 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 = data1 };
70 SerialBuffer buffer2 { size = count2, count = count2, buffer = 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 *, void *, 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));
120 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
121 sqlite3_exec(db, command, null, null, null);
123 if(createOptions != readOnly)
125 sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
126 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
127 if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
130 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
134 result = SQLiteDatabase { db = db };
142 class SQLiteField : Field
147 public LinkElement<SQLiteField> link;
165 int GetLength() { return length; }
180 class SQLiteDatabase : Database
183 AVLTree<String> collations { };
187 sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
191 uint ObjectsCount(ObjectType type)
197 bool RenameObject(ObjectType type, const String name, const String rename)
203 bool DeleteObject(ObjectType type, const String name)
209 Table OpenTable(const String name, OpenOptions options)
213 int nRows = 0, nCols = 0;
215 SQLiteTable table = null;
216 if(options.type == tablesList)
219 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
220 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
221 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
224 table._fields.Add(field);
226 else if(options.type == fieldsList)
230 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
231 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
233 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
235 table._fields.Add(field);
236 field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
238 table._fields.Add(field);
239 field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
241 table._fields.Add(field);
243 else if(options.type == tableRows)
245 bool addFields = false;
247 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
248 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
252 sqlite3_free_table(t);
254 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
255 nCols = 0, nRows = 0;
256 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
258 if((nCols || nRows) || options.create)
260 table = SQLiteTable { db = this, name = CopyString(name) };
263 table.mustCreate = true;
269 for(r = 1; r <= nRows; r++) // There should be only 1 row here
271 char * sql = t[nCols * r];
272 char * bracket = strchr(sql, '(');
284 int sqliteType = SQLITE_BLOB;
285 Class type = class(int);
289 while((ch = bracket[c++]))
291 if(ch == ',' || ch == ')')
294 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
296 memcpy(fieldName, bracket + start, d - start);
297 fieldName[d - start] = 0;
299 memcpy(dataType, bracket + d + 1, c - d - 2);
300 dataType[c - d - 2] = 0;
302 while(ch && bracket[c] == ' ') c++;
304 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
305 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
306 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
307 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
309 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
310 fieldName, type.name, 0);
311 result = sqlite3_exec(db, command, null, null, null);
314 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table._fields.count, sqliteType = sqliteType };
316 table._fields.Add(field);
319 if(!ch || ch == ')') break;
326 Table refTable = null;
327 sqlite3_stmt * statement;
329 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
330 result = sqlite3_prepare_v2(db, command, -1, &statement, null);
332 while(sqlite3_step(statement) != SQLITE_DONE)
334 char * fieldName = sqlite3_column_text(statement, 0);
335 char * typeName = sqlite3_column_text(statement, 1);
336 int length = sqlite3_column_int(statement, 2);
338 int sqliteType = SQLITE_BLOB;
340 ((Class)(&type)).OnGetDataFromString(typeName); // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
344 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
345 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
346 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
347 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
348 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
349 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
350 sqliteType = SQLITE_INTEGER;
351 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
352 sqliteType = SQLITE_FLOAT;
353 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
354 sqliteType = SQLITE_TEXT;
357 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
359 collations.Add(type.fullName);
360 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
362 sqliteType = SQLITE_BLOB;
367 Table * fTable = (Table *)eClass_GetProperty(type, "table");
368 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table._fields.count, sqliteType = sqliteType };
370 if(fTable) refTable = *fTable;
371 if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
372 table.primaryKey = field;
374 table._fields.Add(field);
377 sqlite3_finalize(statement);
381 sqlite3_free_table(t);
390 sprintf(command, "BEGIN;");
391 result = sqlite3_exec(db, command, null, null, null);
393 PrintLn($"BEGIN FAILED!");
394 return result == SQLITE_OK;
401 sprintf(command, "COMMIT;");
402 result = sqlite3_exec(db, command, null, null, null);
404 PrintLn($"COMMIT FAILED!");
405 return result == SQLITE_OK;
408 bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
411 Class cfClass = customFunction._class;
412 customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
413 if(customFunction.method)
415 String typeString = CopyString(customFunction.method.dataTypeString);
417 int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
419 bool variadic = false;
421 for(c = 0; c < count; c++)
424 bool pointer = false;
425 String arg = tokens[c];
427 TrimLSpaces(arg, arg);
428 if(strchr(arg, '*')) pointer = true;
430 // Using String for generic pointer...
431 type = class(String);
434 if((space = strchr(arg, ' '))) *space = 0;
435 if(!strcmp(arg, "void"))
437 else if(!strcmp(arg, "..."))
441 if(cfClass.templateParams.count)
443 ClassTemplateParameter p;
445 for(p = cfClass.templateParams.first; p; p = p.next, id++)
447 if(!strcmp(p.name, arg))
450 if(p && cfClass.templateArgs)
451 arg = cfClass.templateArgs[id].dataTypeString;
453 type = eSystem_FindClass(customFunction._class.module, arg);
455 type = eSystem_FindClass(customFunction._class.module.application, arg);
459 customFunction.returnType = type;
461 customFunction.args.Add(type);
467 // Variadic args don't make sense for SQL custom functions
468 // Note that different CIF must be prepared for different set of arguments
469 // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
473 customFunction.rType = FFIGetType(customFunction.returnType, true);
474 customFunction.argTypes.Add((void *)&ffi_type_pointer); // This pointer for SQLCustomFunction object
475 for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
476 ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
477 result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
484 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
485 FFITypesHolder structFFITypes { };
487 public ffi_type * FFIGetType(Class type, bool structByValue)
496 MapIterator<Class, String> it { map = structFFITypes };
497 ffi_type * ffiType = null;
498 if(it.Index(type, false))
499 ffiType = (void *)it.data;
504 Array<String> memberTypes { };
505 for(member = type.membersAndProperties.first; member; member = member.next)
507 if(!member.isProperty)
509 memberTypes.Add(FFIGetType(member.dataType
513 ffiType = new0 ffi_type[1];
514 ffiType->size = type.structSize;
515 ffiType->type = FFI_TYPE_STRUCT;
516 structFFITypes[type] = (void *)ffiType;
523 return &ffi_type_pointer;
529 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
530 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
532 switch(type.typeSize)
534 case 1: return &ffi_type_uint8;
535 case 2: return &ffi_type_uint16;
536 case 4: return &ffi_type_uint32;
537 case 8: return &ffi_type_uint64;
541 return &ffi_type_void;
545 static SerialBuffer staticBuffer { };
546 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
548 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
550 /* // Simple 1 pointer param returning a string
551 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
552 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
555 void * ret = &retData;
556 Array<String> args { size = sqlFunction.args.count + 1 };
557 Iterator<String> ffiArg { sqlFunction.argTypes };
558 Iterator<String> arg { args };
561 // this * for the SQLCustomFunction
562 args[0] = (void *)&sqlFunction;
564 // Get the arguments from SQLite
565 for(a : sqlFunction.args)
567 ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
576 void ** data = new void *[1];
577 args[i+1] = (void *)data;
578 if(a == class(String))
580 int numBytes = sqlite3_value_bytes(values[i]);
581 char * text = sqlite3_value_text(values[i]);
582 *(char **)data = text ? new byte[numBytes+1] : null;
584 memcpy(*(char **)data, text, numBytes+1);
588 SerialBuffer buffer = staticBuffer; //{ };
590 buffer._size = sqlite3_value_bytes(values[i]);
591 buffer._buffer = sqlite3_value_text(values[i]);
592 //buffer._buffer = sqlite3_value_blob(curStatement);
593 buffer.count = buffer._size;
594 if(a.type == structClass)
595 *data = new byte[a.structSize];
596 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
597 buffer._buffer = null;
606 if(type == &ffi_type_double || type == &ffi_type_float)
608 double d = sqlite3_value_double(values[i]);
611 double * data = new double[1];
612 args[i+1] = (void *)data;
617 float * data = new float[1];
618 args[i+1] = (void *)data;
628 int64 * data = new int64[1];
629 args[i+1] = (void *)data;
630 *data = sqlite3_value_int64(values[i]);
635 int * data = new int[1];
636 args[i+1] = (void *)data;
637 *data = sqlite3_value_int(values[i]);
642 short * data = new short[1];
644 args[i+1] = (void *)data;
645 value = sqlite3_value_int(values[i]);
647 *data = (short)value;
649 *(uint16 *)data = (uint16)value;
654 char * data = new char[1];
657 value = sqlite3_value_int(values[i]);
661 *(byte *)data = (byte)value;
671 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
672 ret = new byte[sqlFunction.returnType.typeSize];
673 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
674 // Give SQLite the return value
675 if(sqlFunction.returnType)
677 ffi_type * type = sqlFunction.rType;
678 Class r = sqlFunction.returnType;
686 void * data = ret ? *(void **)ret : null;
687 if(r.type == structClass)
689 if(r == class(String))
692 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
694 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
698 SerialBuffer buffer { };
699 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
700 sqlite3_result_text(context, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
703 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
704 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
707 if(r.type == structClass)
715 if(type == &ffi_type_double || type == &ffi_type_float)
718 sqlite3_result_double(context, *(double *)ret);
720 sqlite3_result_double(context, (double)*(float *)ret);
727 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
730 sqlite3_result_int(context, *(int *)ret);
736 value = (int)*(short *)ret;
738 //value = (int)*(uint16 *)ret;
739 sqlite3_result_int(context, value);
746 value = (int)*(char *)ret;
748 //value = (int)*(byte *)ret;
749 sqlite3_result_int(context, value);
760 for(type : sqlFunction.args; arg.Next())
763 void * data = *(void **)arg.data;
764 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
765 if(type.type == structClass)
774 class SQLiteTable : Table
779 LinkList<SQLiteField> _fields { };
780 char * specialStatement;
781 SQLiteField primaryKey;
782 FieldIndex * indexFields;
783 int indexFieldsCount;
786 Field AddField(const String fieldName, Class type, int length)
793 Table refTable = null;
794 Field idField = null;
797 if(FindField(fieldName)) return null;
799 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
800 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
801 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
802 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
803 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
804 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
806 strcpy(dataType, "INTEGER");
807 sqliteType = SQLITE_INTEGER;
809 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
811 strcpy(dataType, "REAL");
812 sqliteType = SQLITE_FLOAT;
814 else if(!strcmp(type.name, "CIString"))
816 strcpy(dataType, "TEXT");
817 sqliteType = SQLITE_BLOB;
819 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
821 strcpy(dataType, "TEXT");
822 sqliteType = SQLITE_TEXT;
826 //strcpy(dataType, "BLOB");
827 strcpy(dataType, "TEXT");
828 sqliteType = SQLITE_BLOB;
830 if(!db.collations.Find(type.fullName))
832 db.collations.Add(type.fullName);
833 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
836 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
838 Table * table = (Table *)eClass_GetProperty(type, "table");
839 if(table) refTable = *table;
842 if(primaryKey || refTable != this)
844 for(idField = refTable.firstField; idField; idField = idField.next)
845 if(eClass_IsDerived(type, idField.type)) break;
848 PrintLn("WARNING: field not yet created for class ", (String)type.name);
851 idField = primaryKey;
855 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
861 if(sqliteType == SQLITE_BLOB)
863 if(!strcmp(type.name, "CIString"))
864 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
866 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
870 if(!idField && refTable == this)
871 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
873 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
876 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
877 result = sqlite3_exec(db.db, command, null, null, null);
878 if(result) return null;
883 if(sqliteType == SQLITE_BLOB)
885 if(!strcmp(type.name, "CIString"))
886 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
888 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
892 if(!idField && refTable == this)
894 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
895 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
898 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
901 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
902 result = sqlite3_exec(db.db, command, null, null, null);
903 if(result) return null;
906 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
907 fieldName, type.name, length);
908 result = sqlite3_exec(db.db, command, null, null, null);
910 field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
913 if(!primaryKey && refTable == this)
918 Field FindField(const String name)
920 for(f : _fields; !strcmp(f.name, name))
924 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
927 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
928 if(tablePtr && *tablePtr == this)
937 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
942 char indexName[4096];
945 indexFieldsCount = count;
946 indexFields = new FieldIndex[count];
947 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
949 // TODO: USE CODED INDEX NAME INSTEAD?
950 strcpy(indexName, "index_");
951 strcat(indexName, name);
952 strcat(indexName, "_");
953 for(c = 0; c<count; c++)
955 if(fieldIndexes[c].field)
957 if(count == 1 && fieldIndexes[c].field == primaryKey)
959 strcat(indexName, fieldIndexes[c].field.name);
960 if(fieldIndexes[c].memberField)
962 strcat(indexName, ".");
963 strcat(indexName, fieldIndexes[c].memberField.name);
965 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
971 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
972 for(c = 0; c<count; c++)
974 char columnName[1024];
975 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
976 if(c > 0) strcat(command, ", ");
977 strcat(command, columnName);
979 strcat(command, ");");
980 result = sqlite3_exec(db.db, command, null, null, null);
982 return result == SQLITE_OK;
990 Field GetFirstField()
992 return _fields.first;
995 Field GetPrimaryKey()
1000 uint GetFieldsCount()
1002 return _fields.count;
1012 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1013 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1014 if(result == SQLITE_OK)
1016 rowCount = atoi(t[1]);
1017 sqlite3_free_table(t);
1022 // Returns true if not ordered by row ID
1023 bool GetIndexOrder(char * fullOrder, bool flip)
1025 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1027 strcpy(fullOrder, " ORDER BY ROWID");
1033 strcpy(fullOrder, " ORDER BY ");
1034 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1037 FieldIndex * fIndex = &indexFields[c];
1039 if(c) strcat(order, ", ");
1041 strcat(order, fIndex->field.name);
1043 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1044 strcat(fullOrder, order);
1050 Container<Field> GetFields()
1052 return (Container<Field>)_fields;
1055 DriverRow CreateRow()
1058 sqlite3_stmt * statement;
1059 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1060 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1062 if(specialStatement)
1063 strcpy(command, specialStatement);
1067 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1068 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1069 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1070 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1072 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1073 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1075 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1076 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1078 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1079 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1081 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1082 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1084 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1085 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1087 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1088 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1090 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1092 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1094 GetIndexOrder(order, false);
1095 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1097 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1099 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1100 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1102 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1103 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1106 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1107 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1108 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1114 delete specialStatement;
1120 class SQLiteRow : DriverRow
1123 sqlite3_stmt * curStatement;
1125 sqlite3_stmt * defaultStatement;
1126 sqlite3_stmt * findStatement;
1127 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1128 sqlite3_stmt * nextFindStatement;
1129 sqlite3_stmt * sysIDStatement;
1130 sqlite3_stmt * queryStatement;
1131 sqlite3_stmt * selectRowIDsStmt;
1132 sqlite3_stmt * setRowIDStmt;
1133 sqlite3_stmt * lastStatement;
1134 sqlite3_stmt * previousStatement;
1135 sqlite3_stmt * nextStatement;
1137 sqlite3_stmt * insertStatement;
1138 sqlite3_stmt * deleteStatement;
1139 sqlite3_stmt * updateStatement;
1140 sqlite3_stmt * insertIDStatement;
1144 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1145 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1156 if(defaultStatement) sqlite3_finalize(defaultStatement);
1157 if(findStatement) sqlite3_finalize(findStatement);
1158 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1159 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1160 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1161 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1162 if(insertStatement) sqlite3_finalize(insertStatement);
1163 if(deleteStatement) sqlite3_finalize(deleteStatement);
1164 if(updateStatement) sqlite3_finalize(updateStatement);
1165 if(queryStatement) sqlite3_finalize(queryStatement);
1166 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1167 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1168 if(previousStatement)sqlite3_finalize(previousStatement);
1169 if(nextStatement) sqlite3_finalize(nextStatement);
1170 if(lastStatement) sqlite3_finalize(lastStatement);
1171 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1174 bool Select(MoveOptions move)
1177 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1179 curStatement = defaultStatement;
1184 sqlite3_reset(curStatement);
1185 result = sqlite3_step(curStatement);
1186 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1187 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1188 rowID = sqlite3_column_int64(curStatement, 0);
1193 sqlite3_reset(curStatement);
1194 curStatement = lastStatement;
1195 result = sqlite3_step(curStatement);
1196 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1197 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1198 rowID = sqlite3_column_int64(curStatement, 0);
1206 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1207 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1208 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1210 result = sqlite3_step(curStatement);
1211 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1212 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1213 rowID = sqlite3_column_int64(curStatement, 0);
1215 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1219 int bindId = findBindId;
1220 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1221 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1222 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1223 sqlite3_reset(curStatement);
1224 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1225 result = sqlite3_step(curStatement);
1226 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1227 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1228 rowID = sqlite3_column_int64(curStatement, 0);
1232 int bindId = findBindId;
1233 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1234 sqlite3_reset(curStatement);
1235 curStatement = (move == next) ? findStatement : lastFindStatement;
1236 result = sqlite3_step(curStatement);
1237 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1238 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1239 rowID = sqlite3_column_int64(curStatement, 0);
1244 sqlite3_reset(curStatement);
1245 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1246 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1247 result = sqlite3_step(curStatement);
1248 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1249 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1250 rowID = sqlite3_column_int64(curStatement, 0);
1255 sqlite3_reset(curStatement);
1265 bool Query(char * queryString)
1271 sqlite3_reset(curStatement);
1274 sqlite3_finalize(queryStatement);
1275 queryStatement = null;
1280 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1283 curStatement = queryStatement;
1284 if(!strchr(queryString, '?'))
1286 result = sqlite3_step(queryStatement);
1288 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1289 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1291 rowID = sqlite3_column_int64(queryStatement, 0);
1298 curStatement = null;
1302 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1305 Class dataType = fld.type;
1306 SerialBuffer buffer = null;
1307 switch(fld.sqliteType)
1309 case SQLITE_INTEGER:
1311 switch(dataType.typeSize)
1314 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1317 result = sqlite3_bind_int(statement, pos, *(int *)data);
1323 value = (int)*(short *)data;
1325 value = (int)*(uint16 *)data;
1326 result = sqlite3_bind_int(statement, pos, value);
1333 value = (int)*(char *)data;
1335 value = (int)*(byte *)data;
1336 result = sqlite3_bind_int(statement, pos, value);
1344 if(dataType.typeSize == 8)
1345 result = sqlite3_bind_double(statement, pos, *(double *)data);
1347 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1353 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1355 result = sqlite3_bind_null(statement, pos);
1363 buffer = SerialBuffer { };
1364 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1365 result = sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1368 result = sqlite3_bind_null(statement, pos);
1373 *bufferOut = buffer;
1379 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1381 if(move == next || move == previous)
1383 // Where clauses for index
1387 bool gotPrimaryKey = false;
1389 strcatf(command, " AND (");
1390 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1393 FieldIndex * fIndex = &tbl.indexFields[c];
1397 strcat(where, fIndex->field.name);
1398 strcat(where, "` ");
1399 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1400 strcat(where, " ? OR (");
1401 strcat(where, fIndex->field.name);
1402 if(fIndex->field == tbl.primaryKey)
1403 gotPrimaryKey = true;
1404 strcat(where, " = ? AND (");
1405 strcat(command, where);
1407 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1408 for(c = 0; c < tbl.indexFieldsCount; c++)
1409 strcat(command, "))");
1412 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1416 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1418 if(move == next || move == previous)
1420 // The binds for the Extra ordering Where clauses
1424 /* // Code to not rely on curStatement being set up
1425 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1426 dataRow.GoToSysID((uint)rowID);
1428 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1430 FieldIndex * fIndex = &tbl.indexFields[c];
1432 SQLiteField fld = (SQLiteField)fIndex->field;
1433 Class type = fld.type;
1435 SerialBuffer buffer;
1437 if(type.type == unitClass && !type.typeSize)
1439 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1443 if(type.type == structClass)
1445 data = (int64)new0 byte[type.structSize];
1446 dataPtr = (void *) data;
1448 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1449 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1450 if(type.type == normalClass || type.type == noHeadClass)
1451 dataPtr = (void *) data;
1454 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1455 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1456 // Reuse the buffer for Blobs...
1457 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1459 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1463 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1465 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1470 // Bind for the rowid
1471 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1475 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1477 char order[1024], command[2048];
1480 sqlite3_stmt * stmt = null;
1483 if(fld == tbl.primaryKey)
1485 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1486 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1487 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1488 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1489 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1490 result = GoToSysID(*(int *)data);
1496 useIndex = tbl.GetIndexOrder(order, false);
1498 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1499 AddCursorWhereClauses(command, move, useIndex);
1500 strcat(command, order);
1501 strcat(command, ";");
1502 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1503 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1504 BindCursorData(stmt, move, useIndex, &bindId);
1506 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1507 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1508 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1509 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1510 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1511 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1513 curStatement = findStatement = stmt;
1514 findBindId = bindId;
1516 // For going back to forward find
1518 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1519 AddCursorWhereClauses(command, next, useIndex);
1520 strcat(command, order);
1521 strcat(command, ";");
1522 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1523 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1524 nextFindStatement = stmt;
1527 tbl.GetIndexOrder(order, true);
1528 // For tracing back finds
1530 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1531 AddCursorWhereClauses(command, previous, true);
1532 strcat(command, order);
1533 strcat(command, ";");
1534 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1535 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1536 prevFindStatement = stmt;
1538 // For tracing back from last
1540 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1541 strcat(command, order);
1542 strcat(command, ";");
1543 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1544 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1545 lastFindStatement = stmt;
1547 result = sqlite3_step(findStatement);
1549 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1553 sqlite3_reset(findStatement);
1556 rowID = sqlite3_column_int64(findStatement, 0);
1560 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1563 for(c = 0; c < numFields; c++) \
1565 FieldFindData * fieldFind = &findData[c]; \
1566 SQLiteField sqlFld = (SQLiteField)findData->field; \
1567 Class dataType = sqlFld.type; \
1568 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null); \
1573 char criterias[4096], command[4096], order[1024];
1577 sqlite3_stmt * stmt = null;
1581 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1582 for(c = 0; c < numFields; c++)
1584 FieldFindData * fieldFind = &findData[c];
1586 if(c) strcat(criterias, " AND `");
1587 strcat(criterias, fieldFind->field.name);
1588 strcat(criterias, "` = ?");
1591 useIndex = tbl.GetIndexOrder(order, false);
1592 // Basic Find (multiple)
1593 strcpy(command, criterias);
1594 AddCursorWhereClauses(command, move, useIndex);
1595 strcat(command, order);
1596 strcat(command, ";");
1597 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1599 BindCursorData(stmt, move, useIndex, &bindId);
1601 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1602 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1603 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1604 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1605 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1606 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1608 curStatement = findStatement = stmt;
1609 findBindId = bindId;
1611 // For tracing back forward finds
1613 strcpy(command, criterias);
1614 AddCursorWhereClauses(command, previous, true);
1615 strcat(command, order);
1616 strcat(command, ";");
1617 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1619 nextFindStatement = stmt;
1622 tbl.GetIndexOrder(order, true);
1623 // For tracing back finds
1625 strcpy(command, criterias);
1626 AddCursorWhereClauses(command, next, useIndex);
1627 strcat(command, order);
1628 strcat(command, ";");
1629 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1631 prevFindStatement = stmt;
1633 // For tracing back from last
1635 strcpy(command, criterias);
1636 strcat(command, order);
1637 strcat(command, ";");
1638 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1640 lastFindStatement = stmt;
1642 result = sqlite3_step(findStatement);
1643 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1647 sqlite3_reset(findStatement);
1650 rowID = sqlite3_column_int64(findStatement, 0);
1656 bool Synch(DriverRow to)
1658 SQLiteRow rowTo = (SQLiteRow)to;
1659 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1660 return GoToSysID((uint)rowTo.rowID);
1667 //char command[1024];
1668 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1669 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1672 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1673 result = sqlite3_step(insertIDStatement);
1676 result = sqlite3_step(insertStatement);
1677 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1679 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1680 if(rowID > MAXDWORD)
1682 int64 lastID = tbl.lastID;
1684 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1688 result = sqlite3_step(selectRowIDsStmt);
1689 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1690 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1691 if(id - lastID > 1) break;
1694 sqlite3_reset(selectRowIDsStmt);
1696 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1699 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1700 result = sqlite3_step(setRowIDStmt);
1701 sqlite3_reset(setRowIDStmt);
1703 sqlite3_reset(id ? insertIDStatement : insertStatement);
1704 curStatement = sysIDStatement;
1706 sqlite3_reset(curStatement);
1707 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1708 result = sqlite3_step(curStatement);
1709 done = false; // Make sure 'nil' is false
1712 sqlite3_reset(insertStatement);
1719 //char command[1024];
1720 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1721 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1722 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1723 result = sqlite3_step(deleteStatement);
1724 sqlite3_reset(deleteStatement);
1726 return result == SQLITE_OK || result == SQLITE_DONE;
1729 bool GetData(Field fld, typed_object &data)
1731 SQLiteField sqlFld = (SQLiteField)fld;
1732 int num = sqlFld.num + 1;
1733 Class dataType = sqlFld.type;
1736 switch(sqlFld.sqliteType)
1738 case SQLITE_INTEGER:
1740 switch(dataType.typeSize)
1743 if(fld == tbl.primaryKey)
1744 *(int64 *)data = rowID;
1746 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1749 if(fld == tbl.primaryKey)
1750 *(int *)data = (int)(uint)rowID;
1752 *(int *)data = sqlite3_column_int(curStatement, num);
1757 if(fld == tbl.primaryKey)
1758 value = (int)(uint)rowID;
1760 value = sqlite3_column_int(curStatement, num);
1762 *(short *)data = (short)value;
1764 *(uint16 *)data = (uint16)value;
1770 if(fld == tbl.primaryKey)
1771 value = (int)(uint)rowID;
1773 value = sqlite3_column_int(curStatement, num);
1775 *(char *)data = (char)value;
1777 *(byte *)data = (byte)value;
1785 double d = sqlite3_column_double(curStatement, num);
1786 if(dataType.typeSize == 8)
1787 *(double *)data = d;
1789 *(float *)data = (float)d;
1794 int numBytes = sqlite3_column_bytes(curStatement, num);
1795 char * text = sqlite3_column_text(curStatement, num);
1796 *(char **)data = text ? new byte[numBytes+1] : null;
1798 memcpy(*(char **)data, text, numBytes+1);
1803 SerialBuffer buffer { };
1804 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1805 buffer._size = sqlite3_column_bytes(curStatement, num);
1806 buffer._buffer = sqlite3_column_text(curStatement, num);
1807 buffer.count = buffer._size;
1809 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1811 buffer._buffer = null;
1819 bool SetData(Field fld, typed_object data)
1821 SQLiteField sqlFld = (SQLiteField)fld;
1823 int num = sqlFld.num + 1;
1827 sqlite3_finalize(updateStatement);
1828 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1829 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1830 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1831 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1832 result = sqlite3_step(updateStatement);
1833 sqlite3_reset(updateStatement);
1834 if(fld == tbl.primaryKey)
1835 rowID = *(uint *)data;
1836 return result == SQLITE_DONE;
1841 return (int)(uint)rowID;
1844 bool GoToSysID(uint id)
1846 //char command[1024];
1850 //sqlite3_finalize(statement);
1851 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1852 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1856 sqlite3_reset(curStatement);
1858 curStatement = sysIDStatement;
1859 sqlite3_reset(sysIDStatement);
1860 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1861 result = sqlite3_step(curStatement);
1862 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1863 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1867 bool SetQueryParam(int paramID, int value)
1870 if(curStatement != queryStatement)
1872 if(curStatement) sqlite3_reset(curStatement);
1873 curStatement = queryStatement;
1875 sqlite3_reset(queryStatement);
1876 result = sqlite3_bind_int(queryStatement, paramID, value);
1880 bool SetQueryParam64(int paramID, int64 value)
1883 if(curStatement != queryStatement)
1885 if(curStatement) sqlite3_reset(curStatement);
1886 curStatement = queryStatement;
1888 sqlite3_reset(queryStatement);
1889 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1893 bool SetQueryParamText(int paramID, char * data)
1896 if(curStatement != queryStatement)
1898 if(curStatement) sqlite3_reset(curStatement);
1899 curStatement = queryStatement;
1901 sqlite3_reset(queryStatement);
1903 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1905 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1909 bool SetQueryParamObject(int paramID, void * data, Class type)
1912 if(curStatement != queryStatement)
1914 if(curStatement) sqlite3_reset(curStatement);
1915 curStatement = queryStatement;
1917 sqlite3_reset(queryStatement);
1919 SerialBuffer buffer { };
1920 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1921 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1927 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
1929 if(curStatement != queryStatement)
1931 if(curStatement) sqlite3_reset(curStatement);
1932 curStatement = queryStatement;
1934 sqlite3_reset(queryStatement);
1935 return BindData(queryStatement, pos, fld, data, null);
1938 /*char * GetExtraColumn(int paramID)
1940 SQLiteField lastFld = tbl._fields.last;
1941 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1943 char * GetColumn(int paramID)
1945 return sqlite3_column_text(curStatement, paramID);