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, 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 = (char *)data1 };
50 SerialBuffer buffer2 { size = count2, count = count2, buffer = (char *)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 = (char *)data1 };
70 SerialBuffer buffer2 { size = count2, count = count2, buffer = (char *)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));
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<const 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 const char * fieldName = sqlite3_column_text(statement, 0);
335 const 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(const 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 const String arg = tokens[c];
427 TrimLSpaces(tokens[c], tokens[c]);
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 { };
486 static Iterator dummy; // TOFIX: forward struct declaration issues on Clang
488 public ffi_type * FFIGetType(Class type, bool structByValue)
497 MapIterator<Class, String> it { map = structFFITypes };
498 ffi_type * ffiType = null;
499 if(it.Index(type, false))
500 ffiType = (void *)it.data;
505 Array<String> memberTypes { };
506 for(member = type.membersAndProperties.first; member; member = member.next)
508 if(!member.isProperty)
510 memberTypes.Add(FFIGetType(member.dataType
514 ffiType = new0 ffi_type[1];
515 ffiType->size = type.structSize;
516 ffiType->type = FFI_TYPE_STRUCT;
517 structFFITypes[type] = (void *)ffiType;
524 return &ffi_type_pointer;
530 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
531 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
533 switch(type.typeSize)
535 case 1: return &ffi_type_uint8;
536 case 2: return &ffi_type_uint16;
537 case 4: return &ffi_type_uint32;
538 case 8: return &ffi_type_uint64;
542 return &ffi_type_void;
546 static SerialBuffer staticBuffer { };
547 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
549 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
551 /* // Simple 1 pointer param returning a string
552 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
553 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
556 void * ret = &retData;
557 Array<String> args { size = sqlFunction.args.count + 1 };
558 Iterator<String> ffiArg { sqlFunction.argTypes };
559 Iterator<String> arg { args };
562 // this * for the SQLCustomFunction
563 args[0] = (void *)&sqlFunction;
565 // Get the arguments from SQLite
566 for(a : sqlFunction.args)
568 ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
577 void ** data = new void *[1];
578 args[i+1] = (void *)data;
579 if(a == class(String))
581 int numBytes = sqlite3_value_bytes(values[i]);
582 const char * text = sqlite3_value_text(values[i]);
583 *(char **)data = text ? new byte[numBytes+1] : null;
585 memcpy(*(char **)data, text, numBytes+1);
589 SerialBuffer buffer = staticBuffer; //{ };
591 buffer._size = sqlite3_value_bytes(values[i]);
592 buffer._buffer = (char *)sqlite3_value_text(values[i]);
593 //buffer._buffer = sqlite3_value_blob(curStatement);
594 buffer.count = buffer._size;
595 if(a.type == structClass)
596 *data = new byte[a.structSize];
597 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
598 buffer._buffer = null;
607 if(type == &ffi_type_double || type == &ffi_type_float)
609 double d = sqlite3_value_double(values[i]);
612 double * data = new double[1];
613 args[i+1] = (void *)data;
618 float * data = new float[1];
619 args[i+1] = (void *)data;
629 int64 * data = new int64[1];
630 args[i+1] = (void *)data;
631 *data = sqlite3_value_int64(values[i]);
636 int * data = new int[1];
637 args[i+1] = (void *)data;
638 *data = sqlite3_value_int(values[i]);
643 short * data = new short[1];
645 args[i+1] = (void *)data;
646 value = sqlite3_value_int(values[i]);
648 *data = (short)value;
650 *(uint16 *)data = (uint16)value;
655 char * data = new char[1];
658 value = sqlite3_value_int(values[i]);
662 *(byte *)data = (byte)value;
672 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
673 ret = new byte[sqlFunction.returnType.typeSize];
674 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
675 // Give SQLite the return value
676 if(sqlFunction.returnType)
678 ffi_type * type = sqlFunction.rType;
679 Class r = sqlFunction.returnType;
687 void * data = ret ? *(void **)ret : null;
688 if(r.type == structClass)
690 if(r == class(String))
693 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
695 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
699 SerialBuffer buffer { };
700 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
701 sqlite3_result_text(context, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
704 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
705 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
708 if(r.type == structClass)
716 if(type == &ffi_type_double || type == &ffi_type_float)
719 sqlite3_result_double(context, *(double *)ret);
721 sqlite3_result_double(context, (double)*(float *)ret);
728 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
731 sqlite3_result_int(context, *(int *)ret);
737 value = (int)*(short *)ret;
739 //value = (int)*(uint16 *)ret;
740 sqlite3_result_int(context, value);
747 value = (int)*(char *)ret;
749 //value = (int)*(byte *)ret;
750 sqlite3_result_int(context, value);
761 for(type : sqlFunction.args; arg.Next())
764 void * data = *(void **)arg.data;
765 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
766 if(type.type == structClass)
775 class SQLiteTable : Table
780 LinkList<SQLiteField> _fields { };
781 char * specialStatement;
782 SQLiteField primaryKey;
783 FieldIndex * indexFields;
784 int indexFieldsCount;
787 Field AddField(const String fieldName, Class type, int length)
794 Table refTable = null;
795 Field idField = null;
798 if(FindField(fieldName)) return null;
800 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
801 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
802 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
803 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
804 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
805 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
807 strcpy(dataType, "INTEGER");
808 sqliteType = SQLITE_INTEGER;
810 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
812 strcpy(dataType, "REAL");
813 sqliteType = SQLITE_FLOAT;
815 else if(!strcmp(type.name, "CIString"))
817 strcpy(dataType, "TEXT");
818 sqliteType = SQLITE_BLOB;
820 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
822 strcpy(dataType, "TEXT");
823 sqliteType = SQLITE_TEXT;
827 //strcpy(dataType, "BLOB");
828 strcpy(dataType, "TEXT");
829 sqliteType = SQLITE_BLOB;
831 if(!db.collations.Find(type.fullName))
833 db.collations.Add(type.fullName);
834 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
837 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
839 Table * table = (Table *)eClass_GetProperty(type, "table");
840 if(table) refTable = *table;
843 if(primaryKey || refTable != this)
845 for(idField = refTable.firstField; idField; idField = idField.next)
846 if(eClass_IsDerived(type, idField.type)) break;
849 PrintLn("WARNING: field not yet created for class ", (String)type.name);
852 idField = primaryKey;
856 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
862 if(sqliteType == SQLITE_BLOB)
864 if(!strcmp(type.name, "CIString"))
865 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
867 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
871 if(!idField && refTable == this)
872 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
874 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
877 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
878 result = sqlite3_exec(db.db, command, null, null, null);
879 if(result) return null;
884 if(sqliteType == SQLITE_BLOB)
886 if(!strcmp(type.name, "CIString"))
887 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
889 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
893 if(!idField && refTable == this)
895 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
896 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
899 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
902 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
903 result = sqlite3_exec(db.db, command, null, null, null);
904 if(result) return null;
907 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
908 fieldName, type.name, length);
909 result = sqlite3_exec(db.db, command, null, null, null);
911 field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
914 if(!primaryKey && refTable == this)
919 Field FindField(const String name)
921 for(f : _fields; !strcmp(f.name, name))
925 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
928 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
929 if(tablePtr && *tablePtr == this)
938 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
943 char indexName[4096];
946 indexFieldsCount = count;
947 indexFields = new FieldIndex[count];
948 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
950 // TODO: USE CODED INDEX NAME INSTEAD?
951 strcpy(indexName, "index_");
952 strcat(indexName, name);
953 strcat(indexName, "_");
954 for(c = 0; c<count; c++)
956 if(fieldIndexes[c].field)
958 if(count == 1 && fieldIndexes[c].field == primaryKey)
960 strcat(indexName, fieldIndexes[c].field.name);
961 if(fieldIndexes[c].memberField)
963 strcat(indexName, ".");
964 strcat(indexName, fieldIndexes[c].memberField.name);
966 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
972 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
973 for(c = 0; c<count; c++)
975 char columnName[1024];
976 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
977 if(c > 0) strcat(command, ", ");
978 strcat(command, columnName);
980 strcat(command, ");");
981 result = sqlite3_exec(db.db, command, null, null, null);
983 return result == SQLITE_OK;
991 Field GetFirstField()
993 return _fields.first;
996 Field GetPrimaryKey()
1001 uint GetFieldsCount()
1003 return _fields.count;
1013 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1014 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1015 if(result == SQLITE_OK)
1017 rowCount = atoi(t[1]);
1018 sqlite3_free_table(t);
1023 // Returns true if not ordered by row ID
1024 bool GetIndexOrder(char * fullOrder, bool flip)
1026 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1028 strcpy(fullOrder, " ORDER BY ROWID");
1034 strcpy(fullOrder, " ORDER BY ");
1035 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1038 FieldIndex * fIndex = &indexFields[c];
1040 if(c) strcat(order, ", ");
1042 strcat(order, fIndex->field.name);
1044 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1045 strcat(fullOrder, order);
1051 Container<Field> GetFields()
1053 return (Container<Field>)_fields;
1056 DriverRow CreateRow()
1059 sqlite3_stmt * statement;
1060 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1061 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1063 if(specialStatement)
1064 strcpy(command, specialStatement);
1068 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1069 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1070 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1071 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1073 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1074 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1076 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1077 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1079 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1080 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1082 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1083 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1085 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1086 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1088 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1089 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1091 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1093 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1095 GetIndexOrder(order, false);
1096 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1098 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1100 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1101 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1103 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1104 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1107 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1108 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1109 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1115 delete specialStatement;
1121 class SQLiteRow : DriverRow
1124 sqlite3_stmt * curStatement;
1126 sqlite3_stmt * defaultStatement;
1127 sqlite3_stmt * findStatement;
1128 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1129 sqlite3_stmt * nextFindStatement;
1130 sqlite3_stmt * sysIDStatement;
1131 sqlite3_stmt * queryStatement;
1132 sqlite3_stmt * selectRowIDsStmt;
1133 sqlite3_stmt * setRowIDStmt;
1134 sqlite3_stmt * lastStatement;
1135 sqlite3_stmt * previousStatement;
1136 sqlite3_stmt * nextStatement;
1138 sqlite3_stmt * insertStatement;
1139 sqlite3_stmt * deleteStatement;
1140 sqlite3_stmt * updateStatement;
1141 sqlite3_stmt * insertIDStatement;
1145 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1146 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1157 if(defaultStatement) sqlite3_finalize(defaultStatement);
1158 if(findStatement) sqlite3_finalize(findStatement);
1159 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1160 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1161 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1162 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1163 if(insertStatement) sqlite3_finalize(insertStatement);
1164 if(deleteStatement) sqlite3_finalize(deleteStatement);
1165 if(updateStatement) sqlite3_finalize(updateStatement);
1166 if(queryStatement) sqlite3_finalize(queryStatement);
1167 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1168 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1169 if(previousStatement)sqlite3_finalize(previousStatement);
1170 if(nextStatement) sqlite3_finalize(nextStatement);
1171 if(lastStatement) sqlite3_finalize(lastStatement);
1172 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1175 bool Select(MoveOptions move)
1178 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1180 curStatement = defaultStatement;
1185 sqlite3_reset(curStatement);
1186 result = sqlite3_step(curStatement);
1187 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1188 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1189 rowID = sqlite3_column_int64(curStatement, 0);
1194 sqlite3_reset(curStatement);
1195 curStatement = lastStatement;
1196 result = sqlite3_step(curStatement);
1197 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1198 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1199 rowID = sqlite3_column_int64(curStatement, 0);
1207 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1208 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1209 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1211 result = sqlite3_step(curStatement);
1212 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1213 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1214 rowID = sqlite3_column_int64(curStatement, 0);
1216 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1220 int bindId = findBindId;
1221 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1222 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1223 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1224 sqlite3_reset(curStatement);
1225 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1226 result = sqlite3_step(curStatement);
1227 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1228 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1229 rowID = sqlite3_column_int64(curStatement, 0);
1233 int bindId = findBindId;
1234 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1235 sqlite3_reset(curStatement);
1236 curStatement = (move == next) ? findStatement : lastFindStatement;
1237 result = sqlite3_step(curStatement);
1238 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1239 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1240 rowID = sqlite3_column_int64(curStatement, 0);
1245 sqlite3_reset(curStatement);
1246 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1247 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1248 result = sqlite3_step(curStatement);
1249 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1250 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1251 rowID = sqlite3_column_int64(curStatement, 0);
1256 sqlite3_reset(curStatement);
1266 bool Query(const char * queryString)
1272 sqlite3_reset(curStatement);
1275 sqlite3_finalize(queryStatement);
1276 queryStatement = null;
1281 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1284 curStatement = queryStatement;
1285 if(!strchr(queryString, '?'))
1287 result = sqlite3_step(queryStatement);
1289 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1290 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1292 rowID = sqlite3_column_int64(queryStatement, 0);
1299 curStatement = null;
1303 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1306 Class dataType = fld.type;
1307 SerialBuffer buffer = null;
1308 switch(fld.sqliteType)
1310 case SQLITE_INTEGER:
1312 switch(dataType.typeSize)
1315 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1318 result = sqlite3_bind_int(statement, pos, *(int *)data);
1324 value = (int)*(short *)data;
1326 value = (int)*(uint16 *)data;
1327 result = sqlite3_bind_int(statement, pos, value);
1334 value = (int)*(char *)data;
1336 value = (int)*(byte *)data;
1337 result = sqlite3_bind_int(statement, pos, value);
1345 if(dataType.typeSize == 8)
1346 result = sqlite3_bind_double(statement, pos, *(double *)data);
1348 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1354 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1356 result = sqlite3_bind_null(statement, pos);
1364 buffer = SerialBuffer { };
1365 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1366 result = sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1369 result = sqlite3_bind_null(statement, pos);
1374 *bufferOut = buffer;
1380 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1382 if(move == next || move == previous)
1384 // Where clauses for index
1388 bool gotPrimaryKey = false;
1390 strcatf(command, " AND (");
1391 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1394 FieldIndex * fIndex = &tbl.indexFields[c];
1398 strcat(where, fIndex->field.name);
1399 strcat(where, "` ");
1400 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1401 strcat(where, " ? OR (");
1402 strcat(where, fIndex->field.name);
1403 if(fIndex->field == tbl.primaryKey)
1404 gotPrimaryKey = true;
1405 strcat(where, " = ? AND (");
1406 strcat(command, where);
1408 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1409 for(c = 0; c < tbl.indexFieldsCount; c++)
1410 strcat(command, "))");
1413 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1417 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1419 if(move == next || move == previous)
1421 // The binds for the Extra ordering Where clauses
1425 /* // Code to not rely on curStatement being set up
1426 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1427 dataRow.GoToSysID((uint)rowID);
1429 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1431 FieldIndex * fIndex = &tbl.indexFields[c];
1433 SQLiteField fld = (SQLiteField)fIndex->field;
1434 Class type = fld.type;
1436 SerialBuffer buffer;
1438 if(type.type == unitClass && !type.typeSize)
1440 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1444 if(type.type == structClass)
1446 data = (int64)new0 byte[type.structSize];
1447 dataPtr = (void *) data;
1449 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1450 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1451 if(type.type == normalClass || type.type == noHeadClass)
1452 dataPtr = (void *) data;
1455 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1456 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1457 // Reuse the buffer for Blobs...
1458 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1460 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1464 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1466 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1471 // Bind for the rowid
1472 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1476 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1478 char order[1024], command[2048];
1481 sqlite3_stmt * stmt = null;
1484 if(fld == tbl.primaryKey)
1486 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1487 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1488 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1489 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1490 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1491 result = GoToSysID(*(int *)data);
1497 useIndex = tbl.GetIndexOrder(order, false);
1499 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1500 AddCursorWhereClauses(command, move, useIndex);
1501 strcat(command, order);
1502 strcat(command, ";");
1503 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1504 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1505 BindCursorData(stmt, move, useIndex, &bindId);
1507 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1508 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1509 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1510 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1511 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1512 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1514 curStatement = findStatement = stmt;
1515 findBindId = bindId;
1517 // For going back to forward find
1519 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1520 AddCursorWhereClauses(command, next, useIndex);
1521 strcat(command, order);
1522 strcat(command, ";");
1523 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1524 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1525 nextFindStatement = stmt;
1528 tbl.GetIndexOrder(order, true);
1529 // For tracing back finds
1531 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1532 AddCursorWhereClauses(command, previous, true);
1533 strcat(command, order);
1534 strcat(command, ";");
1535 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1536 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1537 prevFindStatement = stmt;
1539 // For tracing back from last
1541 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1542 strcat(command, order);
1543 strcat(command, ";");
1544 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1545 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1546 lastFindStatement = stmt;
1548 result = sqlite3_step(findStatement);
1550 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1554 sqlite3_reset(findStatement);
1557 rowID = sqlite3_column_int64(findStatement, 0);
1561 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1564 for(c = 0; c < numFields; c++) \
1566 FieldFindData * fieldFind = &findData[c]; \
1567 SQLiteField sqlFld = (SQLiteField)findData->field; \
1568 Class dataType = sqlFld.type; \
1569 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null); \
1574 char criterias[4096], command[4096], order[1024];
1578 sqlite3_stmt * stmt = null;
1582 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1583 for(c = 0; c < numFields; c++)
1585 FieldFindData * fieldFind = &findData[c];
1587 if(c) strcat(criterias, " AND `");
1588 strcat(criterias, fieldFind->field.name);
1589 strcat(criterias, "` = ?");
1592 useIndex = tbl.GetIndexOrder(order, false);
1593 // Basic Find (multiple)
1594 strcpy(command, criterias);
1595 AddCursorWhereClauses(command, move, useIndex);
1596 strcat(command, order);
1597 strcat(command, ";");
1598 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1600 BindCursorData(stmt, move, useIndex, &bindId);
1602 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1603 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1604 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1605 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1606 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1607 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1609 curStatement = findStatement = stmt;
1610 findBindId = bindId;
1612 // For tracing back forward finds
1614 strcpy(command, criterias);
1615 AddCursorWhereClauses(command, previous, true);
1616 strcat(command, order);
1617 strcat(command, ";");
1618 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1620 nextFindStatement = stmt;
1623 tbl.GetIndexOrder(order, true);
1624 // For tracing back finds
1626 strcpy(command, criterias);
1627 AddCursorWhereClauses(command, next, useIndex);
1628 strcat(command, order);
1629 strcat(command, ";");
1630 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1632 prevFindStatement = stmt;
1634 // For tracing back from last
1636 strcpy(command, criterias);
1637 strcat(command, order);
1638 strcat(command, ";");
1639 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1641 lastFindStatement = stmt;
1643 result = sqlite3_step(findStatement);
1644 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1648 sqlite3_reset(findStatement);
1651 rowID = sqlite3_column_int64(findStatement, 0);
1657 bool Synch(DriverRow to)
1659 SQLiteRow rowTo = (SQLiteRow)to;
1660 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1661 return GoToSysID((uint)rowTo.rowID);
1668 //char command[1024];
1669 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1670 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1673 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1674 result = sqlite3_step(insertIDStatement);
1677 result = sqlite3_step(insertStatement);
1678 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1680 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1681 if(rowID > MAXDWORD)
1683 int64 lastID = tbl.lastID;
1685 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1689 result = sqlite3_step(selectRowIDsStmt);
1690 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1691 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1692 if(id - lastID > 1) break;
1695 sqlite3_reset(selectRowIDsStmt);
1697 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1700 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1701 result = sqlite3_step(setRowIDStmt);
1702 sqlite3_reset(setRowIDStmt);
1704 sqlite3_reset(id ? insertIDStatement : insertStatement);
1705 curStatement = sysIDStatement;
1707 sqlite3_reset(curStatement);
1708 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1709 result = sqlite3_step(curStatement);
1710 done = false; // Make sure 'nil' is false
1713 sqlite3_reset(insertStatement);
1720 //char command[1024];
1721 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1722 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1723 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1724 result = sqlite3_step(deleteStatement);
1725 sqlite3_reset(deleteStatement);
1727 return result == SQLITE_OK || result == SQLITE_DONE;
1730 bool GetData(Field fld, typed_object &data)
1732 SQLiteField sqlFld = (SQLiteField)fld;
1733 int num = sqlFld.num + 1;
1734 Class dataType = sqlFld.type;
1737 switch(sqlFld.sqliteType)
1739 case SQLITE_INTEGER:
1741 switch(dataType.typeSize)
1744 if(fld == tbl.primaryKey)
1745 *(int64 *)data = rowID;
1747 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1750 if(fld == tbl.primaryKey)
1751 *(int *)data = (int)(uint)rowID;
1753 *(int *)data = sqlite3_column_int(curStatement, num);
1758 if(fld == tbl.primaryKey)
1759 value = (int)(uint)rowID;
1761 value = sqlite3_column_int(curStatement, num);
1763 *(short *)data = (short)value;
1765 *(uint16 *)data = (uint16)value;
1771 if(fld == tbl.primaryKey)
1772 value = (int)(uint)rowID;
1774 value = sqlite3_column_int(curStatement, num);
1776 *(char *)data = (char)value;
1778 *(byte *)data = (byte)value;
1786 double d = sqlite3_column_double(curStatement, num);
1787 if(dataType.typeSize == 8)
1788 *(double *)data = d;
1790 *(float *)data = (float)d;
1795 int numBytes = sqlite3_column_bytes(curStatement, num);
1796 const char * text = sqlite3_column_text(curStatement, num);
1797 *(char **)data = text ? new byte[numBytes+1] : null;
1799 memcpy(*(char **)data, text, numBytes+1);
1804 SerialBuffer buffer { };
1805 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1806 buffer._size = sqlite3_column_bytes(curStatement, num);
1807 buffer._buffer = (char *)sqlite3_column_text(curStatement, num);
1808 buffer.count = buffer._size;
1810 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1812 buffer._buffer = null;
1820 bool SetData(Field fld, typed_object data)
1822 SQLiteField sqlFld = (SQLiteField)fld;
1824 int num = sqlFld.num + 1;
1828 sqlite3_finalize(updateStatement);
1829 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1830 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1831 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1832 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1833 result = sqlite3_step(updateStatement);
1834 sqlite3_reset(updateStatement);
1835 if(fld == tbl.primaryKey)
1836 rowID = *(uint *)data;
1837 return result == SQLITE_DONE;
1842 return (int)(uint)rowID;
1845 bool GoToSysID(uint id)
1847 //char command[1024];
1851 //sqlite3_finalize(statement);
1852 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1853 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1857 sqlite3_reset(curStatement);
1859 curStatement = sysIDStatement;
1860 sqlite3_reset(sysIDStatement);
1861 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1862 result = sqlite3_step(curStatement);
1863 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1864 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1868 bool SetQueryParam(int paramID, int value)
1871 if(curStatement != queryStatement)
1873 if(curStatement) sqlite3_reset(curStatement);
1874 curStatement = queryStatement;
1876 sqlite3_reset(queryStatement);
1877 result = sqlite3_bind_int(queryStatement, paramID, value);
1881 bool SetQueryParam64(int paramID, int64 value)
1884 if(curStatement != queryStatement)
1886 if(curStatement) sqlite3_reset(curStatement);
1887 curStatement = queryStatement;
1889 sqlite3_reset(queryStatement);
1890 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1894 bool SetQueryParamText(int paramID, const char * data)
1897 if(curStatement != queryStatement)
1899 if(curStatement) sqlite3_reset(curStatement);
1900 curStatement = queryStatement;
1902 sqlite3_reset(queryStatement);
1904 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1906 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1910 bool SetQueryParamObject(int paramID, const void * data, Class type)
1913 if(curStatement != queryStatement)
1915 if(curStatement) sqlite3_reset(curStatement);
1916 curStatement = queryStatement;
1918 sqlite3_reset(queryStatement);
1920 SerialBuffer buffer { };
1921 ((void (*)(void *, const void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1922 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1928 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
1930 if(curStatement != queryStatement)
1932 if(curStatement) sqlite3_reset(curStatement);
1933 curStatement = queryStatement;
1935 sqlite3_reset(queryStatement);
1936 return BindData(queryStatement, pos, fld, data, null);
1939 /*char * GetExtraColumn(int paramID)
1941 SQLiteField lastFld = tbl._fields.last;
1942 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1944 const char * GetColumn(int paramID)
1946 return sqlite3_column_text(curStatement, paramID);