Scanner.cpp 31 KB

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