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, "PRAGMA locking_mode=exclusive", null, null, null);
209 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
210 if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
213 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
217 result = SQLiteDatabase { db = db };
225 class SQLiteField : Field
230 public LinkElement<SQLiteField> link;
248 int GetLength() { return length; }
263 class SQLiteDatabase : Database
266 AVLTree<String> collations { };
270 sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
274 uint ObjectsCount(ObjectType type)
280 bool RenameObject(ObjectType type, const String name, const String rename)
286 bool DeleteObject(ObjectType type, const String name)
292 Table OpenTable(const String name, OpenOptions options)
296 int nRows = 0, nCols = 0;
298 SQLiteTable table = null;
299 if(options.type == tablesList)
302 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
303 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
304 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
307 table.fields.Add(field);
309 else if(options.type == fieldsList)
313 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
314 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
316 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
318 table.fields.Add(field);
319 field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
321 table.fields.Add(field);
322 field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
324 table.fields.Add(field);
326 else if(options.type == tableRows)
328 bool addFields = false;
330 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
331 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
335 sqlite3_free_table(t);
337 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
338 nCols = 0, nRows = 0;
339 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
341 if((nCols || nRows) || options.create)
343 table = SQLiteTable { db = this, name = CopyString(name) };
346 table.mustCreate = true;
352 for(r = 1; r <= nRows; r++) // There should be only 1 row here
354 char * sql = t[nCols * r];
355 char * bracket = strchr(sql, '(');
367 int sqliteType = SQLITE_BLOB;
368 Class type = class(int);
372 while((ch = bracket[c++]))
374 if(ch == ',' || ch == ')')
377 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
379 memcpy(fieldName, bracket + start, d - start);
380 fieldName[d - start] = 0;
382 memcpy(dataType, bracket + d + 1, c - d - 2);
383 dataType[c - d - 2] = 0;
385 while(ch && bracket[c] == ' ') c++;
387 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
388 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
389 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
390 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
392 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
393 fieldName, type.name, 0);
394 result = sqlite3_exec(db, command, null, null, null);
397 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
399 table.fields.Add(field);
402 if(!ch || ch == ')') break;
409 Table refTable = null;
410 sqlite3_stmt * statement;
412 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
413 result = sqlite3_prepare_v2(db, command, -1, &statement, null);
415 while(sqlite3_step(statement) != SQLITE_DONE)
417 char * fieldName = sqlite3_column_text(statement, 0);
418 char * typeName = sqlite3_column_text(statement, 1);
419 int length = sqlite3_column_int(statement, 2);
421 int sqliteType = SQLITE_BLOB;
423 ((Class)(&type)).OnGetDataFromString(typeName); // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
427 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
428 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
429 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
430 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
431 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
432 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
433 sqliteType = SQLITE_INTEGER;
434 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
435 sqliteType = SQLITE_FLOAT;
436 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
437 sqliteType = SQLITE_TEXT;
440 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
442 collations.Add(type.fullName);
443 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
445 sqliteType = SQLITE_BLOB;
450 Table * fTable = (Table *)eClass_GetProperty(type, "table");
451 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
453 if(fTable) refTable = *fTable;
454 if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
455 table.primaryKey = field;
457 table.fields.Add(field);
460 sqlite3_finalize(statement);
464 sqlite3_free_table(t);
473 sprintf(command, "BEGIN;");
474 result = sqlite3_exec(db, command, null, null, null);
476 PrintLn($"BEGIN FAILED!");
477 return result == SQLITE_OK;
484 sprintf(command, "COMMIT;");
485 result = sqlite3_exec(db, command, null, null, null);
487 PrintLn($"COMMIT FAILED!");
488 return result == SQLITE_OK;
491 bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
494 Class cfClass = customFunction._class;
495 customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
496 if(customFunction.method)
498 String typeString = CopyString(customFunction.method.dataTypeString);
500 int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
502 bool variadic = false;
504 for(c = 0; c < count; c++)
507 bool pointer = false;
508 String arg = tokens[c];
510 TrimLSpaces(arg, arg);
511 if(strchr(arg, '*')) pointer = true;
513 // Using String for generic pointer...
514 type = class(String);
517 if((space = strchr(arg, ' '))) *space = 0;
518 if(!strcmp(arg, "void"))
520 else if(!strcmp(arg, "..."))
524 if(cfClass.templateParams.count)
526 ClassTemplateParameter p;
528 for(p = cfClass.templateParams.first; p; p = p.next, id++)
530 if(!strcmp(p.name, arg))
533 if(p && cfClass.templateArgs)
534 arg = cfClass.templateArgs[id].dataTypeString;
536 type = eSystem_FindClass(customFunction._class.module, arg);
538 type = eSystem_FindClass(customFunction._class.module.application, arg);
542 customFunction.returnType = type;
544 customFunction.args.Add(type);
550 // Variadic args don't make sense for SQL custom functions
551 // Note that different CIF must be prepared for different set of arguments
552 // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
556 customFunction.rType = FFIGetType(customFunction.returnType, true);
557 customFunction.argTypes.Add((void *)&ffi_type_pointer); // This pointer for SQLCustomFunction object
558 for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
559 ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
560 result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
567 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
568 FFITypesHolder structFFITypes { };
570 public ffi_type * FFIGetType(Class type, bool structByValue)
579 MapIterator<Class, String> it { map = structFFITypes };
580 ffi_type * ffiType = null;
581 if(it.Index(type, false))
582 ffiType = (void *)it.data;
587 Array<String> memberTypes { };
588 for(member = type.membersAndProperties.first; member; member = member.next)
590 if(!member.isProperty)
592 memberTypes.Add(FFIGetType(member.dataType
596 ffiType = new0 ffi_type[1];
597 ffiType->size = type.structSize;
598 ffiType->type = FFI_TYPE_STRUCT;
599 structFFITypes[type] = (void *)ffiType;
606 return &ffi_type_pointer;
612 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
613 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
615 switch(type.typeSize)
617 case 1: return &ffi_type_uint8;
618 case 2: return &ffi_type_uint16;
619 case 4: return &ffi_type_uint32;
620 case 8: return &ffi_type_uint64;
624 return &ffi_type_void;
628 static SerialBuffer staticBuffer { };
629 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
631 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
633 /* // Simple 1 pointer param returning a string
634 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
635 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
638 void * ret = &retData;
639 Array<String> args { size = sqlFunction.args.count + 1 };
640 Iterator<String> ffiArg { sqlFunction.argTypes };
641 Iterator<String> arg { args };
644 // this * for the SQLCustomFunction
645 args[0] = (void *)&sqlFunction;
647 // Get the arguments from SQLite
648 for(a : sqlFunction.args)
650 ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
659 void ** data = new void *[1];
660 args[i+1] = (void *)data;
661 if(a == class(String))
663 int numBytes = sqlite3_value_bytes(values[i]);
664 char * text = sqlite3_value_text(values[i]);
665 *(char **)data = text ? new byte[numBytes+1] : null;
667 memcpy(*(char **)data, text, numBytes+1);
671 SerialBuffer buffer = staticBuffer; //{ };
673 buffer._size = sqlite3_value_bytes(values[i]);
674 buffer._buffer = sqlite3_value_text(values[i]);
675 //buffer._buffer = sqlite3_value_blob(curStatement);
676 buffer.count = buffer._size;
677 if(a.type == structClass)
678 *data = new byte[a.structSize];
679 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
680 buffer._buffer = null;
689 if(type == &ffi_type_double || type == &ffi_type_float)
691 double d = sqlite3_value_double(values[i]);
694 double * data = new double[1];
695 args[i+1] = (void *)data;
700 float * data = new float[1];
701 args[i+1] = (void *)data;
711 int64 * data = new int64[1];
712 args[i+1] = (void *)data;
713 *data = sqlite3_value_int64(values[i]);
718 int * data = new int[1];
719 args[i+1] = (void *)data;
720 *data = sqlite3_value_int(values[i]);
725 short * data = new short[1];
727 args[i+1] = (void *)data;
728 value = sqlite3_value_int(values[i]);
730 *data = (short)value;
732 *(uint16 *)data = (uint16)value;
737 char * data = new char[1];
740 value = sqlite3_value_int(values[i]);
744 *(byte *)data = (byte)value;
754 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
755 ret = new byte[sqlFunction.returnType.typeSize];
756 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
757 // Give SQLite the return value
758 if(sqlFunction.returnType)
760 ffi_type * type = sqlFunction.rType;
761 Class r = sqlFunction.returnType;
769 void * data = ret ? *(void **)ret : null;
770 if(r.type == structClass)
772 if(r == class(String))
775 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
777 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
781 SerialBuffer buffer { };
782 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
783 sqlite3_result_text(context, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
786 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
787 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
790 if(r.type == structClass)
798 if(type == &ffi_type_double || type == &ffi_type_float)
801 sqlite3_result_double(context, *(double *)ret);
803 sqlite3_result_double(context, (double)*(float *)ret);
810 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
813 sqlite3_result_int(context, *(int *)ret);
819 value = (int)*(short *)ret;
821 //value = (int)*(uint16 *)ret;
822 sqlite3_result_int(context, value);
829 value = (int)*(char *)ret;
831 //value = (int)*(byte *)ret;
832 sqlite3_result_int(context, value);
843 for(type : sqlFunction.args; arg.Next())
846 void * data = *(void **)arg.data;
847 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
848 if(type.type == structClass)
857 class SQLiteTable : Table
862 LinkList<SQLiteField> fields { };
863 char * specialStatement;
864 SQLiteField primaryKey;
865 FieldIndex * indexFields;
866 int indexFieldsCount;
869 Field AddField(const String fieldName, Class type, int length)
876 Table refTable = null;
877 Field idField = null;
880 if(FindField(fieldName)) return null;
882 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
883 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
884 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
885 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
886 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
887 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
889 strcpy(dataType, "INTEGER");
890 sqliteType = SQLITE_INTEGER;
892 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
894 strcpy(dataType, "REAL");
895 sqliteType = SQLITE_FLOAT;
897 else if(!strcmp(type.name, "CIString"))
899 strcpy(dataType, "TEXT");
900 sqliteType = SQLITE_BLOB;
902 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
904 strcpy(dataType, "TEXT");
905 sqliteType = SQLITE_TEXT;
909 //strcpy(dataType, "BLOB");
910 strcpy(dataType, "TEXT");
911 sqliteType = SQLITE_BLOB;
913 if(!db.collations.Find(type.fullName))
915 db.collations.Add(type.fullName);
916 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
919 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
921 Table * table = (Table *)eClass_GetProperty(type, "table");
922 if(table) refTable = *table;
925 if(primaryKey || refTable != this)
927 for(idField = refTable.firstField; idField; idField = idField.next)
928 if(eClass_IsDerived(type, idField.type)) break;
931 PrintLn("WARNING: field not yet created for class ", (String)type.name);
934 idField = primaryKey;
938 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
944 if(sqliteType == SQLITE_BLOB)
946 if(!strcmp(type.name, "CIString"))
947 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
949 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
953 if(!idField && refTable == this)
954 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
956 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
959 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
960 result = sqlite3_exec(db.db, command, null, null, null);
961 if(result) return null;
966 if(sqliteType == SQLITE_BLOB)
968 if(!strcmp(type.name, "CIString"))
969 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
971 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
975 if(!idField && refTable == this)
977 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
978 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
981 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
984 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
985 result = sqlite3_exec(db.db, command, null, null, null);
986 if(result) return null;
989 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
990 fieldName, type.name, length);
991 result = sqlite3_exec(db.db, command, null, null, null);
993 field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
996 if(!primaryKey && refTable == this)
1001 Field FindField(const String name)
1003 for(f : fields; !strcmp(f.name, name))
1007 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
1010 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
1011 if(tablePtr && *tablePtr == this)
1020 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
1025 char indexName[4096];
1028 indexFieldsCount = count;
1029 indexFields = new FieldIndex[count];
1030 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
1032 // TODO: USE CODED INDEX NAME INSTEAD?
1033 strcpy(indexName, "index_");
1034 strcat(indexName, name);
1035 strcat(indexName, "_");
1036 for(c = 0; c<count; c++)
1038 if(fieldIndexes[c].field)
1040 if(count == 1 && fieldIndexes[c].field == primaryKey)
1042 strcat(indexName, fieldIndexes[c].field.name);
1043 if(fieldIndexes[c].memberField)
1045 strcat(indexName, ".");
1046 strcat(indexName, fieldIndexes[c].memberField.name);
1048 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
1054 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
1055 for(c = 0; c<count; c++)
1057 char columnName[1024];
1058 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
1059 if(c > 0) strcat(command, ", ");
1060 strcat(command, columnName);
1062 strcat(command, ");");
1063 result = sqlite3_exec(db.db, command, null, null, null);
1065 return result == SQLITE_OK;
1073 Field GetFirstField()
1075 return fields.first;
1078 Field GetPrimaryKey()
1083 uint GetFieldsCount()
1085 return fields.count;
1095 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1096 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1097 if(result == SQLITE_OK)
1099 rowCount = atoi(t[1]);
1100 sqlite3_free_table(t);
1105 // Returns true if not ordered by row ID
1106 bool GetIndexOrder(char * fullOrder, bool flip)
1108 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1110 strcpy(fullOrder, " ORDER BY ROWID");
1116 strcpy(fullOrder, " ORDER BY ");
1117 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1120 FieldIndex * fIndex = &indexFields[c];
1122 if(c) strcat(order, ", ");
1124 strcat(order, fIndex->field.name);
1126 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1127 strcat(fullOrder, order);
1133 DriverRow CreateRow()
1136 sqlite3_stmt * statement;
1137 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1138 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1140 if(specialStatement)
1141 strcpy(command, specialStatement);
1145 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1146 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1147 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1148 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1150 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1151 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1153 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1154 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1156 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1157 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1159 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1160 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1162 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1163 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1165 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1166 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1168 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1170 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1172 GetIndexOrder(order, false);
1173 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1175 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1177 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1178 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1180 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1181 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1184 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1185 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1186 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1192 delete specialStatement;
1198 class SQLiteRow : DriverRow
1201 sqlite3_stmt * curStatement;
1203 sqlite3_stmt * defaultStatement;
1204 sqlite3_stmt * findStatement;
1205 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1206 sqlite3_stmt * nextFindStatement;
1207 sqlite3_stmt * sysIDStatement;
1208 sqlite3_stmt * queryStatement;
1209 sqlite3_stmt * selectRowIDsStmt;
1210 sqlite3_stmt * setRowIDStmt;
1211 sqlite3_stmt * lastStatement;
1212 sqlite3_stmt * previousStatement;
1213 sqlite3_stmt * nextStatement;
1215 sqlite3_stmt * insertStatement;
1216 sqlite3_stmt * deleteStatement;
1217 sqlite3_stmt * updateStatement;
1218 sqlite3_stmt * insertIDStatement;
1222 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1223 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1234 if(defaultStatement) sqlite3_finalize(defaultStatement);
1235 if(findStatement) sqlite3_finalize(findStatement);
1236 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1237 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1238 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1239 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1240 if(insertStatement) sqlite3_finalize(insertStatement);
1241 if(deleteStatement) sqlite3_finalize(deleteStatement);
1242 if(updateStatement) sqlite3_finalize(updateStatement);
1243 if(queryStatement) sqlite3_finalize(queryStatement);
1244 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1245 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1246 if(previousStatement)sqlite3_finalize(previousStatement);
1247 if(nextStatement) sqlite3_finalize(nextStatement);
1248 if(lastStatement) sqlite3_finalize(lastStatement);
1249 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1252 bool Select(MoveOptions move)
1255 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1257 curStatement = defaultStatement;
1262 sqlite3_reset(curStatement);
1263 result = sqlite3_step(curStatement);
1264 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1265 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1266 rowID = sqlite3_column_int64(curStatement, 0);
1271 sqlite3_reset(curStatement);
1272 curStatement = lastStatement;
1273 result = sqlite3_step(curStatement);
1274 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1275 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1276 rowID = sqlite3_column_int64(curStatement, 0);
1284 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1285 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1286 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1288 result = sqlite3_step(curStatement);
1289 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1290 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1291 rowID = sqlite3_column_int64(curStatement, 0);
1293 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1297 int bindId = findBindId;
1298 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1299 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1300 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1301 sqlite3_reset(curStatement);
1302 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1303 result = sqlite3_step(curStatement);
1304 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1305 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1306 rowID = sqlite3_column_int64(curStatement, 0);
1310 int bindId = findBindId;
1311 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1312 sqlite3_reset(curStatement);
1313 curStatement = (move == next) ? findStatement : lastFindStatement;
1314 result = sqlite3_step(curStatement);
1315 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1316 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1317 rowID = sqlite3_column_int64(curStatement, 0);
1322 sqlite3_reset(curStatement);
1323 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1324 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1325 result = sqlite3_step(curStatement);
1326 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1327 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1328 rowID = sqlite3_column_int64(curStatement, 0);
1333 sqlite3_reset(curStatement);
1343 bool Query(char * queryString)
1349 sqlite3_reset(curStatement);
1352 sqlite3_finalize(queryStatement);
1353 queryStatement = null;
1358 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1361 curStatement = queryStatement;
1362 if(!strchr(queryString, '?'))
1364 result = sqlite3_step(queryStatement);
1366 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1367 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1369 rowID = sqlite3_column_int64(queryStatement, 0);
1376 curStatement = null;
1380 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1383 Class dataType = fld.type;
1384 SerialBuffer buffer = null;
1385 switch(fld.sqliteType)
1387 case SQLITE_INTEGER:
1389 switch(dataType.typeSize)
1392 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1395 result = sqlite3_bind_int(statement, pos, *(int *)data);
1401 value = (int)*(short *)data;
1403 value = (int)*(uint16 *)data;
1404 result = sqlite3_bind_int(statement, pos, value);
1411 value = (int)*(char *)data;
1413 value = (int)*(byte *)data;
1414 result = sqlite3_bind_int(statement, pos, value);
1422 if(dataType.typeSize == 8)
1423 result = sqlite3_bind_double(statement, pos, *(double *)data);
1425 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1431 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1433 result = sqlite3_bind_null(statement, pos);
1441 buffer = SerialBuffer { };
1442 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1443 result = sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1446 result = sqlite3_bind_null(statement, pos);
1451 *bufferOut = buffer;
1457 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1459 if(move == next || move == previous)
1461 // Where clauses for index
1465 bool gotPrimaryKey = false;
1467 strcatf(command, " AND (");
1468 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1471 FieldIndex * fIndex = &tbl.indexFields[c];
1475 strcat(where, fIndex->field.name);
1476 strcat(where, "` ");
1477 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1478 strcat(where, " ? OR (");
1479 strcat(where, fIndex->field.name);
1480 if(fIndex->field == tbl.primaryKey)
1481 gotPrimaryKey = true;
1482 strcat(where, " = ? AND (");
1483 strcat(command, where);
1485 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1486 for(c = 0; c < tbl.indexFieldsCount; c++)
1487 strcat(command, "))");
1490 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1494 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1496 if(move == next || move == previous)
1498 // The binds for the Extra ordering Where clauses
1502 /* // Code to not rely on curStatement being set up
1503 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1504 dataRow.GoToSysID((uint)rowID);
1506 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1508 FieldIndex * fIndex = &tbl.indexFields[c];
1510 SQLiteField fld = (SQLiteField)fIndex->field;
1511 Class type = fld.type;
1513 SerialBuffer buffer;
1515 if(type.type == unitClass && !type.typeSize)
1517 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1521 if(type.type == structClass)
1523 data = (int64)new0 byte[type.structSize];
1524 dataPtr = (void *) data;
1526 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1527 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1528 if(type.type == normalClass || type.type == noHeadClass)
1529 dataPtr = (void *) data;
1532 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1533 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1534 // Reuse the buffer for Blobs...
1535 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1537 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1541 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1543 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1548 // Bind for the rowid
1549 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1553 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1555 char order[1024], command[2048];
1558 sqlite3_stmt * stmt = null;
1561 if(fld == tbl.primaryKey)
1563 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1564 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1565 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1566 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1567 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1568 result = GoToSysID(*(int *)data);
1574 useIndex = tbl.GetIndexOrder(order, false);
1576 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1577 AddCursorWhereClauses(command, move, useIndex);
1578 strcat(command, order);
1579 strcat(command, ";");
1580 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1581 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1582 BindCursorData(stmt, move, useIndex, &bindId);
1584 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1585 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1586 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1587 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1588 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1589 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1591 curStatement = findStatement = stmt;
1592 findBindId = bindId;
1594 // For going back to forward find
1596 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1597 AddCursorWhereClauses(command, next, useIndex);
1598 strcat(command, order);
1599 strcat(command, ";");
1600 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1601 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1602 nextFindStatement = stmt;
1605 tbl.GetIndexOrder(order, true);
1606 // For tracing back finds
1608 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1609 AddCursorWhereClauses(command, previous, true);
1610 strcat(command, order);
1611 strcat(command, ";");
1612 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1613 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1614 prevFindStatement = stmt;
1616 // For tracing back from last
1618 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1619 strcat(command, order);
1620 strcat(command, ";");
1621 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1622 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1623 lastFindStatement = stmt;
1625 result = sqlite3_step(findStatement);
1627 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1631 sqlite3_reset(findStatement);
1634 rowID = sqlite3_column_int64(findStatement, 0);
1638 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1641 for(c = 0; c < numFields; c++) \
1643 FieldFindData * fieldFind = &findData[c]; \
1644 SQLiteField sqlFld = (SQLiteField)findData->field; \
1645 Class dataType = sqlFld.type; \
1646 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null); \
1651 char criterias[4096], command[4096], order[1024];
1655 sqlite3_stmt * stmt = null;
1659 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1660 for(c = 0; c < numFields; c++)
1662 FieldFindData * fieldFind = &findData[c];
1664 if(c) strcat(criterias, " AND `");
1665 strcat(criterias, fieldFind->field.name);
1666 strcat(criterias, "` = ?");
1669 useIndex = tbl.GetIndexOrder(order, false);
1670 // Basic Find (multiple)
1671 strcpy(command, criterias);
1672 AddCursorWhereClauses(command, move, useIndex);
1673 strcat(command, order);
1674 strcat(command, ";");
1675 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1677 BindCursorData(stmt, move, useIndex, &bindId);
1679 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1680 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1681 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1682 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1683 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1684 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1686 curStatement = findStatement = stmt;
1687 findBindId = bindId;
1689 // For tracing back forward finds
1691 strcpy(command, criterias);
1692 AddCursorWhereClauses(command, previous, true);
1693 strcat(command, order);
1694 strcat(command, ";");
1695 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1697 nextFindStatement = stmt;
1700 tbl.GetIndexOrder(order, true);
1701 // For tracing back finds
1703 strcpy(command, criterias);
1704 AddCursorWhereClauses(command, next, useIndex);
1705 strcat(command, order);
1706 strcat(command, ";");
1707 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1709 prevFindStatement = stmt;
1711 // For tracing back from last
1713 strcpy(command, criterias);
1714 strcat(command, order);
1715 strcat(command, ";");
1716 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1718 lastFindStatement = stmt;
1720 result = sqlite3_step(findStatement);
1721 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1725 sqlite3_reset(findStatement);
1728 rowID = sqlite3_column_int64(findStatement, 0);
1734 bool Synch(DriverRow to)
1736 SQLiteRow rowTo = (SQLiteRow)to;
1737 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1738 return GoToSysID((uint)rowTo.rowID);
1745 //char command[1024];
1746 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1747 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1750 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1751 result = sqlite3_step(insertIDStatement);
1754 result = sqlite3_step(insertStatement);
1755 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1757 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1758 if(rowID > MAXDWORD)
1760 int64 lastID = tbl.lastID;
1762 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1766 result = sqlite3_step(selectRowIDsStmt);
1767 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1768 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1769 if(id - lastID > 1) break;
1772 sqlite3_reset(selectRowIDsStmt);
1774 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1777 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1778 result = sqlite3_step(setRowIDStmt);
1779 sqlite3_reset(setRowIDStmt);
1781 sqlite3_reset(id ? insertIDStatement : insertStatement);
1782 curStatement = sysIDStatement;
1784 sqlite3_reset(curStatement);
1785 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1786 result = sqlite3_step(curStatement);
1787 done = false; // Make sure 'nil' is false
1790 sqlite3_reset(insertStatement);
1797 //char command[1024];
1798 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1799 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1800 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1801 result = sqlite3_step(deleteStatement);
1802 sqlite3_reset(deleteStatement);
1804 return result == SQLITE_OK || result == SQLITE_DONE;
1807 bool GetData(Field fld, typed_object &data)
1809 SQLiteField sqlFld = (SQLiteField)fld;
1810 int num = sqlFld.num + 1;
1811 Class dataType = sqlFld.type;
1814 switch(sqlFld.sqliteType)
1816 case SQLITE_INTEGER:
1818 switch(dataType.typeSize)
1821 if(fld == tbl.primaryKey)
1822 *(int64 *)data = rowID;
1824 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1827 if(fld == tbl.primaryKey)
1828 *(int *)data = (int)(uint)rowID;
1830 *(int *)data = sqlite3_column_int(curStatement, num);
1835 if(fld == tbl.primaryKey)
1836 value = (int)(uint)rowID;
1838 value = sqlite3_column_int(curStatement, num);
1840 *(short *)data = (short)value;
1842 *(uint16 *)data = (uint16)value;
1848 if(fld == tbl.primaryKey)
1849 value = (int)(uint)rowID;
1851 value = sqlite3_column_int(curStatement, num);
1853 *(char *)data = (char)value;
1855 *(byte *)data = (byte)value;
1863 double d = sqlite3_column_double(curStatement, num);
1864 if(dataType.typeSize == 8)
1865 *(double *)data = d;
1867 *(float *)data = (float)d;
1872 int numBytes = sqlite3_column_bytes(curStatement, num);
1873 char * text = sqlite3_column_text(curStatement, num);
1874 *(char **)data = text ? new byte[numBytes+1] : null;
1876 memcpy(*(char **)data, text, numBytes+1);
1881 SerialBuffer buffer { };
1882 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1883 buffer._size = sqlite3_column_bytes(curStatement, num);
1884 buffer._buffer = sqlite3_column_text(curStatement, num);
1885 buffer.count = buffer._size;
1887 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1889 buffer._buffer = null;
1897 bool SetData(Field fld, typed_object data)
1899 SQLiteField sqlFld = (SQLiteField)fld;
1901 int num = sqlFld.num + 1;
1905 sqlite3_finalize(updateStatement);
1906 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1907 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1908 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1909 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1910 result = sqlite3_step(updateStatement);
1911 sqlite3_reset(updateStatement);
1912 if(fld == tbl.primaryKey)
1913 rowID = *(uint *)data;
1914 return result == SQLITE_DONE;
1919 return (int)(uint)rowID;
1922 bool GoToSysID(uint id)
1924 //char command[1024];
1928 //sqlite3_finalize(statement);
1929 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1930 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1934 sqlite3_reset(curStatement);
1936 curStatement = sysIDStatement;
1937 sqlite3_reset(sysIDStatement);
1938 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1939 result = sqlite3_step(curStatement);
1940 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1941 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1945 bool SetQueryParam(int paramID, int value)
1948 if(curStatement != queryStatement)
1950 if(curStatement) sqlite3_reset(curStatement);
1951 curStatement = queryStatement;
1953 sqlite3_reset(queryStatement);
1954 result = sqlite3_bind_int(queryStatement, paramID, value);
1958 bool SetQueryParam64(int paramID, int64 value)
1961 if(curStatement != queryStatement)
1963 if(curStatement) sqlite3_reset(curStatement);
1964 curStatement = queryStatement;
1966 sqlite3_reset(queryStatement);
1967 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1971 bool SetQueryParamText(int paramID, char * data)
1974 if(curStatement != queryStatement)
1976 if(curStatement) sqlite3_reset(curStatement);
1977 curStatement = queryStatement;
1979 sqlite3_reset(queryStatement);
1981 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1983 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1987 bool SetQueryParamObject(int paramID, void * data, Class type)
1990 if(curStatement != queryStatement)
1992 if(curStatement) sqlite3_reset(curStatement);
1993 curStatement = queryStatement;
1995 sqlite3_reset(queryStatement);
1997 SerialBuffer buffer { };
1998 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1999 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
2005 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
2007 if(curStatement != queryStatement)
2009 if(curStatement) sqlite3_reset(curStatement);
2010 curStatement = queryStatement;
2012 sqlite3_reset(queryStatement);
2013 return BindData(queryStatement, pos, fld, data, null);
2016 /*char * GetExtraColumn(int paramID)
2018 SQLiteField lastFld = tbl.fields.last;
2019 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
2021 char * GetColumn(int paramID)
2023 return sqlite3_column_text(curStatement, paramID);