2 public import static "ecere"
3 public import static "EDA"
19 __attribute__((unused)) static void UnusedFunction()
27 a.OnEdit(null,null,0,0,0,0,0);
28 a.OnDisplay(null,0,0,0,0,0,0);
29 a.OnGetDataFromString(null);
30 a.OnUnserialize(null);
35 extern int __ecereVMethodID_class_OnGetString;
36 extern int __ecereVMethodID_class_OnGetDataFromString;
37 extern int __ecereVMethodID_class_OnCompare;
38 extern int __ecereVMethodID_class_OnSerialize;
39 extern int __ecereVMethodID_class_OnUnserialize;
40 extern int __ecereVMethodID_class_OnFree;
43 static SerialBuffer collationBuffer1 { };
44 static SerialBuffer collationBuffer2 { };
45 static char storage1[512];
46 static char storage2[512];
48 int CollationCompare(Class type, int count1, const void * data1, int count2, const void * data2)
50 if(type.type == normalClass || type.type == noHeadClass)
52 Instance inst1, inst2;
54 SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
55 SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
57 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst1, buffer1);
58 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, &inst2, buffer2);
60 result = ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
62 buffer1.buffer = null;
63 buffer2.buffer = null;
70 else if(type.type == structClass)
72 void * inst1, * inst2;
74 //SerialBuffer buffer1 { size = count1, count = count1, buffer = (byte *)data1 };
75 //SerialBuffer buffer2 { size = count2, count = count2, buffer = (byte *)data2 };
77 SerialBuffer buffer1 = collationBuffer1;
78 SerialBuffer buffer2 = collationBuffer2;
79 buffer1.buffer = (byte*)data1;
80 buffer1.size = count1;
81 buffer1.count = count1;
83 buffer2.buffer = (byte*)data2;
84 buffer2.size = count2;
85 buffer2.count = count2;
88 if(type.structSize > 512)
90 inst1 = new0 byte[type.structSize];
91 inst2 = new0 byte[type.structSize];
98 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst1, buffer1);
99 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, inst2, buffer2);
101 result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, inst1, inst2);
103 buffer1.buffer = null;
104 buffer2.buffer = null;
107 if(type.structSize > 512)
115 return ((int (*)(void *, const void *, const void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type, data1, data2);
118 public class SQLiteStaticLink { } // Until .imp generation is fixed
120 class SQLiteDataSource : DirFilesDataSourceDriver
122 class_property(name) = "SQLite";
123 class_property(databaseFileExtension) = "sqlite";
125 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
127 Database result = null;
130 String path = MakeDatabasePath(name);
133 // sqlite3_open(path, &db);
134 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
136 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
137 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
139 // fprintf(stderr, "%s\n", s); // interesting
140 printf($"EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
147 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
148 sqlite3_exec(db, command, null, null, null);
150 if(createOptions != readOnly)
152 sqlite3_exec(db, "PRAGMA locking_mode=exclusive", null, null, null);
153 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
154 if(sqlite3_exec(db, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('lockDummy', 'lockDummy', 'lockDummy', 'lockDummy')", null, null, null))
157 sqlite3_exec(db, "DELETE FROM eda_table_fields WHERE Name = 'lockDummy'", null, null, null);
161 result = SQLiteDatabase { db = db };
169 class SQLiteField : Field
174 public LinkElement<SQLiteField> link;
184 const String GetName()
192 int GetLength() { return length; }
207 class SQLiteDatabase : Database
210 AVLTree<const String> collations { };
214 sqlite3_exec(db, "PRAGMA locking_mode=normal", null, null, null);
215 // "Simply setting the locking-mode to NORMAL is not enough - locks are not released until the next time the database file is accessed."
216 sqlite3_exec(db, "SELECT COUNT(*) from eda_table_fields", null, null, null);
220 uint ObjectsCount(ObjectType type)
226 bool RenameObject(ObjectType type, const String name, const String rename)
232 bool DeleteObject(ObjectType type, const String name)
238 Table OpenTable(const String name, OpenOptions options)
242 int nRows = 0, nCols = 0;
244 SQLiteTable table = null;
245 if(options.type == tablesList)
248 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
249 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
250 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
253 table._fields.Add(field);
255 else if(options.type == fieldsList)
259 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
260 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
262 field = { tbl = table, name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
264 table._fields.Add(field);
265 field = { tbl = table, name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
267 table._fields.Add(field);
268 field = { tbl = table, name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
270 table._fields.Add(field);
272 else if(options.type == tableRows)
274 bool addFields = false;
276 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
277 /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
281 sqlite3_free_table(t);
283 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
284 nCols = 0, nRows = 0;
285 /*result = */sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
287 if((nCols || nRows) || options.create)
289 table = SQLiteTable { db = this, name = CopyString(name) };
292 table.mustCreate = true;
298 for(r = 1; r <= nRows; r++) // There should be only 1 row here
300 char * sql = t[nCols * r];
301 char * bracket = strchr(sql, '(');
313 int sqliteType = SQLITE_BLOB;
314 Class type = class(int);
318 while((ch = bracket[c++]))
320 if(ch == ',' || ch == ')')
323 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
325 memcpy(fieldName, bracket + start, d - start);
326 fieldName[d - start] = 0;
328 memcpy(dataType, bracket + d + 1, c - d - 2);
329 dataType[c - d - 2] = 0;
331 while(ch && bracket[c] == ' ') c++;
333 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
334 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
335 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
336 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
338 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
339 fieldName, type.name, 0);
340 /*result = */sqlite3_exec(db, command, null, null, null);
343 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, num = table._fields.count, sqliteType = sqliteType };
345 table._fields.Add(field);
348 if(!ch || ch == ')') break;
355 Table refTable = null;
356 sqlite3_stmt * statement;
358 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
359 /*result = */sqlite3_prepare_v2(db, command, -1, &statement, null);
361 while(sqlite3_step(statement) != SQLITE_DONE)
363 const char * fieldName = (const char *)sqlite3_column_text(statement, 0);
364 const char * typeName = (const char *)sqlite3_column_text(statement, 1);
365 int length = sqlite3_column_int(statement, 2);
367 int sqliteType = SQLITE_BLOB;
369 type.OnGetDataFromString(typeName);
373 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
374 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
375 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
376 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
377 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
378 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
379 sqliteType = SQLITE_INTEGER;
380 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
381 sqliteType = SQLITE_FLOAT;
382 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
383 sqliteType = SQLITE_TEXT;
386 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
388 collations.Add(type.fullName);
389 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
391 sqliteType = SQLITE_BLOB;
396 Table * fTable = (Table *)(intptr)eClass_GetProperty(type, "table");
397 SQLiteField field { tbl = table, name = CopyString(fieldName), type = type, length = length, num = table._fields.count, sqliteType = sqliteType };
399 if(fTable) refTable = *fTable;
400 if(!table.primaryKey && refTable && !strcmp(refTable.name, table.name))
401 table.primaryKey = field;
403 table._fields.Add(field);
406 sqlite3_finalize(statement);
410 sqlite3_free_table(t);
419 sprintf(command, "BEGIN;");
420 result = sqlite3_exec(db, command, null, null, null);
422 PrintLn($"BEGIN FAILED!");
423 return result == SQLITE_OK;
430 sprintf(command, "COMMIT;");
431 result = sqlite3_exec(db, command, null, null, null);
433 PrintLn($"COMMIT FAILED!");
434 return result == SQLITE_OK;
437 bool CreateCustomFunction(const char * name, SQLCustomFunction customFunction)
440 Class cfClass = customFunction._class;
441 customFunction.method = eClass_FindMethod(cfClass, "function", cfClass.module);
442 if(customFunction.method)
444 String typeString = CopyString(customFunction.method.dataTypeString);
446 int count = TokenizeWith(typeString, sizeof(tokens)/sizeof(tokens[0]), tokens, "(,)", false);
448 bool variadic = false;
450 for(c = 0; c < count; c++)
453 bool pointer = false;
454 const String arg = tokens[c];
456 TrimLSpaces(tokens[c], tokens[c]);
457 if(strchr(arg, '*')) pointer = true;
459 // Using String for generic pointer...
460 type = class(String);
463 if((space = strchr(arg, ' '))) *space = 0;
464 if(!strcmp(arg, "void"))
466 else if(!strcmp(arg, "..."))
470 if(cfClass.templateParams.count)
472 ClassTemplateParameter p;
474 for(p = cfClass.templateParams.first; p; p = p.next, id++)
476 if(!strcmp(p.name, arg))
479 if(p && cfClass.templateArgs)
480 arg = cfClass.templateArgs[id].dataTypeString;
482 type = eSystem_FindClass(customFunction._class.module, arg);
484 type = eSystem_FindClass(customFunction._class.module.application, arg);
488 customFunction.returnType = type;
490 customFunction.args.Add(type);
496 // Variadic args don't make sense for SQL custom functions
497 // Note that different CIF must be prepared for different set of arguments
498 // ffi_prep_cif_var(&customFunction.cif, FFI_DEFAULT_ABI, args.count-1, rType, argTypes);
502 customFunction.rType = FFIGetType(customFunction.returnType, true);
503 customFunction.argTypes.Add((void *)&ffi_type_pointer); // This pointer for SQLCustomFunction object
504 for(a : customFunction.args) customFunction.argTypes.Add((void *)FFIGetType(a, false));
505 ffi_prep_cif(&customFunction.cif, FFI_DEFAULT_ABI, customFunction.argTypes.count, customFunction.rType, (ffi_type **) customFunction.argTypes.array);
506 result = sqlite3_create_function(db, name, customFunction.args.count, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null) == SQLITE_OK;
513 static class FFITypesHolder : Map<Class, String> { ~FFITypesHolder() { Free(); } }
514 FFITypesHolder structFFITypes { };
515 __attribute__((unused)) static Iterator dummy; // TOFIX: forward struct declaration issues on Clang
517 public ffi_type * FFIGetType(Class type, bool structByValue)
526 MapIterator<Class, String> it { map = structFFITypes };
527 ffi_type * ffiType = null;
528 if(it.Index(type, false))
529 ffiType = (void *)it.data;
534 Array<String> memberTypes { };
535 for(member = type.membersAndProperties.first; member; member = member.next)
537 if(!member.isProperty)
539 memberTypes.Add(FFIGetType(member.dataType
543 ffiType = new0 ffi_type[1];
544 ffiType->size = type.structSize;
545 ffiType->type = FFI_TYPE_STRUCT;
546 structFFITypes[type] = (void *)ffiType;
553 return &ffi_type_pointer;
559 if(!strcmp(type.dataTypeString, "float")) return &ffi_type_float;
560 else if(!strcmp(type.dataTypeString, "double")) return &ffi_type_double;
562 switch(type.typeSize)
564 case 1: return &ffi_type_uint8;
565 case 2: return &ffi_type_uint16;
566 case 4: return &ffi_type_uint32;
567 case 8: return &ffi_type_uint64;
571 return &ffi_type_void;
575 static SerialBuffer staticBuffer { };
576 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** values)
578 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
580 /* // Simple 1 pointer param returning a string
581 void * p = sqlFunction.method.function(sqlFunction, sqlite3_value_text(values[0]));
582 sqlite3_result_text(context, p, strlen(p), SQLITE_TRANSIENT);
585 void * ret = &retData;
586 Array<String> args { size = sqlFunction.args.count + 1 };
587 Iterator<String> ffiArg { sqlFunction.argTypes };
588 Iterator<String> arg { args };
591 // this * for the SQLCustomFunction
592 args[0] = (void *)&sqlFunction;
594 // Get the arguments from SQLite
595 for(a : sqlFunction.args)
597 ffi_type * type = (ffi_type *)sqlFunction.argTypes[i+1];
606 void ** data = new void *[1];
607 args[i+1] = (void *)data;
608 if(a == class(String))
610 int numBytes = sqlite3_value_bytes(values[i]);
611 const char * text = (const char *)sqlite3_value_text(values[i]);
612 *(char **)data = text ? new byte[numBytes+1] : null;
614 memcpy(*(char **)data, text, numBytes+1);
618 SerialBuffer buffer = staticBuffer; //{ };
620 buffer._size = sqlite3_value_bytes(values[i]);
621 buffer._buffer = (byte *)sqlite3_value_text(values[i]);
622 //buffer._buffer = sqlite3_value_blob(curStatement);
623 buffer.count = buffer._size;
624 if(a.type == structClass)
625 *data = new byte[a.structSize];
626 ((void (*)(void *, void *, void *))(void *)a._vTbl[__ecereVMethodID_class_OnUnserialize])(a, (a.type == structClass) ? *data : data, buffer);
627 buffer._buffer = null;
636 if(type == &ffi_type_double || type == &ffi_type_float)
638 double d = sqlite3_value_double(values[i]);
641 double * data = new double[1];
642 args[i+1] = (void *)data;
647 float * data = new float[1];
648 args[i+1] = (void *)data;
658 int64 * data = new int64[1];
659 args[i+1] = (void *)data;
660 *data = sqlite3_value_int64(values[i]);
665 int * data = new int[1];
666 args[i+1] = (void *)data;
667 *data = sqlite3_value_int(values[i]);
672 short * data = new short[1];
674 args[i+1] = (void *)data;
675 value = sqlite3_value_int(values[i]);
677 *data = (short)value;
679 *(uint16 *)data = (uint16)value;
684 char * data = new char[1];
687 value = sqlite3_value_int(values[i]);
691 *(byte *)data = (byte)value;
701 if(sqlFunction.returnType && sqlFunction.returnType.type == structClass)
702 ret = new byte[sqlFunction.returnType.typeSize];
703 ffi_call(&sqlFunction.cif, (void *)sqlFunction.method.function, ret, args.array);
704 // Give SQLite the return value
705 if(sqlFunction.returnType)
707 ffi_type * type = sqlFunction.rType;
708 Class r = sqlFunction.returnType;
716 void * data = ret ? *(void **)ret : null;
717 if(r.type == structClass)
719 if(r == class(String))
722 sqlite3_result_text(context, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
724 sqlite3_result_text(context, null, 0, SQLITE_TRANSIENT);
728 SerialBuffer buffer { };
729 ((void (*)(void *, void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnSerialize])(r, data, buffer);
730 sqlite3_result_text(context, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
733 // Avoid destroying Strings for now... (Returning memory owned by the Custom Function)
734 ((void (*)(void *, void *))(void *)r._vTbl[__ecereVMethodID_class_OnFree])(r, data);
737 if(r.type == structClass)
745 if(type == &ffi_type_double || type == &ffi_type_float)
748 sqlite3_result_double(context, *(double *)ret);
750 sqlite3_result_double(context, (double)*(float *)ret);
757 sqlite3_result_int64(context, (sqlite3_int64)*(int64 *)ret);
760 sqlite3_result_int(context, *(int *)ret);
766 value = (int)*(short *)ret;
768 //value = (int)*(uint16 *)ret;
769 sqlite3_result_int(context, value);
776 value = (int)*(char *)ret;
778 //value = (int)*(byte *)ret;
779 sqlite3_result_int(context, value);
790 for(type : sqlFunction.args; arg.Next())
793 void * data = *(void **)arg.data;
794 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, data);
795 if(type.type == structClass)
804 class SQLiteTable : Table
809 LinkList<SQLiteField> _fields { };
810 char * specialStatement;
811 SQLiteField primaryKey;
812 FieldIndex * indexFields;
813 int indexFieldsCount;
816 Field AddField(const String fieldName, Class type, int length)
823 Table refTable = null;
824 Field idField = null;
827 if(FindField(fieldName)) return null;
829 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
830 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
831 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
832 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
833 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
834 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
836 strcpy(dataType, "INTEGER");
837 sqliteType = SQLITE_INTEGER;
839 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
841 strcpy(dataType, "REAL");
842 sqliteType = SQLITE_FLOAT;
844 else if(!strcmp(type.name, "CIString"))
846 strcpy(dataType, "TEXT");
847 sqliteType = SQLITE_BLOB;
849 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
851 strcpy(dataType, "TEXT");
852 sqliteType = SQLITE_TEXT;
856 //strcpy(dataType, "BLOB");
857 strcpy(dataType, "TEXT");
858 sqliteType = SQLITE_BLOB;
860 if(!db.collations.Find(type.fullName))
862 db.collations.Add(type.fullName);
863 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
866 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)) && type != class(eda::Id))
868 Table * table = (Table *)(intptr)eClass_GetProperty(type, "table");
869 if(table) refTable = *table;
872 if(primaryKey || refTable != this)
874 for(idField = refTable.firstField; idField; idField = idField.next)
875 if(eClass_IsDerived(type, idField.type)) break;
878 PrintLn("WARNING: field not yet created for class ", (String)type.name);
881 idField = primaryKey;
885 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
891 if(sqliteType == SQLITE_BLOB)
893 if(!strcmp(type.name, "CIString"))
894 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
896 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
900 if(!idField && refTable == this)
901 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
903 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
906 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
907 result = sqlite3_exec(db.db, command, null, null, null);
908 if(result) return null;
913 if(sqliteType == SQLITE_BLOB)
915 if(!strcmp(type.name, "CIString"))
916 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
918 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
922 if(!idField && refTable == this)
924 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
925 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
928 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
931 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
932 result = sqlite3_exec(db.db, command, null, null, null);
933 if(result) return null;
936 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
937 fieldName, type.name, length);
938 result = sqlite3_exec(db.db, command, null, null, null);
940 field = { name = CopyString(fieldName), type = type, num = _fields.count, sqliteType = sqliteType };
943 if(!primaryKey && refTable == this)
948 Field FindField(const String name)
950 for(f : _fields; !strcmp(f.name, name))
954 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
957 Table * tablePtr = (Table *)(intptr)eClass_GetProperty(f.type, "table");
958 if(tablePtr && *tablePtr == this)
967 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
972 char indexName[4096];
975 indexFieldsCount = count;
976 indexFields = new FieldIndex[count];
977 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
979 // TODO: USE CODED INDEX NAME INSTEAD?
980 strcpy(indexName, "index_");
981 strcat(indexName, name);
982 strcat(indexName, "_");
983 for(c = 0; c<count; c++)
985 if(fieldIndexes[c].field)
987 if(count == 1 && fieldIndexes[c].field == primaryKey)
989 strcat(indexName, fieldIndexes[c].field.name);
990 if(fieldIndexes[c].memberField)
992 strcat(indexName, ".");
993 strcat(indexName, fieldIndexes[c].memberField.name);
995 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
1001 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
1002 for(c = 0; c<count; c++)
1004 char columnName[1024];
1005 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
1006 if(c > 0) strcat(command, ", ");
1007 strcat(command, columnName);
1009 strcat(command, ");");
1010 result = sqlite3_exec(db.db, command, null, null, null);
1012 return result == SQLITE_OK;
1015 const String GetName()
1020 Field GetFirstField()
1022 return _fields.first;
1025 Field GetPrimaryKey()
1030 uint GetFieldsCount()
1032 return _fields.count;
1042 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
1043 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
1044 if(result == SQLITE_OK)
1046 rowCount = atoi(t[1]);
1047 sqlite3_free_table(t);
1052 // Returns true if not ordered by row ID
1053 bool GetIndexOrder(char * fullOrder, bool flip)
1055 if(!flip && (!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending)))
1057 strcpy(fullOrder, " ORDER BY ROWID");
1063 strcpy(fullOrder, " ORDER BY ");
1064 for(c = flip ? indexFieldsCount-1 : 0; flip ? (c >= 0) : (c < indexFieldsCount); flip ? c-- : c++)
1067 FieldIndex * fIndex = &indexFields[c];
1069 if(c) strcat(order, ", ");
1071 strcat(order, fIndex->field.name);
1073 if(fIndex->order == (flip ? ascending : descending)) strcat(order, " DESC");
1074 strcat(fullOrder, order);
1080 Container<Field> GetFields()
1082 return (Container<Field>)_fields;
1085 DriverRow CreateRow()
1088 sqlite3_stmt * statement;
1089 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
1090 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
1092 if(specialStatement)
1093 strcpy(command, specialStatement);
1097 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
1098 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
1099 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
1100 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
1102 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
1103 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
1105 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
1106 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
1108 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
1109 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
1111 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
1112 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
1114 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
1115 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
1117 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
1118 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
1120 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
1122 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
1124 GetIndexOrder(order, false);
1125 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
1127 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
1129 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
1130 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
1132 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
1133 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
1136 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
1137 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
1138 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
1144 delete specialStatement;
1150 class SQLiteRow : DriverRow
1153 sqlite3_stmt * curStatement;
1155 sqlite3_stmt * defaultStatement;
1156 sqlite3_stmt * findStatement;
1157 sqlite3_stmt * prevFindStatement, * lastFindStatement;
1158 sqlite3_stmt * nextFindStatement;
1159 sqlite3_stmt * sysIDStatement;
1160 sqlite3_stmt * queryStatement;
1161 sqlite3_stmt * selectRowIDsStmt;
1162 sqlite3_stmt * setRowIDStmt;
1163 sqlite3_stmt * lastStatement;
1164 sqlite3_stmt * previousStatement;
1165 sqlite3_stmt * nextStatement;
1167 sqlite3_stmt * insertStatement;
1168 sqlite3_stmt * deleteStatement;
1169 sqlite3_stmt * updateStatement;
1170 sqlite3_stmt * insertIDStatement;
1174 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
1175 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
1186 if(defaultStatement) sqlite3_finalize(defaultStatement);
1187 if(findStatement) sqlite3_finalize(findStatement);
1188 if(prevFindStatement)sqlite3_finalize(prevFindStatement);
1189 if(lastFindStatement)sqlite3_finalize(lastFindStatement);
1190 if(nextFindStatement)sqlite3_finalize(nextFindStatement);
1191 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
1192 if(insertStatement) sqlite3_finalize(insertStatement);
1193 if(deleteStatement) sqlite3_finalize(deleteStatement);
1194 if(updateStatement) sqlite3_finalize(updateStatement);
1195 if(queryStatement) sqlite3_finalize(queryStatement);
1196 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
1197 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
1198 if(previousStatement)sqlite3_finalize(previousStatement);
1199 if(nextStatement) sqlite3_finalize(nextStatement);
1200 if(lastStatement) sqlite3_finalize(lastStatement);
1201 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
1204 bool Select(MoveOptions move)
1207 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
1209 curStatement = defaultStatement;
1214 sqlite3_reset(curStatement);
1215 result = sqlite3_step(curStatement);
1216 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1217 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1218 rowID = sqlite3_column_int64(curStatement, 0);
1223 sqlite3_reset(curStatement);
1224 curStatement = lastStatement;
1225 result = sqlite3_step(curStatement);
1226 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1227 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1228 rowID = sqlite3_column_int64(curStatement, 0);
1236 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
1237 if((move == next && curStatement != prevFindStatement && curStatement != lastFindStatement && !stepping && (curStatement != sysIDStatement || findSysID)) ||
1238 (move == previous && (curStatement == prevFindStatement || curStatement == lastFindStatement)))
1240 result = sqlite3_step(curStatement);
1241 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1242 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1243 rowID = sqlite3_column_int64(curStatement, 0);
1245 else if(curStatement == prevFindStatement || curStatement == findStatement || curStatement == nextFindStatement || curStatement == lastFindStatement)
1249 int bindId = findBindId;
1250 sqlite3_reset((move == next) ? nextFindStatement : prevFindStatement);
1251 BindCursorData((move == next) ? nextFindStatement : prevFindStatement, move,
1252 (move == next && (!tbl.indexFields || (tbl.indexFieldsCount == 1 && tbl.indexFields[0].field == tbl.primaryKey && tbl.indexFields[0].order == ascending))) ? false : true, &bindId);
1253 sqlite3_reset(curStatement);
1254 curStatement = (move == next) ? nextFindStatement : prevFindStatement;
1255 result = sqlite3_step(curStatement);
1256 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1257 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1258 rowID = sqlite3_column_int64(curStatement, 0);
1262 sqlite3_reset((move == next) ? findStatement : lastFindStatement);
1263 sqlite3_reset(curStatement);
1264 curStatement = (move == next) ? findStatement : lastFindStatement;
1265 result = sqlite3_step(curStatement);
1266 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1267 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1268 rowID = sqlite3_column_int64(curStatement, 0);
1273 sqlite3_reset(curStatement);
1274 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
1275 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
1276 result = sqlite3_step(curStatement);
1277 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1278 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1279 rowID = sqlite3_column_int64(curStatement, 0);
1284 sqlite3_reset(curStatement);
1294 bool Query(const char * queryString)
1300 sqlite3_reset(curStatement);
1303 sqlite3_finalize(queryStatement);
1304 queryStatement = null;
1309 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
1312 curStatement = queryStatement;
1313 if(!strchr(queryString, '?'))
1315 result = sqlite3_step(queryStatement);
1317 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1318 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
1320 rowID = sqlite3_column_int64(queryStatement, 0);
1325 printf("SQLite Query Error: %s\n", queryString);
1330 curStatement = null;
1334 bool BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
1337 Class dataType = fld.type;
1338 SerialBuffer buffer = null;
1339 switch(fld.sqliteType)
1341 case SQLITE_INTEGER:
1343 switch(dataType.typeSize)
1346 result = sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
1349 result = sqlite3_bind_int(statement, pos, *(int *)data);
1355 value = (int)*(short *)data;
1357 value = (int)*(uint16 *)data;
1358 result = sqlite3_bind_int(statement, pos, value);
1365 value = (int)*(char *)data;
1367 value = (int)*(byte *)data;
1368 result = sqlite3_bind_int(statement, pos, value);
1376 if(dataType.typeSize == 8)
1377 result = sqlite3_bind_double(statement, pos, *(double *)data);
1379 result = sqlite3_bind_double(statement, pos, (double)*(float *)data);
1385 result = sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1387 result = sqlite3_bind_null(statement, pos);
1395 buffer = SerialBuffer { };
1396 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnSerialize])(dataType, data, buffer);
1397 result = sqlite3_bind_text(statement, pos, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1400 result = sqlite3_bind_null(statement, pos);
1405 *bufferOut = buffer;
1411 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1413 if(move == next || move == previous)
1415 // Where clauses for index
1419 bool gotPrimaryKey = false;
1421 strcatf(command, " AND (");
1422 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1425 FieldIndex * fIndex = &tbl.indexFields[c];
1429 strcat(where, fIndex->field.name);
1430 strcat(where, "` ");
1431 strcat(where, (fIndex->order == ((move == next) ? descending : ascending)) ? "<" : ">");
1432 strcat(where, " ? OR (");
1433 strcat(where, fIndex->field.name);
1434 if(fIndex->field == tbl.primaryKey)
1435 gotPrimaryKey = true;
1436 strcat(where, " = ? AND (");
1437 strcat(command, where);
1439 strcat(command, gotPrimaryKey ? "1)" : ((move == next) ? "ROWID > ?)" : "ROWID < ?)"));
1440 for(c = 0; c < tbl.indexFieldsCount; c++)
1441 strcat(command, "))");
1444 strcatf(command, (move == next) ? " AND ROWID > ?" : " AND ROWID < ?");
1448 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1450 if(move == next || move == previous)
1452 // The binds for the Extra ordering Where clauses
1456 /* // Code to not rely on curStatement being set up
1457 SQLiteRow dataRow = (SQLiteRow)tbl.CreateRow();
1458 dataRow.GoToSysID((uint)rowID);
1460 for(c = ((move == next) ? 0 : tbl.indexFieldsCount-1); (move == next) ? c < tbl.indexFieldsCount : c >= 0; (move == next) ? c++ : c--)
1462 FieldIndex * fIndex = &tbl.indexFields[c];
1464 SQLiteField fld = (SQLiteField)fIndex->field;
1465 Class type = fld.type;
1467 SerialBuffer buffer;
1469 if(type.type == unitClass && !type.typeSize)
1471 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1475 if(type.type == structClass)
1477 data = (int64)(intptr)new0 byte[type.structSize];
1478 dataPtr = (void *)(intptr)data;
1480 // ((bool (*)())(void *)dataRow.GetData)(dataRow, fld, type, (type.type == structClass) ? (void *)data : &data);
1481 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)(intptr)data : &data);
1482 if(type.type == normalClass || type.type == noHeadClass)
1483 dataPtr = (void *)(intptr)data;
1486 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1487 // NOTE: The data is bound twice, for there are 2x '?' in the query from AddCursorWhereClauses
1488 // Reuse the buffer for Blobs...
1489 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1491 sqlite3_bind_text(stmt, (*bindId)++, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1495 ((bool (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1497 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, dataPtr);
1502 // Bind for the rowid
1503 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1507 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1509 char order[1024], command[2048];
1512 sqlite3_stmt * stmt = null;
1515 if(fld == tbl.primaryKey)
1517 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1518 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1519 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1520 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1521 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1522 result = GoToSysID(*(int *)data);
1528 useIndex = tbl.GetIndexOrder(order, false);
1530 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1531 AddCursorWhereClauses(command, move, useIndex);
1532 strcat(command, order);
1533 strcat(command, ";");
1534 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1535 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1536 BindCursorData(stmt, move, useIndex, &bindId);
1538 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1539 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1540 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1541 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1542 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1543 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1545 curStatement = findStatement = stmt;
1546 findBindId = bindId;
1548 // For going back to forward find
1550 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1551 AddCursorWhereClauses(command, next, useIndex);
1552 strcat(command, order);
1553 strcat(command, ";");
1554 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1555 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1556 nextFindStatement = stmt;
1559 tbl.GetIndexOrder(order, true);
1560 // For tracing back finds
1562 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1563 AddCursorWhereClauses(command, previous, true);
1564 strcat(command, order);
1565 strcat(command, ";");
1566 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1567 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1568 prevFindStatement = stmt;
1570 // For tracing back from last
1572 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?", tbl.name, fld.name);
1573 strcat(command, order);
1574 strcat(command, ";");
1575 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1576 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1577 lastFindStatement = stmt;
1579 result = sqlite3_step(findStatement);
1581 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1585 sqlite3_reset(findStatement);
1588 rowID = sqlite3_column_int64(findStatement, 0);
1592 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1595 for(c = 0; c < numFields; c++) \
1597 FieldFindData * fieldFind = &findData[c]; \
1598 SQLiteField sqlFld = (SQLiteField)findData->field; \
1599 Class dataType = sqlFld.type; \
1600 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null); \
1605 char criterias[4096], command[4096], order[1024];
1609 sqlite3_stmt * stmt = null;
1613 sprintf(criterias, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1614 for(c = 0; c < numFields; c++)
1616 FieldFindData * fieldFind = &findData[c];
1618 if(c) strcat(criterias, " AND `");
1619 strcat(criterias, fieldFind->field.name);
1620 strcat(criterias, "` = ?");
1623 useIndex = tbl.GetIndexOrder(order, false);
1624 // Basic Find (multiple)
1625 strcpy(command, criterias);
1626 AddCursorWhereClauses(command, move, useIndex);
1627 strcat(command, order);
1628 strcat(command, ";");
1629 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1631 BindCursorData(stmt, move, useIndex, &bindId);
1633 // Currently, we can't reset curStatement until after BindCursorData, as current data is read from it
1634 if(curStatement) { sqlite3_reset(curStatement); curStatement = null; }
1635 if(findStatement) { sqlite3_finalize(findStatement); findStatement = null; }
1636 if(nextFindStatement) { sqlite3_finalize(nextFindStatement); nextFindStatement = null; }
1637 if(prevFindStatement) { sqlite3_finalize(prevFindStatement); prevFindStatement = null; }
1638 if(lastFindStatement) { sqlite3_finalize(lastFindStatement); lastFindStatement = null; }
1640 curStatement = findStatement = stmt;
1641 findBindId = bindId;
1643 // For tracing back forward finds
1645 strcpy(command, criterias);
1646 AddCursorWhereClauses(command, previous, true);
1647 strcat(command, order);
1648 strcat(command, ";");
1649 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1651 nextFindStatement = stmt;
1654 tbl.GetIndexOrder(order, true);
1655 // For tracing back finds
1657 strcpy(command, criterias);
1658 AddCursorWhereClauses(command, next, useIndex);
1659 strcat(command, order);
1660 strcat(command, ";");
1661 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1663 prevFindStatement = stmt;
1665 // For tracing back from last
1667 strcpy(command, criterias);
1668 strcat(command, order);
1669 strcat(command, ";");
1670 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1672 lastFindStatement = stmt;
1674 result = sqlite3_step(findStatement);
1675 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1679 sqlite3_reset(findStatement);
1682 rowID = sqlite3_column_int64(findStatement, 0);
1688 bool Synch(DriverRow to)
1690 SQLiteRow rowTo = (SQLiteRow)to;
1691 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1692 return GoToSysID((uint)rowTo.rowID);
1699 //char command[1024];
1700 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1701 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1704 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1705 result = sqlite3_step(insertIDStatement);
1708 result = sqlite3_step(insertStatement);
1709 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1711 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1712 if(rowID > MAXDWORD)
1714 int64 lastID = tbl.lastID;
1716 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1720 result = sqlite3_step(selectRowIDsStmt);
1721 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1722 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1723 if(id - lastID > 1) break;
1726 sqlite3_reset(selectRowIDsStmt);
1728 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1731 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1732 result = sqlite3_step(setRowIDStmt);
1733 sqlite3_reset(setRowIDStmt);
1735 sqlite3_reset(id ? insertIDStatement : insertStatement);
1736 curStatement = sysIDStatement;
1738 sqlite3_reset(curStatement);
1739 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1740 result = sqlite3_step(curStatement);
1741 done = false; // Make sure 'nil' is false
1744 sqlite3_reset(insertStatement);
1751 //char command[1024];
1752 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1753 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1754 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1755 result = sqlite3_step(deleteStatement);
1756 sqlite3_reset(deleteStatement);
1758 return result == SQLITE_OK || result == SQLITE_DONE;
1761 bool GetData(Field fld, typed_object &data)
1763 SQLiteField sqlFld = (SQLiteField)fld;
1764 int num = sqlFld.num + 1;
1765 Class dataType = sqlFld.type;
1768 switch(sqlFld.sqliteType)
1770 case SQLITE_INTEGER:
1772 switch(dataType.typeSize)
1775 if(fld == tbl.primaryKey)
1776 *(int64 *)data = rowID;
1778 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1781 if(fld == tbl.primaryKey)
1782 *(int *)data = (int)(uint)rowID;
1784 *(int *)data = sqlite3_column_int(curStatement, num);
1789 if(fld == tbl.primaryKey)
1790 value = (int)(uint)rowID;
1792 value = sqlite3_column_int(curStatement, num);
1794 *(short *)data = (short)value;
1796 *(uint16 *)data = (uint16)value;
1802 if(fld == tbl.primaryKey)
1803 value = (int)(uint)rowID;
1805 value = sqlite3_column_int(curStatement, num);
1807 *(char *)data = (char)value;
1809 *(byte *)data = (byte)value;
1817 double d = sqlite3_column_double(curStatement, num);
1818 if(dataType.typeSize == 8)
1819 *(double *)data = d;
1821 *(float *)data = (float)d;
1826 int numBytes = sqlite3_column_bytes(curStatement, num);
1827 const char * text = (const char *)sqlite3_column_text(curStatement, num);
1828 *(char **)data = text ? new byte[numBytes+1] : null;
1830 memcpy(*(char **)data, text, numBytes+1);
1835 SerialBuffer buffer { };
1836 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1837 buffer._size = sqlite3_column_bytes(curStatement, num);
1838 buffer._buffer = (byte *)sqlite3_column_text(curStatement, num);
1839 buffer.count = buffer._size;
1841 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnUnserialize])(dataType, data, buffer);
1843 buffer._buffer = null;
1851 bool SetData(Field fld, typed_object data)
1853 SQLiteField sqlFld = (SQLiteField)fld;
1858 sqlite3_finalize(updateStatement);
1859 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1860 // TODO: Shouldn't we cache those update statements per field?
1861 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1862 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1863 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1864 result = sqlite3_step(updateStatement);
1865 sqlite3_reset(updateStatement);
1866 if(fld == tbl.primaryKey)
1867 rowID = *(uint *)data;
1868 return result == SQLITE_DONE;
1873 return (int)(uint)rowID;
1876 bool GoToSysID(uint id)
1878 //char command[1024];
1882 //sqlite3_finalize(statement);
1883 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1884 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1888 sqlite3_reset(curStatement);
1890 curStatement = sysIDStatement;
1891 sqlite3_reset(sysIDStatement);
1892 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1893 result = sqlite3_step(curStatement);
1894 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1895 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1899 bool SetQueryParam(int paramID, int value)
1902 if(curStatement != queryStatement)
1904 if(curStatement) sqlite3_reset(curStatement);
1905 curStatement = queryStatement;
1907 sqlite3_reset(queryStatement);
1908 result = sqlite3_bind_int(queryStatement, paramID, value);
1912 bool SetQueryParam64(int paramID, int64 value)
1915 if(curStatement != queryStatement)
1917 if(curStatement) sqlite3_reset(curStatement);
1918 curStatement = queryStatement;
1920 sqlite3_reset(queryStatement);
1921 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1925 bool SetQueryParamText(int paramID, const char * data)
1928 if(curStatement != queryStatement)
1930 if(curStatement) sqlite3_reset(curStatement);
1931 curStatement = queryStatement;
1933 sqlite3_reset(queryStatement);
1935 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1937 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1941 bool SetQueryParamObject(int paramID, const void * data, Class type)
1944 if(curStatement != queryStatement)
1946 if(curStatement) sqlite3_reset(curStatement);
1947 curStatement = queryStatement;
1949 sqlite3_reset(queryStatement);
1951 SerialBuffer buffer { };
1952 ((void (*)(void *, const void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnSerialize])(type, data, buffer);
1953 result = sqlite3_bind_text(queryStatement, paramID, (char *)buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1959 bool BindQueryData(int pos, SQLiteField fld, typed_object data)
1961 if(curStatement != queryStatement)
1963 if(curStatement) sqlite3_reset(curStatement);
1964 curStatement = queryStatement;
1966 sqlite3_reset(queryStatement);
1967 return BindData(queryStatement, pos, fld, data, null);
1970 /*char * GetExtraColumn(int paramID)
1972 SQLiteField lastFld = tbl._fields.last;
1973 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1975 const char * GetColumn(int paramID)
1977 return (const char *)sqlite3_column_text(curStatement, paramID);