2 public import static "ecere"
3 public import static "EDA"
11 static void UnusedFunction()
19 a.OnEdit(null,null,0,0,0,0,0);
20 a.OnDisplay(null,0,0,0,0,0,0);
21 a.OnGetDataFromString(null);
22 a.OnUnserialize(null);
27 extern int __ecereVMethodID_class_OnGetString;
28 extern int __ecereVMethodID_class_OnGetDataFromString;
29 extern int __ecereVMethodID_class_OnCompare;
30 extern int __ecereVMethodID_class_OnSerialize;
31 extern int __ecereVMethodID_class_OnUnserialize;
32 extern int __ecereVMethodID_class_OnFree;
35 int CollationCompare(Class type, int count1, void * data1, int count2, void * data2)
37 if(type.type == normalClass || type.type == noHeadClass)
39 Instance inst1, inst2;
41 SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
42 SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
44 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst1, buffer1);
45 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, &inst2, buffer2);
47 result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
49 buffer1.buffer = null;
50 buffer2.buffer = null;
57 else if(type.type == structClass)
59 void * inst1, * inst2;
61 SerialBuffer buffer1 { size = count1, count = count1, buffer = data1 };
62 SerialBuffer buffer2 { size = count2, count = count2, buffer = data2 };
64 inst1 = new0 byte[type.structSize];
65 inst2 = new0 byte[type.structSize];
66 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst1, buffer1);
67 type._vTbl[__ecereVMethodID_class_OnUnserialize](type, inst2, buffer2);
69 result = type._vTbl[__ecereVMethodID_class_OnCompare](type, inst1, inst2);
71 buffer1.buffer = null;
72 buffer2.buffer = null;
80 return type._vTbl[__ecereVMethodID_class_OnCompare](type, data1, data2);
83 public class SQLiteStaticLink { } // Until .imp generation is fixed
85 class SQLiteDataSource : DataSourceDriver
87 class_property(name) = "SQLite";
89 OldList listDatabases;
92 String BuildLocator(DataSource ds)
94 return CopyString(ds.host);
97 uint GetDatabasesCount()
99 return databasesCount;
107 bool Connect(const String locator)
110 path = CopyString(locator);
111 // TODO, use user name and password for local security?
112 // TODO, open ds in read or write mode
116 FileListing listing { path, "sqlite" };
118 while(listing.Find())
125 bool RenameDatabase(const String name, const String rename)
127 if(name && rename && path && FileExists(path))
130 path = MakeDatabasePath(name);
135 repath = MakeDatabasePath(rename);
136 renamed = RenameFile(path, repath);
146 bool DeleteDatabase(const String name)
148 if(path && FileExists(path))
151 String path = MakeDatabasePath(name);
152 deleted = DeleteFile(path); // delete file seems to return true even if the file does not exist
160 virtual String MakeDatabasePath(const String name)
164 char build[MAX_LOCATION];
165 strcpy(build, path ? path : "");
166 PathCat(build, name);
167 ChangeExtension(build, "sqlite", build);
168 return CopyString(build);
173 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
175 Database result = null;
178 String path = MakeDatabasePath(name);
181 // sqlite3_open(path, &db);
182 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
184 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
185 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
187 // fprintf(stderr, "%s\n", s); // interesting
188 printf("EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
194 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
195 sqlite3_exec(db, command, null, null, null);
197 result = SQLiteDatabase { db = db };
205 class SQLiteField : Field
210 public LinkElement<SQLiteField> link;
227 int GetLength() { return length; }
238 class SQLiteDatabase : Database
241 AVLTree<String> collations { };
248 uint ObjectsCount(ObjectType type)
254 bool RenameObject(ObjectType type, const String name, const String rename)
260 bool DeleteObject(ObjectType type, const String name)
266 Table OpenTable(const String name, OpenOptions options)
270 int nRows = 0, nCols = 0;
272 SQLiteTable table = null;
273 if(options.type == tablesList)
275 SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
276 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
277 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
280 table.fields.Add(field);
282 else if(options.type == fieldsList)
286 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
287 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
289 field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
291 table.fields.Add(field);
292 field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
294 table.fields.Add(field);
295 field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
297 table.fields.Add(field);
299 else if(options.type == tableRows)
301 bool addFields = false;
303 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
304 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
308 sqlite3_free_table(t);
310 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
311 nCols = 0, nRows = 0;
312 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
314 if((nCols || nRows) || options.create)
316 table = SQLiteTable { db = this, name = CopyString(name) };
319 table.mustCreate = true;
325 for(r = 1; r <= nRows; r++) // There should be only 1 row here
327 char * sql = t[nCols * r];
328 char * bracket = strchr(sql, '(');
340 int sqliteType = SQLITE_BLOB;
341 Class type = class(int);
345 while((ch = bracket[c++]))
347 if(ch == ',' || ch == ')')
350 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
352 memcpy(fieldName, bracket + start, d - start);
353 fieldName[d - start] = 0;
355 memcpy(dataType, bracket + d + 1, c - d - 2);
356 dataType[c - d - 2] = 0;
358 while(ch && bracket[c] == ' ') c++;
360 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
361 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
362 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
363 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
365 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
366 fieldName, type.name, 0);
367 result = sqlite3_exec(db, command, null, null, null);
370 SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
372 table.fields.Add(field);
375 if(!ch || ch == ')') break;
382 sqlite3_stmt * statement;
384 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
385 result = sqlite3_prepare_v2(db, command, -1, &statement, null);
387 while(sqlite3_step(statement) != SQLITE_DONE)
389 char * fieldName = sqlite3_column_text(statement, 0);
390 char * typeName = sqlite3_column_text(statement, 1);
391 int length = sqlite3_column_int(statement, 2);
393 int sqliteType = SQLITE_BLOB;
395 ((Class)(&type)).OnGetDataFromString(typeName); // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
399 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
400 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
401 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
402 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
403 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
404 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
405 sqliteType = SQLITE_INTEGER;
406 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
407 sqliteType = SQLITE_FLOAT;
408 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
409 sqliteType = SQLITE_TEXT;
412 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
414 collations.Add(type.fullName);
415 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
417 sqliteType = SQLITE_BLOB;
422 SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
424 table.fields.Add(field);
427 sqlite3_finalize(statement);
431 sqlite3_free_table(t);
440 sprintf(command, "BEGIN;");
441 result = sqlite3_exec(db, command, null, null, null);
443 PrintLn("BEGIN FAILED!");
444 return result == SQLITE_OK;
451 sprintf(command, "COMMIT;");
452 result = sqlite3_exec(db, command, null, null, null);
454 PrintLn("COMMIT FAILED!");
455 return result == SQLITE_OK;
458 bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
460 int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
461 return result == SQLITE_OK;
465 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
467 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
468 char * text = sqlite3_value_text(*value);
469 sqlFunction.array.size = 1;
470 sqlFunction.array[0] = 0;
471 sqlFunction.Process(text);
472 sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
475 class SQLiteTable : Table
480 LinkList<SQLiteField> fields { };
481 char * specialStatement;
482 SQLiteField primaryKey;
483 FieldIndex * indexFields;
484 int indexFieldsCount;
487 Field AddField(const String fieldName, Class type, int length)
494 Table refTable = null;
495 Field idField = null;
498 if(FindField(fieldName)) return null;
500 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
501 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
502 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
503 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
504 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
505 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
507 strcpy(dataType, "INTEGER");
508 sqliteType = SQLITE_INTEGER;
510 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
512 strcpy(dataType, "REAL");
513 sqliteType = SQLITE_FLOAT;
515 else if(!strcmp(type.name, "CIString"))
517 strcpy(dataType, "TEXT");
518 sqliteType = SQLITE_BLOB;
520 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
522 strcpy(dataType, "TEXT");
523 sqliteType = SQLITE_TEXT;
527 //strcpy(dataType, "BLOB");
528 strcpy(dataType, "TEXT");
529 sqliteType = SQLITE_BLOB;
531 if(!db.collations.Find(type.fullName))
533 db.collations.Add(type.fullName);
534 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
537 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
539 Table * table = (Table *)eClass_GetProperty(type, "table");
540 if(table) refTable = *table;
543 if(primaryKey || refTable != this)
545 for(idField = refTable.firstField; idField; idField = idField.next)
546 if(eClass_IsDerived(type, idField.type)) break;
549 PrintLn("WARNING: field not yet created for class ", (String)type.name);
552 idField = primaryKey;
556 PrintLn("WARNING: Table not yet created for class ", (String)type.name);
562 if(sqliteType == SQLITE_BLOB)
564 if(!strcmp(type.name, "CIString"))
565 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
567 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
571 if(!idField && refTable == this)
572 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
574 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
577 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
578 result = sqlite3_exec(db.db, command, null, null, null);
579 if(result) return null;
584 if(sqliteType == SQLITE_BLOB)
586 if(!strcmp(type.name, "CIString"))
587 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
589 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
593 if(!idField && refTable == this)
595 PrintLn("WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
596 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
599 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
602 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
603 result = sqlite3_exec(db.db, command, null, null, null);
604 if(result) return null;
607 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
608 fieldName, type.name, length);
609 result = sqlite3_exec(db.db, command, null, null, null);
611 field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
614 if(!primaryKey && refTable == this)
619 Field FindField(const String name)
621 for(f : fields; !strcmp(f.name, name))
625 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
628 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
629 if(tablePtr && *tablePtr == this)
638 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
643 char indexName[4096];
646 indexFieldsCount = count;
647 indexFields = new FieldIndex[count];
648 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
650 // TODO: USE CODED INDEX NAME INSTEAD?
651 strcpy(indexName, "index_");
652 strcat(indexName, name);
653 strcat(indexName, "_");
654 for(c = 0; c<count; c++)
656 if(fieldIndexes[c].field)
658 if(count == 1 && fieldIndexes[c].field == primaryKey)
660 strcat(indexName, fieldIndexes[c].field.name);
661 if(fieldIndexes[c].memberField)
663 strcat(indexName, ".");
664 strcat(indexName, fieldIndexes[c].memberField.name);
666 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
672 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
673 for(c = 0; c<count; c++)
675 char columnName[1024];
676 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
677 if(c > 0) strcat(command, ", ");
678 strcat(command, columnName);
680 strcat(command, ");");
681 result = sqlite3_exec(db.db, command, null, null, null);
683 return result == SQLITE_OK;
691 Field GetFirstField()
696 uint GetFieldsCount()
708 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
709 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
710 if(result == SQLITE_OK)
712 rowCount = atoi(t[1]);
713 sqlite3_free_table(t);
718 // Returns true if not ordered by row ID
719 bool GetIndexOrder(char * fullOrder)
721 if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
723 strcpy(fullOrder, " ORDER BY ROWID");
729 strcpy(fullOrder, " ORDER BY ");
730 for(c = 0; c < indexFieldsCount; c++)
733 FieldIndex * fIndex = &indexFields[c];
735 if(c) strcat(order, ", ");
737 strcat(order, fIndex->field.name);
739 if(fIndex->order == descending) strcat(order, " DESC");
740 strcat(fullOrder, order);
746 DriverRow CreateRow()
749 sqlite3_stmt * statement;
750 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
751 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
754 strcpy(command, specialStatement);
758 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
759 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
760 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
761 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
763 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
764 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
766 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
767 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
769 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
770 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
772 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
773 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
775 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
776 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
778 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
779 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
781 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
783 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
785 GetIndexOrder(order);
786 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
788 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
790 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
791 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
793 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
794 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
797 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
798 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
799 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
805 delete specialStatement;
811 class SQLiteRow : DriverRow
814 sqlite3_stmt * curStatement;
816 sqlite3_stmt * defaultStatement;
817 sqlite3_stmt * findStatement;
818 sqlite3_stmt * sysIDStatement;
819 sqlite3_stmt * queryStatement;
820 sqlite3_stmt * findMultipleStatement;
821 sqlite3_stmt * selectRowIDsStmt;
822 sqlite3_stmt * setRowIDStmt;
823 sqlite3_stmt * lastStatement;
824 sqlite3_stmt * previousStatement;
825 sqlite3_stmt * nextStatement;
827 sqlite3_stmt * insertStatement;
828 sqlite3_stmt * deleteStatement;
829 sqlite3_stmt * updateStatement;
830 sqlite3_stmt * insertIDStatement;
842 if(defaultStatement) sqlite3_finalize(defaultStatement);
843 if(findStatement) sqlite3_finalize(findStatement);
844 if(findMultipleStatement) sqlite3_finalize(findMultipleStatement);
845 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
846 if(insertStatement) sqlite3_finalize(insertStatement);
847 if(deleteStatement) sqlite3_finalize(deleteStatement);
848 if(updateStatement) sqlite3_finalize(updateStatement);
849 if(queryStatement) sqlite3_finalize(queryStatement);
850 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
851 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
852 if(previousStatement)sqlite3_finalize(previousStatement);
853 if(nextStatement) sqlite3_finalize(nextStatement);
854 if(lastStatement) sqlite3_finalize(lastStatement);
855 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
858 bool Select(MoveOptions move)
861 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
863 curStatement = defaultStatement;
868 sqlite3_reset(curStatement);
869 result = sqlite3_step(curStatement);
870 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
871 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
872 rowID = sqlite3_column_int64(curStatement, 0);
877 sqlite3_reset(curStatement);
878 curStatement = lastStatement;
879 result = sqlite3_step(curStatement);
880 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
881 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
882 rowID = sqlite3_column_int64(curStatement, 0);
890 result = sqlite3_step(curStatement);
891 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
892 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
893 rowID = sqlite3_column_int64(curStatement, 0);
898 sqlite3_reset(curStatement);
899 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
900 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
901 result = sqlite3_step(curStatement);
902 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
903 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
904 rowID = sqlite3_column_int64(curStatement, 0);
908 sqlite3_reset(curStatement);
918 bool Query(char * queryString)
924 sqlite3_reset(curStatement);
927 sqlite3_finalize(queryStatement);
928 queryStatement = null;
933 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
934 curStatement = queryStatement;
935 if(!strchr(queryString, '?'))
937 result = sqlite3_step(queryStatement);
939 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
940 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
942 rowID = sqlite3_column_int64(queryStatement, 0);
950 void BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
952 Class dataType = fld.type;
953 SerialBuffer buffer = null;
954 switch(fld.sqliteType)
958 switch(dataType.typeSize)
961 sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
964 sqlite3_bind_int(statement, pos, *(int *)data);
970 value = (int)*(short *)data;
972 value = (int)*(uint16 *)data;
973 sqlite3_bind_int(statement, pos, value);
980 value = (int)*(char *)data;
982 value = (int)*(byte *)data;
983 sqlite3_bind_int(statement, pos, value);
991 if(dataType.typeSize == 8)
992 sqlite3_bind_double(statement, pos, *(double *)data);
994 sqlite3_bind_double(statement, pos, (double)*(float *)data);
1000 sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1002 sqlite3_bind_text(statement, pos, null, 0, SQLITE_TRANSIENT);
1008 buffer = SerialBuffer { };
1009 dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
1010 sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1015 *bufferOut = buffer;
1020 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1024 // Where clauses for index
1028 bool gotPrimaryKey = false;
1030 strcatf(command, " AND (");
1031 for(c = 0; c < tbl.indexFieldsCount; c++)
1034 FieldIndex * fIndex = &tbl.indexFields[c];
1038 strcat(where, fIndex->field.name);
1039 strcat(where, "` ");
1040 strcat(where, fIndex->order == descending ? "<" : ">");
1041 strcat(where, " ? OR (");
1042 strcat(where, fIndex->field.name);
1043 if(fIndex->field == tbl.primaryKey)
1044 gotPrimaryKey = true;
1045 strcat(where, " = ? AND (");
1046 strcat(command, where);
1048 strcat(command, gotPrimaryKey ? "1)" : "ROWID > ?)");
1050 strcat(command, "))");
1053 strcatf(command, " AND ROWID > ?");
1057 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1061 // The binds for the Extra ordering Where clauses
1065 for(c = 0; c < tbl.indexFieldsCount; c++)
1067 FieldIndex * fIndex = &tbl.indexFields[c];
1069 SQLiteField fld = (SQLiteField)fIndex->field;
1070 Class type = fld.type;
1072 SerialBuffer buffer;
1074 if(type.type == unitClass && !type.typeSize)
1076 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1080 if(type.type == structClass)
1082 data = (int64)new0 byte[type.structSize];
1083 dataPtr = (void *) data;
1085 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1086 if(type.type == normalClass || type.type == noHeadClass)
1087 dataPtr = (void *) data;
1090 ((void (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1091 // Reuse the buffer for Blobs...
1092 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1094 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1098 ((void (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1100 type._vTbl[__ecereVMethodID_class_OnFree](type, dataPtr);
1104 // Bind for the rowid
1105 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1109 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1111 char order[1024], command[2048];
1114 sqlite3_stmt * stmt = null;
1117 if(fld == tbl.primaryKey)
1119 return GoToSysID(*(int *)data);
1122 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ", tbl.name);
1123 strcatf(command, "`%s` = ?", fld.name);
1124 useIndex = tbl.GetIndexOrder(order);
1125 AddCursorWhereClauses(command, move, useIndex);
1126 strcat(command, order);
1127 strcat(command, ";");
1129 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1131 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1132 BindCursorData(stmt, move, useIndex, &bindId);
1135 sqlite3_reset(curStatement);
1137 sqlite3_finalize(findStatement);
1138 curStatement = findStatement = stmt;
1140 result = sqlite3_step(findStatement);
1142 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1146 sqlite3_reset(findStatement);
1149 rowID = sqlite3_column_int64(findStatement, 0);
1153 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1157 char command[4096], order[1024];
1161 sqlite3_stmt * stmt = null;
1164 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1165 for(c = 0; c < numFields; c++)
1167 FieldFindData * fieldFind = &findData[c];
1169 if(c) strcat(command, " AND `");
1170 strcat(command, fieldFind->field.name);
1171 strcat(command, "` = ?");
1174 useIndex = tbl.GetIndexOrder(order);
1175 AddCursorWhereClauses(command, move, useIndex);
1176 strcat(command, order);
1177 strcat(command, ";");
1179 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1181 for(c = 0; c < numFields; c++)
1183 FieldFindData * fieldFind = &findData[c];
1184 SQLiteField sqlFld = (SQLiteField)findData->field;
1185 Class dataType = sqlFld.type;
1186 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null);
1188 BindCursorData(stmt, move, useIndex, &bindId);
1191 sqlite3_reset(curStatement);
1192 if(findMultipleStatement)
1193 sqlite3_finalize(findMultipleStatement);
1195 curStatement = findMultipleStatement = stmt;
1197 result = sqlite3_step(findMultipleStatement);
1198 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1202 sqlite3_reset(findMultipleStatement);
1205 rowID = sqlite3_column_int64(findMultipleStatement, 0);
1211 bool Synch(DriverRow to)
1213 SQLiteRow rowTo = (SQLiteRow)to;
1214 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1215 return GoToSysID((uint)rowTo.rowID);
1222 //char command[1024];
1223 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1224 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1227 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1228 result = sqlite3_step(insertIDStatement);
1231 result = sqlite3_step(insertStatement);
1232 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1234 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1235 if(rowID > MAXDWORD)
1237 int64 lastID = tbl.lastID;
1239 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1243 result = sqlite3_step(selectRowIDsStmt);
1244 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1245 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1246 if(id - lastID > 1) break;
1249 sqlite3_reset(selectRowIDsStmt);
1251 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1254 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1255 result = sqlite3_step(setRowIDStmt);
1256 sqlite3_reset(setRowIDStmt);
1258 sqlite3_reset(id ? insertIDStatement : insertStatement);
1259 curStatement = sysIDStatement;
1260 sqlite3_reset(curStatement);
1261 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1262 result = sqlite3_step(curStatement);
1265 sqlite3_reset(insertStatement);
1272 //char command[1024];
1273 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1274 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1275 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1276 result = sqlite3_step(deleteStatement);
1277 sqlite3_reset(deleteStatement);
1279 return result == SQLITE_OK || result == SQLITE_DONE;
1282 bool GetData(Field fld, typed_object &data)
1284 SQLiteField sqlFld = (SQLiteField)fld;
1285 int num = sqlFld.num + 1;
1286 Class dataType = sqlFld.type;
1289 switch(sqlFld.sqliteType)
1291 case SQLITE_INTEGER:
1293 switch(dataType.typeSize)
1296 if(fld == tbl.primaryKey)
1297 *(int64 *)data = rowID;
1299 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1302 if(fld == tbl.primaryKey)
1303 *(int *)data = (int)(uint)rowID;
1305 *(int *)data = sqlite3_column_int(curStatement, num);
1310 if(fld == tbl.primaryKey)
1311 value = (int)(uint)rowID;
1313 value = sqlite3_column_int(curStatement, num);
1315 *(short *)data = (short)value;
1317 *(uint16 *)data = (uint16)value;
1323 if(fld == tbl.primaryKey)
1324 value = (int)(uint)rowID;
1326 value = sqlite3_column_int(curStatement, num);
1328 *(char *)data = (char)value;
1330 *(byte *)data = (byte)value;
1338 double d = sqlite3_column_double(curStatement, num);
1339 if(dataType.typeSize == 8)
1340 *(double *)data = d;
1342 *(float *)data = (float)d;
1347 int numBytes = sqlite3_column_bytes(curStatement, num);
1348 char * text = sqlite3_column_text(curStatement, num);
1349 *(char **)data = text ? new byte[numBytes+1] : null;
1351 memcpy(*(char **)data, text, numBytes+1);
1356 SerialBuffer buffer { };
1357 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1358 buffer._size = sqlite3_column_bytes(curStatement, num);
1359 buffer._buffer = sqlite3_column_text(curStatement, num);
1360 buffer.count = buffer._size;
1362 dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
1364 buffer._buffer = null;
1372 bool SetData(Field fld, typed_object data)
1374 SQLiteField sqlFld = (SQLiteField)fld;
1376 int num = sqlFld.num + 1;
1380 sqlite3_finalize(updateStatement);
1381 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1382 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1383 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1384 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1385 result = sqlite3_step(updateStatement);
1386 sqlite3_reset(updateStatement);
1387 if(fld == tbl.primaryKey)
1388 rowID = *(uint *)data;
1389 return result == SQLITE_DONE;
1394 return (int)(uint)rowID;
1397 bool GoToSysID(uint id)
1399 //char command[1024];
1403 //sqlite3_finalize(statement);
1404 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1405 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1408 sqlite3_reset(curStatement);
1410 curStatement = sysIDStatement;
1411 sqlite3_reset(sysIDStatement);
1412 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1413 result = sqlite3_step(curStatement);
1414 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1415 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1419 bool SetQueryParam(int paramID, int value)
1422 if(curStatement != queryStatement)
1424 if(curStatement) sqlite3_reset(curStatement);
1425 curStatement = queryStatement;
1427 sqlite3_reset(queryStatement);
1428 result = sqlite3_bind_int(queryStatement, paramID, value);
1432 bool SetQueryParam64(int paramID, int64 value)
1435 if(curStatement != queryStatement)
1437 if(curStatement) sqlite3_reset(curStatement);
1438 curStatement = queryStatement;
1440 sqlite3_reset(queryStatement);
1441 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1445 bool SetQueryParamText(int paramID, char * data)
1448 if(curStatement != queryStatement)
1450 if(curStatement) sqlite3_reset(curStatement);
1451 curStatement = queryStatement;
1453 sqlite3_reset(queryStatement);
1455 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1457 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1461 bool SetQueryParamObject(int paramID, void * data, Class type)
1464 if(curStatement != queryStatement)
1466 if(curStatement) sqlite3_reset(curStatement);
1467 curStatement = queryStatement;
1469 sqlite3_reset(queryStatement);
1471 SerialBuffer buffer { };
1472 type._vTbl[__ecereVMethodID_class_OnSerialize](type, data, buffer);
1473 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1479 /*char * GetExtraColumn(int paramID)
1481 SQLiteField lastFld = tbl.fields.last;
1482 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1484 char * GetColumn(int paramID)
1486 return sqlite3_column_text(curStatement, paramID);