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 // Returns true if not ordered by row ID
717 bool GetIndexOrder(char * fullOrder)
719 if(!indexFields || (indexFieldsCount == 1 && indexFields[0].field == primaryKey && indexFields[0].order == ascending))
721 strcpy(fullOrder, " ORDER BY ROWID");
727 strcpy(fullOrder, " ORDER BY ");
728 for(c = 0; c < indexFieldsCount; c++)
731 FieldIndex * fIndex = &indexFields[c];
733 if(c) strcat(order, ", ");
735 strcat(order, fIndex->field.name);
737 if(fIndex->order == descending) strcat(order, " DESC");
738 strcat(fullOrder, order);
744 DriverRow CreateRow()
747 sqlite3_stmt * statement;
748 sqlite3_stmt * sysIDStmt = null, * insertStmt = null, * deleteStmt = null, * selectRowIDsStmt = null, * setRowIDStmt = null;
749 sqlite3_stmt * prevStmt = null, * nextStmt = null, * lastStmt = null, * insertIDStmt = null;
752 strcpy(command, specialStatement);
756 /*sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ? = ?;", name);
757 sqlite3_prepare_v2(db.db, command, -1, &findStmt, null);*/
758 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", name);
759 sqlite3_prepare_v2(db.db, command, -1, &sysIDStmt, null);
761 sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", name);
762 sqlite3_prepare_v2(db.db, command, -1, &insertStmt, null);
764 sprintf(command, "INSERT INTO `%s` (ROWID) VALUES(?);", name);
765 sqlite3_prepare_v2(db.db, command, -1, &insertIDStmt, null);
767 sprintf(command, "DELETE FROM `%s` WHERE ROWID = ?;", name);
768 sqlite3_prepare_v2(db.db, command, -1, &deleteStmt, null);
770 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 1;", name);
771 sqlite3_prepare_v2(db.db, command, -1, &prevStmt, null);
773 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID > ? ORDER BY ROWID LIMIT 1;", name);
774 sqlite3_prepare_v2(db.db, command, -1, &nextStmt, null);
776 sprintf(command, "SELECT MAX(ROWID), * FROM `%s`", name);
777 sqlite3_prepare_v2(db.db, command, -1, &lastStmt, null);
779 /*sprintf(command, "UPDATE `%s` SET ? = ? WHERE ROWID = ?;", name);
781 sqlite3_prepare_v2(db.db, command, -1, &updateStmt, null);*/
783 GetIndexOrder(order);
784 sprintf(command, "SELECT ROWID, * FROM `%s`%s;", name, order);
786 sqlite3_prepare_v2(db.db, command, -1, &statement, null);
788 sprintf(command, "SELECT ROWID FROM `%s` WHERE ROWID > ?", name);
789 sqlite3_prepare_v2(db.db, command, -1, &selectRowIDsStmt, null);
791 sprintf(command, "UPDATE `%s` SET ROWID = ? WHERE ROWID = ?", name);
792 sqlite3_prepare_v2(db.db, command, -1, &setRowIDStmt, null);
795 { tbl = this, defaultStatement = statement, curStatement = statement, sysIDStatement = sysIDStmt,
796 insertStatement = insertStmt, deleteStatement = deleteStmt, selectRowIDsStmt = selectRowIDsStmt, setRowIDStmt = setRowIDStmt,
797 previousStatement = prevStmt, nextStatement = nextStmt, lastStatement = lastStmt, insertIDStatement = insertIDStmt };
803 delete specialStatement;
809 class SQLiteRow : DriverRow
812 sqlite3_stmt * curStatement;
814 sqlite3_stmt * defaultStatement;
815 sqlite3_stmt * findStatement;
816 sqlite3_stmt * sysIDStatement;
817 sqlite3_stmt * queryStatement;
818 sqlite3_stmt * findMultipleStatement;
819 sqlite3_stmt * selectRowIDsStmt;
820 sqlite3_stmt * setRowIDStmt;
821 sqlite3_stmt * lastStatement;
822 sqlite3_stmt * previousStatement;
823 sqlite3_stmt * nextStatement;
825 sqlite3_stmt * insertStatement;
826 sqlite3_stmt * deleteStatement;
827 sqlite3_stmt * updateStatement;
828 sqlite3_stmt * insertIDStatement;
840 if(defaultStatement) sqlite3_finalize(defaultStatement);
841 if(findStatement) sqlite3_finalize(findStatement);
842 if(findMultipleStatement) sqlite3_finalize(findMultipleStatement);
843 if(sysIDStatement) sqlite3_finalize(sysIDStatement);
844 if(insertStatement) sqlite3_finalize(insertStatement);
845 if(deleteStatement) sqlite3_finalize(deleteStatement);
846 if(updateStatement) sqlite3_finalize(updateStatement);
847 if(queryStatement) sqlite3_finalize(queryStatement);
848 if(selectRowIDsStmt) sqlite3_finalize(selectRowIDsStmt);
849 if(setRowIDStmt) sqlite3_finalize(setRowIDStmt);
850 if(previousStatement)sqlite3_finalize(previousStatement);
851 if(nextStatement) sqlite3_finalize(nextStatement);
852 if(lastStatement) sqlite3_finalize(lastStatement);
853 if(insertIDStatement) sqlite3_finalize(insertIDStatement);
856 bool Select(MoveOptions move)
859 bool stepping = curStatement == previousStatement || curStatement == nextStatement || curStatement == lastStatement;
861 curStatement = defaultStatement;
866 sqlite3_reset(curStatement);
867 result = sqlite3_step(curStatement);
868 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
869 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
870 rowID = sqlite3_column_int64(curStatement, 0);
875 sqlite3_reset(curStatement);
876 curStatement = lastStatement;
877 result = sqlite3_step(curStatement);
878 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
879 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
880 rowID = sqlite3_column_int64(curStatement, 0);
888 result = sqlite3_step(curStatement);
889 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
890 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
891 rowID = sqlite3_column_int64(curStatement, 0);
896 sqlite3_reset(curStatement);
897 curStatement = (move == previous) ? (rowID ? previousStatement : lastStatement) : (rowID ? nextStatement : defaultStatement);
898 sqlite3_bind_int64(curStatement, 1, (sqlite3_int64)rowID);
899 result = sqlite3_step(curStatement);
900 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
901 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
902 rowID = sqlite3_column_int64(curStatement, 0);
906 sqlite3_reset(curStatement);
916 bool Query(char * queryString)
922 sqlite3_reset(curStatement);
925 sqlite3_finalize(queryStatement);
926 queryStatement = null;
931 result = sqlite3_prepare_v2(tbl.db.db, queryString, -1, &queryStatement, null);
932 curStatement = queryStatement;
933 if(!strchr(queryString, '?'))
935 result = sqlite3_step(queryStatement);
937 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
938 if(done) { rowID = 0; sqlite3_reset(queryStatement); return false; }
940 rowID = sqlite3_column_int64(queryStatement, 0);
948 void BindData(sqlite3_stmt * statement, int pos, SQLiteField fld, typed_object data, SerialBuffer * bufferOut)
950 Class dataType = fld.type;
951 SerialBuffer buffer = null;
952 switch(fld.sqliteType)
956 switch(dataType.typeSize)
959 sqlite3_bind_int64(statement, pos, (sqlite3_int64)*(int64 *)data);
962 sqlite3_bind_int(statement, pos, *(int *)data);
968 value = (int)*(short *)data;
970 value = (int)*(uint16 *)data;
971 sqlite3_bind_int(statement, pos, value);
978 value = (int)*(char *)data;
980 value = (int)*(byte *)data;
981 sqlite3_bind_int(statement, pos, value);
989 if(dataType.typeSize == 8)
990 sqlite3_bind_double(statement, pos, *(double *)data);
992 sqlite3_bind_double(statement, pos, (double)*(float *)data);
998 sqlite3_bind_text(statement, pos, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1000 sqlite3_bind_text(statement, pos, null, 0, SQLITE_TRANSIENT);
1006 buffer = SerialBuffer { };
1007 dataType._vTbl[__ecereVMethodID_class_OnSerialize](dataType, data, buffer);
1008 sqlite3_bind_text(statement, pos, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1013 *bufferOut = buffer;
1018 void AddCursorWhereClauses(char * command, MoveOptions move, bool useIndex)
1022 // Where clauses for index
1026 bool gotPrimaryKey = false;
1028 strcatf(command, " AND (");
1029 for(c = 0; c < tbl.indexFieldsCount; c++)
1032 FieldIndex * fIndex = &tbl.indexFields[c];
1036 strcat(where, fIndex->field.name);
1037 strcat(where, "` ");
1038 strcat(where, fIndex->order == descending ? "<" : ">");
1039 strcat(where, " ? OR (");
1040 strcat(where, fIndex->field.name);
1041 if(fIndex->field == tbl.primaryKey)
1042 gotPrimaryKey = true;
1043 strcat(where, " = ? AND (");
1044 strcat(command, where);
1046 strcat(command, gotPrimaryKey ? "1)" : "ROWID > ?)");
1048 strcat(command, "))");
1051 strcatf(command, " AND ROWID > ?");
1055 void BindCursorData(sqlite3_stmt * stmt, MoveOptions move, bool useIndex, int * bindId)
1059 // The binds for the Extra ordering Where clauses
1063 for(c = 0; c < tbl.indexFieldsCount; c++)
1065 FieldIndex * fIndex = &tbl.indexFields[c];
1067 SQLiteField fld = (SQLiteField)fIndex->field;
1068 Class type = fld.type;
1070 SerialBuffer buffer;
1072 if(type.type == unitClass && !type.typeSize)
1074 Class dataType = eSystem_FindClass(type.module, type.dataTypeString);
1078 if(type.type == structClass)
1080 data = (int64)new0 byte[type.structSize];
1081 dataPtr = (void *) data;
1083 ((bool (*)())(void *)this.GetData)(this, fld, type, (type.type == structClass) ? (void *)data : &data);
1084 if(type.type == normalClass || type.type == noHeadClass)
1085 dataPtr = (void *) data;
1088 ((void (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, &buffer);
1089 // Reuse the buffer for Blobs...
1090 if(fld.sqliteType == SQLITE_BLOB || fld.sqliteType == SQLITE_NULL)
1092 sqlite3_bind_text(stmt, (*bindId)++, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1096 ((void (*)())(void *)this.BindData)(this, stmt, (*bindId)++, fld, type, dataPtr, null);
1098 type._vTbl[__ecereVMethodID_class_OnFree](type, dataPtr);
1102 // Bind for the rowid
1103 sqlite3_bind_int64(stmt, (*bindId)++, (sqlite3_int64)rowID);
1107 bool Find(Field fld, MoveOptions move, MatchOptions match, typed_object data)
1109 char order[1024], command[2048];
1112 sqlite3_stmt * stmt = null;
1115 if(fld == tbl.primaryKey)
1117 return GoToSysID(*(int *)data);
1120 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ", tbl.name);
1121 strcatf(command, "`%s` = ?", fld.name);
1122 useIndex = tbl.GetIndexOrder(order);
1123 AddCursorWhereClauses(command, move, useIndex);
1124 strcat(command, order);
1125 strcat(command, ";");
1127 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1129 BindData(stmt, bindId++, (SQLiteField)fld, data, null);
1130 BindCursorData(stmt, move, useIndex, &bindId);
1133 sqlite3_reset(curStatement);
1135 sqlite3_finalize(findStatement);
1136 curStatement = findStatement = stmt;
1138 result = sqlite3_step(findStatement);
1140 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1144 sqlite3_reset(findStatement);
1147 rowID = sqlite3_column_int64(findStatement, 0);
1151 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1155 char command[4096], order[1024];
1159 sqlite3_stmt * stmt = null;
1162 sprintf(command, "SELECT ROWID, * FROM `%s` WHERE `", tbl.name);
1163 for(c = 0; c < numFields; c++)
1165 FieldFindData * fieldFind = &findData[c];
1167 if(c) strcat(command, " AND `");
1168 strcat(command, fieldFind->field.name);
1169 strcat(command, "` = ?");
1172 useIndex = tbl.GetIndexOrder(order);
1173 AddCursorWhereClauses(command, move, useIndex);
1174 strcat(command, order);
1175 strcat(command, ";");
1177 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &stmt, null);
1179 for(c = 0; c < numFields; c++)
1181 FieldFindData * fieldFind = &findData[c];
1182 SQLiteField sqlFld = (SQLiteField)findData->field;
1183 Class dataType = sqlFld.type;
1184 BindData(stmt, bindId++, sqlFld, (dataType.type == structClass || dataType.type == noHeadClass || dataType.type == normalClass) ? fieldFind->value.p : &fieldFind->value.i, null);
1186 BindCursorData(stmt, move, useIndex, &bindId);
1189 sqlite3_reset(curStatement);
1190 if(findMultipleStatement)
1191 sqlite3_finalize(findMultipleStatement);
1193 curStatement = findMultipleStatement = stmt;
1195 result = sqlite3_step(findMultipleStatement);
1196 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1200 sqlite3_reset(findMultipleStatement);
1203 rowID = sqlite3_column_int64(findMultipleStatement, 0);
1209 bool Synch(DriverRow to)
1211 SQLiteRow rowTo = (SQLiteRow)to;
1212 if(tbl && rowTo.tbl && !strcmp(tbl.name, rowTo.tbl.name))
1213 return GoToSysID((uint)rowTo.rowID);
1220 //char command[1024];
1221 //sprintf(command, "INSERT INTO `%s` DEFAULT VALUES;", tbl.name);
1222 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1225 sqlite3_bind_int64(insertIDStatement, 1, (sqlite3_int64)id);
1226 result = sqlite3_step(insertIDStatement);
1229 result = sqlite3_step(insertStatement);
1230 if(result == SQLITE_DONE) // if(result == SQLITE_OK)
1232 rowID = sqlite3_last_insert_rowid(tbl.db.db);
1233 if(rowID > MAXDWORD)
1235 int64 lastID = tbl.lastID;
1237 sqlite3_bind_int64(selectRowIDsStmt, 1, (sqlite3_int64)lastID);
1241 result = sqlite3_step(selectRowIDsStmt);
1242 if(result == SQLITE_DONE || result != SQLITE_ROW) break;
1243 id = sqlite3_column_int64(selectRowIDsStmt, 0);
1244 if(id - lastID > 1) break;
1247 sqlite3_reset(selectRowIDsStmt);
1249 sqlite3_bind_int64(setRowIDStmt, 2, (sqlite3_int64)rowID);
1252 sqlite3_bind_int64(setRowIDStmt, 1, (sqlite3_int64)rowID);
1253 result = sqlite3_step(setRowIDStmt);
1254 sqlite3_reset(setRowIDStmt);
1256 sqlite3_reset(id ? insertIDStatement : insertStatement);
1257 curStatement = sysIDStatement;
1258 sqlite3_reset(curStatement);
1259 sqlite3_bind_int64(sysIDStatement, 1, (sqlite3_int64)rowID);
1260 result = sqlite3_step(curStatement);
1263 sqlite3_reset(insertStatement);
1270 //char command[1024];
1271 //sprintf(command, "DELETE FROM `%s` WHERE ROWID = %d;", tbl.name, rowID);
1272 //result = sqlite3_exec(tbl.db.db, command, null, null, null);
1273 sqlite3_bind_int64(deleteStatement, 1, (sqlite3_int64)rowID);
1274 result = sqlite3_step(deleteStatement);
1275 sqlite3_reset(deleteStatement);
1277 return result == SQLITE_OK || result == SQLITE_DONE;
1280 bool GetData(Field fld, typed_object &data)
1282 SQLiteField sqlFld = (SQLiteField)fld;
1283 int num = sqlFld.num + 1;
1284 Class dataType = sqlFld.type;
1287 switch(sqlFld.sqliteType)
1289 case SQLITE_INTEGER:
1291 switch(dataType.typeSize)
1294 if(fld == tbl.primaryKey)
1295 *(int64 *)data = rowID;
1297 *(int64 *)data = sqlite3_column_int64(curStatement, num);
1300 if(fld == tbl.primaryKey)
1301 *(int *)data = (int)(uint)rowID;
1303 *(int *)data = sqlite3_column_int(curStatement, num);
1308 if(fld == tbl.primaryKey)
1309 value = (int)(uint)rowID;
1311 value = sqlite3_column_int(curStatement, num);
1313 *(short *)data = (short)value;
1315 *(uint16 *)data = (uint16)value;
1321 if(fld == tbl.primaryKey)
1322 value = (int)(uint)rowID;
1324 value = sqlite3_column_int(curStatement, num);
1326 *(char *)data = (char)value;
1328 *(byte *)data = (byte)value;
1336 double d = sqlite3_column_double(curStatement, num);
1337 if(dataType.typeSize == 8)
1338 *(double *)data = d;
1340 *(float *)data = (float)d;
1345 int numBytes = sqlite3_column_bytes(curStatement, num);
1346 char * text = sqlite3_column_text(curStatement, num);
1347 *(char **)data = text ? new byte[numBytes+1] : null;
1349 memcpy(*(char **)data, text, numBytes+1);
1354 SerialBuffer buffer { };
1355 //buffer._buffer = sqlite3_column_blob(curStatement, num);
1356 buffer._size = sqlite3_column_bytes(curStatement, num);
1357 buffer._buffer = sqlite3_column_text(curStatement, num);
1358 buffer.count = buffer._size;
1360 dataType._vTbl[__ecereVMethodID_class_OnUnserialize](dataType, data, buffer);
1362 buffer._buffer = null;
1370 bool SetData(Field fld, typed_object data)
1372 SQLiteField sqlFld = (SQLiteField)fld;
1374 int num = sqlFld.num + 1;
1378 sqlite3_finalize(updateStatement);
1379 sprintf(command, "UPDATE `%s` SET `%s` = ? WHERE ROWID = ?;", tbl.name, sqlFld.name);
1380 result = sqlite3_prepare_v2(tbl.db.db, command, -1, &updateStatement, null);
1381 sqlite3_bind_int64(updateStatement, 2, (sqlite3_int64)rowID);
1382 BindData(updateStatement, 1, (SQLiteField)fld, data, null);
1383 result = sqlite3_step(updateStatement);
1384 sqlite3_reset(updateStatement);
1385 if(fld == tbl.primaryKey)
1386 rowID = *(uint *)data;
1387 return result == SQLITE_DONE;
1392 return (int)(uint)rowID;
1395 bool GoToSysID(uint id)
1397 //char command[1024];
1401 //sqlite3_finalize(statement);
1402 //sprintf(command, "SELECT ROWID, * FROM `%s` WHERE ROWID = ?;", tbl.name);
1403 //result = sqlite3_prepare_v2(tbl.db.db, command, -1, &statement, null);
1406 sqlite3_reset(curStatement);
1408 curStatement = sysIDStatement;
1409 sqlite3_reset(sysIDStatement);
1410 sqlite3_bind_int64(curStatement, 1, (sqlite_int64)rowID);
1411 result = sqlite3_step(curStatement);
1412 done = result == SQLITE_DONE || (result && result != SQLITE_ROW);
1413 if(done) { rowID = 0; sqlite3_reset(curStatement); return false; }
1417 bool SetQueryParam(int paramID, int value)
1420 if(curStatement != queryStatement)
1422 if(curStatement) sqlite3_reset(curStatement);
1423 curStatement = queryStatement;
1425 sqlite3_reset(queryStatement);
1426 result = sqlite3_bind_int(queryStatement, paramID, value);
1430 bool SetQueryParam64(int paramID, int64 value)
1433 if(curStatement != queryStatement)
1435 if(curStatement) sqlite3_reset(curStatement);
1436 curStatement = queryStatement;
1438 sqlite3_reset(queryStatement);
1439 result = sqlite3_bind_int64(queryStatement, paramID, (sqlite_int64)value);
1443 bool SetQueryParamText(int paramID, char * data)
1446 if(curStatement != queryStatement)
1448 if(curStatement) sqlite3_reset(curStatement);
1449 curStatement = queryStatement;
1451 sqlite3_reset(queryStatement);
1453 result = sqlite3_bind_text(queryStatement, paramID, (char *)data, strlen((char *)data), SQLITE_TRANSIENT);
1455 result = sqlite3_bind_text(queryStatement, paramID, null, 0, SQLITE_TRANSIENT);
1459 bool SetQueryParamObject(int paramID, void * data, Class type)
1462 if(curStatement != queryStatement)
1464 if(curStatement) sqlite3_reset(curStatement);
1465 curStatement = queryStatement;
1467 sqlite3_reset(queryStatement);
1469 SerialBuffer buffer { };
1470 type._vTbl[__ecereVMethodID_class_OnSerialize](type, data, buffer);
1471 result = sqlite3_bind_text(queryStatement, paramID, buffer._buffer, buffer.count, SQLITE_TRANSIENT);
1477 /*char * GetExtraColumn(int paramID)
1479 SQLiteField lastFld = tbl.fields.last;
1480 return sqlite3_column_text(curStatement, lastFld.num + 1 + paramID);
1482 char * GetColumn(int paramID)
1484 return sqlite3_column_text(curStatement, paramID);