1
0

Scanner.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. /* ---------------------------------------------------------------------------
  2. Nullsoft Database Engine
  3. --------------------
  4. codename: Near Death Experience
  5. --------------------------------------------------------------------------- */
  6. /* ---------------------------------------------------------------------------
  7. Scanner Class
  8. --------------------------------------------------------------------------- */
  9. #include "nde.h"
  10. #include "../nu/AutoChar.h"
  11. #include "../nu/AutoWide.h"
  12. #include "BinaryField.h"
  13. #include "Binary32Field.h"
  14. #include <assert.h>
  15. //---------------------------------------------------------------------------
  16. Scanner::Scanner(Table *parentTable)
  17. {
  18. disable_date_resolution=0;
  19. index = NULL;
  20. pTable = parentTable;
  21. Edition=FALSE;
  22. lastLocateIndex = NULL;
  23. lastLocateId = -1;
  24. lastLocateIdx = -1;
  25. lastLocateFrom = -128;
  26. lastLocateFieldClone = NULL;
  27. CurrentRecord=NULL;
  28. CurrentRecordIdx=0;
  29. iModified = FALSE;
  30. FiltersOK = FALSE;
  31. search_any = FALSE;
  32. ResultPtr = 0;
  33. /*inMatchJoins = 0;
  34. lastJoinCache = 0;
  35. invalidJoinCache = 1;*/
  36. last_query = NULL;
  37. last_query_failed = FALSE;
  38. token = NULL;
  39. in_query_parser = 0;
  40. }
  41. //---------------------------------------------------------------------------
  42. Scanner::~Scanner()
  43. {
  44. if (CurrentRecord) CurrentRecord->Release();
  45. if (lastLocateFieldClone)
  46. {
  47. delete lastLocateFieldClone;
  48. }
  49. Query_CleanUp();
  50. if (token) CFRelease(token);
  51. if (last_query) CFRelease(last_query);
  52. }
  53. //---------------------------------------------------------------------------
  54. Record *Scanner::GetRecord(int Idx)
  55. {
  56. int Ptr;
  57. Ptr = index->Get(Idx);
  58. Record *r = pTable->RowCache_Get(Ptr);
  59. if (r)
  60. {
  61. return r;
  62. }
  63. r = new Record(Ptr, Idx, pTable->Handle, pTable);
  64. pTable->RowCache_Add(r, Ptr);
  65. return r;
  66. }
  67. //---------------------------------------------------------------------------
  68. void Scanner::GetCurrentRecord(void)
  69. {
  70. /*
  71. if (Eof() || Bof())
  72. {
  73. if (CurrentRecord) CurrentRecord->Release();
  74. CurrentRecord = NULL;
  75. return;
  76. }
  77. Record *old_record = CurrentRecord;
  78. CurrentRecord = NULL;
  79. Record *new_record = GetRecord(CurrentRecordIdx);
  80. if (old_record) old_record->Release();
  81. CurrentRecord = new_record;
  82. */
  83. if (CurrentRecord) CurrentRecord->Release();
  84. CurrentRecord = NULL;
  85. //invalidJoinCache = 1;
  86. if (Eof() || Bof()) return;
  87. CurrentRecord = GetRecord(CurrentRecordIdx);
  88. }
  89. //---------------------------------------------------------------------------
  90. void Scanner::GetRecordById(int Id, BOOL checkFilters)
  91. {
  92. CurrentRecordIdx=max(min(index->NEntries, Id+NUM_SPECIAL_RECORDS), 0);
  93. GetCurrentRecord();
  94. if (!checkFilters || MatchFilters())
  95. return;
  96. Next();
  97. }
  98. //---------------------------------------------------------------------------
  99. void Scanner::First(int *killswitch)
  100. {
  101. if (last_query_failed) return;
  102. GetRecordById(0);
  103. if (!MatchFilters() && !Eof())
  104. Next(killswitch);
  105. }
  106. //---------------------------------------------------------------------------
  107. int Scanner::Next(int *killswitch)
  108. {
  109. if (last_query_failed) return 0;
  110. while (!Eof() && !Bof())
  111. {
  112. CurrentRecordIdx++;
  113. GetCurrentRecord();
  114. if (MatchFilters())
  115. break;
  116. else
  117. {
  118. if ((killswitch && *killswitch))
  119. return 0;
  120. }
  121. }
  122. return 1;
  123. }
  124. //---------------------------------------------------------------------------
  125. int Scanner::Previous(int *killswitch)
  126. {
  127. if (last_query_failed) return 0;
  128. while (CurrentRecordIdx >= NUM_SPECIAL_RECORDS)
  129. {
  130. CurrentRecordIdx--;
  131. GetCurrentRecord();
  132. if (MatchFilters())
  133. break;
  134. else
  135. {
  136. if ((killswitch && *killswitch))
  137. return 0;
  138. }
  139. }
  140. return 1;
  141. }
  142. //---------------------------------------------------------------------------
  143. void Scanner::Last(int *killswitch)
  144. {
  145. if (last_query_failed) return;
  146. GetRecordById(index->NEntries-NUM_SPECIAL_RECORDS-1); // -3 here because 1)GetRecordById is public, so -NUM_SPECIAL_RECORDS, and 2)last entry is nentries-1, so -1
  147. if (!MatchFilters() && !Bof())
  148. Previous(killswitch);
  149. if (CurrentRecordIdx < NUM_SPECIAL_RECORDS)
  150. {
  151. CurrentRecordIdx = index->NEntries;
  152. GetCurrentRecord(); // will only delete current record if it exists
  153. }
  154. }
  155. //---------------------------------------------------------------------------
  156. BOOL Scanner::Eof(void)
  157. {
  158. if (last_query_failed) return TRUE;
  159. return CurrentRecordIdx >= index->NEntries;
  160. }
  161. //---------------------------------------------------------------------------
  162. BOOL Scanner::Bof(void)
  163. {
  164. if (last_query_failed) return TRUE;
  165. return CurrentRecordIdx < NUM_SPECIAL_RECORDS;
  166. }
  167. //---------------------------------------------------------------------------
  168. #ifdef _WIN32
  169. Field *Scanner::GetFieldByName(const wchar_t *FieldName)
  170. {
  171. ColumnField *header = pTable->GetColumnByName(FieldName);
  172. if (header)
  173. {
  174. unsigned char Idx = header->ID;
  175. return GetFieldById(Idx);
  176. }
  177. return NULL;
  178. }
  179. #else
  180. Field *Scanner::GetFieldByName(CFStringRef FieldName)
  181. {
  182. ColumnField *header = pTable->GetColumnByName(FieldName);
  183. if (header)
  184. {
  185. unsigned char Idx = header->ID;
  186. return GetFieldById(Idx);
  187. }
  188. return NULL;
  189. }
  190. #endif
  191. //---------------------------------------------------------------------------
  192. Field *Scanner::GetFieldById(unsigned char Id)
  193. {
  194. if (!CurrentRecord)
  195. return NULL;
  196. Field *field = CurrentRecord->GetField(Id);
  197. if (field)
  198. {
  199. int column_type = pTable->GetColumnType(Id);
  200. if (!CompatibleFields(field->GetType(), column_type))
  201. {
  202. return NULL;
  203. }
  204. }
  205. return field;
  206. }
  207. //---------------------------------------------------------------------------
  208. #ifdef _WIN32
  209. Field *Scanner::NewFieldByName(const wchar_t *fieldName, unsigned char Perm)
  210. {
  211. ColumnField *header = pTable->GetColumnByName(fieldName);
  212. if (header)
  213. {
  214. unsigned char Id = header->ID;
  215. Field *field = NewFieldById(Id, Perm);
  216. return field;
  217. }
  218. return NULL;
  219. }
  220. #else
  221. Field *Scanner::NewFieldByName(CFStringRef fieldName, unsigned char Perm)
  222. {
  223. ColumnField *header = pTable->GetColumnByName(fieldName);
  224. if (header)
  225. {
  226. unsigned char Id = header->ID;
  227. Field *field = NewFieldById(Id, Perm);
  228. return field;
  229. }
  230. return NULL;
  231. }
  232. #endif
  233. //---------------------------------------------------------------------------
  234. Field *Scanner::NewFieldById(unsigned char Id, unsigned char Perm)
  235. {
  236. ColumnField *field = GetColumnById(Id);
  237. if (!field)
  238. return NULL;
  239. Field *O=GetFieldById(Id);
  240. if (O) return O;
  241. switch (field->GetDataType())
  242. {
  243. case FIELD_STRING:
  244. O = new StringField();
  245. break;
  246. case FIELD_INTEGER:
  247. O = new IntegerField();
  248. break;
  249. case FIELD_INT64:
  250. O = new Int64Field();
  251. break;
  252. case FIELD_INT128:
  253. O = new Int128Field();
  254. break;
  255. case FIELD_DATETIME:
  256. if (disable_date_resolution)
  257. O= new StringField();
  258. else
  259. O = new DateTimeField();
  260. break;
  261. case FIELD_LENGTH:
  262. O = new LengthField();
  263. break;
  264. case FIELD_FILENAME:
  265. O = new FilenameField();
  266. break;
  267. case FIELD_BINARY:
  268. O = new BinaryField();
  269. break;
  270. case FIELD_BINARY32:
  271. O = new Binary32Field();
  272. break;
  273. default:
  274. #ifdef WIN32
  275. MessageBox(NULL, "unknown field type for id", "debug", 0);
  276. #else
  277. printf("NDE Error: unknown field type for id\n");
  278. #endif
  279. O = new Field();
  280. break;
  281. }
  282. O->Type = field->GetDataType();
  283. O->ID = Id;
  284. CurrentRecord->AddField(O);
  285. return O;
  286. }
  287. //---------------------------------------------------------------------------
  288. void Scanner::Post(void)
  289. {
  290. if (!CurrentRecord) return;
  291. /*if (CurrentRecord->RecordIndex == NEW_RECORD)
  292. NEntries++;*/
  293. if (pTable->use_row_cache && CurrentRecordIdx != NEW_RECORD)
  294. {
  295. int Ptr;
  296. Ptr = index->Get(CurrentRecordIdx);
  297. pTable->RowCache_Remove(Ptr);
  298. }
  299. CurrentRecordIdx = CurrentRecord->WriteFields(pTable, CurrentRecordIdx);
  300. Edition=FALSE;
  301. if (pTable->use_row_cache)
  302. {
  303. int Ptr;
  304. Ptr = index->Get(CurrentRecordIdx);
  305. pTable->RowCache_Add(CurrentRecord, Ptr);
  306. }
  307. }
  308. //---------------------------------------------------------------------------
  309. void Scanner::New(void)
  310. {
  311. if (CurrentRecord) CurrentRecord->Release();
  312. CurrentRecord = NULL;
  313. CurrentRecord = new Record(0, index->NEntries, pTable->Handle, pTable);
  314. CurrentRecordIdx = NEW_RECORD;
  315. Edition = TRUE;
  316. }
  317. //---------------------------------------------------------------------------
  318. void Scanner::Insert(void)
  319. {
  320. if (CurrentRecord) CurrentRecord->Release();
  321. CurrentRecord = NULL;
  322. CurrentRecord = new Record(0, CurrentRecordIdx, pTable->Handle, pTable);
  323. CurrentRecordIdx = NEW_RECORD;
  324. Edition=TRUE;
  325. }
  326. //---------------------------------------------------------------------------
  327. void Scanner::Delete(void)
  328. {
  329. if (CurrentRecord)
  330. {
  331. if (pTable->use_row_cache && CurrentRecordIdx != NEW_RECORD)
  332. {
  333. int Ptr;
  334. Ptr = index->Get(CurrentRecordIdx);
  335. pTable->RowCache_Delete(Ptr);
  336. }
  337. CurrentRecord->Delete(pTable, CurrentRecordIdx);
  338. }
  339. if (Eof())
  340. Previous();
  341. GetRecordById(CurrentRecordIdx-NUM_SPECIAL_RECORDS);
  342. }
  343. //---------------------------------------------------------------------------
  344. int Scanner::GetRecordId(void)
  345. {
  346. return CurrentRecordIdx != NEW_RECORD ? CurrentRecordIdx-NUM_SPECIAL_RECORDS : CurrentRecordIdx;
  347. }
  348. //---------------------------------------------------------------------------
  349. void Scanner::Edit(void)
  350. {
  351. if (Edition) return;
  352. if (!CurrentRecord)
  353. return;
  354. /*Field *f = (Field *)CurrentRecord->Fields->GetHead();
  355. while (f)
  356. {
  357. f->SubtableRecord = INVALID_RECORD;
  358. f = (Field *)f->GetNext();
  359. }*/
  360. if (CurrentRecord->InCache()) // if it's in the cache
  361. {
  362. // benski> make copy of CurrentRecord, outside the cache
  363. int Ptr;
  364. Ptr = index->Get(CurrentRecordIdx);
  365. pTable->RowCache_Remove(Ptr);
  366. Record *r = new Record(Ptr, CurrentRecordIdx, pTable->Handle, pTable);
  367. CurrentRecord->Release();
  368. CurrentRecord = r;
  369. }
  370. Edition = TRUE;
  371. }
  372. //---------------------------------------------------------------------------
  373. void Scanner::Cancel(void)
  374. {
  375. Edition = FALSE;
  376. GetCurrentRecord();
  377. }
  378. //---------------------------------------------------------------------------
  379. #ifdef _WIN32
  380. BOOL Scanner::LocateByName(const wchar_t *col, int From, Field *field, int *nskip)
  381. {
  382. ColumnField *f = pTable->GetColumnByName(col);
  383. if (!f)
  384. return NULL;
  385. return LocateById(f->GetFieldId(), From, field, nskip);
  386. }
  387. #else
  388. BOOL Scanner::LocateByName(CFStringRef col, int From, Field *field, int *nskip)
  389. {
  390. ColumnField *f = pTable->GetColumnByName(col);
  391. if (!f)
  392. return NULL;
  393. return LocateById(f->GetFieldId(), From, field, nskip);
  394. }
  395. #endif
  396. //---------------------------------------------------------------------------
  397. void Scanner::CacheLastLocate(int Id, int From, Field *field, Index *i, int j)
  398. {
  399. lastLocateId = Id;
  400. lastLocateFrom = From;
  401. if (lastLocateFieldClone)
  402. {
  403. delete lastLocateFieldClone;
  404. lastLocateFieldClone = NULL;
  405. }
  406. lastLocateFieldClone = field->Clone(pTable);
  407. lastLocateIndex = i;
  408. i->locateUpToDate = TRUE;
  409. pTable->SetGlobalLocateUpToDate(TRUE);
  410. lastLocateIdx = j;
  411. }
  412. //---------------------------------------------------------------------------
  413. BOOL Scanner::LocateById(int Id, int From, Field *field, int *nskip)
  414. {
  415. return LocateByIdEx(Id, From, field, nskip, COMPARE_MODE_EXACT);
  416. }
  417. //---------------------------------------------------------------------------
  418. BOOL Scanner::LocateByIdEx(int Id, int From, Field *field, int *nskip, int comp_mode)
  419. {
  420. IndexField *i = pTable->GetIndexById(Id);
  421. Field *compField;
  422. int j;
  423. int n;
  424. Field *cfV;
  425. if (index->NEntries == NUM_SPECIAL_RECORDS)
  426. return FALSE;
  427. int success;
  428. if (nskip) *nskip=0;
  429. // I know this is stupid but.... May be do something later
  430. switch (comp_mode)
  431. {
  432. case COMPARE_MODE_CONTAINS:
  433. while (1)
  434. {
  435. success = FALSE;
  436. if (!i)
  437. {
  438. // No index for this column. Using slow locate, enumerates the database, still faster than what the user
  439. // can do since we have access to QuickFindField which only read field headers
  440. // in order to locate the field we have to compare. user could only read the entire record.
  441. if (From == FIRST_RECORD)
  442. From = NUM_SPECIAL_RECORDS;
  443. else
  444. From+=(NUM_SPECIAL_RECORDS+1);
  445. if (From == lastLocateFrom && Id == lastLocateId && field->Contains(lastLocateFieldClone)==0 && index == lastLocateIndex && (index->locateUpToDate || pTable->GLocateUpToDate))
  446. {
  447. if (CurrentRecordIdx != lastLocateIdx) GetRecordById(lastLocateIdx-NUM_SPECIAL_RECORDS, FALSE);
  448. success = TRUE;
  449. goto nextiter_1;
  450. }
  451. for (j=From;j<index->NEntries;j++)
  452. {
  453. compField = index->QuickFindField(Id, index->Get(j));
  454. cfV = /*(compField && compField->Type == FIELD_PRIVATE) ? ((PrivateField *)compField)->myField :*/ compField;
  455. if (!field->Contains(cfV))
  456. {
  457. if (compField)
  458. {
  459. delete compField;
  460. }
  461. if (CurrentRecordIdx != j) GetRecordById(j-NUM_SPECIAL_RECORDS, FALSE);
  462. CacheLastLocate(Id, From, field, index, j);
  463. success = TRUE;
  464. goto nextiter_1;
  465. }
  466. delete compField;
  467. }
  468. success = FALSE;
  469. goto nextiter_1;
  470. }
  471. else
  472. {
  473. // Index available. Using fast locate. nfetched=log2(nrecords) for first locate, 1 more fetch per locate on same criteria
  474. int p;
  475. if (From == FIRST_RECORD) From = NUM_SPECIAL_RECORDS;
  476. else From = index->TranslateIndex(From+NUM_SPECIAL_RECORDS, i->index)+1;
  477. if (From == lastLocateFrom && Id == lastLocateId && field->Contains(lastLocateFieldClone)==0 && index == lastLocateIndex && (i->index->locateUpToDate || pTable->GLocateUpToDate))
  478. {
  479. if (CurrentRecordIdx != lastLocateIdx) GetRecordById(lastLocateIdx-NUM_SPECIAL_RECORDS, FALSE);
  480. success = TRUE;
  481. goto nextiter_1;
  482. }
  483. if (From >= index->NEntries)
  484. {
  485. return FALSE;
  486. }
  487. compField = i->index->QuickFindField(Id, i->index->Get(From));
  488. cfV = /*(compField && compField->Type == FIELD_PRIVATE) ? ((PrivateField *)compField)->myField :*/ compField;
  489. if (field->Contains(cfV) == 0)
  490. {
  491. delete compField;
  492. n = i->index->TranslateIndex(From, index);
  493. if (CurrentRecordIdx != n) GetRecordById(n-NUM_SPECIAL_RECORDS, FALSE);
  494. CacheLastLocate(Id, From, field, i->index, n);
  495. success = TRUE;
  496. goto nextiter_1;
  497. }
  498. delete compField;
  499. p = i->index->QuickFindEx(Id, field, From, comp_mode);
  500. if (p != FIELD_NOT_FOUND)
  501. {
  502. n = (index->GetId() == Id) ? p : i->index->TranslateIndex(p, index);
  503. if (CurrentRecordIdx != n) GetRecordById(n-NUM_SPECIAL_RECORDS, FALSE);
  504. CacheLastLocate(Id, From, field, i->index, n);
  505. success = TRUE;
  506. goto nextiter_1;
  507. }
  508. }
  509. nextiter_1: // eek
  510. if (success)
  511. {
  512. if (!MatchFilters() && !Eof())
  513. {
  514. From = GetRecordId();
  515. if (nskip) (*nskip)++;
  516. }
  517. else break;
  518. }
  519. else break;
  520. }
  521. break;
  522. case COMPARE_MODE_EXACT:
  523. while (1)
  524. {
  525. success = FALSE;
  526. if (!i)
  527. {
  528. // No index for this column. Using slow locate, enumerates the database, still faster than what the user
  529. // can do since we have access to QuickFindField which only read field headers
  530. // in order to locate the field we have to compare. user could only read the entire record.
  531. if (From == FIRST_RECORD)
  532. From = NUM_SPECIAL_RECORDS;
  533. else
  534. From+=(NUM_SPECIAL_RECORDS+1);
  535. if (From == lastLocateFrom && Id == lastLocateId && field->Compare(lastLocateFieldClone)==0 && index == lastLocateIndex && (index->locateUpToDate || pTable->GLocateUpToDate))
  536. {
  537. if (CurrentRecordIdx != lastLocateIdx) GetRecordById(lastLocateIdx-NUM_SPECIAL_RECORDS, FALSE);
  538. success = TRUE;
  539. goto nextiter_2;
  540. }
  541. for (j=From;j<index->NEntries;j++)
  542. {
  543. compField = index->QuickFindField(Id, index->Get(j));
  544. cfV = /*(compField && compField->Type == FIELD_PRIVATE) ? ((PrivateField *)compField)->myField :*/ compField;
  545. if (!field->Compare(cfV))
  546. {
  547. delete compField;
  548. if (CurrentRecordIdx != j) GetRecordById(j-NUM_SPECIAL_RECORDS, FALSE);
  549. CacheLastLocate(Id, From, field, index, j);
  550. success = TRUE;
  551. goto nextiter_2;
  552. }
  553. delete compField;
  554. }
  555. success = FALSE;
  556. goto nextiter_2;
  557. }
  558. else
  559. {
  560. // Index available. Using fast locate. nfetched=log2(nrecords) for first locate, 1 more fetch per locate on same criteria
  561. int p;
  562. if (From == FIRST_RECORD) From = NUM_SPECIAL_RECORDS;
  563. else From = index->TranslateIndex(From+NUM_SPECIAL_RECORDS, i->index)+1;
  564. if (From == lastLocateFrom && Id == lastLocateId && field->Compare(lastLocateFieldClone)==0 && index == lastLocateIndex && (i->index->locateUpToDate || pTable->GLocateUpToDate))
  565. {
  566. if (CurrentRecordIdx != lastLocateIdx) GetRecordById(lastLocateIdx-NUM_SPECIAL_RECORDS, FALSE);
  567. success = TRUE;
  568. goto nextiter_2;
  569. }
  570. if (From >= index->NEntries)
  571. {
  572. return FALSE;
  573. }
  574. compField = i->index->QuickFindField(Id, i->index->Get(From));
  575. cfV = /*(compField && compField->Type == FIELD_PRIVATE) ? ((PrivateField *)compField)->myField :*/ compField;
  576. if (field->Compare(cfV) == 0)
  577. {
  578. if (compField)
  579. {
  580. delete compField;
  581. }
  582. n = i->index->TranslateIndex(From, index);
  583. if (CurrentRecordIdx != n) GetRecordById(n-NUM_SPECIAL_RECORDS, FALSE);
  584. CacheLastLocate(Id, From, field, i->index, n);
  585. success = TRUE;
  586. goto nextiter_2;
  587. }
  588. delete compField;
  589. p = i->index->QuickFindEx(Id, field, From, comp_mode);
  590. if (p != FIELD_NOT_FOUND)
  591. {
  592. n = (index->GetId() == Id) ? p : i->index->TranslateIndex(p, index);
  593. if (CurrentRecordIdx != n) GetRecordById(n-NUM_SPECIAL_RECORDS, FALSE);
  594. CacheLastLocate(Id, From, field, i->index, n);
  595. success = TRUE;
  596. goto nextiter_2;
  597. }
  598. }
  599. nextiter_2: // eek
  600. if (success)
  601. {
  602. if (!MatchFilters() && !Eof())
  603. {
  604. From = GetRecordId();
  605. if (nskip) (*nskip)++;
  606. }
  607. else break;
  608. }
  609. else break;
  610. }
  611. break;
  612. case COMPARE_MODE_STARTS:
  613. while (1)
  614. {
  615. success = FALSE;
  616. if (!i)
  617. {
  618. // No index for this column. Using slow locate, enumerates the database, still faster than what the user
  619. // can do since we have access to QuickFindField which only read field headers
  620. // in order to locate the field we have to compare. user could only read the entire record.
  621. if (From == FIRST_RECORD)
  622. From = NUM_SPECIAL_RECORDS;
  623. else
  624. From+=(NUM_SPECIAL_RECORDS+1);
  625. if (From == lastLocateFrom && Id == lastLocateId && field->Starts(lastLocateFieldClone)==0 && index == lastLocateIndex && (index->locateUpToDate || pTable->GLocateUpToDate))
  626. {
  627. if (CurrentRecordIdx != lastLocateIdx) GetRecordById(lastLocateIdx-NUM_SPECIAL_RECORDS, FALSE);
  628. success = TRUE;
  629. goto nextiter_3;
  630. }
  631. for (j=From;j<index->NEntries;j++)
  632. {
  633. compField = index->QuickFindField(Id, index->Get(j));
  634. cfV = /*(compField && compField->Type == FIELD_PRIVATE) ? ((PrivateField *)compField)->myField :*/ compField;
  635. if (!field->Starts(cfV))
  636. {
  637. if (compField)
  638. {
  639. delete compField;
  640. }
  641. if (CurrentRecordIdx != j) GetRecordById(j-NUM_SPECIAL_RECORDS, FALSE);
  642. CacheLastLocate(Id, From, field, index, j);
  643. success = TRUE;
  644. goto nextiter_3;
  645. }
  646. if (compField)
  647. {
  648. delete compField;
  649. }
  650. }
  651. success = FALSE;
  652. goto nextiter_3;
  653. }
  654. else
  655. {
  656. // Index available. Using fast locate. nfetched=log2(nrecords) for first locate, 1 more fetch per locate on same criteria
  657. int p;
  658. if (From == FIRST_RECORD) From = NUM_SPECIAL_RECORDS;
  659. else From = index->TranslateIndex(From+NUM_SPECIAL_RECORDS, i->index)+1;
  660. if (From == lastLocateFrom && Id == lastLocateId && field->Starts(lastLocateFieldClone)==0 && index == lastLocateIndex && (i->index->locateUpToDate || pTable->GLocateUpToDate))
  661. {
  662. if (CurrentRecordIdx != lastLocateIdx) GetRecordById(lastLocateIdx-NUM_SPECIAL_RECORDS, FALSE);
  663. success = TRUE;
  664. goto nextiter_3;
  665. }
  666. if (From >= index->NEntries)
  667. {
  668. return FALSE;
  669. }
  670. compField = i->index->QuickFindField(Id, i->index->Get(From));
  671. cfV = /*(compField && compField->Type == FIELD_PRIVATE) ? ((PrivateField *)compField)->myField :*/ compField;
  672. if (field->Starts(cfV) == 0)
  673. {
  674. delete compField;
  675. n = i->index->TranslateIndex(From, index);
  676. if (CurrentRecordIdx != n) GetRecordById(n-NUM_SPECIAL_RECORDS, FALSE);
  677. CacheLastLocate(Id, From, field, i->index, n);
  678. success = TRUE;
  679. goto nextiter_3;
  680. }
  681. delete compField;
  682. p = i->index->QuickFindEx(Id, field, From, comp_mode);
  683. if (p != FIELD_NOT_FOUND)
  684. {
  685. n = (index->GetId() == Id) ? p : i->index->TranslateIndex(p, index);
  686. if (CurrentRecordIdx != n) GetRecordById(n-NUM_SPECIAL_RECORDS, FALSE);
  687. CacheLastLocate(Id, From, field, i->index, n);
  688. success = TRUE;
  689. goto nextiter_3;
  690. }
  691. }
  692. nextiter_3: // eek
  693. if (success)
  694. {
  695. if (!MatchFilters() && !Eof())
  696. {
  697. From = GetRecordId();
  698. if (nskip) (*nskip)++;
  699. }
  700. else break;
  701. }
  702. else break;
  703. }
  704. break;
  705. }
  706. return success;
  707. }
  708. //---------------------------------------------------------------------------
  709. #ifdef _WIN32
  710. void Scanner::DeleteFieldByName(const wchar_t *name)
  711. {
  712. ColumnField *header = pTable->GetColumnByName(name);
  713. if (header)
  714. {
  715. unsigned char Idx = header->ID;
  716. DeleteFieldById(Idx);
  717. }
  718. return;
  719. }
  720. #else
  721. void Scanner::DeleteFieldByName(CFStringRef name)
  722. {
  723. ColumnField *header = pTable->GetColumnByName(name);
  724. if (header)
  725. {
  726. unsigned char Idx = header->ID;
  727. DeleteFieldById(Idx);
  728. }
  729. return;
  730. }
  731. #endif
  732. //---------------------------------------------------------------------------
  733. void Scanner::DeleteFieldById(unsigned char Id)
  734. {
  735. Field *field = CurrentRecord->GetField(Id);
  736. if (!field) return;
  737. CurrentRecord->RemoveField(field);
  738. }
  739. //---------------------------------------------------------------------------
  740. void Scanner::DeleteField(Field *field)
  741. {
  742. if (!field) return;
  743. CurrentRecord->RemoveField(field);
  744. }
  745. static bool TotalSizeCalculator(Record *record, Field *f, void *context)
  746. {
  747. size_t *totalSize = (size_t *)context;
  748. *totalSize += f->GetTotalSize();
  749. return true;
  750. }
  751. //---------------------------------------------------------------------------
  752. float Scanner::FragmentationLevel(void)
  753. {
  754. int oldP = GetRecordId();
  755. int i;
  756. size_t totalSize=0;
  757. if (CurrentRecord)
  758. {
  759. if (CurrentRecord) CurrentRecord->Release();
  760. CurrentRecord = NULL;
  761. CurrentRecordIdx = 0;
  762. }
  763. for (i=0;i<index->NEntries;i++)
  764. {
  765. Record *r = GetRecord(i);
  766. if (r)
  767. {
  768. r->WalkFields(TotalSizeCalculator, &totalSize);
  769. r->Release();
  770. }
  771. }
  772. GetRecordById(oldP);
  773. Vfseek(pTable->Handle, 0, SEEK_END);
  774. return (((float)(Vftell(pTable->Handle)-strlen(__TABLE_SIGNATURE__)) / (float)totalSize) - 1) * 100;
  775. }
  776. //---------------------------------------------------------------------------
  777. int Scanner::GetRecordsCount(void)
  778. {
  779. if (index)
  780. return index->NEntries-NUM_SPECIAL_RECORDS;
  781. else
  782. return 0;
  783. }
  784. //---------------------------------------------------------------------------
  785. BOOL Scanner::SetWorkingIndexById(unsigned char Id)
  786. {
  787. IndexField *indx = pTable->GetIndexById(Id);
  788. int v = CurrentRecordIdx;
  789. if (indx)
  790. {
  791. if (!Eof() && !Bof())
  792. {
  793. IndexField *f = index->SecIndex;
  794. v = index->GetCooperative(CurrentRecordIdx);
  795. while (f != indx)
  796. {
  797. v = f->index->GetCooperative(v);
  798. f = f->index->SecIndex;
  799. }
  800. }
  801. index = indx->index;
  802. CurrentRecordIdx = v;
  803. GetCurrentRecord();
  804. }
  805. return (indx != NULL);
  806. }
  807. //---------------------------------------------------------------------------
  808. #ifdef _WIN32
  809. BOOL Scanner::SetWorkingIndexByName(const wchar_t *desc)
  810. {
  811. IndexField *indx = pTable->GetIndexByName(desc);
  812. if (indx)
  813. return SetWorkingIndexById(indx->ID);
  814. else
  815. return SetWorkingIndexById(-1);
  816. }
  817. #else
  818. BOOL Scanner::SetWorkingIndexByName(CFStringRef desc)
  819. {
  820. IndexField *indx = pTable->GetIndexByName(desc);
  821. if (indx)
  822. return SetWorkingIndexById(indx->ID);
  823. else
  824. return SetWorkingIndexById(-1);
  825. }
  826. #endif
  827. //---------------------------------------------------------------------------
  828. void Scanner::IndexModified(void)
  829. {
  830. iModified = TRUE;
  831. }
  832. //---------------------------------------------------------------------------
  833. void Scanner::ClearDirtyBit(void)
  834. {
  835. iModified = FALSE;
  836. }
  837. //---------------------------------------------------------------------------
  838. Table *Scanner::GetTable(void)
  839. {
  840. return pTable;
  841. }
  842. //---------------------------------------------------------------------------
  843. #ifdef _WIN32
  844. ColumnField *Scanner::GetColumnByName(const wchar_t *FieldName)
  845. {
  846. return pTable->GetColumnByName(FieldName);
  847. }
  848. #else
  849. ColumnField *Scanner::GetColumnByName(CFStringRef FieldName)
  850. {
  851. return pTable->GetColumnByName(FieldName);
  852. }
  853. #endif
  854. //---------------------------------------------------------------------------
  855. ColumnField *Scanner::GetColumnById(unsigned char Idx)
  856. {
  857. return pTable->GetColumnById(Idx);
  858. }
  859. //---------------------------------------------------------------------------
  860. #ifdef _WIN32
  861. int Scanner::AddFilterByName(const wchar_t *name, Field *Data, unsigned char Op)
  862. {
  863. ColumnField *f = pTable->GetColumnByName(name);
  864. if (f)
  865. return AddFilterById(f->GetFieldId(), Data, Op);
  866. return ADDFILTER_FAILED;
  867. }
  868. #else
  869. int Scanner::AddFilterByName(CFStringRef name, Field *Data, unsigned char Op)
  870. {
  871. ColumnField *f = pTable->GetColumnByName(name);
  872. if (f)
  873. return AddFilterById(f->GetFieldId(), Data, Op);
  874. return ADDFILTER_FAILED;
  875. }
  876. #endif
  877. //---------------------------------------------------------------------------
  878. int Scanner::AddFilterById(unsigned char Id, Field *Data, unsigned char Op)
  879. {
  880. ColumnField *f = pTable->GetColumnById(Id);
  881. if (f)
  882. {
  883. Filter *filter = new Filter(Data, f->GetFieldId(), Op);
  884. FilterList.AddEntry(filter, TRUE);
  885. }
  886. else
  887. return ADDFILTER_FAILED;
  888. if (in_query_parser) return 1;
  889. return CheckFilters();
  890. }
  891. //---------------------------------------------------------------------------
  892. int Scanner::AddFilterOp(unsigned char Op)
  893. {
  894. Filter *filter = new Filter(Op);
  895. FilterList.AddEntry(filter, TRUE);
  896. if (in_query_parser) return 1;
  897. return CheckFilters();
  898. }
  899. //---------------------------------------------------------------------------
  900. Filter *Scanner::GetLastFilter(void)
  901. {
  902. if (FilterList.GetNElements() == 0) return NULL;
  903. return (Filter *)FilterList.GetFoot();
  904. }
  905. //---------------------------------------------------------------------------
  906. void Scanner::RemoveFilters(void)
  907. {
  908. last_query_failed = FALSE;
  909. while (FilterList.GetNElements() > 0)
  910. FilterList.RemoveEntry(FilterList.GetHead());
  911. FiltersOK = FALSE;
  912. }
  913. //---------------------------------------------------------------------------
  914. BOOL Scanner::CheckFilters(void)
  915. {
  916. int f=0;
  917. FiltersOK = FALSE;
  918. if (FilterList.GetNElements() == 0) // Should never happen
  919. return FILTERS_INVALID;
  920. Filter *filter = (Filter *)FilterList.GetHead();
  921. while (filter)
  922. {
  923. if (f == 256) return FILTERS_INVALID;
  924. int op = filter->GetOp();
  925. if (filter->Data() || op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
  926. f++;
  927. else
  928. {
  929. if (op != FILTER_NOT)
  930. f--;
  931. }
  932. if (f == 0) return FILTERS_INVALID;
  933. filter = (Filter *)filter->GetNext();
  934. }
  935. if (f == 1)
  936. {
  937. FiltersOK = TRUE;
  938. return FILTERS_COMPLETE;
  939. }
  940. return FILTERS_INCOMPLETE;
  941. }
  942. //---------------------------------------------------------------------------
  943. static bool EmptyMeansTrue(int op)
  944. {
  945. return op == FILTER_ISEMPTY
  946. || op == FILTER_NOTEQUALS
  947. || op == FILTER_NOTCONTAINS;
  948. }
  949. //---------------------------------------------------------------------------
  950. bool Scanner::MatchFilter(Filter *filter)
  951. {
  952. Field *field = GetFieldById(filter->GetId());
  953. int op = filter->GetOp();
  954. Field * f = filter->Data();
  955. /* old behaviour
  956. if (!field)
  957. return EmptyMeansTrue(op);
  958. else if (op == FILTER_ISEMPTY)
  959. return FALSE;
  960. else if (op == FILTER_ISNOTEMPTY)
  961. return TRUE;
  962. */
  963. // new behaviour
  964. if (!field)
  965. {
  966. // if field is empty and we're doing an equals op, match if f is also empty
  967. if (op == FILTER_EQUALS && f) return f->ApplyFilter(f,FILTER_ISEMPTY);
  968. if (op == FILTER_NOTEQUALS && f) return f->ApplyFilter(f,FILTER_ISNOTEMPTY);
  969. return EmptyMeansTrue(op);
  970. }
  971. // no need to check for op == FILTER_ISEMPTY, the fields now handle that
  972. return field->ApplyFilter(f, op);
  973. }
  974. struct Results
  975. {
  976. void operator=(bool _val)
  977. {
  978. calculated=true;
  979. value=_val;
  980. }
  981. bool Calc(Scanner *scanner)
  982. {
  983. if (!calculated)
  984. {
  985. #if 0 /* if we want to do field-to-field comparisons */
  986. Field *compare_column = filter->Data();
  987. if (compare_column && compare_column->Type == FIELD_COLUMN)
  988. {
  989. Field *field = scanner->GetFieldById(filter->GetId());
  990. Field *compare_field = scanner->GetFieldById(compare_column->ID);
  991. int op = filter->GetOp();
  992. value = field->ApplyFilter(compare_field, op);
  993. calculated=true;
  994. return value;
  995. }
  996. #endif
  997. value = scanner->MatchFilter(filter);
  998. calculated=true;
  999. }
  1000. return value;
  1001. }
  1002. void SetFilter(Filter *_filter)
  1003. {
  1004. calculated=false;
  1005. filter=_filter;
  1006. }
  1007. private:
  1008. bool value;
  1009. bool calculated;
  1010. Filter *filter;
  1011. };
  1012. bool Scanner::MatchSearch(const SearchFields &fields, StringField *search_field)
  1013. {
  1014. for (SearchFields::const_iterator itr = fields.begin(); itr != fields.end();itr++)
  1015. {
  1016. Field *f = GetFieldById(*itr);
  1017. if (f && f->Contains(search_field))
  1018. {
  1019. return true;
  1020. }
  1021. }
  1022. return false; // if none of the fields matched the search strings, then bail out
  1023. }
  1024. bool Scanner::MatchSearches()
  1025. {
  1026. // no search means always match
  1027. if (search_strings.empty())
  1028. return true;
  1029. Scanner *s = pTable->GetDefaultScanner(); // kind of a hack but gets around private member variables
  1030. const SearchFields &fields = s->search_fields;
  1031. if (search_any)
  1032. {
  1033. for (SearchStrings::const_iterator field_itr=search_strings.begin();field_itr!=search_strings.end();field_itr++)
  1034. {
  1035. StringField *search_field = *field_itr;
  1036. if (MatchSearch(fields, search_field) == true)
  1037. return true;
  1038. }
  1039. return false; // we'll only get here if no search strings matched
  1040. }
  1041. else
  1042. { // normal search (subsequent terms do further filtering
  1043. for (SearchStrings::const_iterator field_itr=search_strings.begin();field_itr!=search_strings.end();field_itr++)
  1044. {
  1045. StringField *search_field = *field_itr;
  1046. if (MatchSearch(fields, search_field) == false)
  1047. return false;
  1048. }
  1049. return true; // we'll only get here if all search strings have a match
  1050. }
  1051. }
  1052. //---------------------------------------------------------------------------
  1053. bool Scanner::MatchFilters(void)
  1054. {
  1055. if (!FiltersOK || FilterList.GetNElements() == 0)
  1056. {
  1057. // return MatchJoins();
  1058. return true;
  1059. }
  1060. //if (!MatchSearches())
  1061. //return false;
  1062. ResultPtr = 0;
  1063. Results resultTable[256];
  1064. Filter *filter = (Filter *)FilterList.GetHead();
  1065. while (filter)
  1066. {
  1067. if (ResultPtr == 256)
  1068. {
  1069. FiltersOK = FALSE; // Should never happen, case already discarded by CheckFilters
  1070. return TRUE;
  1071. }
  1072. int op = filter->GetOp();
  1073. if (filter->Data() || op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
  1074. resultTable[ResultPtr++].SetFilter(filter);
  1075. else
  1076. switch (op)
  1077. {
  1078. case FILTER_AND:
  1079. if (ResultPtr > 1)
  1080. resultTable[ResultPtr-2] = resultTable[ResultPtr-2].Calc(this) && resultTable[ResultPtr-1].Calc(this);
  1081. ResultPtr--;
  1082. break;
  1083. case FILTER_OR:
  1084. if (ResultPtr > 1)
  1085. resultTable[ResultPtr-2] = resultTable[ResultPtr-2].Calc(this) || resultTable[ResultPtr-1].Calc(this);
  1086. ResultPtr--;
  1087. break;
  1088. case FILTER_NOT:
  1089. if (ResultPtr > 0)
  1090. resultTable[ResultPtr-1] = !resultTable[ResultPtr-1].Calc(this);
  1091. break;
  1092. }
  1093. filter = (Filter *)filter->GetNext();
  1094. }
  1095. if (ResultPtr != 1) // Should never happen, case already discarded by CheckFilters
  1096. {
  1097. FiltersOK = FALSE;
  1098. return TRUE;
  1099. }
  1100. if (!resultTable[0].Calc(this)) return 0;
  1101. // return MatchJoins();
  1102. //return FALSE;
  1103. return MatchSearches();
  1104. }
  1105. void Scanner::WalkFilters(FilterWalker callback, void *context)
  1106. {
  1107. if (callback)
  1108. {
  1109. LinkedListEntry *entry = FilterList.GetHead();
  1110. while (entry)
  1111. {
  1112. if (!callback(this, (Filter *)entry, context))
  1113. break;
  1114. entry = entry->Next;
  1115. }
  1116. }
  1117. }
  1118. #ifdef _WIN32
  1119. void Scanner::Search(const wchar_t *search_string)
  1120. {
  1121. // first, clear existing search terms
  1122. for (SearchStrings::iterator itr=search_strings.begin();itr!=search_strings.end();itr++)
  1123. {
  1124. delete *itr;
  1125. }
  1126. search_strings.clear();
  1127. if (*search_string == L'*' && search_string[1] == L' ')
  1128. {
  1129. search_any=true;
  1130. search_string += 2;
  1131. }
  1132. else
  1133. search_any=false;
  1134. if (search_string)
  1135. {
  1136. while (*search_string)
  1137. {
  1138. while (*search_string && (*search_string == ' ' || *search_string == '\t'))
  1139. search_string++;
  1140. const wchar_t *end=search_string;
  1141. wchar_t c = *search_string;
  1142. if (c == L'\"') // a quoted string
  1143. {
  1144. end++;
  1145. search_string++;
  1146. while (*end && *end != '\"')
  1147. end++;
  1148. if (*search_string) // make sure it's not just a quote by itself
  1149. {
  1150. if (*end == 0) // no terminating quotes
  1151. {
  1152. wchar_t *search_term = ndestring_wcsndup(search_string, end-search_string);
  1153. search_strings.push_back(new StringField(search_term, STRING_IS_NDESTRING));
  1154. }
  1155. else if (end > (search_string+1)) // at least one character in the quotes
  1156. {
  1157. wchar_t *search_term = ndestring_wcsndup(search_string, end-search_string-1);
  1158. search_strings.push_back(new StringField(search_term, STRING_IS_NDESTRING));
  1159. end++;
  1160. }
  1161. }
  1162. search_string=end;
  1163. }
  1164. else if (c)
  1165. {
  1166. while (*end && *end != ' ' && *end != '\t')
  1167. end++;
  1168. wchar_t *search_term = ndestring_wcsndup(search_string, end-search_string-1);
  1169. search_strings.push_back(new StringField(search_term, STRING_IS_NDESTRING));
  1170. }
  1171. }
  1172. }
  1173. }
  1174. #endif