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 class SQLiteDataSource : DataSourceDriver
85 class_property(name) = "SQLite";
87 OldList listDatabases;
90 String BuildLocator(DataSource ds)
92 return CopyString(ds.host);
95 uint GetDatabasesCount()
97 return databasesCount;
105 bool Connect(const String locator)
108 path = CopyString(locator);
109 // TODO, use user name and password for local security?
110 // TODO, open ds in read or write mode
114 FileListing listing { path, "sqlite" };
116 while(listing.Find())
123 bool RenameDatabase(const String name, const String rename)
125 if(name && rename && path && FileExists(path))
128 path = MakeDatabasePath(name);
133 repath = MakeDatabasePath(rename);
134 renamed = RenameFile(path, repath);
144 bool DeleteDatabase(const String name)
146 if(path && FileExists(path))
149 String path = MakeDatabasePath(name);
150 deleted = DeleteFile(path); // delete file seems to return true even if the file does not exist
158 virtual String MakeDatabasePath(const String name)
162 char build[MAX_LOCATION];
163 strcpy(build, path ? path : "");
164 PathCat(build, name);
165 ChangeExtension(build, "sqlite", build);
166 return CopyString(build);
171 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
173 Database result = null;
176 String path = MakeDatabasePath(name);
179 // sqlite3_open(path, &db);
180 // sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY /*SQLITE_OPEN_READWRITE*/ /*SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE*/, null );
182 if(sqlite3_open_v2(path, &db, (createOptions == readOnly) ? SQLITE_OPEN_READONLY :
183 (SQLITE_OPEN_READWRITE | ((createOptions == create) ? SQLITE_OPEN_CREATE : 0)), null))
185 // fprintf(stderr, "%s\n", s); // interesting
186 printf("EDASQLite: Can't open database (%s): %s\n", path, sqlite3_errmsg(db));
192 sprintf(command, "CREATE TABLE eda_table_fields(Table_Name TEXT, Name TEXT, Type TEXT, Length INT);");
193 sqlite3_exec(db, command, null, null, null);
195 result = SQLiteDatabase { db = db };
203 class SQLiteField : Field
208 public LinkElement<SQLiteField> link;
225 int GetLength() { return length; }
236 class SQLiteDatabase : Database
239 AVLTree<String> collations { };
246 uint ObjectsCount(ObjectType type)
252 bool RenameObject(ObjectType type, const String name, const String rename)
258 bool DeleteObject(ObjectType type, const String name)
264 Table OpenTable(const String name, OpenOptions options)
268 int nRows = 0, nCols = 0;
270 SQLiteTable table = null;
271 if(options.type == tablesList)
273 SQLiteField field { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
274 strcpy(command, "SELECT name FROM sqlite_master WHERE type='table' AND name!='eda_table_fields';");
275 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
278 table.fields.Add(field);
280 else if(options.type == fieldsList)
284 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
285 table = SQLiteTable { db = this, specialStatement = CopyString(command) };
287 field = { name = CopyString("Name"), type = class(String), num = -1, sqliteType = SQLITE_TEXT };
289 table.fields.Add(field);
290 field = { name = CopyString("Type"), type = class(Class), num = 0, sqliteType = SQLITE_TEXT };
292 table.fields.Add(field);
293 field = { name = CopyString("Length"), type = class(int), num = 1, sqliteType = SQLITE_INTEGER };
295 table.fields.Add(field);
297 else if(options.type == tableRows)
299 bool addFields = false;
301 sprintf(command, "SELECT Name FROM eda_table_fields WHERE Table_Name='%s';", name);
302 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
306 sqlite3_free_table(t);
308 sprintf(command, "SELECT sql FROM sqlite_master WHERE type='table' AND name='%s';", name);
309 nCols = 0, nRows = 0;
310 result = sqlite3_get_table(db, command, &t, &nRows, &nCols, null);
312 if((nCols || nRows) || options.create)
314 table = SQLiteTable { db = this, name = CopyString(name) };
317 table.mustCreate = true;
323 for(r = 1; r <= nRows; r++) // There should be only 1 row here
325 char * sql = t[nCols * r];
326 char * bracket = strchr(sql, '(');
339 Class type = class(int);
343 while((ch = bracket[c++]))
345 if(ch == ',' || ch == ')')
348 for(d = c-1; d >= 0 && bracket[d] != ' '; d--);
350 memcpy(fieldName, bracket + start, d - start);
351 fieldName[d - start] = 0;
353 memcpy(dataType, bracket + d + 1, c - d - 2);
354 dataType[c - d - 2] = 0;
356 while(ch && bracket[c] == ' ') c++;
358 if(!strcmp(dataType, "REAL")) { sqliteType = SQLITE_FLOAT; type = class(double); }
359 else if(!strcmp(dataType, "TEXT")) { sqliteType = SQLITE_TEXT; type = class(String); }
360 else if(!strcmp(dataType, "INTEGER")) { sqliteType = SQLITE_INTEGER; type = class(int); }
361 else if(!strcmp(dataType, "BLOB")) { sqliteType = SQLITE_BLOB; type = class(char *); } //class(byte *);
363 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
364 fieldName, type.name, 0);
365 result = sqlite3_exec(db, command, null, null, null);
368 SQLiteField field { name = CopyString(fieldName), type = type, num = table.fields.count, sqliteType = sqliteType };
370 table.fields.Add(field);
373 if(!ch || ch == ')') break;
380 sqlite3_stmt * statement;
382 sprintf(command, "SELECT Name, Type, Length FROM eda_table_fields WHERE Table_Name='%s';", name);
383 result = sqlite3_prepare_v2(db, command, -1, &statement, null);
385 while(sqlite3_step(statement) != SQLITE_DONE)
387 char * fieldName = sqlite3_column_text(statement, 0);
388 char * typeName = sqlite3_column_text(statement, 1);
389 int length = sqlite3_column_int(statement, 2);
393 ((Class)(&type)).OnGetDataFromString(typeName); // TODO: THIS REQUIRES A FIX SOMEWHERE ELSE
397 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
398 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
399 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
400 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
401 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
402 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
403 sqliteType = SQLITE_INTEGER;
404 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
405 sqliteType = SQLITE_FLOAT;
406 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
407 sqliteType = SQLITE_TEXT;
410 if(strcmp(type.fullName, "CIString") && !collations.Find(type.fullName))
412 collations.Add(type.fullName);
413 sqlite3_create_collation_v2(table.db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
415 sqliteType = SQLITE_BLOB;
420 SQLiteField field { name = CopyString(fieldName), type = type, length = length, num = table.fields.count, sqliteType = sqliteType };
422 table.fields.Add(field);
425 sqlite3_finalize(statement);
429 sqlite3_free_table(t);
438 sprintf(command, "BEGIN;");
439 result = sqlite3_exec(db, command, null, null, null);
441 PrintLn("BEGIN FAILED!");
442 return result == SQLITE_OK;
449 sprintf(command, "COMMIT;");
450 result = sqlite3_exec(db, command, null, null, null);
452 PrintLn("COMMIT FAILED!");
453 return result == SQLITE_OK;
456 bool CreateCustomFunction(char * name, SQLCustomFunction customFunction)
458 int result = sqlite3_create_function(db, name, 1, SQLITE_UTF8, customFunction, SQLiteFunctionProcessor, null, null);
459 return result == SQLITE_OK;
463 void SQLiteFunctionProcessor(sqlite3_context* context, int n, sqlite3_value** value)
465 SQLCustomFunction sqlFunction = sqlite3_user_data(context);
466 char * text = sqlite3_value_text(*value);
467 sqlFunction.array.size = 1;
468 sqlFunction.array[0] = 0;
469 sqlFunction.Process(text);
470 sqlite3_result_text(context, sqlFunction.array.array, sqlFunction.array.count ? sqlFunction.array.count - 1 : 0, SQLITE_TRANSIENT);
473 class SQLiteTable : Table
478 LinkList<SQLiteField> fields { };
479 char * specialStatement;
480 SQLiteField primaryKey;
481 FieldIndex * indexFields;
482 int indexFieldsCount;
485 Field AddField(const String fieldName, Class type, int length)
492 Table refTable = null;
493 Field idField = null;
496 if(FindField(fieldName)) return null;
498 if(!strcmp(type.dataTypeString, "int") || !strcmp(type.dataTypeString, "unsigned int") ||
499 !strcmp(type.dataTypeString, "long") || !strcmp(type.dataTypeString, "long int") ||
500 !strcmp(type.dataTypeString, "uint") || !strcmp(type.dataTypeString, "uint32") ||
501 !strcmp(type.dataTypeString, "int64") || !strcmp(type.dataTypeString, "unsigned int64") || !strcmp(type.dataTypeString, "uint64") ||
502 !strcmp(type.dataTypeString, "short") || !strcmp(type.dataTypeString, "unsigned short") || !strcmp(type.dataTypeString, "uint16") ||
503 !strcmp(type.dataTypeString, "char") || !strcmp(type.dataTypeString, "unsigned char") || !strcmp(type.dataTypeString, "byte"))
505 strcpy(dataType, "INTEGER");
506 sqliteType = SQLITE_INTEGER;
508 else if(!strcmp(type.dataTypeString, "double") || !strcmp(type.dataTypeString, "float"))
510 strcpy(dataType, "REAL");
511 sqliteType = SQLITE_FLOAT;
513 else if(!strcmp(type.name, "CIString"))
515 strcpy(dataType, "TEXT");
516 sqliteType = SQLITE_BLOB;
518 else if(!strcmp(type.dataTypeString, "String") || !strcmp(type.dataTypeString, "char *"))
520 strcpy(dataType, "TEXT");
521 sqliteType = SQLITE_TEXT;
525 //strcpy(dataType, "BLOB");
526 strcpy(dataType, "TEXT");
527 sqliteType = SQLITE_BLOB;
529 if(!db.collations.Find(type.fullName))
531 db.collations.Add(type.fullName);
532 result = sqlite3_create_collation_v2(db.db, type.fullName, SQLITE_UTF8, type, CollationCompare, null);
535 if(sqliteType != SQLITE_BLOB && eClass_IsDerived(type, class(eda::Id)))
537 Table * table = (Table *)eClass_GetProperty(type, "table");
538 if(table) refTable = *table;
541 if(primaryKey || refTable != this)
543 for(idField = refTable.firstField; idField; idField = idField.next)
544 if(eClass_IsDerived(type, idField.type)) break;
547 PrintLn("WARNING: field not yet created for class ", (String)type.name);
550 idField = primaryKey;
554 PrintLn("WARNING: Table not yet created for class ", (String)type.name);
560 if(sqliteType == SQLITE_BLOB)
562 if(!strcmp(type.name, "CIString"))
563 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE NOCASE);", name, fieldName, dataType);
565 sprintf(command, "CREATE TABLE `%s`(%s %s COLLATE '%s');", name, fieldName, dataType, type.fullName);
569 if(!idField && refTable == this)
570 sprintf(command, "CREATE TABLE `%s`(`%s` %s PRIMARY KEY);", name, fieldName, dataType);
572 sprintf(command, "CREATE TABLE `%s`(`%s` %s REFERENCES `%s`(`%s`));", name, fieldName, dataType, refTable.name, idField.name);
575 sprintf(command, "CREATE TABLE `%s`(`%s` %s);", name, fieldName, dataType);
576 result = sqlite3_exec(db.db, command, null, null, null);
577 if(result) return null;
582 if(sqliteType == SQLITE_BLOB)
584 if(!strcmp(type.name, "CIString"))
585 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE NOCASE;", name, fieldName, dataType);
587 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s COLLATE `%s`;", name, fieldName, dataType, type.fullName);
591 if(!idField && refTable == this)
593 PrintLn("WARNING: ALTER TABLE DOESN'T WORK WITH PRIMARY KEY FOR ", (String)name);
594 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s PRIMARY KEY;", name, fieldName, dataType);
597 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s REFERENCES `%s`(`%s`);", name, fieldName, dataType, refTable.name, idField.name);
600 sprintf(command, "ALTER TABLE `%s` ADD `%s` %s;", name, fieldName, dataType);
601 result = sqlite3_exec(db.db, command, null, null, null);
602 if(result) return null;
605 sprintf(command, "INSERT INTO eda_table_fields (Table_Name, Name, Type, Length) VALUES ('%s', '%s', '%s', %d);", name,
606 fieldName, type.name, length);
607 result = sqlite3_exec(db.db, command, null, null, null);
609 field = { name = CopyString(fieldName), type = type, num = fields.count, sqliteType = sqliteType };
612 if(!primaryKey && refTable == this)
617 Field FindField(const String name)
619 for(f : fields; !strcmp(f.name, name))
623 if(f.sqliteType != SQLITE_BLOB && eClass_IsDerived(f.type, class(eda::Id)))
626 Table * tablePtr = (Table *)eClass_GetProperty(f.type, "table");
627 if(tablePtr && *tablePtr == this)
636 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
641 char indexName[4096];
644 indexFieldsCount = count;
645 indexFields = new FieldIndex[count];
646 memcpy(indexFields, fieldIndexes, count * sizeof(FieldIndex));
648 // TODO: USE CODED INDEX NAME INSTEAD?
649 strcpy(indexName, "index_");
650 strcat(indexName, name);
651 strcat(indexName, "_");
652 for(c = 0; c<count; c++)
654 if(fieldIndexes[c].field)
656 if(count == 1 && fieldIndexes[c].field == primaryKey)
658 strcat(indexName, fieldIndexes[c].field.name);
659 if(fieldIndexes[c].memberField)
661 strcat(indexName, ".");
662 strcat(indexName, fieldIndexes[c].memberField.name);
664 strcat(indexName, (fieldIndexes[c].order == ascending) ? "+" : "-");
670 sprintf(command, "CREATE INDEX IF NOT EXISTS `%s` ON `%s` (", indexName, name);
671 for(c = 0; c<count; c++)
673 char columnName[1024];
674 sprintf(columnName, "`%s` %s", fieldIndexes[c].field.name, (fieldIndexes[c].order == ascending) ? "ASC" : "DESC");
675 if(c > 0) strcat(command, ", ");
676 strcat(command, columnName);
678 strcat(command, ");");
679 result = sqlite3_exec(db.db, command, null, null, null);
681 return result == SQLITE_OK;
689 Field GetFirstField()
694 uint GetFieldsCount()
706 sprintf(command, "SELECT COUNT(*) FROM `%s`;", name);
707 result = sqlite3_get_table(db.db, command, &t, &nRows, &nCols, null);
708 if(result == SQLITE_OK)
710 rowCount = atoi(t[1]);
711 sqlite3_free_table(t);
716 DriverRow CreateRow()
719 sqlite3_stmt * statement;
720 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
721 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null;
724 strcpy(command, specialStatement);
727 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
728 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
729 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
730 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
732 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
733 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
734 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
735 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
737 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
738 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
740 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
741 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
743 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
744 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
746 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
748 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
750 if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
751 sprintf(command, "SELECT ROWID, * FROM `%s`;", name);
755 sprintf(command, "SELECT ROWID, * FROM `%s` ORDER BY ", name);
756 for(c = 0; c < indexFieldsCount; c++)
759 FieldIndex * fIndex = &indexFields[c];
761 if(c) strcat(order, ", ");
763 strcat(order, fIndex->field.name);
765 if(fIndex->order == descending) strcat(order, " DESC");
766 strcat(command, order);
768 strcat(command, ";");
771 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
773 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
774 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
776 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
777 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
780 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
781 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
782 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt };
788 delete specialStatement;
794 class SQLiteRow : DriverRow
797 sqlite3_stmt * curStatement;
799 sqlite3_stmt * defaultStatement;
800 sqlite3_stmt * findStatement;
801 sqlite3_stmt * sysIDStatement;
802 sqlite3_stmt * queryStatement;
803 sqlite3_stmt * findMultipleStatement;
804 sqlite3_stmt * selectRowIDsStmt;
805 sqlite3_stmt * setRowIDStmt;
806 sqlite3_stmt * lastStatement;
807 sqlite3_stmt * previousStatement;
808 sqlite3_stmt * nextStatement;
810 sqlite3_stmt * insertStatement;
811 sqlite3_stmt * deleteStatement;
812 sqlite3_stmt * updateStatement;
824 if(defaultStatement) sqlite3_finalize(defaultStatement);
825 if(findStatement) sqlite3_finalize(findStatement);
826 if(findMultipleStatement) sqlite3_finalize(findMultipleStatement);
827 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
828 if(insertStatement) sqlite3_finalize(insertStatement);
829 if(deleteStatement) sqlite3_finalize(deleteStatement);
830 if(updateStatement) sqlite3_finalize(updateStatement);
831 if(queryStatement) sqlite3_finalize(queryStatement);
832 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
833 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
834 if(previousStatement)sqlite3_finalize(previousStatement);
835 if(nextStatement) sqlite3_finalize(nextStatement);
836 if(lastStatement) sqlite3_finalize(lastStatement);
839 bool Select(MoveOptions move)
842 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
844 curStatement = defaultStatement;
849 sqlite3_reset(curStatement);
850 result = sqlite3_step(curStatement);
851 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
852 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
853 rowID = sqlite3_column_int64(curStatement, 0);
858 sqlite3_reset(curStatement);
859 curStatement = lastStatement;
860 result = sqlite3_step(curStatement);
861 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
862 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
863 rowID = sqlite3_column_int64(curStatement, 0);
871 result = sqlite3_step(curStatement);
872 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
873 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
874 rowID = sqlite3_column_int64(curStatement, 0);
879 sqlite3_reset(curStatement);
880 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
881 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
882 result = sqlite3_step(curStatement);
883 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
884 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
885 rowID = sqlite3_column_int64(curStatement, 0);
889 sqlite3_reset(curStatement);
899 bool Query(char * queryString)
905 sqlite3_reset(curStatement);
908 sqlite3_finalize(queryStatement);
909 queryStatement = null;
914 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
915 curStatement = queryStatement;
916 if(!strchr(queryString, '?'))
918 result = sqlite3_step(queryStatement);
920 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
921 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
923 rowID = sqlite3_column_int64(queryStatement, 0);
931 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
935 SQLiteField sqlFld = (SQLiteField)fld;
936 Class dataType = sqlFld.type;
938 if(fld == tbl.primaryKey)
940 return GoToSysID(*(int *)data);
944 sqlite3_reset(curStatement);
946 sqlite3_finalize(findStatement);
948 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `%s` = ?;", tbl.name, fld.name);
949 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findStatement, null);
951 // result = sqlite3_bind_text(findStatement, 1, fld.name, strlen(fld.name), SQLITE_STATIC);
953 curStatement = findStatement;
954 switch(sqlFld.sqliteType)
958 switch(dataType.typeSize)
961 sqlite3_bind_int64(findStatement, 1, (sqlite3_int64)*(int64 *)data);
964 sqlite3_bind_int(findStatement, 1, *(int *)data);
970 value = (int)*(short *)data;
972 value = (int)*(uint16 *)data;
973 sqlite3_bind_int(findStatement, 1, value);
980 value = (int)*(char *)data;
982 value = (int)*(byte *)data;
983 sqlite3_bind_int(findStatement, 1, value);
991 if(dataType.typeSize == 8)
992 sqlite3_bind_double(findStatement, 1, *(double *)data);
994 sqlite3_bind_double(findStatement, 1, (double)*(float *)data);
1000 sqlite3_bind_text(findStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
1002 sqlite3_bind_text(findStatement, 1, null, 0, SQLITE_STATIC);
1008 SerialBuffer buffer { };
1010 dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
1011 //sqlite3_bind_blob(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
1012 sqlite3_bind_text(findStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
1013 result = sqlite3_step(findStatement);
1015 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1016 if(done) { rowID = 0; sqlite3_reset(findStatement); delete buffer; return false; }
1018 rowID = sqlite3_column_int64(findStatement, 0);
1025 result = sqlite3_step(findStatement);
1027 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1028 if(done) { rowID = 0; sqlite3_reset(findStatement); return false; }
1030 rowID = sqlite3_column_int64(findStatement, 0);
1034 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1041 Array<SerialBuffer> serialBuffers { };
1044 sqlite3_reset(curStatement);
1045 if(findMultipleStatement)
1046 sqlite3_finalize(findMultipleStatement);
1048 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1049 for(c = 0; c < numFields; c++)
1051 FieldFindData * fieldFind = &findData[c];
1053 if(c) strcat(command, " AND `");
1054 strcat(command, fieldFind->field.name);
1055 strcat(command, "` = ?");
1057 strcat(command, ";");
1059 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &findMultipleStatement, null);
1060 curStatement = findMultipleStatement;
1062 for(c = 0; c < numFields; c++)
1064 FieldFindData * fieldFind = &findData[c];
1065 SQLiteField sqlFld = (SQLiteField)fieldFind->field;
1066 Class dataType = sqlFld.type;
1068 switch(sqlFld.sqliteType)
1070 case SQLITE_INTEGER:
1072 switch(dataType.typeSize)
1075 sqlite3_bind_int64(findMultipleStatement, 1 + c, (sqlite_int64)fieldFind->value.i64);
1078 sqlite3_bind_int(findMultipleStatement, 1 + c, fieldFind->value.i);
1084 value = (int)fieldFind->value.s;
1086 value = (int)fieldFind->value.us;
1087 sqlite3_bind_int(findMultipleStatement, 1 + c, value);
1094 value = (int)fieldFind->value.c;
1096 value = (int)fieldFind->value.uc;
1097 sqlite3_bind_int(findMultipleStatement, 1 + c, value);
1105 if(dataType.typeSize == 8)
1106 sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.d);
1108 sqlite3_bind_double(findMultipleStatement, 1 + c, fieldFind->value.f);
1113 if(fieldFind->value.p)
1114 sqlite3_bind_text(findMultipleStatement, 1 + c, (char *)fieldFind->value.p, strlen(fieldFind->value.p), SQLITE_STATIC);
1116 sqlite3_bind_text(findMultipleStatement, 1 + c, null, 0, SQLITE_STATIC);
1122 SerialBuffer buffer { };
1124 dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, fieldFind->value.p, buffer);
1125 //sqlite3_bind_blob(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
1126 sqlite3_bind_text(findMultipleStatement, 1 + c, buffer._buffer, buffer.count, SQLITE_STATIC);
1128 serialBuffers.Add(buffer);
1134 result = sqlite3_step(findMultipleStatement);
1136 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1140 sqlite3_reset(findMultipleStatement);
1142 serialBuffers.Free();
1143 delete serialBuffers;
1148 rowID = sqlite3_column_int64(findMultipleStatement, 0);
1150 serialBuffers.Free();
1151 delete serialBuffers;
1158 bool Synch(DriverRow to)
1166 //char command[1024];
1167 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1168 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1169 result = sqlite3_step(insertStatement);
1170 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1172 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1173 if(rowID > MAXDWORD)
1175 int64 lastID = tbl.lastID;
1177 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1181 result = sqlite3_step(selectRowIDsStmt);
1182 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1183 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1184 if(id - lastID > 1) break;
1187 sqlite3_reset(selectRowIDsStmt);
1189 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1192 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1193 result = sqlite3_step(setRowIDStmt);
1194 sqlite3_reset(setRowIDStmt);
1196 sqlite3_reset(insertStatement);
1197 curStatement = sysIDStatement;
1198 sqlite3_reset(curStatement);
1201 sqlite3_reset(insertStatement);
1208 //char command[1024];
1209 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1210 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1211 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1212 result = sqlite3_step(deleteStatement);
1213 sqlite3_reset(deleteStatement);
1215 return result == SQLITE_OK || result == SQLITE_DONE;
1218 bool GetData(Field fld, typed_object &data)
1220 SQLiteField sqlFld = (SQLiteField)fld;
1221 int num = sqlFld.num + 1;
1222 Class dataType = sqlFld.type;
1223 switch(sqlFld.sqliteType)
1225 case SQLITE_INTEGER:
1227 switch(dataType.typeSize)
1230 if(fld == tbl.primaryKey)
1231 *(int64 *)data = rowID;
1233 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1236 if(fld == tbl.primaryKey)
1237 *(int *)data = (int)(uint)rowID;
1239 *(int *)data = sqlite3_column_int(curStatement, num);
1244 if(fld == tbl.primaryKey)
1245 value = (int)(uint)rowID;
1247 value = sqlite3_column_int(curStatement, num);
1249 *(short *)data = (short)value;
1251 *(uint16 *)data = (uint16)value;
1257 if(fld == tbl.primaryKey)
1258 value = (int)(uint)rowID;
1260 value = sqlite3_column_int(curStatement, num);
1262 *(char *)data = (char)value;
1264 *(byte *)data = (byte)value;
1272 double d = sqlite3_column_double(curStatement, num);
1273 if(dataType.typeSize == 8)
1274 *(double *)data = d;
1276 *(float *)data = (float)d;
1281 int numBytes = sqlite3_column_bytes(curStatement, num);
1282 char * text = sqlite3_column_text(curStatement, num);
1283 *(char **)data = text ? new byte[numBytes+1] : null;
1285 memcpy(*(char **)data, text, numBytes+1);
1290 SerialBuffer buffer { };
1291 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1292 buffer._size = sqlite3_column_bytes(curStatement, num);
1293 buffer._buffer = sqlite3_column_text(curStatement, num);
1294 buffer.count = buffer._size;
1296 dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
1298 buffer._buffer = null;
1306 bool SetData(Field fld, typed_object data)
1308 SQLiteField sqlFld = (SQLiteField)fld;
1311 int num = sqlFld.num + 1;
1312 Class dataType = sqlFld.type;
1314 //sqlite3_stmt * setStatement;
1317 sqlite3_finalize(updateStatement);
1319 // sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = %d;", tbl.name, sqlFld.name, rowID);
1320 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1322 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1324 //sqlite3_bind_text(updateStatement, 1, sqlFld.name, strlen(sqlFld.name), SQLITE_STATIC);
1325 //sqlite3_bind_int64(updateStatement, 3, (sqlite3_int64)rowID);
1327 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1328 switch(sqlFld.sqliteType)
1330 case SQLITE_INTEGER:
1332 switch(dataType.typeSize)
1335 sqlite3_bind_int64(updateStatement, 1, (sqlite3_int64)*(int64 *)data);
1338 sqlite3_bind_int(updateStatement, 1, *(int *)data);
1344 value = (int)*(short *)data;
1346 value = (int)*(uint16 *)data;
1347 sqlite3_bind_int(updateStatement, 1, value);
1354 value = (int)*(char *)data;
1356 value = (int)*(byte *)data;
1357 sqlite3_bind_int(updateStatement, 1, value);
1365 if(dataType.typeSize == 8)
1366 sqlite3_bind_double(updateStatement, 1, *(double *)data);
1368 sqlite3_bind_double(updateStatement, 1, (double)*(float *)data);
1373 // TOFIX: Checking a not casted typed_object for null should generate a compiler error (crashes!)
1375 sqlite3_bind_text(updateStatement, 1, (char *)data, strlen((char *)data), SQLITE_STATIC);
1377 sqlite3_bind_text(updateStatement, 1, null, 0, SQLITE_STATIC);
1383 SerialBuffer buffer { };
1385 dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
1386 //sqlite3_bind_blob(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
1387 sqlite3_bind_text(updateStatement, 1, buffer._buffer, buffer.count, SQLITE_STATIC);
1388 sqlite3_step(updateStatement);
1389 sqlite3_reset(updateStatement);
1395 result = sqlite3_step(updateStatement);
1396 sqlite3_reset(updateStatement);
1397 if(fld == tbl.primaryKey)
1399 rowID = *(uint *)data;
1401 return result == SQLITE_DONE;
1406 return (int)(uint)rowID;
1409 bool GoToSysID(int 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);
1420 sqlite3_reset(curStatement);
1422 curStatement = sysIDStatement;
1423 sqlite3_reset(sysIDStatement);
1424 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1425 result = sqlite3_step(curStatement);
1426 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1427 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1431 bool SetQueryParam(int paramID, int value)
1434 if(curStatement != queryStatement)
1436 if(curStatement) sqlite3_reset(curStatement);
1437 curStatement = queryStatement;
1439 sqlite3_reset(queryStatement);
1440 result = sqlite3_bind_int(queryStatement, paramID, value);
1444 bool SetQueryParam64(int paramID, int64 value)
1447 if(curStatement != queryStatement)
1449 if(curStatement) sqlite3_reset(curStatement);
1450 curStatement = queryStatement;
1452 sqlite3_reset(queryStatement);
1453 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1457 bool SetQueryParamText(int paramID, char * data)
1460 if(curStatement != queryStatement)
1462 if(curStatement) sqlite3_reset(curStatement);
1463 curStatement = queryStatement;
1465 sqlite3_reset(queryStatement);
1467 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_STATIC);
1469 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_STATIC);
1473 bool SetQueryParamObject(int paramID, void * data, Class type)
1476 if(curStatement != queryStatement)
1478 if(curStatement) sqlite3_reset(curStatement);
1479 curStatement = queryStatement;
1481 sqlite3_reset(queryStatement);
1483 SerialBuffer buffer { };
1484 type._vTbl[__ecereVMethodID_class_OnSerialize](type, data, buffer);
1485 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1491 /*char * GetExtraColumn(int paramID)
1493 SQLiteField lastFld = tbl.fields.last;
1494 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1496 char * GetColumn(int paramID)
1498 return sqlite3_column_text(curStatement, paramID);