3 public class EDBIndexOptions
6 bool saveIndex:1, deleteIndex:1;
9 public void SetEDBIndexOptions(EDBIndexOptions options)
11 indexOptions = options;
14 EDBIndexOptions indexOptions { saveIndex = true, deleteIndex = false; };
16 static void UnusedFunction()
24 a.OnEdit(null,null,0,0,0,0,0);
25 a.OnDisplay(null,0,0,0,0,0,0);
26 a.OnGetDataFromString(null);
27 a.OnUnserialize(null);
32 extern int __ecereVMethodID_class_OnGetString;
33 extern int __ecereVMethodID_class_OnGetDataFromString;
34 extern int __ecereVMethodID_class_OnCompare;
35 extern int __ecereVMethodID_class_OnSerialize;
36 extern int __ecereVMethodID_class_OnUnserialize;
37 extern int __ecereVMethodID_class_OnFree;
40 enum RowsCountFileAction { init, add, del, reuse };
41 void RowsCountFileEdit(Archive archive, const String apath, const RowsCountFileAction action, int * allocatedRowsCount, int * deletedRowsCount, uint * rowsCountPosition)
45 if(!*rowsCountPosition)
48 File f = ((EDBArchive)archive).f;
49 EDBArchiveDir dir = (EDBArchiveDir) archive.OpenDirectory(apath, FileStats { }, readOnlyDir);
52 f.Seek(dir.position, start);
56 char fileName[MAX_FILENAME];
57 if(!f.Seek(position, start)) break;
58 if(!f.Read(entry, sizeof(EAREntry), 1)) break;
59 f.Read(fileName, 1, entry.nameLen);
60 fileName[entry.nameLen] = '\0';
61 if(!strcmp(fileName, "rowsCount"))
63 *rowsCountPosition = position;
67 position = entry.next;
74 f = *rowsCountPosition ? archive.FileOpenAtPosition(*rowsCountPosition) : null;
77 f.Get(temp); *allocatedRowsCount = temp;
78 f.Get(temp); *deletedRowsCount = temp;
83 *allocatedRowsCount = 0;
84 *deletedRowsCount = 0;
90 case add: (*allocatedRowsCount)++; break;
91 case del: (*deletedRowsCount)++; break;
92 case reuse: (*deletedRowsCount)--; break;
99 temp = *allocatedRowsCount; tf.Put(temp);
100 temp = *deletedRowsCount; tf.Put(temp);
103 dir = archive.OpenDirectory(apath, FileStats { }, replace);
104 dir.AddFromFileAtPosition(*rowsCountPosition, "rowsCount", tf, { size = tf.GetSize() }, replace, 0, null, rowsCountPosition);
110 static class EDBDataSource : DataSourceDriver
112 class_property(name) = "EDB";
115 //OldList listDatabases;
118 String BuildLocator(DataSource ds)
120 return CopyString(ds.host);
123 uint GetDatabasesCount()
125 return databasesCount;
133 bool Connect(const String locator)
136 path = CopyString(locator);
137 // TODO, use user name and password for local security?
138 // TODO, open ds in read or write mode
142 FileListing listing { path, "edb" };
144 while(listing.Find())
153 Log($"Status: Feeling groovy!\n");
157 Table OpenDatabasesListTable(subclass(DataDriver) driver)
159 // get the table for databasesList using a temporary archive of a db with a table databases filled
160 // with the list of edb files in data source's dirPath
163 //ArchiveFile af = ArchiveOpen
169 bool RenameDatabase(const String name, const String rename)
171 if(name && rename && path && FileExists(path))
174 path = MakeDatabasePath(name);
179 repath = MakeDatabasePath(rename);
180 renamed = RenameFile(path, repath);
190 bool DeleteDatabase(const String name)
192 if(path && FileExists(path))
195 String path = MakeDatabasePath(name);
196 deleted = DeleteFile(path); // delete file seems to return true even if the file does not exist
204 String MakeDatabasePath(const String name)
208 char build[MAX_LOCATION];
209 strcpy(build, path ? path : "");
210 PathCat(build, name);
211 ChangeExtension(build, "edb", build);
212 return CopyString(build);
217 Database OpenDatabase(const String name, CreateOptions createOptions, DataSource ds)
221 String path = MakeDatabasePath(name);
222 Archive archive = null;
225 // Check if it's a valid archive because we don't want to create an archive at the end of another file
226 archive = ArchiveOpen(path, { false, false, false });
229 // If we want write access
231 archive = ArchiveOpen(path, { true, true, true });
234 printf($"Invalid, corrupted or in use (%s) database file.\n", path);
236 else if(createOptions == create)
238 archive = ArchiveOpen(path, { true, true, true });
244 EDBDatabase db { path = path, archive = archive };
245 if(!archive.FileExists("-/tables"))
247 int allocatedRowsCount, deletedRowsCount;
248 RowsCountFileEdit(archive, "-/tables", init, &allocatedRowsCount, &deletedRowsCount, &db.tablesCountPosition);
252 else if(createOptions == create)
253 Logf($"Database file (%s) could not be created.\n", path);
255 Logf($"Database file (%s) could not be opened.\n", path);
262 static enum EAREntryType { ENTRY_FILE = 1, ENTRY_FOLDER = 2 };
264 static struct EAREntry
267 TimeStamp32 created, modified;
268 FileSize size, cSize;
271 // null terminated file name follows
274 static class EDBArchive : Archive
279 static class EDBArchiveDir : ArchiveDir
287 static class DBTable : struct
293 OldList fields { offset = (uint)&((EDBField)0).prev; };
296 uint rowsCountPosition;
297 // uint fieldsCountPosition;
299 uint rowPositionsSize;
302 int allocatedRowsCount;
303 int deletedRowsCount;
310 if(indexOptions.saveIndex)
313 for(index = indexes.first; index; index = index.next)
317 char indexName[1024];
322 strcpy(indexName, "index_");
323 for(c = 0; c<index.numFields; c++)
325 strcat(indexName, index.fieldIndexes[c].field.name);
326 if(index.fieldIndexes[c].memberField)
328 strcat(indexName, ".");
329 strcat(indexName, index.fieldIndexes[c].memberField.name);
331 strcat(indexName, (index.fieldIndexes[c].order == ascending) ? "+" : "-");
335 dirTable = db.archive.OpenDirectory(apath, FileStats { }, replace);
336 dirTable.AddFromFile(indexName, tf, { size = tf.GetSize() }, replace, 0, null, null);
349 fields.RemoveAll(EDBField::Free);
350 indexes.RemoveAll(DBIndex::Free);
353 void Free() { delete this; }
359 class EDBDatabase : Database
364 uint tablesCountPosition;
366 property uint bufferSize { set { archive.bufferSize = value; } }
367 property uint bufferRead { set { archive.bufferRead = value; } }
371 dbTables.RemoveAll(DBTable::Free);
378 return path; // TOFIX
381 DBTable GetDBTable(char * apath, OpenOptions options)
384 for(dbTbl = dbTables.first; dbTbl; dbTbl = dbTbl.next)
385 if(!strcmp(apath, dbTbl.apath))
389 char build[MAX_LOCATION];
390 ArchiveDir dirTable = archive.OpenDirectory(apath, FileStats { }, replace);
392 dbTbl = DBTable { this, apath = CopyString(apath) };
393 strcpy(build, apath);
394 PathCat(build, "fields");
395 dbTbl.apathFields = CopyString(build);
398 dbTbl.dir = archive.OpenDirectory(apath, null, readOnlyDir);
400 RowsCountFileEdit(archive, apath, init, &dbTbl.allocatedRowsCount, &dbTbl.deletedRowsCount, &dbTbl.rowsCountPosition);
401 dbTbl.rowsCount = dbTbl.allocatedRowsCount - dbTbl.deletedRowsCount;
405 File f = ((EDBArchive)archive).f;
406 EDBArchiveDir dir = (EDBArchiveDir) dbTbl.dir;
409 uint allocatedCount = dbTbl.allocatedRowsCount;
410 f.Seek(dir.position, start);
411 dbTbl.rowPositionsSize = dbTbl.allocatedRowsCount;
412 dbTbl.rowPositions = new0 uint[Max(1,dbTbl.rowPositionsSize)];
413 position = dir.first;
417 char fileName[MAX_FILENAME] = "";
419 f.Seek(position, start);
420 f.Read(entry, sizeof(EAREntry), 1);
421 f.Read(fileName, 1, entry.nameLen);
422 fileName[entry.nameLen] = '\0';
423 number = atoi(fileName);
424 if(number && number <= allocatedCount)
425 dbTbl.rowPositions[number - 1] = position;
427 position = entry.next;
433 if(options.type == tablesList)
435 dbTbl.fields.Add(EDBField
438 name = CopyString("Name"),
439 type = class(String),
443 dbTbl.fieldsCount = 1;
445 else if(options.type == fieldsList)
447 dbTbl.fields.Add(EDBField
450 name = CopyString("Name"),
451 type = class(String),
455 dbTbl.fields.Add(EDBField
458 name = CopyString("Type"),
463 dbTbl.fields.Add(EDBField
466 name = CopyString("Length"),
471 dbTbl.fieldsCount = 3;
475 int num, rowsCount, deletedRowsCount;
476 DBTable fieldsTable = dbTbl.fieldsTable;
477 if(!fieldsTable) fieldsTable = dbTbl.fieldsTable = GetDBTable(dbTbl.apathFields, { fieldsList });
478 RowsCountFileEdit(archive, dbTbl.apathFields, init, &rowsCount, &deletedRowsCount, &dbTbl.fieldsTable.rowsCountPosition /*fieldsCountPosition*/);
480 for(num = 1; num <= rowsCount; num++) // TOFIX in future a field position might have been deleted
482 EDBField fld { tbl = dbTbl, num = num };
485 dbTbl.fields.Add(fld);
487 dbTbl.fieldsCount = rowsCount;
493 uint ObjectsCount(ObjectType type)
499 bool RenameObject(ObjectType type, const String name, const String rename)
505 bool DeleteObject(ObjectType type, const String name)
511 Table OpenTable(const String name, OpenOptions options)
514 char apath[MAX_LOCATION] = "";
523 // get the table for databasesList using a temporary archive of a db with a table databases filled
524 // with the list of edb files in data source's dirPath
532 Table tblTables = OpenTable(null, { tablesList });
535 Row rowTables { tblTables };
536 Field fldTableName = tblTables.FindField("Name");
539 if(!rowTables.Find(fldTableName, first, nil, name))
541 if(options.create == create)
545 rowTables.SetData(fldTableName, name);
548 Logf($"Table (%s) does not exist.\n", name);
557 Log($"Unable to detect if table exists!\n");
561 strcpy(apath, "-/tables");
567 PathCat(apath, "fields");
572 if(apath[0] && archive)
574 DBTable dbTable = GetDBTable(apath, options);
577 tbl = EDBTable { dbTable = dbTable };
585 static struct IndexBinaryTree : BinaryTree
590 static int IndexCompareRows(IndexBinaryTree tree, uint r1, uint r2)
592 DBIndex index = tree.index;
594 EDBRow row1 = index.row1;
595 EDBRow row2 = index.row2;
597 if(index.cache && index.cache._num == r1)
601 row1.tbl = index.dbTable;
605 if(index.cache && index.cache._num == r2)
609 row2.tbl = index.dbTable;
613 for(f = 0; f < index.numFields; f++)
615 Field field = index.fieldIndexes[f].field;
616 int order = (index.fieldIndexes[f].order == ascending) ? 1 : -1;
617 Field memberField = index.fieldIndexes[f].memberField;
620 Class type = field.type;
621 int64 data1 = 0, data2 = 0;
623 if(type.type == structClass)
625 data1 = (int64)new0 byte[type.structSize];
626 data2 = (int64)new0 byte[type.structSize];
628 ((bool (*)())(void *)row1.GetData)(row1, field, type, (type.type == structClass) ? (void *)data1 : &data1);
629 ((bool (*)())(void *)row2.GetData)(row2, field, type, (type.type == structClass) ? (void *)data2 : &data2);
630 fieldResult = order * ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type,
631 (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &data1 : (void *)data1,
632 (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &data2 : (void *)data2);
633 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)data1);
634 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)data2);
635 if(field.type.type == structClass)
637 void * dataPtr = (void *)data1;
639 dataPtr = (void *)data2;
647 row1.tbl = ((EDBTable)index.fieldIndexes[f].memberTable).dbTable;
648 row1.index = ((EDBTable)index.fieldIndexes[f].memberTable).index;
650 row1.Find(index.fieldIndexes[f].memberIdField, middle, nil, data1);
653 row2.tbl = ((EDBTable)index.fieldIndexes[f].memberTable).dbTable;
654 row2.index = ((EDBTable)index.fieldIndexes[f].memberTable).index;
656 row2.Find(index.fieldIndexes[f].memberIdField, middle, nil, data2);
676 static class DBIndex : struct
681 FieldIndex * fieldIndexes;
688 CompareKey = (void *)IndexCompareRows;
697 void Free() { delete this; }
700 static class EDBTable : Table
705 Field AddField(const String name, Class type, int length)
707 EDBDatabase edb = dbTable.db;
711 name = CopyString(name),
715 DBTable fieldsTable = dbTable.fieldsTable;
717 if(!fieldsTable) fieldsTable = dbTable.fieldsTable = edb.GetDBTable(dbTable.apathFields, { fieldsList });
719 RowsCountFileEdit(edb.archive, dbTable.apathFields, add, &fieldsTable.allocatedRowsCount, &fieldsTable.deletedRowsCount, &fieldsTable.rowsCountPosition /*dbTable.fieldsCountPosition*/);
720 fieldsTable.rowsCount = fieldsTable.allocatedRowsCount - fieldsTable.deletedRowsCount;
722 // What should this be?
723 fieldsTable.rowPositions = renew0 fieldsTable.rowPositions uint[fieldsTable.allocatedRowsCount];
725 dbTable.fields.Add(field);
727 // Field num starts at index base 1 !
728 field.num = dbTable.fields.count;
733 Field FindField(const String name)
736 for(fld = dbTable.fields.first; fld; fld = fld.next)
737 if(!strcmp(fld.name, name))
742 Field GetFirstField()
744 return dbTable.fields.first;
747 DriverRow CreateRow()
749 return EDBRow { tbl = dbTable, index = index, num = 0 };
752 bool GenerateIndex(int count, FieldIndex * fieldIndexes, bool init)
754 DBIndex index = null;
755 //Time startTime = GetTime();
758 for(index = dbTable.indexes.first; index; index = index.next)
760 if(index.numFields == count)
763 for(c = 0; c<count; c++)
764 if(index.fieldIndexes[c].field != fieldIndexes[c].field ||
765 index.fieldIndexes[c].order != fieldIndexes[c].order ||
766 index.fieldIndexes[c].memberField != fieldIndexes[c].memberField)
776 for(c = 0; c<count; c++)
778 if(!fieldIndexes[c].field)
783 for(field = dbTable.fields.first; field; field = field.next)
784 if(field == fieldIndexes[c].field)
790 index = DBIndex { numFields = count, dbTable = dbTable, init = init };
791 index.fieldIndexes = new FieldIndex[count];
792 memcpy(index.fieldIndexes, fieldIndexes, count * sizeof(FieldIndex));
793 dbTable.indexes.Add(index);
797 //char output[10000];
799 char indexName[1024];
802 strcpy(indexName, "index_");
803 for(c = 0; c<index.numFields; c++)
805 strcat(indexName, index.fieldIndexes[c].field.name);
806 if(index.fieldIndexes[c].memberField)
808 strcat(indexName, ".");
809 strcat(indexName, index.fieldIndexes[c].memberField.name);
811 strcat(indexName, (index.fieldIndexes[c].order == ascending) ? "+" : "-");
814 f = dbTable.dir.FileOpen(indexName);
817 ArchiveDir dir = dbTable.db.archive.OpenDirectory(dbTable.apath, FileStats { }, replace);
820 if(indexOptions.deleteIndex)
821 dir.Delete(indexName);
826 index.cache = EDBRow { tbl = dbTable };
827 for(c = 1; c<= dbTable.allocatedRowsCount; c++)
829 char file[MAX_FILENAME];
830 sprintf(file, "%d", c);
832 if(dbTable.rowPositions[c - 1])
833 index.tree.Add(BTNode { c });
839 index.tree.Print(output, inOrder);
840 printf("\n\n%s - %s:\n", dbTable.apath, indexName);
850 //Logf("Indexing took %f seconds\n", GetTime() - startTime);
857 return dbTable.apath;
860 uint GetFieldsCount()
862 return dbTable.fieldsCount;
867 return dbTable.rowsCount;
871 static class EDBField : Field
885 char file[MAX_FILENAME];
886 char build[MAX_LOCATION];
887 sprintf(file, "%d", num);
888 strcpy(build, tbl.apath);
889 PathCat(build, "fields");
890 PathCat(build, file);
891 apath = CopyString(build);
892 aname = CopyString(file);
904 String GetName() { return name; }
905 Class GetType() { return type; }
906 int GetLength() { return length; }
907 Field GetNext() { return next; }
908 Field GetPrev() { return prev; }
909 Table GetTable() { return (Table)tbl; }
920 EDBDatabase edb = tbl.db;
923 File f = edb.archive.FileOpen(apath);
929 f.Read(offsets, sizeof(uint), 3);
936 Log($"Error reading field");
945 EDBDatabase edb = tbl.db;
949 f.Write(offsets, sizeof(uint), numFields);
950 offsets[0] = f.Tell();
952 offsets[1] = f.Tell();
954 offsets[2] = f.Tell();
956 f.Seek(sizeof(uint), start);
957 f.Write(offsets, sizeof(uint), numFields);
960 dir = edb.archive.OpenDirectory(tbl.apathFields, FileStats { }, replace);
961 dir.AddFromFile(aname, f, { size = f.GetSize() }, replace, 0, null, null);
966 void Free() { delete this; }
969 static class EDBRow : DriverRow
986 char file[MAX_FILENAME];
987 sprintf(file, "%d", _num);
988 aname = CopyString(file);
998 bool GetData(EDBField field, typed_object & data)
1000 bool result = false;
1001 EDBDatabase edb = tbl.db;
1002 File f = (_num && tbl.rowPositions[_num - 1]) ? edb.archive.FileOpenAtPosition(tbl.rowPositions[_num - 1]) : null;
1003 if(f && data._class)
1010 uint * offsets = new0 uint[numFields];
1011 f.Read(offsets, sizeof(uint), numFields);
1012 if(((field.num < numFields && offsets[field.num-1] && offsets[field.num-1] != offsets[field.num]) || (field.num == numFields && offsets[field.num-1])))
1014 f.Seek(offsets[field.num-1], start);
1015 ((void (*)(void *, void *, void *))(void *)field.type._vTbl[__ecereVMethodID_class_OnUnserialize])(field.type, data, f);
1026 bool SetData(EDBField field, typed_object data)
1028 EDBDatabase edb = tbl.db;
1029 File f = (_num && tbl.rowPositions[_num - 1]) ? edb.archive.FileOpenAtPosition(tbl.rowPositions[_num - 1]) : null;
1033 ArchiveDir dirTable;
1035 uint numFields, oldNumFields = 0;
1037 f.Get(oldNumFields);
1038 numFields = Max(oldNumFields, tbl.fields.count);
1042 uint * offsets = new0 uint[numFields];
1043 byte * buffer = null;
1045 f.Read(offsets, sizeof(uint), oldNumFields);
1048 tf.Write(offsets, sizeof(uint), numFields);
1051 if(field.num-1 < oldNumFields)
1053 // We will read right up to to the field we're writing to
1054 // (Size will be from right after the offset table to that offset)
1055 if(offsets[field.num-1])
1056 // *** Fields are based at index 1, if we're writing the last field we need to set size to its offset
1057 // because we will be rewriting over it. ***
1058 size = offsets[field.num-1];
1062 // If this field does not exist yet (offsets[field.num-1] == 0), we want to write at the end (leave size = f.GetSize()),
1063 for(c = field.num; c < oldNumFields; c++)
1074 // Subtract the header (numFields + offsets table), that's where we're at right now
1079 buffer = renew buffer byte[size];
1080 f.Read(buffer, 1, size);
1081 tf.Write(buffer, 1, size);
1084 // Update the offset of the field we're writing to
1085 offsets[field.num-1] = tf.Tell();
1086 // Serialize the data we're writing
1087 ((void (*)(void *, void *, void *))(void *)field.type._vTbl[__ecereVMethodID_class_OnSerialize])(field.type, data, tf);
1089 if(field.num < numFields)
1093 for(c = field.num; c<numFields; c++)
1097 difference = tf.Tell() - offsets[c];
1104 int fileSize = f.GetSize();
1105 f.Seek(offsets[c], start);
1106 size = fileSize - offsets[c];
1107 buffer = renew buffer byte[size];
1108 f.Read(buffer, 1, size);
1109 tf.Write(buffer, 1, size);
1111 for(; c<numFields; c++)
1114 offsets[c] += difference;
1117 if(numFields > oldNumFields)
1120 for(c = 0; c < field.num - 1; c++)
1123 offsets[c] += (numFields - oldNumFields) * sizeof(uint);
1127 tf.Seek(sizeof(uint), start);
1128 tf.Write(offsets, sizeof(uint), numFields);
1135 dirTable = edb.archive.OpenDirectory(tbl.apath, FileStats { }, replace);
1139 char file[MAX_FILENAME];
1140 sprintf(file, "%d", _num);
1141 aname = CopyString(file);
1143 dirTable.AddFromFileAtPosition(tbl.rowPositions[_num - 1], aname, tf, { size = tf.GetSize() }, replace, 0, null, &tbl.rowPositions[_num - 1]);
1149 for(i = tbl.indexes.first; i; i = i.next)
1151 BTNode n = (i == index) ? node : null;
1153 for(c = 0; c<i.numFields; c++)
1154 if(i.fieldIndexes[c].field == field ||
1155 i.fieldIndexes[c].memberField == field ||
1156 i.fieldIndexes[c].memberIdField == field)
1158 if(c == i.numFields) continue;
1161 n = i.tree.FindAll(_num);
1178 bool Select(MoveOptions move)
1180 EDBDatabase edb = tbl.db;
1188 node = index.tree.first;
1189 num = node ? (uint)node.key : 0;
1192 node = node ? node.next : index.tree.first;
1193 num = node ? (uint)node.key : 0;
1196 node = index.tree.last;
1197 num = node ? (uint)node.key : 0;
1200 node = node ? node.prev : index.tree.last;
1201 num = node ? (uint)node.key : 0;
1204 node = index.tree.root;
1205 num = node ? (uint)node.key : 0;
1218 while(_num < tbl.allocatedRowsCount)
1221 if(tbl.rowPositions[_num - 1])
1227 num = tbl.allocatedRowsCount + 1;
1232 if(tbl.rowPositions[_num - 1])
1245 int CompareRowNum(int num, EDBField field, typed_object data)
1248 EDBDatabase edb = tbl.db;
1250 f = (num && tbl.rowPositions[num - 1]) ? edb.archive.FileOpenAtPosition(tbl.rowPositions[num - 1]) : null;
1251 if(f && data._class)
1255 if(field.num <= numFields)
1257 uint * offsets = new0 uint[numFields];
1258 Class type = field.type;
1261 f.Read(offsets, sizeof(uint), numFields);
1263 if(((field.num < numFields && offsets[field.num-1] && offsets[field.num-1] != offsets[field.num]) || (field.num == numFields && offsets[field.num-1])))
1265 f.Seek(offsets[field.num-1], start);
1266 if(type.type == structClass)
1267 read = (int64)new0 byte[type.structSize];
1268 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, (type.type == structClass) ? (void *)read : &read, f);
1270 //if(data._class == type)
1272 result = ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type,
1273 (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &read : (void *)read, data);
1275 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)read);
1276 if(type.type == structClass)
1278 void * dataPtr = (void *)read;
1289 int CompareRow(EDBField field, typed_object data)
1291 return CompareRowNum(_num, field, data);
1294 bool Find(EDBField field, MoveOptions move, MatchOptions match, typed_object data)
1296 EDBDatabase edb = tbl.db;
1297 if(tbl == field.tbl)
1304 if(index && index.fieldIndexes[0].field == field && !index.fieldIndexes[0].memberField)
1306 BTNode node = this.node, lastNode = null;
1308 int order = (index.fieldIndexes[0].order == ascending) ? 1 : -1;
1310 if(move == next || move == nil)
1313 node = node ? node.next : null;
1316 result = node ? order * CompareRowNum((uint)node.key, field, data) : 1;
1317 // We won't find this on our right
1324 // The next row is good
1325 else if(result == 0)
1328 num = (uint)node.key;
1332 else if(move == previous)
1334 node = node ? node.prev : null;
1335 result = node ? order * CompareRowNum((uint)node.key, field, data) : -1;
1336 // We won't find this on our left
1343 // The previous row is good
1344 else if(result == 0)
1347 num = (uint)node.key;
1352 // Go up as high as we need to
1357 BTNode max = node.maximum, min = node.minimum;
1358 int maxResult = order * CompareRowNum((uint)max.key, field, data);
1359 int minResult = order * CompareRowNum((uint)min.key, field, data);
1360 if(maxResult >= 0 && minResult <= 0) break;
1364 else if(move == first || move == next)
1367 node = index.tree.first;
1370 BTNode max = node.maximum;
1371 result = order * CompareRowNum((uint)max.key, field, data);
1372 if(result >= 0) break;
1376 else if(move == last || move == previous)
1378 node = index.tree.last;
1381 BTNode min = node.minimum;
1382 result = order * CompareRowNum((uint)min.key, field, data);
1383 if(result <= 0) break;
1387 else if(move == middle)
1388 node = index.tree.root;
1393 result = order * CompareRowNum((uint)node.key, field, data);
1395 node = (result < 0) ? node.right : node.left;
1398 // Look for closest matching row to search point
1399 while(node && !result)
1402 node = (move == last || move == previous) ? node.next : node.prev;
1403 if(node) result = order * CompareRowNum((uint)node.key, field, data);
1405 this.node = lastNode;
1406 num = lastNode ? (uint)lastNode.key : 0;
1407 return lastNode ? true : false;
1411 if(move == first || move == middle)
1416 else if(move == last)
1421 else if(move == next)
1423 else if(move == previous)
1425 else if(move == nil)
1429 int result = CompareRow(field, data);
1442 int MultipleCompareRowNum(int num, FieldFindData * findData, int numFindFields)
1445 EDBDatabase edb = tbl.db;
1447 f = (num && tbl.rowPositions[num - 1]) ? edb.archive.FileOpenAtPosition(tbl.rowPositions[num - 1]) : null;
1454 offsets = new0 uint[numFields];
1455 f.Read(offsets, sizeof(uint), numFields);
1457 for(c = 0; c<numFindFields; c++)
1459 EDBField field = (EDBField)findData[c].field;
1460 int order = (!index || index.fieldIndexes[c].order == ascending) ? 1 : -1;
1462 if(field.num <= numFields)
1464 Class type = field.type;
1467 if(((field.num < numFields && offsets[field.num-1] && offsets[field.num-1] != offsets[field.num]) || (field.num == numFields && offsets[field.num-1])))
1469 f.Seek(offsets[field.num-1], start);
1471 if(type.type == structClass)
1472 read = (int64)new0 byte[type.structSize];
1473 ((void (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnUnserialize])(type, (type.type == structClass) ? (void *)read : &read, f);
1475 //if(data._class == type)
1477 result = order * ((int (*)(void *, void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnCompare])(type,
1478 (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &read : (void *)read,
1479 (type.type == systemClass || type.type == bitClass || type.type == enumClass || type.type == unitClass) ? &findData[c].value.i64 : (void *)findData[c].value.i64);
1481 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)read);
1482 if(type.type == structClass)
1484 void * dataPtr = (void *)read;
1497 int MultipleCompareRow(FieldFindData * findData, int numFields)
1499 return MultipleCompareRowNum(_num, findData, numFields);
1502 bool FindMultiple(FieldFindData * findData, MoveOptions move, int numFields)
1504 EDBDatabase edb = tbl.db;
1506 for(c = 0; c<numFields; c++)
1507 if(tbl != ((EDBField)findData[c].field).tbl)
1513 bool indexedFind = false;
1518 for(c = 0; c<numFields; c++)
1520 if(index.numFields <= c || index.fieldIndexes[c].field != findData[c].field || index.fieldIndexes[c].memberField)
1528 BTNode node = this.node, lastNode = null;
1531 if(move == next || move == nil)
1534 node = node ? node.next : null;
1537 result = node ? MultipleCompareRowNum((uint)node.key, findData, numFields) : 1;
1538 // We won't find this on our right
1545 // The next row is good
1546 else if(result == 0)
1549 num = (uint)node.key;
1553 else if(move == previous)
1555 node = node ? node.prev : null;
1556 result = node ? MultipleCompareRowNum((uint)node.key, findData, numFields) : -1;
1557 // We won't find this on our left
1564 // The previous row is good
1565 else if(result == 0)
1568 num = (uint)node.key;
1573 // Go up as high as we need to
1574 if(move == first || move == next)
1577 node = index.tree.first;
1580 BTNode max = node.maximum;
1581 result = MultipleCompareRowNum((uint)max.key, findData, numFields);
1582 if(result >= 0) break;
1586 else if(move == last || move == previous)
1588 node = index.tree.last;
1591 BTNode min = node.minimum;
1592 result = MultipleCompareRowNum((uint)min.key, findData, numFields);
1593 if(result <= 0) break;
1597 else if(move == middle)
1598 node = index.tree.root;
1603 result = MultipleCompareRowNum((uint)node.key, findData, numFields);
1605 node = (result < 0) ? node.right : node.left;
1608 // Look for closest matching row to search point
1609 while(node && !result)
1612 node = (move == last || move == previous) ? node.next : node.prev;
1613 if(node) result = MultipleCompareRowNum((uint)node.key, findData, numFields);
1615 this.node = lastNode;
1616 num = lastNode ? (uint)lastNode.key : 0;
1617 return lastNode ? true : false;
1621 if(move == first || move == middle)
1626 else if(move == last)
1631 else if(move == nil)
1637 int result = MultipleCompareRow(findData, numFields);
1650 bool Synch(DriverRow to)
1652 EDBRow rowTo = (EDBRow)to;
1653 if(tbl == rowTo.tbl)
1664 bool reused = tbl.deletedRowsCount != 0;
1665 EDBDatabase edb = tbl.db;
1667 ArchiveDir dirTable;
1669 RowsCountFileEdit(edb.archive, tbl.apath, reused ? reuse : add, &tbl.allocatedRowsCount, &tbl.deletedRowsCount, &tbl.rowsCountPosition);
1670 tbl.rowsCount = tbl.allocatedRowsCount - tbl.deletedRowsCount;
1674 for(n = 1; n <= tbl.allocatedRowsCount; n++)
1676 if(!tbl.rowPositions[n - 1])
1683 num = tbl.rowsCount;
1685 if(tbl.allocatedRowsCount > tbl.rowPositionsSize)
1687 tbl.rowPositionsSize = tbl.allocatedRowsCount + tbl.allocatedRowsCount / 2;
1688 //tbl.rowPositionsSize = tbl.allocatedRowsCount;
1689 tbl.rowPositions = renew0 tbl.rowPositions uint[Max(1, tbl.rowPositionsSize)];
1691 tbl.rowPositions[tbl.allocatedRowsCount - 1] = 0;
1694 dirTable = edb.archive.OpenDirectory(tbl.apath, FileStats { }, replace);
1701 char file[MAX_FILENAME];
1702 sprintf(file, "%d", _num);
1703 aname = CopyString(file);
1705 dirTable.AddFromFileAtPosition(tbl.rowPositions[_num - 1], aname, f, { size = f.GetSize() }, replace, 0, null, &tbl.rowPositions[_num - 1]);
1712 for(i = tbl.indexes.first; i; i = i.next)
1727 EDBDatabase edb = tbl.db;
1728 ArchiveDir dirTable;
1729 BTNode node = this.node;
1730 int oldNum = this._num;
1732 RowsCountFileEdit(edb.archive, tbl.apath, del, &tbl.allocatedRowsCount, &tbl.deletedRowsCount, &tbl.rowsCountPosition);
1733 tbl.rowsCount = tbl.allocatedRowsCount - tbl.deletedRowsCount;
1734 tbl.rowPositions[_num - 1] = 0;
1736 dirTable = edb.archive.OpenDirectory(tbl.apath, FileStats { }, replace);
1739 char file[MAX_FILENAME];
1740 sprintf(file, "%d", _num);
1741 aname = CopyString(file);
1743 dirTable.Delete(aname);
1752 for(i = tbl.indexes.first; i; i = i.next)
1754 BTNode n = (i == index) ? node : null;
1756 n = i.tree.FindAll(oldNum);
1774 bool GoToSysID(int id)
1776 if(tbl.allocatedRowsCount >= id && id > 0 && tbl.rowPositions[id - 1])
1781 node = index.tree.FindAll(id);