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 : DataSourceDriver
95 class_property(name) = "SQLite";
97 OldList listDatabases;
100 String BuildLocator(DataSource ds)
102 return CopyString(ds.host);
105 uint GetDatabasesCount()
107 return databasesCount;
115 bool Connect(const String locator)
118 path = CopyString(locator);
119 // TODO, use user name and password for local security?
120 // TODO, open ds in read or write mode
124 FileListing listing { path, "sqlite" };
126 while(listing.Find())
133 bool RenameDatabase(const String name, const String rename)
135 if(name && rename && path && FileExists(path))
138 path = MakeDatabasePath(name);
143 repath = MakeDatabasePath(rename);
144 renamed = RenameFile(path, repath);
154 bool DeleteDatabase(const String name)
156 if(path && FileExists(path))
159 String path = MakeDatabasePath(name);
160 deleted = DeleteFile(path); // delete file seems to return true even if the file does not exist
168 virtual String MakeDatabasePath(const String name)
172 char build[MAX_LOCATION];
173 strcpy(build, path ? path : "");
174 PathCat(build, name);
175 ChangeExtension(build, "sqlite", build);
176 return CopyString(build);
181 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
183 Database result = null;
186 String path = MakeDatabasePath(name);
189 // sqlite3_open(path, &db);
190 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
192 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
193 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
195 // fprintf(stderr, "%s\n", s); // interesting
196 printf($"EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
203 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
204 if(sqlite3_exec(db, command, null, null, null))
206 if(createOptions != readOnly)
208 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
209 if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
212 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
216 result = SQLiteDatabase { db = db };
224 class SQLiteField : Field
229 public LinkElement<SQLiteField> link;
247 int GetLength() { return length; }
262 class SQLiteDatabase : Database
265 AVLTree<String> collations { };
272 uint ObjectsCount(ObjectType type)
278 bool RenameObject(ObjectType type, const String name, const String rename)
284 bool DeleteObject(ObjectType type, const String name)
290 Table OpenTable(const String name, OpenOptions options)
294 int nRows = 0, nCols = 0;
296 SQLiteTable table = null;
297 if(options.type == tablesList)
300 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
301 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
302 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
305 table.fields.Add(field);
307 else if(options.type == fieldsList)
311 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
312 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
314 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
316 table.fields.Add(field);
317 field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
319 table.fields.Add(field);
320 field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
322 table.fields.Add(field);
324 else if(options.type == tableRows)
326 bool addFields = false;
328 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
329 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
333 sqlite3_free_table(t);
335 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
336 nCols = 0, nRows = 0;
337 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
339 if((nCols || nRows) || options.create)
341 table = SQLiteTable { db = this, name = CopyString(name) };
344 table.mustCreate = true;
350 for(r = 1; r <= nRows; r++) // There should be only 1 row here
352 char * sql = t[nCols * r];
353 char * bracket = strchr(sql, '(');
365 int sqliteType = SQLITE_BLOB;
366 Class type = class(int);
370 while((ch = bracket[c++]))
372 if(ch == ',' || ch == ')')
375 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
377 memcpy(fieldName, bracket + start, d - start);
378 fieldName[d - start] = 0;
380 memcpy(dataType, bracket + d + 1, c - d - 2);
381 dataType[c - d - 2] = 0;
383 while(ch && bracket[c] == ' ') c++;
385 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
386 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
387 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
388 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
390 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
391 fieldName, type.name, 0);
392 result = sqlite3_exec(db, command, null, null, null);
395 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
397 table.fields.Add(field);
400 if(!ch || ch == ')') break;
407 Table refTable = null;
408 sqlite3_stmt * statement;
410 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
411 result = sqlite3_prepare_v2(db, command, -1, &statement, null);
413 while(sqlite3_step(statement) != SQLITE_DONE)
415 char * fieldName = sqlite3_column_text(statement, 0);
416 char * typeName = sqlite3_column_text(statement, 1);
417 int length = sqlite3_column_int(statement, 2);
419 int sqliteType = SQLITE_BLOB;
421 ((Class)(&type)).OnGetDataFromString(typeName); // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
425 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
426 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
427 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
428 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
429 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
430 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
431 sqliteType = SQLITE_INTEGER;
432 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
433 sqliteType = SQLITE_FLOAT;
434 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
435 sqliteType = SQLITE_TEXT;
438 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
440 collations.Add(type.fullName);
441 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
443 sqliteType = SQLITE_BLOB;
448 Table * fTable = (Table *)eClass_GetProperty(type, "table");
449 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
451 if(fTable) refTable = *fTable;
452 if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
453 table.primaryKey = field;
455 table.fields.Add(field);
458 sqlite3_finalize(statement);
462 sqlite3_free_table(t);
471 sprintf(command, "BEGIN;");
472 result = sqlite3_exec(db, command, null, null, null);
474 PrintLn($"BEGIN FAILED!");
475 return result == SQLITE_OK;
482 sprintf(command, "COMMIT;");
483 result = sqlite3_exec(db, command, null, null, null);
485 PrintLn($"COMMIT FAILED!");
486 return result == SQLITE_OK;
489 bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
492 Class cfClass = customFunction._class;
493 customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
494 if(customFunction.method)
496 String typeString = CopyString(customFunction.method.dataTypeString);
498 int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
500 bool variadic = false;
502 for(c = 0; c < count; c++)
505 bool pointer = false;
506 String arg = tokens[c];
508 TrimLSpaces(arg, arg);
509 if(strchr(arg, '*')) pointer = true;
511 // Using String for generic pointer...
512 type = class(String);
515 if((space = strchr(arg, ' '))) *space = 0;
516 if(!strcmp(arg, "void"))
518 else if(!strcmp(arg, "..."))
522 if(cfClass.templateParams.count)
524 ClassTemplateParameter p;
526 for(p = cfClass.templateParams.first; p; p = p.next, id++)
528 if(!strcmp(p.name, arg))
531 if(p && cfClass.templateArgs)
532 arg = cfClass.templateArgs[id].dataTypeString;
534 type = eSystem_FindClass(customFunction._class.module, arg);
536 type = eSystem_FindClass(customFunction._class.module.application, arg);
540 customFunction.returnType = type;
542 customFunction.args.Add(type);
548 // Variadic args don't make sense for SQL custom functions
549 // Note that different CIF must be prepared for different set of arguments
550 // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
554 customFunction.rType = FFIGetType(customFunction.returnType, true);
555 customFunction.argTypes.Add((void *)&ffi_type_pointer); // This pointer for SQLCustomFunction object
556 for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
557 ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
558 result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
565 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
566 FFITypesHolder structFFITypes { };
568 public ffi_type * FFIGetType(Class type, bool structByValue)
577 MapIterator<Class, String> it { map = structFFITypes };
578 ffi_type * ffiType = null;
579 if(it.Index(type, false))
580 ffiType = (void *)it.data;
585 Array<String> memberTypes { };
586 for(member = type.membersAndProperties.first; member; member = member.next)
588 if(!member.isProperty)
590 memberTypes.Add(FFIGetType(member.dataType
594 ffiType = new0 ffi_type[1];
595 ffiType->size = type.structSize;
596 ffiType->type = FFI_TYPE_STRUCT;
597 structFFITypes[type] = (void *)ffiType;
604 return &ffi_type_pointer;
610 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
611 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
613 switch(type.typeSize)
615 case 1: return &ffi_type_uint8;
616 case 2: return &ffi_type_uint16;
617 case 4: return &ffi_type_uint32;
618 case 8: return &ffi_type_uint64;
622 return &ffi_type_void;
626 static SerialBuffer staticBuffer { };
627 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
629 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
631 /* // Simple 1 pointer param returning a string
632 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
633 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
636 void * ret = &retData;
637 Array<String> args { size = sqlFunction.args.count + 1 };
638 Iterator<String> ffiArg { sqlFunction.argTypes };
639 Iterator<String> arg { args };
642 // this * for the SQLCustomFunction
643 args[0] = (void *)&sqlFunction;
645 // Get the arguments from SQLite
646 for(a : sqlFunction.args)
648 ffi_type * type = (ffi_type *)ffiArg.data;
657 void ** data = new void *[1];
658 args[i+1] = (void *)data;
659 if(a == class(String))
661 int numBytes = sqlite3_value_bytes(values[i]);
662 char * text = sqlite3_value_text(values[i]);
663 *(char **)data = text ? new byte[numBytes+1] : null;
665 memcpy(*(char **)data, text, numBytes+1);
669 SerialBuffer buffer = staticBuffer; //{ };
671 buffer._size = sqlite3_value_bytes(values[i]);
672 buffer._buffer = sqlite3_value_text(values[i]);
673 //buffer._buffer = sqlite3_value_blob(curStatement);
674 buffer.count = buffer._size;
675 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, data, buffer);
676 buffer._buffer = null;
685 if(type == &ffi_type_double || type == &ffi_type_float)
687 double d = sqlite3_value_double(values[i]);
690 double * data = new double[1];
691 args[i+1] = (void *)data;
696 float * data = new float[1];
697 args[i+1] = (void *)data;
707 int64 * data = new int64[1];
708 args[i+1] = (void *)data;
709 *data = sqlite3_value_int64(values[i]);
714 int * data = new int[1];
715 args[i+1] = (void *)data;
716 *data = sqlite3_value_int(values[i]);
721 short * data = new short[1];
723 args[i+1] = (void *)data;
724 value = sqlite3_value_int(values[i]);
726 *data = (short)value;
728 *(uint16 *)data = (uint16)value;
733 char * data = new char[1];
736 value = sqlite3_value_int(values[i]);
740 *(byte *)data = (byte)value;
750 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
751 ret = new byte[sqlFunction.returnType.typeSize];
752 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
753 // Give SQLite the return value
754 if(sqlFunction.returnType)
756 ffi_type * type = sqlFunction.rType;
757 Class r = sqlFunction.returnType;
765 void * data = ret ? *(void **)ret : null;
766 if(r.type == structClass)
768 if(r == class(String))
771 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
773 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
777 SerialBuffer buffer { };
778 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
779 sqlite3_result_text(context, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
782 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
783 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
786 if(r.type == structClass)
794 if(type == &ffi_type_double || type == &ffi_type_float)
797 sqlite3_result_double(context, *(double *)ret);
799 sqlite3_result_double(context, (double)*(float *)ret);
806 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
809 sqlite3_result_int(context, *(int *)ret);
815 value = (int)*(short *)ret;
817 //value = (int)*(uint16 *)ret;
818 sqlite3_result_int(context, value);
825 value = (int)*(char *)ret;
827 //value = (int)*(byte *)ret;
828 sqlite3_result_int(context, value);
839 for(type : sqlFunction.args; arg.Next())
842 void * data = *(void **)arg.data;
843 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
851 class SQLiteTable : Table
856 LinkList<SQLiteField> fields { };
857 char * specialStatement;
858 SQLiteField primaryKey;
859 FieldIndex * indexFields;
860 int indexFieldsCount;
863 Field AddField(const String fieldName, Class type, int length)
870 Table refTable = null;
871 Field idField = null;
874 if(FindField(fieldName)) return null;
876 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
877 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
878 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
879 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
880 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
881 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
883 strcpy(dataType, "INTEGER");
884 sqliteType = SQLITE_INTEGER;
886 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
888 strcpy(dataType, "REAL");
889 sqliteType = SQLITE_FLOAT;
891 else if(!strcmp(type.name, "CIString"))
893 strcpy(dataType, "TEXT");
894 sqliteType = SQLITE_BLOB;
896 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
898 strcpy(dataType, "TEXT");
899 sqliteType = SQLITE_TEXT;
903 //strcpy(dataType, "BLOB");
904 strcpy(dataType, "TEXT");
905 sqliteType = SQLITE_BLOB;
907 if(!db.collations.Find(type.fullName))
909 db.collations.Add(type.fullName);
910 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
913 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
915 Table * table = (Table *)eClass_GetProperty(type, "table");
916 if(table) refTable = *table;
919 if(primaryKey || refTable != this)
921 for(idField = refTable.firstField; idField; idField = idField.next)
922 if(eClass_IsDerived(type, idField.type)) break;
925 PrintLn("WARNING: field not yet created for class ", (String)type.name);
928 idField = primaryKey;
932 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
938 if(sqliteType == SQLITE_BLOB)
940 if(!strcmp(type.name, "CIString"))
941 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
943 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
947 if(!idField && refTable == this)
948 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
950 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
953 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
954 result = sqlite3_exec(db.db, command, null, null, null);
955 if(result) return null;
960 if(sqliteType == SQLITE_BLOB)
962 if(!strcmp(type.name, "CIString"))
963 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
965 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
969 if(!idField && refTable == this)
971 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
972 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
975 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
978 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
979 result = sqlite3_exec(db.db, command, null, null, null);
980 if(result) return null;
983 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
984 fieldName, type.name, length);
985 result = sqlite3_exec(db.db, command, null, null, null);
987 field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
990 if(!primaryKey && refTable == this)
995 Field FindField(const String name)
997 for(f : fields; !strcmp(f.name, name))
1001 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
1004 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
1005 if(tablePtr && *tablePtr == this)
1014 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
1019 char indexName[4096];
1022 indexFieldsCount = count;
1023 indexFields = new FieldIndex[count];
1024 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
1026 // TODO: USE CODED INDEX NAME INSTEAD?
1027 strcpy(indexName, "index_");
1028 strcat(indexName, name);
1029 strcat(indexName, "_");
1030 for(c = 0; c<count; c++)
1032 if(fieldIndexes[c].field)
1034 if(count == 1 && fieldIndexes[c].field == primaryKey)
1036 strcat(indexName, fieldIndexes[c].field.name);
1037 if(fieldIndexes[c].memberField)
1039 strcat(indexName, ".");
1040 strcat(indexName, fieldIndexes[c].memberField.name);
1042 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
1048 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
1049 for(c = 0; c<count; c++)
1051 char columnName[1024];
1052 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
1053 if(c > 0) strcat(command, ", ");
1054 strcat(command, columnName);
1056 strcat(command, ");");
1057 result = sqlite3_exec(db.db, command, null, null, null);
1059 return result == SQLITE_OK;
1067 Field GetFirstField()
1069 return fields.first;
1072 Field GetPrimaryKey()
1077 uint GetFieldsCount()
1079 return fields.count;
1089 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1090 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1091 if(result == SQLITE_OK)
1093 rowCount = atoi(t[1]);
1094 sqlite3_free_table(t);
1099 // Returns true if not ordered by row ID
1100 bool GetIndexOrder(char * fullOrder, bool flip)
1102 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1104 strcpy(fullOrder, " ORDER BY ROWID");
1110 strcpy(fullOrder, " ORDER BY ");
1111 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1114 FieldIndex * fIndex = &indexFields[c];
1116 if(c) strcat(order, ", ");
1118 strcat(order, fIndex->field.name);
1120 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1121 strcat(fullOrder, order);
1127 DriverRow CreateRow()
1130 sqlite3_stmt * statement;
1131 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1132 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1134 if(specialStatement)
1135 strcpy(command, specialStatement);
1139 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1140 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1141 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1142 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1144 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1145 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1147 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1148 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1150 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1151 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1153 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1154 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1156 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1157 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1159 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1160 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1162 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1164 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1166 GetIndexOrder(order, false);
1167 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1169 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1171 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1172 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1174 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1175 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1178 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1179 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1180 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1186 delete specialStatement;
1192 class SQLiteRow : DriverRow
1195 sqlite3_stmt * curStatement;
1197 sqlite3_stmt * defaultStatement;
1198 sqlite3_stmt * findStatement;
1199 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1200 sqlite3_stmt * nextFindStatement;
1201 sqlite3_stmt * sysIDStatement;
1202 sqlite3_stmt * queryStatement;
1203 sqlite3_stmt * selectRowIDsStmt;
1204 sqlite3_stmt * setRowIDStmt;
1205 sqlite3_stmt * lastStatement;
1206 sqlite3_stmt * previousStatement;
1207 sqlite3_stmt * nextStatement;
1209 sqlite3_stmt * insertStatement;
1210 sqlite3_stmt * deleteStatement;
1211 sqlite3_stmt * updateStatement;
1212 sqlite3_stmt * insertIDStatement;
1216 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1217 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1228 if(defaultStatement) sqlite3_finalize(defaultStatement);
1229 if(findStatement) sqlite3_finalize(findStatement);
1230 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1231 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1232 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1233 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1234 if(insertStatement) sqlite3_finalize(insertStatement);
1235 if(deleteStatement) sqlite3_finalize(deleteStatement);
1236 if(updateStatement) sqlite3_finalize(updateStatement);
1237 if(queryStatement) sqlite3_finalize(queryStatement);
1238 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1239 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1240 if(previousStatement)sqlite3_finalize(previousStatement);
1241 if(nextStatement) sqlite3_finalize(nextStatement);
1242 if(lastStatement) sqlite3_finalize(lastStatement);
1243 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1246 bool Select(MoveOptions move)
1249 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1251 curStatement = defaultStatement;
1256 sqlite3_reset(curStatement);
1257 result = sqlite3_step(curStatement);
1258 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1259 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1260 rowID = sqlite3_column_int64(curStatement, 0);
1265 sqlite3_reset(curStatement);
1266 curStatement = lastStatement;
1267 result = sqlite3_step(curStatement);
1268 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1269 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1270 rowID = sqlite3_column_int64(curStatement, 0);
1278 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1279 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1280 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1282 result = sqlite3_step(curStatement);
1283 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1284 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1285 rowID = sqlite3_column_int64(curStatement, 0);
1287 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1291 int bindId = findBindId;
1292 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1293 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1294 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1295 sqlite3_reset(curStatement);
1296 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1297 result = sqlite3_step(curStatement);
1298 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1299 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1300 rowID = sqlite3_column_int64(curStatement, 0);
1304 int bindId = findBindId;
1305 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1306 sqlite3_reset(curStatement);
1307 curStatement = (move == next) ? findStatement : lastFindStatement;
1308 result = sqlite3_step(curStatement);
1309 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1310 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1311 rowID = sqlite3_column_int64(curStatement, 0);
1316 sqlite3_reset(curStatement);
1317 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1318 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1319 result = sqlite3_step(curStatement);
1320 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1321 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1322 rowID = sqlite3_column_int64(curStatement, 0);
1327 sqlite3_reset(curStatement);
1337 bool Query(char * queryString)
1343 sqlite3_reset(curStatement);
1346 sqlite3_finalize(queryStatement);
1347 queryStatement = null;
1352 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1355 curStatement = queryStatement;
1356 if(!strchr(queryString, '?'))
1358 result = sqlite3_step(queryStatement);
1360 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1361 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1363 rowID = sqlite3_column_int64(queryStatement, 0);
1370 curStatement = null;
1374 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1377 Class dataType = fld.type;
1378 SerialBuffer buffer = null;
1379 switch(fld.sqliteType)
1381 case SQLITE_INTEGER:
1383 switch(dataType.typeSize)
1386 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1389 result = sqlite3_bind_int(statement, pos, *(int *)data);
1395 value = (int)*(short *)data;
1397 value = (int)*(uint16 *)data;
1398 result = sqlite3_bind_int(statement, pos, value);
1405 value = (int)*(char *)data;
1407 value = (int)*(byte *)data;
1408 result = sqlite3_bind_int(statement, pos, value);
1416 if(dataType.typeSize == 8)
1417 result = sqlite3_bind_double(statement, pos, *(double *)data);
1419 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1425 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1427 result = sqlite3_bind_null(statement, pos);
1435 buffer = SerialBuffer { };
1436 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1437 result = sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1440 result = sqlite3_bind_null(statement, pos);
1445 *bufferOut = buffer;
1451 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1453 if(move == next || move == previous)
1455 // Where clauses for index
1459 bool gotPrimaryKey = false;
1461 strcatf(command, " AND (");
1462 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1465 FieldIndex * fIndex = &tbl.indexFields[c];
1469 strcat(where, fIndex->field.name);
1470 strcat(where, "` ");
1471 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1472 strcat(where, " ? OR (");
1473 strcat(where, fIndex->field.name);
1474 if(fIndex->field == tbl.primaryKey)
1475 gotPrimaryKey = true;
1476 strcat(where, " = ? AND (");
1477 strcat(command, where);
1479 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1480 for(c = 0; c < tbl.indexFieldsCount; c++)
1481 strcat(command, "))");
1484 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1488 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1490 if(move == next || move == previous)
1492 // The binds for the Extra ordering Where clauses
1496 /* // Code to not rely on curStatement being set up
1497 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1498 dataRow.GoToSysID((uint)rowID);
1500 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1502 FieldIndex * fIndex = &tbl.indexFields[c];
1504 SQLiteField fld = (SQLiteField)fIndex->field;
1505 Class type = fld.type;
1507 SerialBuffer buffer;
1509 if(type.type == unitClass && !type.typeSize)
1511 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1515 if(type.type == structClass)
1517 data = (int64)new0 byte[type.structSize];
1518 dataPtr = (void *) data;
1520 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1521 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1522 if(type.type == normalClass || type.type == noHeadClass)
1523 dataPtr = (void *) data;
1526 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1527 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1528 // Reuse the buffer for Blobs...
1529 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1531 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1535 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1537 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1542 // Bind for the rowid
1543 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1547 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1549 char order[1024], command[2048];
1552 sqlite3_stmt * stmt = null;
1555 if(fld == tbl.primaryKey)
1557 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1558 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1559 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1560 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1561 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1562 result = GoToSysID(*(int *)data);
1568 useIndex = tbl.GetIndexOrder(order, false);
1570 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1571 AddCursorWhereClauses(command, move, useIndex);
1572 strcat(command, order);
1573 strcat(command, ";");
1574 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1575 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1576 BindCursorData(stmt, move, useIndex, &bindId);
1578 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1579 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1580 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1581 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1582 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1583 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1585 curStatement = findStatement = stmt;
1586 findBindId = bindId;
1588 // For going back to forward find
1590 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1591 AddCursorWhereClauses(command, next, useIndex);
1592 strcat(command, order);
1593 strcat(command, ";");
1594 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1595 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1596 nextFindStatement = stmt;
1599 tbl.GetIndexOrder(order, true);
1600 // For tracing back finds
1602 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1603 AddCursorWhereClauses(command, previous, true);
1604 strcat(command, order);
1605 strcat(command, ";");
1606 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1607 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1608 prevFindStatement = stmt;
1610 // For tracing back from last
1612 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1613 strcat(command, order);
1614 strcat(command, ";");
1615 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1616 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1617 lastFindStatement = stmt;
1619 result = sqlite3_step(findStatement);
1621 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1625 sqlite3_reset(findStatement);
1628 rowID = sqlite3_column_int64(findStatement, 0);
1632 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1635 for(c = 0; c < numFields; c++) \
1637 FieldFindData * fieldFind = &findData[c]; \
1638 SQLiteField sqlFld = (SQLiteField)findData->field; \
1639 Class dataType = sqlFld.type; \
1640 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null); \
1645 char criterias[4096], command[4096], order[1024];
1649 sqlite3_stmt * stmt = null;
1653 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1654 for(c = 0; c < numFields; c++)
1656 FieldFindData * fieldFind = &findData[c];
1658 if(c) strcat(criterias, " AND `");
1659 strcat(criterias, fieldFind->field.name);
1660 strcat(criterias, "` = ?");
1663 useIndex = tbl.GetIndexOrder(order, false);
1664 // Basic Find (multiple)
1665 strcpy(command, criterias);
1666 AddCursorWhereClauses(command, move, useIndex);
1667 strcat(command, order);
1668 strcat(command, ";");
1669 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1671 BindCursorData(stmt, move, useIndex, &bindId);
1673 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1674 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1675 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1676 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1677 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1678 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1680 curStatement = findStatement = stmt;
1681 findBindId = bindId;
1683 // For tracing back forward finds
1685 strcpy(command, criterias);
1686 AddCursorWhereClauses(command, previous, true);
1687 strcat(command, order);
1688 strcat(command, ";");
1689 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1691 nextFindStatement = stmt;
1694 tbl.GetIndexOrder(order, true);
1695 // For tracing back finds
1697 strcpy(command, criterias);
1698 AddCursorWhereClauses(command, next, useIndex);
1699 strcat(command, order);
1700 strcat(command, ";");
1701 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1703 prevFindStatement = stmt;
1705 // For tracing back from last
1707 strcpy(command, criterias);
1708 strcat(command, order);
1709 strcat(command, ";");
1710 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1712 lastFindStatement = stmt;
1714 result = sqlite3_step(findStatement);
1715 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1719 sqlite3_reset(findStatement);
1722 rowID = sqlite3_column_int64(findStatement, 0);
1728 bool Synch(DriverRow to)
1730 SQLiteRow rowTo = (SQLiteRow)to;
1731 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1732 return GoToSysID((uint)rowTo.rowID);
1739 //char command[1024];
1740 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1741 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1744 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1745 result = sqlite3_step(insertIDStatement);
1748 result = sqlite3_step(insertStatement);
1749 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1751 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1752 if(rowID > MAXDWORD)
1754 int64 lastID = tbl.lastID;
1756 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1760 result = sqlite3_step(selectRowIDsStmt);
1761 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1762 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1763 if(id - lastID > 1) break;
1766 sqlite3_reset(selectRowIDsStmt);
1768 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1771 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1772 result = sqlite3_step(setRowIDStmt);
1773 sqlite3_reset(setRowIDStmt);
1775 sqlite3_reset(id ? insertIDStatement : insertStatement);
1776 curStatement = sysIDStatement;
1778 sqlite3_reset(curStatement);
1779 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1780 result = sqlite3_step(curStatement);
1781 done = false; // Make sure 'nil' is false
1784 sqlite3_reset(insertStatement);
1791 //char command[1024];
1792 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1793 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1794 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1795 result = sqlite3_step(deleteStatement);
1796 sqlite3_reset(deleteStatement);
1798 return result == SQLITE_OK || result == SQLITE_DONE;
1801 bool GetData(Field fld, typed_object &data)
1803 SQLiteField sqlFld = (SQLiteField)fld;
1804 int num = sqlFld.num + 1;
1805 Class dataType = sqlFld.type;
1808 switch(sqlFld.sqliteType)
1810 case SQLITE_INTEGER:
1812 switch(dataType.typeSize)
1815 if(fld == tbl.primaryKey)
1816 *(int64 *)data = rowID;
1818 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1821 if(fld == tbl.primaryKey)
1822 *(int *)data = (int)(uint)rowID;
1824 *(int *)data = sqlite3_column_int(curStatement, num);
1829 if(fld == tbl.primaryKey)
1830 value = (int)(uint)rowID;
1832 value = sqlite3_column_int(curStatement, num);
1834 *(short *)data = (short)value;
1836 *(uint16 *)data = (uint16)value;
1842 if(fld == tbl.primaryKey)
1843 value = (int)(uint)rowID;
1845 value = sqlite3_column_int(curStatement, num);
1847 *(char *)data = (char)value;
1849 *(byte *)data = (byte)value;
1857 double d = sqlite3_column_double(curStatement, num);
1858 if(dataType.typeSize == 8)
1859 *(double *)data = d;
1861 *(float *)data = (float)d;
1866 int numBytes = sqlite3_column_bytes(curStatement, num);
1867 char * text = sqlite3_column_text(curStatement, num);
1868 *(char **)data = text ? new byte[numBytes+1] : null;
1870 memcpy(*(char **)data, text, numBytes+1);
1875 SerialBuffer buffer { };
1876 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1877 buffer._size = sqlite3_column_bytes(curStatement, num);
1878 buffer._buffer = sqlite3_column_text(curStatement, num);
1879 buffer.count = buffer._size;
1881 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1883 buffer._buffer = null;
1891 bool SetData(Field fld, typed_object data)
1893 SQLiteField sqlFld = (SQLiteField)fld;
1895 int num = sqlFld.num + 1;
1899 sqlite3_finalize(updateStatement);
1900 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1901 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1902 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1903 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1904 result = sqlite3_step(updateStatement);
1905 sqlite3_reset(updateStatement);
1906 if(fld == tbl.primaryKey)
1907 rowID = *(uint *)data;
1908 return result == SQLITE_DONE;
1913 return (int)(uint)rowID;
1916 bool GoToSysID(uint id)
1918 //char command[1024];
1922 //sqlite3_finalize(statement);
1923 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1924 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1928 sqlite3_reset(curStatement);
1930 curStatement = sysIDStatement;
1931 sqlite3_reset(sysIDStatement);
1932 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1933 result = sqlite3_step(curStatement);
1934 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1935 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1939 bool SetQueryParam(int paramID, int value)
1942 if(curStatement != queryStatement)
1944 if(curStatement) sqlite3_reset(curStatement);
1945 curStatement = queryStatement;
1947 sqlite3_reset(queryStatement);
1948 result = sqlite3_bind_int(queryStatement, paramID, value);
1952 bool SetQueryParam64(int paramID, int64 value)
1955 if(curStatement != queryStatement)
1957 if(curStatement) sqlite3_reset(curStatement);
1958 curStatement = queryStatement;
1960 sqlite3_reset(queryStatement);
1961 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1965 bool SetQueryParamText(int paramID, char * data)
1968 if(curStatement != queryStatement)
1970 if(curStatement) sqlite3_reset(curStatement);
1971 curStatement = queryStatement;
1973 sqlite3_reset(queryStatement);
1975 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1977 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1981 bool SetQueryParamObject(int paramID, void * data, Class type)
1984 if(curStatement != queryStatement)
1986 if(curStatement) sqlite3_reset(curStatement);
1987 curStatement = queryStatement;
1989 sqlite3_reset(queryStatement);
1991 SerialBuffer buffer { };
1992 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1993 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1999 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
2001 if(curStatement != queryStatement)
2003 if(curStatement) sqlite3_reset(curStatement);
2004 curStatement = queryStatement;
2006 sqlite3_reset(queryStatement);
2007 return BindData(queryStatement, pos, fld, data, null);
2010 /*char * GetExtraColumn(int paramID)
2012 SQLiteField lastFld = tbl.fields.last;
2013 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
2015 char * GetColumn(int paramID)
2017 return sqlite3_column_text(curStatement, paramID);