1
0

Scanner.cpp 32 KB

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