Table.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. /* ---------------------------------------------------------------------------
  2. Nullsoft Database Engine
  3. --------------------
  4. codename: Near Death Experience
  5. --------------------------------------------------------------------------- */
  6. /* ---------------------------------------------------------------------------
  7. Table Class
  8. Android (linux) implementation
  9. --------------------------------------------------------------------------- */
  10. #include "Table.h"
  11. #include "../nde.h"
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include "../CRC.H"
  15. #include "../NDEString.h"
  16. #include "IndexField.h"
  17. #include "ColumnField.h"
  18. #include "../DBUtils.h"
  19. const char *tSign="NDETABLE";
  20. //---------------------------------------------------------------------------
  21. Table::Table(const char *TableName, const char *Idx, int Create, Database *_db, int _Cached)
  22. : Scanner(this), use_row_cache(false), columns_cached(false)
  23. {
  24. Handle = 0;
  25. memset(column_ids, FIELD_UNKNOWN, 255);
  26. Cached = _Cached;
  27. db = _db;
  28. AutoCreate = Create;
  29. Name = ndestring_wcsdup(TableName);
  30. IdxName = ndestring_wcsdup(Idx);
  31. Init();
  32. }
  33. //---------------------------------------------------------------------------
  34. void Table::Init()
  35. {
  36. numErrors = 0;
  37. Scanners = new LinkedList();
  38. // benski> cut: Handle=NULL;
  39. IdxHandle=NULL;
  40. FieldsRecord=NULL;
  41. IndexList=NULL;
  42. GLocateUpToDate = FALSE;
  43. }
  44. //---------------------------------------------------------------------------
  45. Table::~Table()
  46. {
  47. Reset();
  48. if (Handle) // Reset doesn't completely destroy Handle
  49. Vfdestroy(Handle);
  50. Handle = 0;
  51. ndestring_release(Name);
  52. ndestring_release(IdxName);
  53. }
  54. //---------------------------------------------------------------------------
  55. void Table::Reset()
  56. {
  57. if (IndexList) IndexList->Release();
  58. IndexList=0;
  59. if (FieldsRecord) FieldsRecord->Release();
  60. FieldsRecord=0;
  61. delete Scanners;
  62. Scanners=0;
  63. if (Handle)
  64. Vfclose(Handle); // close (but don't destroy) to keep mutex open.
  65. if (IdxHandle)
  66. Vfdestroy(IdxHandle);
  67. IdxHandle = 0;
  68. for (RowCache::iterator itr=rowCache.begin();itr!=rowCache.end();itr++)
  69. {
  70. if (itr->second)
  71. itr->second->Release();
  72. }
  73. rowCache.clear();
  74. memset(column_ids, FIELD_UNKNOWN, 255);
  75. columns_cached=false;
  76. }
  77. struct IndexNewWalkerContext
  78. {
  79. IndexNewWalkerContext(Table *_table)
  80. {
  81. N = -1;
  82. table = _table;
  83. }
  84. int N;
  85. Table *table;
  86. };
  87. bool Table::IndexNewWalker(IndexRecord *record, Field *entry, void *context_in)
  88. {
  89. IndexNewWalkerContext *context = (IndexNewWalkerContext *)context_in;
  90. IndexField *p = (IndexField *)entry;
  91. p->index = new Index(context->table->IdxHandle, p->ID, context->N++, p->Type, FALSE, 0, context->table);
  92. return true;
  93. }
  94. //---------------------------------------------------------------------------
  95. bool Table::Open()
  96. {
  97. bool Valid;
  98. int justcreated = 0;
  99. if (!Handle)
  100. Handle = Vfnew(Name, "r+b", Cached);
  101. if (!Handle) return FALSE;
  102. if (!Vflock(Handle))
  103. {
  104. Vfdestroy(Handle);
  105. Handle = 0;
  106. return FALSE;
  107. }
  108. Handle = Vfopen(Handle, Name, "r+b", Cached);
  109. IdxHandle = Vfopen(0, IdxName, "r+b", 1);
  110. Valid = (Handle && IdxHandle);
  111. // unlock
  112. if (Valid || !AutoCreate)
  113. {
  114. //if (Handle)
  115. //Vfunlock(Handle);
  116. }
  117. else
  118. {
  119. if (Handle)
  120. {
  121. Vfclose(Handle);
  122. if (IdxHandle)
  123. Vfdestroy(IdxHandle);
  124. IdxHandle = 0;
  125. }
  126. else
  127. {
  128. if (IdxHandle)
  129. Vfdestroy(IdxHandle);
  130. IdxHandle = 0;
  131. Handle = Vfnew(Name, "w+b", Cached);
  132. if (!Vflock(Handle))
  133. {
  134. Vfdestroy(Handle);
  135. return FALSE;
  136. }
  137. }
  138. Handle = Vfopen(Handle, Name, "w+b", Cached);
  139. IdxHandle = Vfopen(0, IdxName, "w+b", 1);
  140. Valid = (Handle && IdxHandle);
  141. if (Valid)
  142. {
  143. Vfwrite(__TABLE_SIGNATURE__, strlen(__TABLE_SIGNATURE__), Handle);
  144. Vfwrite(__INDEX_SIGNATURE__, strlen(__TABLE_SIGNATURE__), IdxHandle);
  145. // TODO bensk> change if NUM_SPECIAL_RECORDS ever increases
  146. int v=NUM_SPECIAL_RECORDS;//strlen(__TABLE_SIGNATURE__);
  147. Vfwrite(&v, sizeof(v), IdxHandle);
  148. // v = 0; fwrite(&v, sizeof(v), 1, IdxHandle);
  149. v = -1; Vfwrite(&v, sizeof(v), IdxHandle); // write ID
  150. v = 0;
  151. for (int i=0;i<NUM_SPECIAL_RECORDS;i++)
  152. {
  153. Vfwrite(&v, sizeof(v), IdxHandle);
  154. Vfwrite(&v, sizeof(v), IdxHandle);
  155. }
  156. Sync();
  157. justcreated = 1;
  158. }
  159. }
  160. if (!Valid)
  161. {
  162. if (Handle) Vfdestroy(Handle);
  163. if (IdxHandle) Vfdestroy(IdxHandle);
  164. Handle = NULL;
  165. IdxHandle = NULL;
  166. }
  167. else
  168. {
  169. int Ptr;
  170. char test1[9]={0,};
  171. char test2[9]={0,};
  172. Vfseek(Handle, 0, SEEK_SET);
  173. Vfread(test1, strlen(__TABLE_SIGNATURE__), Handle);
  174. Vfseek(IdxHandle, 0, SEEK_SET);
  175. Vfread(test2, strlen(__INDEX_SIGNATURE__), IdxHandle);
  176. test1[8]=0;
  177. test2[8]=0;
  178. if (strcmp(test1, __TABLE_SIGNATURE__) || strcmp(test2, __INDEX_SIGNATURE__))
  179. {
  180. if (Handle) Vfdestroy(Handle);
  181. Handle = 0;
  182. if (IdxHandle) Vfdestroy(IdxHandle);
  183. IdxHandle = 0;
  184. return FALSE;
  185. }
  186. // Load default index
  187. IndexField *field;
  188. field = new IndexField(PRIMARY_INDEX, -1, -1, "None");
  189. field->index = new Index(IdxHandle, PRIMARY_INDEX, -1, -1, FALSE, 0, this);
  190. // Get indexes
  191. Ptr = field->index->Get(INDEX_RECORD_NUM);
  192. IndexList = new IndexRecord(Ptr, INDEX_RECORD_NUM, Handle, this);
  193. if (!IndexList)
  194. {
  195. delete field;
  196. if (Handle) Vfdestroy(Handle);
  197. Handle = 0;
  198. if (IdxHandle) Vfdestroy(IdxHandle);
  199. IdxHandle = 0;
  200. return FALSE;
  201. }
  202. // Init them
  203. IndexNewWalkerContext newContext(this);
  204. IndexList->WalkFields(IndexNewWalker, &newContext);
  205. // Add default in case its not there (if it is it won't be added by addfield)
  206. IndexList->AddField(field);
  207. // Get the default index (whether loaded or preloaded)
  208. Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
  209. // If it's different from preloaded, delete preloaded
  210. if (field->index != Scanner::index)
  211. {
  212. delete field;
  213. field=0;
  214. }
  215. // Set up colaboration
  216. IndexList->BuildCollaboration();
  217. // Get columns
  218. Ptr = Scanner::index->Get(FIELDS_RECORD_NUM);
  219. FieldsRecord = new Record(Ptr, FIELDS_RECORD_NUM, Handle, this);
  220. if (!FieldsRecord)
  221. {
  222. IndexList->Release();
  223. IndexList=0;
  224. if (Handle) Vfdestroy(Handle);
  225. Handle = 0;
  226. if (IdxHandle) Vfdestroy(IdxHandle);
  227. IdxHandle = 0;
  228. return FALSE;
  229. }
  230. // update the column cache
  231. FieldsRecord->WalkFields(BuildColumnCache, this);
  232. columns_cached=true;
  233. }
  234. #if 0 // TODO
  235. if (Valid && !justcreated)
  236. {
  237. if (IndexList->NeedFix())
  238. Compact();
  239. }
  240. #endif
  241. if (Valid) First();
  242. if (Handle)
  243. Vfunlock(Handle);
  244. return Valid;
  245. }
  246. //---------------------------------------------------------------------------
  247. void Table::Close(void)
  248. {
  249. int v=0;
  250. if (Handle && IndexList && Vflock(Handle, 0))
  251. {
  252. IndexList->WalkFields(IndexWriteWalker, 0);
  253. }
  254. delete Scanners;
  255. Scanners = NULL;
  256. Vsync(Handle);
  257. if (IdxHandle)
  258. {
  259. Vfdestroy(IdxHandle);
  260. IdxHandle = NULL;
  261. v |= 2;
  262. }
  263. if (Handle)
  264. {
  265. Vfdestroy(Handle);
  266. Handle = NULL;
  267. v |= 1;
  268. }
  269. if (v != 3)
  270. return;
  271. }
  272. bool Table::IndexWriteWalker(IndexRecord *record, Field *entry, void *context)
  273. {
  274. IndexField *field = (IndexField *)entry;
  275. field->index->WriteIndex();
  276. return true;
  277. }
  278. //---------------------------------------------------------------------------
  279. void Table::Sync(void)
  280. {
  281. if (!Vflock(Handle))
  282. return;
  283. if (IndexList)
  284. IndexList->WalkFields(IndexWriteWalker, 0);
  285. int err=0;
  286. if (!err && Handle) err|=Vsync(Handle);
  287. if (!err && IdxHandle) err|=Vsync(IdxHandle);
  288. Vfunlock(Handle);
  289. }
  290. //---------------------------------------------------------------------------
  291. ColumnField *Table::NewColumn(unsigned char FieldID, const char *FieldName, unsigned char FieldType, bool indexUnique)
  292. {
  293. columns_cached=false; // if they start writing new columns, kill the columns cache until they PostColumns()
  294. ColumnField *f = GetColumnById(FieldID);
  295. if (f) {
  296. int t = f->GetDataType();
  297. if (t != FieldType) {
  298. if (CompatibleFields(t, FieldType))
  299. {
  300. f->SetDataType(FieldType);
  301. goto aok;
  302. }
  303. }
  304. return NULL;
  305. }
  306. aok:
  307. if (GetColumnByName(FieldName))
  308. return NULL;
  309. ColumnField *field = new ColumnField(FieldID, FieldName, FieldType, this);
  310. column_ids[FieldID]=FieldType;
  311. FieldsRecord->AddField(field);
  312. return field;
  313. }
  314. void Table::SetFieldSearchableById(unsigned char field_id, bool searchable)
  315. {
  316. ColumnField *column = GetColumnById(field_id);
  317. if (column)
  318. column->SetSearchable(searchable);
  319. if (searchable)
  320. {
  321. search_fields.insert(field_id);
  322. }
  323. else
  324. {
  325. search_fields.erase(field_id);
  326. }
  327. }
  328. //---------------------------------------------------------------------------
  329. bool Table::BuildColumnCache(Record *record, Field *entry, void *context)
  330. {
  331. Table *table = (Table *)context;
  332. ColumnField *column = (ColumnField *)entry;
  333. unsigned char field_id=column->GetFieldId();
  334. table->column_ids[field_id] = column->GetDataType();
  335. if (column->IsSearchableField())
  336. {
  337. table->search_fields.insert(field_id);
  338. }
  339. else
  340. {
  341. table->search_fields.erase(field_id);
  342. }
  343. return true;
  344. }
  345. //---------------------------------------------------------------------------
  346. void Table::PostColumns(void)
  347. {
  348. FieldsRecord->WriteFields(this, FIELDS_RECORD_NUM);
  349. memset(column_ids, FIELD_UNKNOWN, 255);
  350. FieldsRecord->WalkFields(BuildColumnCache, this);
  351. columns_cached=true;
  352. }
  353. unsigned char Table::GetColumnType(unsigned char Id)
  354. {
  355. if (columns_cached)
  356. {
  357. return column_ids[Id];
  358. }
  359. else
  360. {
  361. return GetColumnById(Id)->GetDataType();
  362. }
  363. }
  364. //---------------------------------------------------------------------------
  365. IndexField *Table::GetIndexByName(const char *name)
  366. {
  367. if (!IndexList)
  368. return NULL;
  369. return IndexList->GetIndexByName(name);
  370. }
  371. //---------------------------------------------------------------------------
  372. IndexField *Table::GetIndexById(unsigned char Id)
  373. {
  374. if (!IndexList)
  375. return NULL;
  376. return (IndexField *)IndexList->GetField(Id);
  377. }
  378. //---------------------------------------------------------------------------
  379. void Table::AddIndexByName(const char *name, const char *desc)
  380. {
  381. ColumnField *header = GetColumnByName(name);
  382. if (header)
  383. {
  384. unsigned char Idx = header->ID;
  385. AddIndexById(Idx, desc);
  386. }
  387. }
  388. //---------------------------------------------------------------------------
  389. void Table::AddIndexById(unsigned char Id, const char *desc)
  390. {
  391. if (GetIndexById(Id)) return;
  392. ColumnField *col = GetColumnById(Id);
  393. if (!col)
  394. return;
  395. IndexField *newindex = new IndexField(Id, IndexList->GetColumnCount(), col->GetDataType(), desc);
  396. newindex->index = new Index(IdxHandle, Id, IndexList->GetColumnCount(), col->GetDataType(), true, Scanner::index->NEntries, this);
  397. IndexList->AddField(newindex);
  398. IndexField *previous = (IndexField *)newindex->prev;
  399. previous->index->Colaborate(newindex);
  400. IndexField *primary_index = (IndexField *)IndexList->GetField(PRIMARY_INDEX);
  401. newindex->index->Colaborate(primary_index);
  402. previous->index->Propagate();
  403. IndexList->WriteFields(this);
  404. }
  405. //---------------------------------------------------------------------------
  406. bool Table::CheckIndexing(void)
  407. {
  408. if (IndexList->GetColumnCount() == 0) return true;
  409. for (int i=0;i<Scanner::index->NEntries;i++)
  410. {
  411. if (!IndexList->CheckIndexing(i))
  412. return FALSE;
  413. }
  414. return true;
  415. }
  416. struct IndexWalkerThunkContext
  417. {
  418. void *context;
  419. Table *_this;
  420. Table::IndexWalker callback;
  421. };
  422. bool Table::IndexWalkerThunk(IndexRecord *record, Field *entry, void *context_in)
  423. {
  424. IndexWalkerThunkContext *context = (IndexWalkerThunkContext *)context_in;
  425. return context->callback(context->_this, (IndexField *)entry, context->context);
  426. }
  427. //---------------------------------------------------------------------------
  428. void Table::WalkIndices(IndexWalker callback, void *context)
  429. {
  430. if (IndexList && callback)
  431. {
  432. IndexWalkerThunkContext walkerContext = { context, this, callback };
  433. IndexList->WalkFields(IndexWalkerThunk, &walkerContext);
  434. }
  435. }
  436. //---------------------------------------------------------------------------
  437. void Table::DropIndex(IndexField *Ptr)
  438. {
  439. if (!Ptr || Ptr->Type != FIELD_INDEX) return;
  440. if (Scanner::index == Ptr->index)
  441. {
  442. Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
  443. IndexList->BuildCollaboration();
  444. }
  445. IndexList->RemoveField(Ptr);
  446. if (Scanner::index->SecIndex == Ptr)
  447. Scanner::index->SecIndex = 0;
  448. IndexList->WriteFields(this);
  449. }
  450. //---------------------------------------------------------------------------
  451. void Table::DropIndexByName(const char *desc)
  452. {
  453. IndexField *indx = GetIndexByName(desc);
  454. if (!strcasecmp(desc, "None")) return;
  455. if (indx)
  456. DropIndex(indx);
  457. }
  458. //---------------------------------------------------------------------------
  459. void Table::DropIndexById(unsigned char Id)
  460. {
  461. if (!IndexList)
  462. return;
  463. if (Id == (unsigned char)PRIMARY_INDEX) return;
  464. IndexField *indx=(IndexField *)IndexList->GetField(Id);
  465. if (indx)
  466. DropIndex(indx);
  467. }
  468. //---------------------------------------------------------------------------
  469. bool Table::LocateByIdEx(int Id, int From, Field *field, int comp_mode)
  470. {
  471. return Scanner::LocateByIdEx(Id, From, field, NULL, comp_mode);
  472. }
  473. //---------------------------------------------------------------------------
  474. Record *Table::GetColumns(void)
  475. {
  476. if (!FieldsRecord)
  477. return NULL;
  478. return FieldsRecord;
  479. }
  480. //---------------------------------------------------------------------------
  481. Scanner *Table::NewScanner()
  482. {
  483. Scanner *s = new Scanner(this);
  484. /*if (Scanners->GetNElements() > 0)*/
  485. s->index = Scanner::index;
  486. Scanners->AddEntry(s, true);
  487. return s;
  488. }
  489. //---------------------------------------------------------------------------
  490. Scanner *Table::GetDefaultScanner()
  491. {
  492. return this;
  493. }
  494. //---------------------------------------------------------------------------
  495. void Table::DeleteScanner(Scanner *scan)
  496. {
  497. if (!scan) return;
  498. Scanners->RemoveEntry(scan);
  499. }
  500. //---------------------------------------------------------------------------
  501. void Table::IndexModified(void)
  502. {
  503. Scanner *s = (Scanner *)Scanners->GetHead();
  504. while (s)
  505. {
  506. s->IndexModified();
  507. s = (Scanner *)s->GetNext();
  508. }
  509. }
  510. //---------------------------------------------------------------------------
  511. void Table::SetGlobalLocateUpToDate(bool is) {
  512. GLocateUpToDate = is;
  513. }
  514. struct ColumnWalkContext
  515. {
  516. Table *ctable;
  517. };
  518. bool Table::Compact_ColumnWalk(Record *record, Field *entry, void *context_in)
  519. {
  520. ColumnField *field = static_cast<ColumnField *>(entry);
  521. ColumnWalkContext *context = (ColumnWalkContext *)context_in;
  522. Table *ctable = context->ctable;
  523. ctable->NewColumn(field->GetFieldId(), field->GetFieldName(), field->GetDataType(), FALSE);
  524. return true;
  525. }
  526. struct ColumnWalk2Context
  527. {
  528. Table *ctable;
  529. Table *thisTable;
  530. uint8_t *data;
  531. size_t data_size;
  532. int gotstuff;
  533. };
  534. bool Table::Compact_ColumnWalk2(Record *record, Field *entry, void *context_in)
  535. {
  536. ColumnField *colfield = (ColumnField *)entry;
  537. ColumnWalk2Context *context = (ColumnWalk2Context *)context_in;
  538. unsigned char fieldid = colfield->GetFieldId();
  539. //char *fieldname = colfield->GetFieldName();
  540. Field *mfield = context->thisTable->GetFieldById(fieldid);
  541. //Field *mfield = GetFieldByName(fieldname);
  542. if (mfield != NULL) {
  543. if (!context->gotstuff) {
  544. context->ctable->New();
  545. context->gotstuff = 1;
  546. }
  547. Field *cfield = context->ctable->NewFieldById(fieldid, 0);
  548. //Field *cfield = ctable->NewFieldByName(fieldname, mfield->GetPerm());
  549. size_t len = mfield->GetDataSize();
  550. if (len > context->data_size)
  551. {
  552. context->data_size = len;
  553. context->data = (uint8_t *)realloc(context->data, context->data_size);
  554. }
  555. mfield->WriteTypedData(context->data, len);
  556. cfield->ReadTypedData(context->data, len);
  557. }
  558. return true;
  559. }
  560. bool Table::Compact_IndexWalk(Table *table, IndexField *field, void *context)
  561. {
  562. Table *ctable = (Table *)context;
  563. if (strcasecmp(field->GetIndexName(), "None"))
  564. ctable->AddIndexById(field->GetFieldId(), field->GetIndexName());
  565. return true;
  566. }
  567. #if 0 // TODO
  568. //---------------------------------------------------------------------------
  569. void Table::Compact(int *progress) {
  570. // ok so we're gonna be cheating a bit, instead of figuring out how to safely modify all those
  571. // nifty indexes that cross reference themselves and blablabla, we're just gonna duplicate the
  572. // whole table from scratch, overwrite ourselves, and reopen the table. duh.
  573. if (!Vflock(Handle))
  574. {
  575. if (progress != NULL) *progress = 100;
  576. return;
  577. }
  578. // create a temporary table in windows temp dir
  579. wchar_t temp_table[MAX_PATH+12];
  580. wchar_t temp_index[MAX_PATH+12];
  581. wchar_t old_table[MAX_PATH+12];
  582. wchar_t old_index[MAX_PATH+12];
  583. DWORD pid=GetCurrentProcessId();
  584. StringCbPrintfW(temp_table, sizeof(temp_table), L"%s.new%08X", Name,pid);
  585. StringCbPrintfW(temp_index, sizeof(temp_index),L"%s.new%08X", IdxName,pid);
  586. StringCbPrintfW(old_table, sizeof(old_table),L"%s.old%08X", Name,pid);
  587. StringCbPrintfW(old_index, sizeof(old_index),L"%s.old%08X", IdxName,pid);
  588. // delete them, in case we crashed while packing
  589. DeleteFileW(temp_table);
  590. DeleteFileW(temp_index);
  591. DeleteFileW(old_table);
  592. DeleteFileW(old_index);
  593. // create a brand new db and a brand new table
  594. Table *ctable = db->OpenTable(temp_table, temp_index, NDE_OPEN_ALWAYS, Cached);
  595. // duplicate the columns
  596. Record *record = GetColumns();
  597. if (record != NULL)
  598. {
  599. ColumnWalkContext context;
  600. context.ctable = ctable;
  601. record->WalkFields(Compact_ColumnWalk, &context);
  602. }
  603. ctable->PostColumns();
  604. // duplicate the indexes
  605. WalkIndices(Compact_IndexWalk, (void *)ctable);
  606. // duplicate the data
  607. int reccount = GetRecordsCount();
  608. int count = 0;
  609. First();
  610. ColumnWalk2Context context;
  611. context.data_size = 65536;
  612. context.data = (uint8_t *)malloc(65536);
  613. context.ctable = ctable;
  614. context.thisTable = this;
  615. while (1) {
  616. int lasterr = NumErrors();
  617. GetDefaultScanner()->GetRecordById(count, FALSE);
  618. count++;
  619. if (Eof() || count > reccount) break;
  620. if (NumErrors() > lasterr)
  621. continue;
  622. Index *idx = GetDefaultScanner()->GetIndex();
  623. int pos = idx->Get(GetDefaultScanner()->GetRecordId());
  624. if (pos == 0) continue;
  625. int pr = (int)((float)GetRecordId()/(float)reccount*100.0f);
  626. if (progress != NULL) *progress = pr;
  627. context.gotstuff = 0;
  628. if (record != NULL)
  629. record->WalkFields(Compact_ColumnWalk2, &context);
  630. if (context.gotstuff)
  631. ctable->Post();
  632. }
  633. free(context.data);
  634. // done creating temp table
  635. db->CloseTable(ctable);
  636. // reset the data structures and close underlying file handles
  637. Reset();
  638. if (MoveFileW(Name,old_table))
  639. {
  640. if (MoveFileW(IdxName,old_index))
  641. {
  642. if (!MoveFileW(temp_table,Name) || !MoveFileW(temp_index,IdxName))
  643. {
  644. // failed, try to copy back
  645. DeleteFileW(Name);
  646. DeleteFileW(IdxName);
  647. MoveFileW(old_table,Name); // restore old file
  648. MoveFileW(old_index,IdxName); // restore old file
  649. }
  650. }
  651. else
  652. {
  653. MoveFileW(old_table,Name); // restore old file
  654. }
  655. }
  656. // clean up our temp files
  657. DeleteFileW(temp_table);
  658. DeleteFileW(temp_index);
  659. DeleteFileW(old_table);
  660. DeleteFileW(old_index);
  661. if (progress != NULL) *progress = 100;
  662. // reopen our table
  663. Init();
  664. Open();
  665. }
  666. #endif
  667. ColumnField *Table::GetColumnById(unsigned char Idx)
  668. {
  669. if (!FieldsRecord)
  670. return NULL;
  671. return (ColumnField *)FieldsRecord->GetField(Idx);
  672. }
  673. ColumnField *Table::GetColumnByName(const char *FieldName)
  674. {
  675. return FieldsRecord->GetColumnByName(FieldName);
  676. }
  677. void Table::RowCache_Delete(int position)
  678. {
  679. if (use_row_cache)
  680. {
  681. RowCache::iterator found = rowCache.find(position);
  682. if (found != rowCache.end())
  683. {
  684. if (found->second)
  685. found->second->Release();
  686. rowCache.erase(found);
  687. }
  688. }
  689. }
  690. void Table::RowCache_Remove(int position)
  691. {
  692. if (use_row_cache)
  693. {
  694. Record *&row = rowCache[position];
  695. if (row)
  696. {
  697. row->Release();
  698. }
  699. row = 0;
  700. }
  701. }
  702. void Table::RowCache_Add(Record *record, int position)
  703. {
  704. if (use_row_cache)
  705. {
  706. record->Retain();
  707. Record *&row = rowCache[position];
  708. if (row)
  709. {
  710. row->Release();
  711. }
  712. row = record;
  713. }
  714. }
  715. Record *Table::RowCache_Get(int position)
  716. {
  717. if (!use_row_cache)
  718. return 0;
  719. Record *row = rowCache[position];
  720. if (row)
  721. row->Retain();
  722. return row;
  723. }
  724. void Table::EnableRowCache()
  725. {
  726. use_row_cache=true;
  727. }