2 public import static "ecere"
3 public import static "EDA"
15 static void UnusedFunction()
23 a.OnEdit(null,null,0,0,0,0,0);
24 a.OnDisplay(null,0,0,0,0,0,0);
25 a.OnGetDataFromString(null);
26 a.OnUnserialize(null);
31 extern int __ecereVMethodID_class_OnGetString;
32 extern int __ecereVMethodID_class_OnGetDataFromString;
33 extern int __ecereVMethodID_class_OnCompare;
34 extern int __ecereVMethodID_class_OnSerialize;
35 extern int __ecereVMethodID_class_OnUnserialize;
36 extern int __ecereVMethodID_class_OnFree;
39 int CollationCompare(Class type, int count1, void * data1, int count2, void * data2)
41 if(type.type == normalClass || type.type == noHeadClass)
43 Instance inst1, inst2;
45 SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
46 SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
48 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
49 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
51 result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
53 buffer1.buffer = null;
54 buffer2.buffer = null;
61 else if(type.type == structClass)
63 void * inst1, * inst2;
65 SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
66 SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
68 inst1 = new0 byte[type.structSize];
69 inst2 = new0 byte[type.structSize];
70 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
71 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
73 result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
75 buffer1.buffer = null;
76 buffer2.buffer = null;
84 return type._vTbl[__ecereVMethodID_class_OnCompare](type, data1, data2);
87 public class SQLiteStaticLink { } // Until .imp generation is fixed
89 class SQLiteDataSource : DataSourceDriver
91 class_property(name) = "SQLite";
93 OldList listDatabases;
96 String BuildLocator(DataSource ds)
98 return CopyString(ds.host);
101 uint GetDatabasesCount()
103 return databasesCount;
111 bool Connect(const String locator)
114 path = CopyString(locator);
115 // TODO, use user name and password for local security?
116 // TODO, open ds in read or write mode
120 FileListing listing { path, "sqlite" };
122 while(listing.Find())
129 bool RenameDatabase(const String name, const String rename)
131 if(name && rename && path && FileExists(path))
134 path = MakeDatabasePath(name);
139 repath = MakeDatabasePath(rename);
140 renamed = RenameFile(path, repath);
150 bool DeleteDatabase(const String name)
152 if(path && FileExists(path))
155 String path = MakeDatabasePath(name);
156 deleted = DeleteFile(path); // delete file seems to return true even if the file does not exist
164 virtual String MakeDatabasePath(const String name)
168 char build[MAX_LOCATION];
169 strcpy(build, path ? path : "");
170 PathCat(build, name);
171 ChangeExtension(build, "sqlite", build);
172 return CopyString(build);
177 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
179 Database result = null;
182 String path = MakeDatabasePath(name);
185 // sqlite3_open(path, &db);
186 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
188 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
189 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
191 // fprintf(stderr, "%s\n", s); // interesting
192 printf($"EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
198 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
199 sqlite3_exec(db, command, null, null, null);
201 result = SQLiteDatabase { db = db };
209 class SQLiteField : Field
214 public LinkElement<SQLiteField> link;
231 int GetLength() { return length; }
242 class SQLiteDatabase : Database
245 AVLTree<String> collations { };
252 uint ObjectsCount(ObjectType type)
258 bool RenameObject(ObjectType type, const String name, const String rename)
264 bool DeleteObject(ObjectType type, const String name)
270 Table OpenTable(const String name, OpenOptions options)
274 int nRows = 0, nCols = 0;
276 SQLiteTable table = null;
277 if(options.type == tablesList)
279 SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
280 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
281 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
284 table.fields.Add(field);
286 else if(options.type == fieldsList)
290 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
291 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
293 field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
295 table.fields.Add(field);
296 field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
298 table.fields.Add(field);
299 field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
301 table.fields.Add(field);
303 else if(options.type == tableRows)
305 bool addFields = false;
307 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
308 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
312 sqlite3_free_table(t);
314 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
315 nCols = 0, nRows = 0;
316 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
318 if((nCols || nRows) || options.create)
320 table = SQLiteTable { db = this, name = CopyString(name) };
323 table.mustCreate = true;
329 for(r = 1; r <= nRows; r++) // There should be only 1 row here
331 char * sql = t[nCols * r];
332 char * bracket = strchr(sql, '(');
344 int sqliteType = SQLITE_BLOB;
345 Class type = class(int);
349 while((ch = bracket[c++]))
351 if(ch == ',' || ch == ')')
354 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
356 memcpy(fieldName, bracket + start, d - start);
357 fieldName[d - start] = 0;
359 memcpy(dataType, bracket + d + 1, c - d - 2);
360 dataType[c - d - 2] = 0;
362 while(ch && bracket[c] == ' ') c++;
364 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
365 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
366 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
367 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
369 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
370 fieldName, type.name, 0);
371 result = sqlite3_exec(db, command, null, null, null);
374 SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
376 table.fields.Add(field);
379 if(!ch || ch == ')') break;
386 sqlite3_stmt * statement;
388 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
389 result = sqlite3_prepare_v2(db, command, -1, &statement, null);
391 while(sqlite3_step(statement) != SQLITE_DONE)
393 char * fieldName = sqlite3_column_text(statement, 0);
394 char * typeName = sqlite3_column_text(statement, 1);
395 int length = sqlite3_column_int(statement, 2);
397 int sqliteType = SQLITE_BLOB;
399 ((Class)(&type)).OnGetDataFromString(typeName); // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
403 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
404 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
405 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
406 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
407 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
408 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
409 sqliteType = SQLITE_INTEGER;
410 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
411 sqliteType = SQLITE_FLOAT;
412 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
413 sqliteType = SQLITE_TEXT;
416 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
418 collations.Add(type.fullName);
419 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
421 sqliteType = SQLITE_BLOB;
426 SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
428 table.fields.Add(field);
431 sqlite3_finalize(statement);
435 sqlite3_free_table(t);
444 sprintf(command, "BEGIN;");
445 result = sqlite3_exec(db, command, null, null, null);
447 PrintLn($"BEGIN FAILED!");
448 return result == SQLITE_OK;
455 sprintf(command, "COMMIT;");
456 result = sqlite3_exec(db, command, null, null, null);
458 PrintLn($"COMMIT FAILED!");
459 return result == SQLITE_OK;
462 bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
464 int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
465 return result == SQLITE_OK;
469 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
471 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
472 char * text = sqlite3_value_text(*value);
473 sqlFunction.array.size = 1;
474 sqlFunction.array[0] = 0;
475 sqlFunction.Process(text);
476 sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
479 class SQLiteTable : Table
484 LinkList<SQLiteField> fields { };
485 char * specialStatement;
486 SQLiteField primaryKey;
487 FieldIndex * indexFields;
488 int indexFieldsCount;
491 Field AddField(const String fieldName, Class type, int length)
498 Table refTable = null;
499 Field idField = null;
502 if(FindField(fieldName)) return null;
504 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
505 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
506 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
507 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
508 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
509 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
511 strcpy(dataType, "INTEGER");
512 sqliteType = SQLITE_INTEGER;
514 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
516 strcpy(dataType, "REAL");
517 sqliteType = SQLITE_FLOAT;
519 else if(!strcmp(type.name, "CIString"))
521 strcpy(dataType, "TEXT");
522 sqliteType = SQLITE_BLOB;
524 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
526 strcpy(dataType, "TEXT");
527 sqliteType = SQLITE_TEXT;
531 //strcpy(dataType, "BLOB");
532 strcpy(dataType, "TEXT");
533 sqliteType = SQLITE_BLOB;
535 if(!db.collations.Find(type.fullName))
537 db.collations.Add(type.fullName);
538 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
541 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
543 Table * table = (Table *)eClass_GetProperty(type, "table");
544 if(table) refTable = *table;
547 if(primaryKey || refTable != this)
549 for(idField = refTable.firstField; idField; idField = idField.next)
550 if(eClass_IsDerived(type, idField.type)) break;
553 PrintLn("WARNING: field not yet created for class ", (String)type.name);
556 idField = primaryKey;
560 PrintLn($"WARNING: Table not yet created for class ", (String)type.name);
566 if(sqliteType == SQLITE_BLOB)
568 if(!strcmp(type.name, "CIString"))
569 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
571 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
575 if(!idField && refTable == this)
576 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
578 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
581 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
582 result = sqlite3_exec(db.db, command, null, null, null);
583 if(result) return null;
588 if(sqliteType == SQLITE_BLOB)
590 if(!strcmp(type.name, "CIString"))
591 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
593 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
597 if(!idField && refTable == this)
599 PrintLn($"WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
600 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
603 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
606 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
607 result = sqlite3_exec(db.db, command, null, null, null);
608 if(result) return null;
611 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
612 fieldName, type.name, length);
613 result = sqlite3_exec(db.db, command, null, null, null);
615 field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
618 if(!primaryKey && refTable == this)
623 Field FindField(const String name)
625 for(f : fields; !strcmp(f.name, name))
629 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
632 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
633 if(tablePtr && *tablePtr == this)
642 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
647 char indexName[4096];
650 indexFieldsCount = count;
651 indexFields = new FieldIndex[count];
652 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
654 // TODO: USE CODED INDEX NAME INSTEAD?
655 strcpy(indexName, "index_");
656 strcat(indexName, name);
657 strcat(indexName, "_");
658 for(c = 0; c<count; c++)
660 if(fieldIndexes[c].field)
662 if(count == 1 && fieldIndexes[c].field == primaryKey)
664 strcat(indexName, fieldIndexes[c].field.name);
665 if(fieldIndexes[c].memberField)
667 strcat(indexName, ".");
668 strcat(indexName, fieldIndexes[c].memberField.name);
670 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
676 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
677 for(c = 0; c<count; c++)
679 char columnName[1024];
680 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
681 if(c > 0) strcat(command, ", ");
682 strcat(command, columnName);
684 strcat(command, ");");
685 result = sqlite3_exec(db.db, command, null, null, null);
687 return result == SQLITE_OK;
695 Field GetFirstField()
700 uint GetFieldsCount()
712 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
713 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
714 if(result == SQLITE_OK)
716 rowCount = atoi(t[1]);
717 sqlite3_free_table(t);
722 // Returns true if not ordered by row ID
723 bool GetIndexOrder(char * fullOrder)
725 if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
727 strcpy(fullOrder, " ORDER BY ROWID");
733 strcpy(fullOrder, " ORDER BY ");
734 for(c = 0; c < indexFieldsCount; c++)
737 FieldIndex * fIndex = &indexFields[c];
739 if(c) strcat(order, ", ");
741 strcat(order, fIndex->field.name);
743 if(fIndex->order == descending) strcat(order, " DESC");
744 strcat(fullOrder, order);
750 DriverRow CreateRow()
753 sqlite3_stmt * statement;
754 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
755 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
758 strcpy(command, specialStatement);
762 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
763 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
764 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
765 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
767 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
768 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
770 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
771 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
773 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
774 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
776 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
777 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
779 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
780 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
782 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
783 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
785 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
787 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
789 GetIndexOrder(order);
790 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
792 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
794 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
795 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
797 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
798 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
801 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
802 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
803 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
809 delete specialStatement;
815 class SQLiteRow : DriverRow
818 sqlite3_stmt * curStatement;
820 sqlite3_stmt * defaultStatement;
821 sqlite3_stmt * findStatement;
822 sqlite3_stmt * sysIDStatement;
823 sqlite3_stmt * queryStatement;
824 sqlite3_stmt * findMultipleStatement;
825 sqlite3_stmt * selectRowIDsStmt;
826 sqlite3_stmt * setRowIDStmt;
827 sqlite3_stmt * lastStatement;
828 sqlite3_stmt * previousStatement;
829 sqlite3_stmt * nextStatement;
831 sqlite3_stmt * insertStatement;
832 sqlite3_stmt * deleteStatement;
833 sqlite3_stmt * updateStatement;
834 sqlite3_stmt * insertIDStatement;
838 // Because we use GoToSysID() and the sysIDStatement when searching for a primary key with Find(),
839 // this flag is used to distinguish between a Find() and a GoToSysID() for Select(next) purposes:
849 if(defaultStatement) sqlite3_finalize(defaultStatement);
850 if(findStatement) sqlite3_finalize(findStatement);
851 if(findMultipleStatement) sqlite3_finalize(findMultipleStatement);
852 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
853 if(insertStatement) sqlite3_finalize(insertStatement);
854 if(deleteStatement) sqlite3_finalize(deleteStatement);
855 if(updateStatement) sqlite3_finalize(updateStatement);
856 if(queryStatement) sqlite3_finalize(queryStatement);
857 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
858 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
859 if(previousStatement)sqlite3_finalize(previousStatement);
860 if(nextStatement) sqlite3_finalize(nextStatement);
861 if(lastStatement) sqlite3_finalize(lastStatement);
862 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
865 bool Select(MoveOptions move)
868 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
870 curStatement = defaultStatement;
875 sqlite3_reset(curStatement);
876 result = sqlite3_step(curStatement);
877 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
878 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
879 rowID = sqlite3_column_int64(curStatement, 0);
884 sqlite3_reset(curStatement);
885 curStatement = lastStatement;
886 result = sqlite3_step(curStatement);
887 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
888 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
889 rowID = sqlite3_column_int64(curStatement, 0);
895 // For sysID statement, for a Find() we want to go through next/previous in order, otherwise we just go to nil
896 if(!stepping && (curStatement != sysIDStatement || findSysID))
898 result = sqlite3_step(curStatement);
899 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
900 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
901 rowID = sqlite3_column_int64(curStatement, 0);
906 sqlite3_reset(curStatement);
907 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
908 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
909 result = sqlite3_step(curStatement);
910 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
911 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
912 rowID = sqlite3_column_int64(curStatement, 0);
916 sqlite3_reset(curStatement);
926 bool Query(char * queryString)
932 sqlite3_reset(curStatement);
935 sqlite3_finalize(queryStatement);
936 queryStatement = null;
941 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
942 curStatement = queryStatement;
943 if(!strchr(queryString, '?'))
945 result = sqlite3_step(queryStatement);
947 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
948 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
950 rowID = sqlite3_column_int64(queryStatement, 0);
958 void BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
960 Class dataType = fld.type;
961 SerialBuffer buffer = null;
962 switch(fld.sqliteType)
966 switch(dataType.typeSize)
969 sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
972 sqlite3_bind_int(statement, pos, *(int *)data);
978 value = (int)*(short *)data;
980 value = (int)*(uint16 *)data;
981 sqlite3_bind_int(statement, pos, value);
988 value = (int)*(char *)data;
990 value = (int)*(byte *)data;
991 sqlite3_bind_int(statement, pos, value);
999 if(dataType.typeSize == 8)
1000 sqlite3_bind_double(statement, pos, *(double *)data);
1002 sqlite3_bind_double(statement, pos, (double)*(float *)data);
1008 sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1010 sqlite3_bind_text(statement, pos, null, 0, SQLITE_TRANSIENT);
1016 buffer = SerialBuffer { };
1017 dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
1018 sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1023 *bufferOut = buffer;
1028 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1032 // Where clauses for index
1036 bool gotPrimaryKey = false;
1038 strcatf(command, " AND (");
1039 for(c = 0; c < tbl.indexFieldsCount; c++)
1042 FieldIndex * fIndex = &tbl.indexFields[c];
1046 strcat(where, fIndex->field.name);
1047 strcat(where, "` ");
1048 strcat(where, fIndex->order == descending ? "<" : ">");
1049 strcat(where, " ? OR (");
1050 strcat(where, fIndex->field.name);
1051 if(fIndex->field == tbl.primaryKey)
1052 gotPrimaryKey = true;
1053 strcat(where, " = ? AND (");
1054 strcat(command, where);
1056 strcat(command, gotPrimaryKey ? "1)" : "ROWID > ?)");
1058 strcat(command, "))");
1061 strcatf(command, " AND ROWID > ?");
1065 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1069 // The binds for the Extra ordering Where clauses
1073 for(c = 0; c < tbl.indexFieldsCount; c++)
1075 FieldIndex * fIndex = &tbl.indexFields[c];
1077 SQLiteField fld = (SQLiteField)fIndex->field;
1078 Class type = fld.type;
1080 SerialBuffer buffer;
1082 if(type.type == unitClass && !type.typeSize)
1084 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1088 if(type.type == structClass)
1090 data = (int64)new0 byte[type.structSize];
1091 dataPtr = (void *) data;
1093 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1094 if(type.type == normalClass || type.type == noHeadClass)
1095 dataPtr = (void *) data;
1098 ((void (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1099 // Reuse the buffer for Blobs...
1100 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1102 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1106 ((void (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1108 type._vTbl[__ecereVMethodID_class_OnFree](type, dataPtr);
1112 // Bind for the rowid
1113 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1117 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1119 char order[1024], command[2048];
1122 sqlite3_stmt * stmt = null;
1125 if(fld == tbl.primaryKey)
1127 result = GoToSysID(*(int *)data);
1133 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ", tbl.name);
1134 strcatf(command, "`%s` = ?", fld.name);
1135 useIndex = tbl.GetIndexOrder(order);
1136 AddCursorWhereClauses(command, move, useIndex);
1137 strcat(command, order);
1138 strcat(command, ";");
1140 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1142 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1143 BindCursorData(stmt, move, useIndex, &bindId);
1146 sqlite3_reset(curStatement);
1148 sqlite3_finalize(findStatement);
1149 curStatement = findStatement = stmt;
1151 result = sqlite3_step(findStatement);
1153 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1157 sqlite3_reset(findStatement);
1160 rowID = sqlite3_column_int64(findStatement, 0);
1164 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1168 char command[4096], order[1024];
1172 sqlite3_stmt * stmt = null;
1175 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1176 for(c = 0; c < numFields; c++)
1178 FieldFindData * fieldFind = &findData[c];
1180 if(c) strcat(command, " AND `");
1181 strcat(command, fieldFind->field.name);
1182 strcat(command, "` = ?");
1185 useIndex = tbl.GetIndexOrder(order);
1186 AddCursorWhereClauses(command, move, useIndex);
1187 strcat(command, order);
1188 strcat(command, ";");
1190 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1192 for(c = 0; c < numFields; c++)
1194 FieldFindData * fieldFind = &findData[c];
1195 SQLiteField sqlFld = (SQLiteField)findData->field;
1196 Class dataType = sqlFld.type;
1197 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null);
1199 BindCursorData(stmt, move, useIndex, &bindId);
1202 sqlite3_reset(curStatement);
1203 if(findMultipleStatement)
1204 sqlite3_finalize(findMultipleStatement);
1206 curStatement = findMultipleStatement = stmt;
1208 result = sqlite3_step(findMultipleStatement);
1209 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1213 sqlite3_reset(findMultipleStatement);
1216 rowID = sqlite3_column_int64(findMultipleStatement, 0);
1222 bool Synch(DriverRow to)
1224 SQLiteRow rowTo = (SQLiteRow)to;
1225 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1226 return GoToSysID((uint)rowTo.rowID);
1233 //char command[1024];
1234 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1235 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1238 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1239 result = sqlite3_step(insertIDStatement);
1242 result = sqlite3_step(insertStatement);
1243 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1245 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1246 if(rowID > MAXDWORD)
1248 int64 lastID = tbl.lastID;
1250 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1254 result = sqlite3_step(selectRowIDsStmt);
1255 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1256 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1257 if(id - lastID > 1) break;
1260 sqlite3_reset(selectRowIDsStmt);
1262 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1265 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1266 result = sqlite3_step(setRowIDStmt);
1267 sqlite3_reset(setRowIDStmt);
1269 sqlite3_reset(id ? insertIDStatement : insertStatement);
1270 curStatement = sysIDStatement;
1272 sqlite3_reset(curStatement);
1273 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1274 result = sqlite3_step(curStatement);
1277 sqlite3_reset(insertStatement);
1284 //char command[1024];
1285 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1286 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1287 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1288 result = sqlite3_step(deleteStatement);
1289 sqlite3_reset(deleteStatement);
1291 return result == SQLITE_OK || result == SQLITE_DONE;
1294 bool GetData(Field fld, typed_object &data)
1296 SQLiteField sqlFld = (SQLiteField)fld;
1297 int num = sqlFld.num + 1;
1298 Class dataType = sqlFld.type;
1301 switch(sqlFld.sqliteType)
1303 case SQLITE_INTEGER:
1305 switch(dataType.typeSize)
1308 if(fld == tbl.primaryKey)
1309 *(int64 *)data = rowID;
1311 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1314 if(fld == tbl.primaryKey)
1315 *(int *)data = (int)(uint)rowID;
1317 *(int *)data = sqlite3_column_int(curStatement, num);
1322 if(fld == tbl.primaryKey)
1323 value = (int)(uint)rowID;
1325 value = sqlite3_column_int(curStatement, num);
1327 *(short *)data = (short)value;
1329 *(uint16 *)data = (uint16)value;
1335 if(fld == tbl.primaryKey)
1336 value = (int)(uint)rowID;
1338 value = sqlite3_column_int(curStatement, num);
1340 *(char *)data = (char)value;
1342 *(byte *)data = (byte)value;
1350 double d = sqlite3_column_double(curStatement, num);
1351 if(dataType.typeSize == 8)
1352 *(double *)data = d;
1354 *(float *)data = (float)d;
1359 int numBytes = sqlite3_column_bytes(curStatement, num);
1360 char * text = sqlite3_column_text(curStatement, num);
1361 *(char **)data = text ? new byte[numBytes+1] : null;
1363 memcpy(*(char **)data, text, numBytes+1);
1368 SerialBuffer buffer { };
1369 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1370 buffer._size = sqlite3_column_bytes(curStatement, num);
1371 buffer._buffer = sqlite3_column_text(curStatement, num);
1372 buffer.count = buffer._size;
1374 dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
1376 buffer._buffer = null;
1384 bool SetData(Field fld, typed_object data)
1386 SQLiteField sqlFld = (SQLiteField)fld;
1388 int num = sqlFld.num + 1;
1392 sqlite3_finalize(updateStatement);
1393 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1394 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1395 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1396 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1397 result = sqlite3_step(updateStatement);
1398 sqlite3_reset(updateStatement);
1399 if(fld == tbl.primaryKey)
1400 rowID = *(uint *)data;
1401 return result == SQLITE_DONE;
1406 return (int)(uint)rowID;
1409 bool GoToSysID(uint id)
1411 //char command[1024];
1415 //sqlite3_finalize(statement);
1416 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1417 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1421 sqlite3_reset(curStatement);
1423 curStatement = sysIDStatement;
1424 sqlite3_reset(sysIDStatement);
1425 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1426 result = sqlite3_step(curStatement);
1427 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1428 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1432 bool SetQueryParam(int paramID, int value)
1435 if(curStatement != queryStatement)
1437 if(curStatement) sqlite3_reset(curStatement);
1438 curStatement = queryStatement;
1440 sqlite3_reset(queryStatement);
1441 result = sqlite3_bind_int(queryStatement, paramID, value);
1445 bool SetQueryParam64(int paramID, int64 value)
1448 if(curStatement != queryStatement)
1450 if(curStatement) sqlite3_reset(curStatement);
1451 curStatement = queryStatement;
1453 sqlite3_reset(queryStatement);
1454 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1458 bool SetQueryParamText(int paramID, char * data)
1461 if(curStatement != queryStatement)
1463 if(curStatement) sqlite3_reset(curStatement);
1464 curStatement = queryStatement;
1466 sqlite3_reset(queryStatement);
1468 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1470 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1474 bool SetQueryParamObject(int paramID, void * data, Class type)
1477 if(curStatement != queryStatement)
1479 if(curStatement) sqlite3_reset(curStatement);
1480 curStatement = queryStatement;
1482 sqlite3_reset(queryStatement);
1484 SerialBuffer buffer { };
1485 type._vTbl[__ecereVMethodID_class_OnSerialize](type, data, buffer);
1486 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1492 /*char * GetExtraColumn(int paramID)
1494 SQLiteField lastFld = tbl.fields.last;
1495 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1497 char * GetColumn(int paramID)
1499 return sqlite3_column_text(curStatement, paramID);