rtlnewkey.cpp 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121
  1. /*##############################################################################
  2. you may not use this file except in compliance with the License.
  3. You may obtain a copy of the License at
  4. http://www.apache.org/licenses/LICENSE-2.0
  5. Unless required by applicable law or agreed to in writing, software
  6. distributed under the License is distributed on an "AS IS" BASIS,
  7. WITHOUT WARRANTIES OR getValue OF ANY KIND, either express or implied.
  8. See the License for the specific language governing permissions and
  9. limitations under the License.
  10. ############################################################################## */
  11. #include <initializer_list>
  12. #include "jlib.hpp"
  13. #include "jdebug.hpp"
  14. #include "jsort.hpp"
  15. #include "jexcept.hpp"
  16. #include "rtlnewkey.hpp"
  17. #include "eclrtl_imp.hpp"
  18. #include "rtlrecord.hpp"
  19. #include "rtlkey.hpp"
  20. #include "rtlnewkey.hpp"
  21. #include "rtlfield.hpp"
  22. #include "rtldynfield.hpp"
  23. /*
  24. * Read a single quoted string from in until the terminating quote is found
  25. *
  26. * @param out The resulting string with embedded escaped quote characters resolved.
  27. * @param in A reference to the start of the string. Updated to point to the end of the string.
  28. *
  29. */
  30. static void readString(StringBuffer &out, const char * &in)
  31. {
  32. const char *start = in;
  33. // Find terminating quote, skipping any escaped ones
  34. for (;;)
  35. {
  36. char c = *in++;
  37. if (!c)
  38. throw MakeStringException(0, "Invalid filter - missing closing '");
  39. if (c=='\'')
  40. break;
  41. if (c=='\\')
  42. c = *in++;
  43. }
  44. StringBuffer errmsg;
  45. unsigned errpos;
  46. if (!checkUnicodeLiteral(start, in-start-1, errpos, errmsg))
  47. throw makeStringExceptionV(0, "Invalid filter - %s", errmsg.str());
  48. rtlDataAttr temp;
  49. size32_t newlen = 0; // NOTE - this will be in codepoints, not bytes
  50. rtlCodepageToUtf8XUnescape(newlen, temp.refstr(), in-start-1, start, "UTF-8");
  51. size32_t newsize = rtlUtf8Size(newlen, temp.getstr());
  52. out.append(newsize, temp.getstr());
  53. }
  54. /*
  55. * Read a single string from in until a matching terminator is found
  56. *
  57. * @param out The resulting string.
  58. * @param in A reference to the start of the string. Updated to point to the end of the string.
  59. * @param term Characters that can serve as terminators.
  60. */
  61. static void readUntilTerminator(StringBuffer & out, const char * & in, const char * terminators)
  62. {
  63. const char * start = in;
  64. const char * pbrk = strpbrk(start, terminators);
  65. if (!pbrk)
  66. throw makeStringExceptionV(0, "Invalid filter - expected terminator '%s'", terminators);
  67. out.append(pbrk - start, start);
  68. in = pbrk;
  69. }
  70. void readFieldFromFieldFilter(StringBuffer & fieldText, const char * & src)
  71. {
  72. readUntilTerminator(fieldText, src, "=*:");
  73. }
  74. void deserializeSet(ISetCreator & creator, const char * filter)
  75. {
  76. while (*filter)
  77. {
  78. char startRange = *filter++;
  79. if (startRange != '(' && startRange != '[')
  80. throw MakeStringException(0, "Invalid filter string: expected [ or ( at start of range");
  81. StringBuffer upperString, lowerString;
  82. if (*filter=='\'')
  83. {
  84. filter++;
  85. readString(lowerString, filter);
  86. }
  87. else
  88. readUntilTerminator(lowerString, filter, ",])");
  89. if (*filter == ',')
  90. {
  91. filter++;
  92. if (*filter=='\'')
  93. {
  94. filter++;
  95. readString(upperString, filter);
  96. }
  97. else
  98. readUntilTerminator(upperString, filter, "])");
  99. }
  100. else
  101. upperString.set(lowerString);
  102. char endRange = *filter++;
  103. if (endRange != ')' && endRange != ']')
  104. throw MakeStringException(0, "Invalid filter string: expected ] or ) at end of range");
  105. if (*filter==',')
  106. filter++;
  107. else if (*filter)
  108. throw MakeStringException(0, "Invalid filter string: expected , between ranges");
  109. TransitionMask lowerMask = (startRange == '(') ? CMPgt : CMPge;
  110. TransitionMask upperMask = (endRange == ')') ? CMPlt : CMPle;
  111. creator.addRange(lowerMask, lowerString, upperMask, upperString);
  112. }
  113. }
  114. // A class wrapped for adding ranges to IValueSets
  115. class ValueSetCreator : implements ISetCreator
  116. {
  117. public:
  118. ValueSetCreator(IValueSet & _set) : set(_set) {}
  119. virtual void addRange(TransitionMask lowerMask, const StringBuffer & lowerString, TransitionMask upperMask, const StringBuffer & upperString) override
  120. {
  121. Owned<IValueTransition> lower = lowerString ? set.createUtf8Transition(lowerMask, rtlUtf8Length(lowerString.length(), lowerString), lowerString) : nullptr;
  122. Owned<IValueTransition> upper = upperString ? set.createUtf8Transition(upperMask, rtlUtf8Length(upperString.length(), upperString), upperString) : nullptr;
  123. set.addRange(lower, upper);
  124. }
  125. protected:
  126. IValueSet & set;
  127. };
  128. void deserializeSet(IValueSet & set, const char * filter)
  129. {
  130. ValueSetCreator creator(set);
  131. deserializeSet(creator, filter);
  132. }
  133. void getStretchedValue(MemoryBuffer & target, const RtlTypeInfo & newType, const RtlTypeInfo & oldType, const byte * value)
  134. {
  135. MemoryBufferBuilder builder(target, 0);
  136. translateScalar(builder, 0, nullptr, newType, oldType, value);
  137. }
  138. //---------------------------------------------------------------------------------------------------------------------
  139. /*
  140. * This class represents a value and a comparison condition and is used for representing ranges of values
  141. *
  142. * A lowerbound will always have the CMPgt bit set in the mask, and upper bound will have CMPlt set in the mask.
  143. * The value is always represented in the same way as a field of that type would be in a record.
  144. */
  145. class ValueTransition : implements CInterfaceOf<IValueTransition>
  146. {
  147. public:
  148. ValueTransition(TransitionMask _mask, const RtlTypeInfo & type, const void *_value)
  149. {
  150. mask = _mask;
  151. dbgassertex(_value || isMinimum() || isMaximum());
  152. if (_value)
  153. {
  154. size32_t size = type.size((const byte *)_value, nullptr);
  155. value.allocateN(size, false);
  156. memcpy(value, _value, size);
  157. }
  158. }
  159. ValueTransition(const RtlTypeInfo & type, MemoryBuffer & in)
  160. {
  161. byte inmask;
  162. in.read(inmask);
  163. if (!(inmask & CMPnovalue))
  164. {
  165. mask = (TransitionMask)inmask;
  166. size32_t size = type.size(in.readDirect(0), nullptr);
  167. value.allocateN(size, false);
  168. in.read(size, value);
  169. }
  170. else
  171. {
  172. mask = (TransitionMask)(inmask & ~CMPnovalue);
  173. }
  174. }
  175. ValueTransition(TransitionMask _mask) : mask(_mask)
  176. {
  177. dbgassertex(isMaximum() || isMinimum());
  178. }
  179. bool equals(const RtlTypeInfo & type, const ValueTransition & other) const
  180. {
  181. if (mask != other.mask)
  182. return false;
  183. if (value && other.value)
  184. {
  185. return type.compare(value, other.value) == 0;
  186. }
  187. else
  188. return !value && !other.value;
  189. }
  190. MemoryBuffer & serialize(const RtlTypeInfo & type, MemoryBuffer & out) const
  191. {
  192. byte outmask = mask;
  193. if (value)
  194. {
  195. size32_t size = type.size(value, nullptr);
  196. out.append(outmask);
  197. out.append(size, value);
  198. }
  199. else
  200. {
  201. outmask |= CMPnovalue;
  202. out.append(outmask);
  203. }
  204. return out;
  205. }
  206. int compareRaw(const RtlTypeInfo & type, const byte * field) const
  207. {
  208. if (!value)
  209. {
  210. if (mask & CMPmin)
  211. return +1;
  212. if (mask & CMPmax)
  213. return -1;
  214. }
  215. return type.compare(field, value.get());
  216. }
  217. int compare(const RtlTypeInfo & type, const byte * field) const
  218. {
  219. int c = compareRaw(type, field);
  220. if (c == 0)
  221. {
  222. if (mask & CMPeq)
  223. return 0;
  224. //Lower bound
  225. if (mask & CMPgt)
  226. return -1;
  227. //Check against upper bound
  228. if (mask & CMPlt)
  229. return +1;
  230. throwUnexpected();
  231. }
  232. return c;
  233. }
  234. int compareRaw(const RtlTypeInfo & type, const ValueTransition & other) const
  235. {
  236. if (!value || !other.value)
  237. {
  238. if (isMinimum())
  239. return other.isMinimum() ? 0 : -1;
  240. if (isMaximum())
  241. return other.isMaximum() ? 0 : +1;
  242. if (other.isMinimum())
  243. return +1;
  244. if (other.isMaximum())
  245. return -1;
  246. throwUnexpected();
  247. }
  248. return type.compare(value, other.value);
  249. }
  250. StringBuffer & describe(const RtlTypeInfo & type, StringBuffer & out) const
  251. {
  252. if (mask & CMPgt)
  253. {
  254. if (mask & CMPeq)
  255. out.append("[");
  256. else
  257. out.append("(");
  258. }
  259. if (value)
  260. {
  261. size32_t len;
  262. rtlDataAttr text;
  263. type.getUtf8(len, text.refstr(), value);
  264. size32_t size = rtlUtf8Size(len, text.getstr());
  265. if (type.isNumeric())
  266. {
  267. out.append(size, text.getstr());
  268. }
  269. else
  270. {
  271. out.append("'");
  272. appendUtf8AsECL(out, size, text.getstr());
  273. out.append("'");
  274. }
  275. }
  276. if (mask & CMPlt)
  277. {
  278. if (mask & CMPeq)
  279. out.append("]");
  280. else
  281. out.append(")");
  282. }
  283. return out;
  284. }
  285. bool isPreviousBound(const RtlTypeInfo & type, const ValueTransition & other) const
  286. {
  287. if (isInclusiveBound() || other.isInclusiveBound())
  288. {
  289. if (compareRaw(type, other) == 0)
  290. return true;
  291. }
  292. if (isInclusiveBound() && other.isInclusiveBound())
  293. {
  294. //MORE: if isPreviousValue(other)
  295. //if (oneless(hival, t.getValue()))
  296. }
  297. return false;
  298. }
  299. //If this transition isn't shared then modify it directly, otherwise clone. Always return a linked object.
  300. ValueTransition * modifyTransition(const RtlTypeInfo & type, TransitionMask newMask)
  301. {
  302. assertex(value);
  303. if (IsShared())
  304. {
  305. return new ValueTransition(newMask, type, value);
  306. }
  307. else
  308. {
  309. mask = newMask;
  310. return LINK(this);
  311. }
  312. }
  313. ValueTransition * modifyInverse(const RtlTypeInfo & type)
  314. {
  315. TransitionMask newMask = (TransitionMask)(mask ^ (CMPgt|CMPlt|CMPeq));
  316. return modifyTransition(type, newMask);
  317. }
  318. ValueTransition * cast(const RtlTypeInfo & newType, const RtlTypeInfo & oldType)
  319. {
  320. if (!value)
  321. return LINK(this);
  322. MemoryBuffer resized;
  323. getStretchedValue(resized, newType, oldType, value);
  324. MemoryBuffer recast;
  325. getStretchedValue(recast, oldType, newType, resized.bytes());
  326. TransitionMask newMask = mask;
  327. if (oldType.compare(value, recast.bytes()) != 0)
  328. {
  329. // x >= 'ab' becomes x > 'a' => clear the equal item
  330. // x < 'ab' becomes x <= 'a' => set the equal item
  331. if (newMask & CMPlt)
  332. newMask |= CMPeq;
  333. else if (newMask & CMPgt)
  334. newMask &= ~CMPeq;
  335. }
  336. return new ValueTransition(newMask, newType, resized.toByteArray());
  337. }
  338. bool isLowerBound() const { return (mask & CMPgt) != 0; }
  339. bool isUpperBound() const { return (mask & CMPlt) != 0; }
  340. bool isInclusiveBound() const { return (mask & CMPeq) != 0; }
  341. bool isMinimum() const { return (mask & CMPmin) != 0; }
  342. bool isMaximum() const { return (mask & CMPmax) != 0; }
  343. private:
  344. TransitionMask mask;
  345. OwnedMalloc<byte> value;
  346. };
  347. typedef IArrayOf<ValueTransition> ValueTransitionArray;
  348. //---------------------------------------------------------------------------------------------------------------------
  349. /*
  350. * The ValueSet class represents a set of ranges of values.
  351. *
  352. * The transitions always come in pairs - an upper and lower bound. Each bound can be inclusive or exclusive.
  353. */
  354. class ValueSet : public CInterfaceOf<IValueSet>
  355. {
  356. public:
  357. ValueSet(const RtlTypeInfo & _type) : type(_type)
  358. {
  359. }
  360. ValueSet(const RtlTypeInfo & _type, MemoryBuffer & in) : type(_type)
  361. {
  362. unsigned cnt;
  363. in.readPacked(cnt);
  364. for (unsigned i = 0; i < cnt; i++)
  365. transitions.append(*new ValueTransition(type, in));
  366. }
  367. // Methods for creating a value set
  368. virtual IValueTransition * createTransition(TransitionMask mask, unsigned __int64 value) const override
  369. {
  370. MemoryBuffer buff;
  371. MemoryBufferBuilder builder(buff, 0);
  372. type.buildInt(builder, 0, nullptr, value);
  373. return new ValueTransition(mask, type, buff.toByteArray());
  374. }
  375. virtual IValueTransition * createStringTransition(TransitionMask mask, size32_t len, const char * value) const override
  376. {
  377. MemoryBuffer buff;
  378. MemoryBufferBuilder builder(buff, 0);
  379. type.buildString(builder, 0, nullptr, len, value);
  380. return new ValueTransition(mask, type, buff.toByteArray());
  381. }
  382. virtual IValueTransition * createUtf8Transition(TransitionMask mask, size32_t len, const char * value) const override
  383. {
  384. MemoryBuffer buff;
  385. MemoryBufferBuilder builder(buff, 0);
  386. type.buildUtf8(builder, 0, nullptr, len, value);
  387. return new ValueTransition(mask, type, buff.toByteArray());
  388. }
  389. virtual void addRange(IValueTransition * _lower, IValueTransition * _upper) override
  390. {
  391. ValueTransition * lower = static_cast<ValueTransition *>(_lower);
  392. ValueTransition * upper = static_cast<ValueTransition *>(_upper);
  393. Owned<ValueTransition> minBound;
  394. Owned<ValueTransition> maxBound;
  395. if (!lower)
  396. {
  397. minBound.setown(new ValueTransition(CMPminmask));
  398. lower = minBound;
  399. }
  400. if (!upper)
  401. {
  402. maxBound.setown(new ValueTransition(CMPmaxmask));
  403. upper = maxBound;
  404. }
  405. if (!lower->isLowerBound() || !upper->isUpperBound())
  406. throw MakeStringException(1, "Invalid range bounds");
  407. //If lower > upper then it is an empty range
  408. int rc = lower->compareRaw(type, *upper);
  409. if (rc > 0)
  410. return;
  411. //Check for exclusive ranges for a single value
  412. if (rc == 0)
  413. {
  414. if (!lower->isInclusiveBound() || !upper->isInclusiveBound())
  415. return;
  416. }
  417. // binchop to find last transition > val...
  418. unsigned int low = 0;
  419. unsigned high = transitions.ordinality();
  420. while (low < high)
  421. {
  422. unsigned mid = low + (high - low) / 2;
  423. int rc = lower->compareRaw(type, transitions.item(mid));
  424. if (rc <= 0)
  425. high = mid;
  426. else
  427. low = mid+1;
  428. }
  429. unsigned idx;
  430. if (transitions.isItem(low))
  431. {
  432. ValueTransition & next = transitions.item(low);
  433. if (lower->compareRaw(type, next) == 0)
  434. {
  435. if (next.isLowerBound())
  436. {
  437. if (!next.isInclusiveBound() && lower->isInclusiveBound())
  438. transitions.replace(*LINK(lower), low);
  439. idx = low+1;
  440. }
  441. else
  442. {
  443. if (next.isInclusiveBound() || lower->isInclusiveBound())
  444. {
  445. transitions.remove(low);
  446. idx = low;
  447. }
  448. else
  449. {
  450. transitions.add(*LINK(lower), low+1);
  451. idx = low + 2;
  452. }
  453. }
  454. }
  455. else
  456. {
  457. if (next.isLowerBound())
  458. {
  459. transitions.add(*LINK(lower), low);
  460. idx = low + 1;
  461. }
  462. else
  463. {
  464. //previous must exist and be lower => ignore this one
  465. idx = low;
  466. }
  467. }
  468. }
  469. else
  470. {
  471. transitions.append(*LINK(lower));
  472. transitions.append(*LINK(upper));
  473. return;
  474. }
  475. //Walk the remaining transitions until you find one that is higher than the current one (or run out)
  476. while (transitions.isItem(idx))
  477. {
  478. ValueTransition & cur = transitions.item(idx);
  479. int rc = cur.compareRaw(type, *upper);
  480. if (rc > 0)
  481. {
  482. if (cur.isUpperBound())
  483. return;
  484. break;
  485. }
  486. if (rc == 0)
  487. {
  488. if (cur.isUpperBound())
  489. {
  490. if (!cur.isInclusiveBound() && upper->isInclusiveBound())
  491. transitions.replace(*LINK(upper), idx);
  492. return;
  493. }
  494. //Upper value matches the next lower bound - could either remove the next item if either is inclusive, otherwise add
  495. if (cur.isInclusiveBound() || upper->isInclusiveBound())
  496. {
  497. transitions.remove(idx);
  498. return;
  499. }
  500. break;
  501. }
  502. transitions.remove(idx);
  503. }
  504. if (transitions.isItem(idx))
  505. {
  506. ValueTransition & cur = transitions.item(idx);
  507. assertex(cur.isLowerBound());
  508. if (upper->isPreviousBound(type, cur))
  509. {
  510. transitions.remove(idx);
  511. return;
  512. }
  513. }
  514. transitions.add(*LINK(upper), idx);
  515. }
  516. virtual void addAll() override
  517. {
  518. reset();
  519. addRange(nullptr, nullptr);
  520. }
  521. virtual void killRange(IValueTransition * _lower, IValueTransition * _upper) override
  522. {
  523. ValueTransition * lower = static_cast<ValueTransition *>(_lower);
  524. ValueTransition * upper = static_cast<ValueTransition *>(_upper);
  525. Owned<ValueTransition> minBound;
  526. Owned<ValueTransition> maxBound;
  527. if (!lower)
  528. {
  529. minBound.setown(new ValueTransition(CMPminmask));
  530. lower = minBound;
  531. }
  532. if (!upper)
  533. {
  534. maxBound.setown(new ValueTransition(CMPmaxmask));
  535. upper = maxBound;
  536. }
  537. if (!lower->isLowerBound() || !upper->isUpperBound())
  538. throw MakeStringException(1, "Invalid range bounds");
  539. //If lower > upper then it is an empty range
  540. int rc = lower->compareRaw(type, *upper);
  541. if (rc > 0)
  542. return;
  543. //Check for exclusive ranges for a single value
  544. if (rc == 0)
  545. {
  546. if (!lower->isInclusiveBound() || !upper->isInclusiveBound())
  547. return;
  548. }
  549. // binchop to find last transition > val...
  550. unsigned int low = 0;
  551. unsigned high = transitions.ordinality();
  552. while (low < high)
  553. {
  554. unsigned mid = low + (high - low) / 2;
  555. int rc = lower->compareRaw(type, transitions.item(mid));
  556. if (rc <= 0)
  557. high = mid;
  558. else
  559. low = mid+1;
  560. }
  561. unsigned idx = low;
  562. if (!transitions.isItem(low))
  563. return;
  564. //First terminate any set that overlaps the start of the range
  565. ValueTransition & next = transitions.item(low);
  566. if (lower->compareRaw(type, next) == 0)
  567. {
  568. if (next.isLowerBound())
  569. {
  570. // Range [x..y] remove [x..]
  571. if (!lower->isInclusiveBound() && next.isInclusiveBound())
  572. {
  573. //[x,y] - (x,z) = [x],{ (x,y)-(x,z)
  574. transitions.add(*lower->modifyTransition(type, CMPle), low+1);
  575. idx = low+2;
  576. }
  577. else
  578. transitions.remove(low);
  579. }
  580. else
  581. {
  582. //[x..y]-[y..z) -> [x..y)
  583. if (lower->isInclusiveBound() && next.isInclusiveBound())
  584. {
  585. //Convert to an exclusive bound. This must be different from the lower bound
  586. //(otherwise it would have matched that bound 1st)
  587. ValueTransition * newTransition = next.modifyTransition(type, CMPlt);
  588. transitions.replace(*newTransition, low);
  589. idx = low+1;
  590. }
  591. else
  592. idx = low+1;
  593. }
  594. }
  595. else
  596. {
  597. if (next.isUpperBound())
  598. {
  599. transitions.add(*lower->modifyTransition(type, lower->isInclusiveBound() ? CMPlt : CMPle), idx);
  600. idx++;
  601. }
  602. }
  603. //Walk the remaining transitions until you find one that is higher than the current one (or run out)
  604. while (transitions.isItem(idx))
  605. {
  606. ValueTransition & cur = transitions.item(idx);
  607. int rc = cur.compareRaw(type, *upper);
  608. if (rc > 0)
  609. {
  610. if (cur.isUpperBound())
  611. transitions.add(*upper->modifyTransition(type, upper->isInclusiveBound() ? CMPgt : CMPge), idx);
  612. return;
  613. }
  614. if (rc == 0)
  615. {
  616. if (cur.isUpperBound())
  617. {
  618. //[x..y] remove [y..y)
  619. if (cur.isInclusiveBound() && !upper->isInclusiveBound())
  620. transitions.add(*upper->modifyTransition(type, CMPge), idx);
  621. else
  622. transitions.remove(idx);
  623. return;
  624. }
  625. else
  626. {
  627. if (!upper->isInclusiveBound())
  628. return;
  629. }
  630. }
  631. transitions.remove(idx);
  632. }
  633. }
  634. virtual void reset() override
  635. {
  636. transitions.kill();
  637. }
  638. virtual void invertSet() override
  639. {
  640. if (transitions.empty())
  641. {
  642. addAll();
  643. return;
  644. }
  645. unsigned idx = 0;
  646. ValueTransitionArray newTransitions;
  647. if (!transitions.item(0).isMinimum())
  648. newTransitions.append(*new ValueTransition(CMPminmask));
  649. else
  650. idx++;
  651. bool unboundedUpper = transitions.tos().isMaximum();
  652. unsigned max = transitions.ordinality();
  653. if (unboundedUpper)
  654. max--;
  655. for (; idx < max; idx ++)
  656. newTransitions.append(*transitions.item(idx).modifyInverse(type));
  657. if (!unboundedUpper)
  658. newTransitions.append(*new ValueTransition(CMPmaxmask));
  659. transitions.swapWith(newTransitions);
  660. }
  661. virtual void unionSet(const IValueSet * _other) override
  662. {
  663. //Iterate through the ranges in other and add them to this set
  664. const ValueSet * other = static_cast<const ValueSet *>(_other);
  665. for (unsigned i=0; i < other->transitions.ordinality(); i+=2)
  666. addRange(&other->transitions.item(i), &other->transitions.item(i+1));
  667. }
  668. virtual void excludeSet(const IValueSet * _other) override
  669. {
  670. //Iterate through the ranges in other and add them to this set
  671. const ValueSet * other = static_cast<const ValueSet *>(_other);
  672. for (unsigned i=0; i < other->transitions.ordinality(); i+=2)
  673. killRange(&other->transitions.item(i), &other->transitions.item(i+1));
  674. }
  675. virtual void intersectSet(IValueSet const * _other) override
  676. {
  677. const ValueSet * other = static_cast<const ValueSet *>(_other);
  678. //Iterate through the ranges in other and remove them from this set
  679. unsigned curOther = 0;
  680. unsigned otherMax = other->numTransitions();
  681. ValueTransitionArray newTransitions;
  682. for (unsigned i = 0; i < numTransitions(); i+=2)
  683. {
  684. ValueTransition & lower = transitions.item(i);
  685. ValueTransition & upper = transitions.item(i+1);
  686. for (;;)
  687. {
  688. if (curOther == otherMax)
  689. goto done; // break out of both loops.
  690. ValueTransition & otherLower = other->transitions.item(curOther);
  691. ValueTransition & otherUpper = other->transitions.item(curOther+1);
  692. //If upper is lower than the other lower bound then no rows overlap, skip this range
  693. int rc1 = upper.compareRaw(type, otherLower);
  694. if (rc1 < 0 ||
  695. ((rc1 == 0) && (!upper.isInclusiveBound() || !otherLower.isInclusiveBound())))
  696. break;
  697. //If other upper is lower than the lower bound then no rows overlap, skip other range
  698. int rc2 = otherUpper.compareRaw(type, lower);
  699. if (rc2 < 0 ||
  700. ((rc2 == 0) && (!otherUpper.isInclusiveBound() || !lower.isInclusiveBound())))
  701. {
  702. curOther += 2;
  703. continue;
  704. }
  705. //Lower bound of the intersection is the higher of the two lower bounds
  706. int rc3 = lower.compareRaw(type, otherLower);
  707. if (rc3 < 0 || ((rc3 == 0) && lower.isInclusiveBound()))
  708. newTransitions.append(OLINK(otherLower));
  709. else
  710. newTransitions.append(OLINK(lower));
  711. //Upper bound of the intersection is the lower of the two bounds - and move onto next range that is consumed
  712. int rc4 = upper.compareRaw(type, otherUpper);
  713. if (rc4 < 0 || ((rc4 == 0) && !upper.isInclusiveBound()))
  714. {
  715. newTransitions.append(OLINK(upper));
  716. break;
  717. }
  718. else
  719. {
  720. newTransitions.append(OLINK(otherUpper));
  721. curOther += 2;
  722. }
  723. }
  724. }
  725. done:
  726. transitions.swapWith(newTransitions);
  727. }
  728. virtual ValueTransition * createRawTransition(TransitionMask mask, const void * value) const override
  729. {
  730. return new ValueTransition(mask, type, value);
  731. }
  732. virtual void addRawRange(const void * lower, const void * upper) override
  733. {
  734. Owned<ValueTransition> lowerBound = lower ? createRawTransition(CMPge, lower) : nullptr;
  735. Owned<ValueTransition> upperBound = upper ? createRawTransition(CMPle, upper) : nullptr;
  736. addRange(lowerBound, upperBound);
  737. }
  738. virtual void killRawRange(const void * lower, const void * upper) override
  739. {
  740. Owned<ValueTransition> lowerBound = lower ? createRawTransition(CMPge, lower) : nullptr;
  741. Owned<ValueTransition> upperBound = upper ? createRawTransition(CMPle, upper) : nullptr;
  742. killRange(lowerBound, upperBound);
  743. }
  744. virtual bool equals(const IValueSet & _other) const override
  745. {
  746. const ValueSet & other = static_cast<const ValueSet &>(_other);
  747. if (!type.equivalent(&other.type))
  748. return false;
  749. if (transitions.ordinality() != other.transitions.ordinality())
  750. return false;
  751. ForEachItemIn(i, transitions)
  752. {
  753. if (!transitions.item(i).equals(type, other.transitions.item(i)))
  754. return false;
  755. }
  756. return true;
  757. }
  758. virtual IValueSet * cast(const RtlTypeInfo & newType) const
  759. {
  760. Owned<IValueSet> newSet = new ValueSet(newType);
  761. unsigned max = transitions.ordinality();
  762. for (unsigned i=0; i < max; i += 2)
  763. {
  764. Owned<IValueTransition> newLower = transitions.item(i).cast(newType, type);
  765. Owned<IValueTransition> newUpper = transitions.item(i+1).cast(newType, type);
  766. newSet->addRange(newLower, newUpper);
  767. }
  768. return newSet.getClear();
  769. }
  770. // Methods for using a value set
  771. virtual bool isWild() const override;
  772. virtual unsigned numRanges() const override;
  773. virtual int compareLowest(const byte * field, unsigned range) const override;
  774. virtual int compareHighest(const byte * field, unsigned range) const override;
  775. virtual int findForwardMatchRange(const byte * field, unsigned & matchRange) const override;
  776. // Does this field match any range?
  777. virtual bool matches(const byte * field) const override;
  778. // Does this field match this particular range?
  779. virtual bool matches(const byte * field, unsigned range) const override;
  780. virtual StringBuffer & serialize(StringBuffer & out) const override
  781. {
  782. //Does this need to include the type information?
  783. return describe(out);
  784. }
  785. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override
  786. {
  787. out.appendPacked((unsigned)transitions.ordinality());
  788. ForEachItemIn(i, transitions)
  789. transitions.item(i).serialize(type, out);
  790. return out;
  791. }
  792. virtual const RtlTypeInfo & queryType() const override
  793. {
  794. return type;
  795. }
  796. protected:
  797. inline int compareRaw(const byte * field, ValueTransition * transition) const __attribute__((always_inline))
  798. {
  799. return transition->compareRaw(type, field);
  800. }
  801. inline int compare(const byte * field, ValueTransition * transition) const __attribute__((always_inline))
  802. {
  803. return transition->compare(type, field);
  804. }
  805. ValueTransition * queryTransition(unsigned i) const { return &transitions.item(i); }
  806. unsigned numTransitions() const { return transitions.ordinality(); }
  807. StringBuffer & describe(StringBuffer & out) const
  808. {
  809. for (unsigned i = 0; i < transitions.ordinality(); i += 2)
  810. {
  811. if (i != 0)
  812. out.append(",");
  813. ValueTransition & lower = transitions.item(i);
  814. ValueTransition & upper = transitions.item(i+1);
  815. lower.describe(type, out);
  816. if (lower.compareRaw(type, upper) != 0)
  817. {
  818. out.append(",");
  819. upper.describe(type, out);
  820. }
  821. else
  822. out.append("]");
  823. }
  824. return out;
  825. }
  826. bool hasLowerBound() const
  827. {
  828. if (transitions.empty())
  829. return false;
  830. return !transitions.item(0).isMinimum();
  831. }
  832. bool hasUpperBound() const
  833. {
  834. if (transitions.empty())
  835. return false;
  836. return !transitions.tos().isMaximum();
  837. }
  838. protected:
  839. const RtlTypeInfo & type;
  840. ValueTransitionArray transitions;
  841. };
  842. unsigned ValueSet::numRanges() const
  843. {
  844. return transitions.ordinality() / 2;
  845. }
  846. bool ValueSet::isWild() const
  847. {
  848. if (transitions.ordinality() != 2)
  849. return false;
  850. return queryTransition(0)->isMinimum() && queryTransition(1)->isMaximum();
  851. }
  852. bool ValueSet::matches(const byte * field) const
  853. {
  854. //NOTE: It is guaranteed that transitions with the same value are merged if possible - which allows the loop to terminate early on equality.
  855. unsigned high = numRanges();
  856. unsigned low = 0;
  857. while (low < high)
  858. {
  859. unsigned mid = low + (high-low)/2;
  860. unsigned lower = mid * 2;
  861. //Using compareRaw allows early termination for equalities that actually fail to match.
  862. int rc = compareRaw(field, queryTransition(lower));
  863. if (rc < 0)
  864. {
  865. high = mid;
  866. }
  867. else if (rc == 0)
  868. {
  869. if (queryTransition(lower)->isInclusiveBound())
  870. return true;
  871. else
  872. return false;
  873. }
  874. else
  875. {
  876. unsigned upper = lower + 1;
  877. rc = compareRaw(field, queryTransition(upper));
  878. if (rc < 0)
  879. return true;
  880. if (rc == 0)
  881. {
  882. if (queryTransition(upper)->isInclusiveBound())
  883. return true;
  884. else
  885. return false;
  886. }
  887. low = mid+1;
  888. }
  889. }
  890. return false;
  891. }
  892. bool ValueSet::matches(const byte * field, unsigned range) const
  893. {
  894. if (range >= numRanges())
  895. return false;
  896. unsigned lower = range * 2;
  897. int rc = compare(field, queryTransition(lower));
  898. if (rc < 0)
  899. return false;
  900. if (rc == 0)
  901. return true;
  902. unsigned upper = lower + 1;
  903. rc = compare(field, queryTransition(upper));
  904. return (rc <= 0);
  905. }
  906. int ValueSet::compareLowest(const byte * field, unsigned range) const
  907. {
  908. return compare(field, queryTransition(range*2));
  909. }
  910. int ValueSet::compareHighest(const byte * field, unsigned range) const
  911. {
  912. return compare(field, queryTransition(range*2+1));
  913. }
  914. /*
  915. //find the last range where the lower bound <= the field, returns 0 if the field matches the lower bound, > 0 otherwise.
  916. //matchRange is set to the range number, set to numRanges if there is no possible match. Uses a binary chop
  917. int ValueSet::findCandidateRange(const byte * field, unsigned & matchRange) const
  918. {
  919. //NOTE: It is guaranteed that transitions are merged if possible - which allows the loop to terminate early.
  920. unsigned high = numRanges();
  921. unsigned low = 0;
  922. int rc = 0;
  923. while (low < high)
  924. {
  925. unsigned mid = low + (high - low) / 2;
  926. unsigned lower = mid * 2;
  927. rc = compare(field, queryTransition(lower));
  928. if (rc <= 0)
  929. high = mid;
  930. else
  931. low = mid + 1;
  932. }
  933. matchRange = low;
  934. return rc;
  935. }
  936. //find the last range where the lower bound <= the field, returns 0 if the field matches the lower bound, > 0 otherwise.
  937. //starts searching from curRange (which is likely to match). Uses a sequential search.
  938. int ValueSet::checkNextCandidateRange(const byte * field, unsigned & curRange) const
  939. {
  940. unsigned cur = curRange;
  941. while (cur < numRanges())
  942. {
  943. unsigned lower = cur * 2;
  944. int rc = compare(field, queryTransition(lower));
  945. if (rc >= 0)
  946. {
  947. curRange = cur;
  948. return rc;
  949. }
  950. cur++;
  951. }
  952. curRange = numRanges();
  953. return 0;
  954. }
  955. */
  956. //If field lies within a range return true and set matchRange to the index of the range.
  957. //If field is outside a range return false and set matchRange to the index of the next range, i.e. min(range.lower) where range.lower > field
  958. //Find the largest transition value that is <= field, and then check if within upper limit
  959. //Could have a version that starts from the previous match to shorten the binary chop, or use a linear search instead
  960. int ValueSet::findForwardMatchRange(const byte * field, unsigned & matchRange) const
  961. {
  962. unsigned ranges = numRanges();
  963. unsigned high = ranges;
  964. unsigned low = 0;
  965. //Find the largest transition that is <= the search value
  966. while (high - low > 1)
  967. {
  968. unsigned mid = low + (high - low) / 2;
  969. unsigned lower = mid * 2;
  970. int rc = compare(field, queryTransition(lower));
  971. if (rc < 0)
  972. {
  973. // field is less than transition, so transition with value < search must be before.
  974. high = mid; // exclude mid and all transitions after it
  975. }
  976. else if (rc > 0)
  977. {
  978. // field is greater than transition, so transition with value > search must be this or after.
  979. low = mid; // exclude mid-1 and all transitions before it
  980. }
  981. else
  982. {
  983. matchRange = mid;
  984. return true;
  985. }
  986. }
  987. //rc is comparison from element mid.
  988. if (low != ranges)
  989. {
  990. if (compare(field, queryTransition(low*2)) >= 0)
  991. {
  992. int rc = compare(field, queryTransition(low*2+1));
  993. if (rc <= 0)
  994. {
  995. matchRange = low;
  996. return true;
  997. }
  998. low++;
  999. }
  1000. }
  1001. matchRange = low;
  1002. return false;
  1003. }
  1004. IValueSet * createValueSet(const RtlTypeInfo & _type) { return new ValueSet(_type); }
  1005. IValueSet * createValueSet(const RtlTypeInfo & _type, MemoryBuffer & in) { return new ValueSet(_type, in); }
  1006. //---------------------------------------------------------------------------------------------------------------------
  1007. /*
  1008. * Base implementation class for field filters.
  1009. */
  1010. class FieldFilter : public CInterfaceOf<IFieldFilter>
  1011. {
  1012. public:
  1013. FieldFilter(unsigned _field, const RtlTypeInfo & _type) : field(_field), type(_type) {}
  1014. //More complex index matching
  1015. virtual int compareRow(const RtlRow & left, const RtlRow & right) const override
  1016. {
  1017. return type.compare(left.queryField(field), right.queryField(field));
  1018. }
  1019. virtual unsigned queryFieldIndex() const override
  1020. {
  1021. return field;
  1022. }
  1023. virtual const RtlTypeInfo & queryType() const override
  1024. {
  1025. return type;
  1026. }
  1027. protected:
  1028. unsigned field;
  1029. const RtlTypeInfo & type;
  1030. };
  1031. /*
  1032. * A field filter that can match a set of values.
  1033. */
  1034. class SetFieldFilter : public FieldFilter
  1035. {
  1036. public:
  1037. SetFieldFilter(unsigned _field, IValueSet * _values) : FieldFilter(_field, _values->queryType()), values(_values) {}
  1038. SetFieldFilter(unsigned _field, const RtlTypeInfo & fieldType, IValueSet * _values) : FieldFilter(_field, fieldType), values(_values) {}
  1039. //Simple row matching
  1040. virtual bool matches(const RtlRow & row) const override;
  1041. virtual bool isEmpty() const override;
  1042. virtual bool isWild() const override;
  1043. //More complex index matching
  1044. virtual unsigned numRanges() const override;
  1045. virtual int compareLowest(const RtlRow & left, unsigned range) const override;
  1046. virtual int compareHighest(const RtlRow & left, unsigned range) const override;
  1047. virtual int findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const override;
  1048. virtual unsigned queryScore() const override;
  1049. virtual IFieldFilter *remap(unsigned newField) const override { return new SetFieldFilter(newField, values); }
  1050. virtual StringBuffer & serialize(StringBuffer & out) const override;
  1051. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override;
  1052. protected:
  1053. Linked<IValueSet> values;
  1054. };
  1055. bool SetFieldFilter::matches(const RtlRow & row) const
  1056. {
  1057. return values->matches(row.queryField(field));
  1058. }
  1059. bool SetFieldFilter::isEmpty() const
  1060. {
  1061. return values->numRanges() == 0;
  1062. }
  1063. bool SetFieldFilter::isWild() const
  1064. {
  1065. return values->isWild();
  1066. }
  1067. unsigned SetFieldFilter::numRanges() const
  1068. {
  1069. return values->numRanges();
  1070. }
  1071. int SetFieldFilter::compareLowest(const RtlRow & left, unsigned range) const
  1072. {
  1073. return values->compareLowest(left.queryField(field), range);
  1074. }
  1075. int SetFieldFilter::compareHighest(const RtlRow & left, unsigned range) const
  1076. {
  1077. return values->compareHighest(left.queryField(field), range);
  1078. }
  1079. int SetFieldFilter::findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const
  1080. {
  1081. return values->findForwardMatchRange(row.queryField(field), matchRange);
  1082. }
  1083. unsigned SetFieldFilter::queryScore() const
  1084. {
  1085. // MORE - the score should probably depend on the number and nature of ranges too.
  1086. unsigned score = type.getMinSize();
  1087. if (!score)
  1088. score = 5; // Arbitrary guess for average field length in a variable size field
  1089. return score;
  1090. }
  1091. StringBuffer & SetFieldFilter::serialize(StringBuffer & out) const
  1092. {
  1093. out.append(field).append('=');
  1094. return values->serialize(out);
  1095. }
  1096. MemoryBuffer & SetFieldFilter::serialize(MemoryBuffer & out) const
  1097. {
  1098. out.appendPacked(field).append('=');
  1099. return values->serialize(out);
  1100. }
  1101. IFieldFilter * createFieldFilter(unsigned fieldId, IValueSet * values)
  1102. {
  1103. return new SetFieldFilter(fieldId, values);
  1104. }
  1105. IFieldFilter * createEmptyFieldFilter(unsigned fieldId, const RtlTypeInfo & type)
  1106. {
  1107. Owned<IValueSet> values = createValueSet(type);
  1108. return new SetFieldFilter(fieldId, values);
  1109. }
  1110. IFieldFilter * createFieldFilter(unsigned fieldId, const RtlTypeInfo & type, const void * value)
  1111. {
  1112. Owned<IValueSet> values = createValueSet(type);
  1113. values->addRawRange(value, value);
  1114. return new SetFieldFilter(fieldId, values);
  1115. }
  1116. //---------------------------------------------------------------------------------------------------------------------
  1117. /*
  1118. * A link counted version of an RtlTypeInfo
  1119. */
  1120. class SharedRtlTypeInfo : public CInterface
  1121. {
  1122. public:
  1123. SharedRtlTypeInfo(const RtlTypeInfo * _type) : type(_type) {}
  1124. ~SharedRtlTypeInfo() { type->doDelete(); }
  1125. const RtlTypeInfo * const type;
  1126. };
  1127. /*
  1128. * A field filter that can match a set of values.
  1129. */
  1130. class SubStringFieldFilter : public SetFieldFilter
  1131. {
  1132. public:
  1133. SubStringFieldFilter(unsigned _field, const RtlTypeInfo & _fieldType, SharedRtlTypeInfo * _subType, IValueSet * _values)
  1134. : SetFieldFilter(_field, _fieldType, _values), subType(_subType)
  1135. {
  1136. subLength = subType->type->length;
  1137. }
  1138. virtual StringBuffer & serialize(StringBuffer & out) const override;
  1139. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override;
  1140. protected:
  1141. Linked<SharedRtlTypeInfo> subType;
  1142. size32_t subLength;
  1143. };
  1144. StringBuffer & SubStringFieldFilter::serialize(StringBuffer & out) const
  1145. {
  1146. out.append(field).append(':').append(subLength).append("=");
  1147. return values->serialize(out);
  1148. }
  1149. MemoryBuffer & SubStringFieldFilter::serialize(MemoryBuffer & out) const
  1150. {
  1151. out.appendPacked(field).append(':').append(subLength);
  1152. return values->serialize(out);
  1153. }
  1154. class FixedSubStringFieldFilter : public SubStringFieldFilter
  1155. {
  1156. public:
  1157. FixedSubStringFieldFilter(unsigned _field, const RtlTypeInfo & _fieldType, SharedRtlTypeInfo * _subType, IValueSet * _values)
  1158. : SubStringFieldFilter(_field, _fieldType, _subType, _values)
  1159. {
  1160. }
  1161. virtual IFieldFilter *remap(unsigned newField) const override { return new SubStringFieldFilter(newField, type, subType, values); }
  1162. };
  1163. class VariableSubStringFieldFilter : public SubStringFieldFilter
  1164. {
  1165. public:
  1166. VariableSubStringFieldFilter(unsigned _field, const RtlTypeInfo & _fieldType, SharedRtlTypeInfo * _subType, IValueSet * _values)
  1167. : SubStringFieldFilter(_field, _fieldType, _subType, _values),
  1168. maxTempLength(subLength * 4) //Maximum expansion from length to size is 4 bytes for utf8
  1169. {
  1170. }
  1171. //Simple row matching
  1172. virtual bool matches(const RtlRow & row) const override;
  1173. //More complex index matching
  1174. virtual int compareLowest(const RtlRow & left, unsigned range) const override;
  1175. virtual int compareHighest(const RtlRow & left, unsigned range) const override;
  1176. virtual int findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const override;
  1177. virtual IFieldFilter *remap(unsigned newField) const override { return new VariableSubStringFieldFilter(newField, type, subType, values); }
  1178. protected:
  1179. const unsigned maxTempLength;
  1180. };
  1181. bool VariableSubStringFieldFilter::matches(const RtlRow & row) const
  1182. {
  1183. const byte * ptr = row.queryField(field);
  1184. size32_t len = *reinterpret_cast<const size32_t *>(ptr);
  1185. if (likely(len >= subLength))
  1186. return values->matches(ptr + sizeof(size32_t));
  1187. //Clone and expand the string to the expected length
  1188. byte * temp = (byte *)alloca(maxTempLength);
  1189. RtlStaticRowBuilder builder(temp, maxTempLength);
  1190. translateScalar(builder, 0, nullptr, *subType->type, type, ptr);
  1191. return values->matches(temp);
  1192. }
  1193. int VariableSubStringFieldFilter::compareLowest(const RtlRow & left, unsigned range) const
  1194. {
  1195. const byte * ptr = left.queryField(field);
  1196. size32_t len = *reinterpret_cast<const size32_t *>(ptr);
  1197. if (likely(len >= subLength))
  1198. return values->compareLowest(ptr + sizeof(size32_t), range);
  1199. //Clone and expand the string to the expected length
  1200. byte * temp = (byte *)alloca(maxTempLength);
  1201. RtlStaticRowBuilder builder(temp, maxTempLength);
  1202. translateScalar(builder, 0, nullptr, *subType->type, type, ptr);
  1203. return values->compareLowest(temp, range);
  1204. }
  1205. int VariableSubStringFieldFilter::compareHighest(const RtlRow & left, unsigned range) const
  1206. {
  1207. const byte * ptr = left.queryField(field);
  1208. size32_t len = *reinterpret_cast<const size32_t *>(ptr);
  1209. if (likely(len >= subLength))
  1210. return values->compareHighest(ptr + sizeof(size32_t), range);
  1211. //Clone and expand the string to the expected length
  1212. byte * temp = (byte *)alloca(maxTempLength);
  1213. RtlStaticRowBuilder builder(temp, maxTempLength);
  1214. translateScalar(builder, 0, nullptr, *subType->type, type, ptr);
  1215. return values->compareHighest(temp, range);
  1216. }
  1217. int VariableSubStringFieldFilter::findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const
  1218. {
  1219. const byte * ptr = row.queryField(field);
  1220. size32_t len = *reinterpret_cast<const size32_t *>(ptr);
  1221. if (likely(len >= subLength))
  1222. return values->findForwardMatchRange(ptr + sizeof(size32_t), matchRange);
  1223. //Clone and expand the string to the expected length
  1224. byte * temp = (byte *)alloca(maxTempLength);
  1225. RtlStaticRowBuilder builder(temp, maxTempLength);
  1226. translateScalar(builder, 0, nullptr, *subType->type, type, ptr);
  1227. return values->findForwardMatchRange(temp, matchRange);
  1228. }
  1229. IFieldFilter * createSubStringFieldFilter(unsigned fieldId, size32_t subLength, IValueSet * values)
  1230. {
  1231. const RtlTypeInfo & type = values->queryType();
  1232. if (subLength == 0)
  1233. {
  1234. //Does the set include a blank value?
  1235. MemoryBuffer blank;
  1236. MemoryBufferBuilder builder(blank, 0);
  1237. type.buildString(builder, 0, nullptr, 0, "");
  1238. bool valuesMatchBlank = values->matches(blank.bytes());
  1239. if (valuesMatchBlank)
  1240. return createWildFieldFilter(fieldId, type);
  1241. else
  1242. return createEmptyFieldFilter(fieldId, type);
  1243. }
  1244. //Check for substring that doesn't truncate the field.
  1245. if (type.isFixedSize())
  1246. {
  1247. size32_t fieldLength = type.length;
  1248. if (subLength >= fieldLength)
  1249. return new SetFieldFilter(fieldId, values);
  1250. }
  1251. switch (type.getType())
  1252. {
  1253. case type_string:
  1254. case type_qstring:
  1255. case type_unicode:
  1256. case type_utf8:
  1257. case type_data:
  1258. break;
  1259. default:
  1260. throw MakeStringException(2, "Invalid type for substring filter");
  1261. }
  1262. //Created a truncated type
  1263. FieldTypeInfoStruct info;
  1264. info.fieldType = (type.fieldType & ~RFTMunknownsize);
  1265. info.length = subLength;
  1266. Owned<SharedRtlTypeInfo> subType(new SharedRtlTypeInfo(info.createRtlTypeInfo(nullptr)));
  1267. //Create a new set of values truncated to the appropriate length.
  1268. Owned<IValueSet> newValues = values->cast(*subType->type);
  1269. if (type.isFixedSize())
  1270. {
  1271. //The standard compare will only look at the first subLength characters.
  1272. return new FixedSubStringFieldFilter(fieldId, type, subType, newValues);
  1273. }
  1274. //Check that the temporary buffer that *might* be required is a sensible size for storing on the stack
  1275. if (subLength > 256)
  1276. throw MakeStringException(3, "Substring [1..%u] range is too large for a variable size field", subLength);
  1277. //Use a class which will expand the string to the sub length if it is shorter
  1278. return new VariableSubStringFieldFilter(fieldId, type, subType, newValues);
  1279. }
  1280. //---------------------------------------------------------------------------------------------------------------------
  1281. /*
  1282. * A field filter that can match any value.
  1283. */
  1284. class WildFieldFilter : public FieldFilter
  1285. {
  1286. public:
  1287. WildFieldFilter(unsigned _field, const RtlTypeInfo & _type) : FieldFilter(_field, _type) {}
  1288. //Simple row matching
  1289. virtual bool matches(const RtlRow & row) const override
  1290. {
  1291. return true;
  1292. }
  1293. virtual bool isEmpty() const override
  1294. {
  1295. return false;
  1296. }
  1297. virtual bool isWild() const override
  1298. {
  1299. return true;
  1300. }
  1301. //More complex index matching
  1302. virtual unsigned numRanges() const override
  1303. {
  1304. return 1;
  1305. }
  1306. virtual int compareLowest(const RtlRow & left, unsigned range) const override
  1307. {
  1308. //Should pass through to compare using the type.
  1309. //return type.compareLowest(left.queryField(fieldId));
  1310. //MORE
  1311. return +1;
  1312. }
  1313. virtual int compareHighest(const RtlRow & left, unsigned range) const override
  1314. {
  1315. //Should pass through to compare using the type.
  1316. //return type.compareLowest(left.queryField(fieldId));
  1317. //MORE
  1318. return -1;
  1319. }
  1320. virtual int findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const override
  1321. {
  1322. matchRange = 0;
  1323. return true;
  1324. }
  1325. virtual unsigned queryScore() const override
  1326. {
  1327. return 0;
  1328. }
  1329. virtual IFieldFilter *remap(unsigned newField) const override { return new WildFieldFilter(newField, type); }
  1330. virtual StringBuffer & serialize(StringBuffer & out) const override
  1331. {
  1332. return out.append(field).append('*');
  1333. }
  1334. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override
  1335. {
  1336. return out.appendPacked(field).append('*');
  1337. }
  1338. };
  1339. IFieldFilter * createWildFieldFilter(unsigned fieldId, const RtlTypeInfo & type)
  1340. {
  1341. //MORE: Is it worth special casing, or would a SetFieldFilter of null..null be just as good?
  1342. return new WildFieldFilter(fieldId, type);
  1343. }
  1344. //---------------------------------------------------------------------------------------------------------------------
  1345. //Note, the fieldId could be serialized within the string, but it is needed to determine the type, and
  1346. //passing it in allows this code to be decoupled from the type serialization code.
  1347. IFieldFilter * deserializeFieldFilter(unsigned fieldId, const RtlTypeInfo & type, const char * src)
  1348. {
  1349. switch (*src)
  1350. {
  1351. case '*':
  1352. return createWildFieldFilter(fieldId, type);
  1353. case '=':
  1354. {
  1355. Owned<IValueSet> values = createValueSet(type);
  1356. deserializeSet(*values, src+1);
  1357. return createFieldFilter(fieldId, values);
  1358. }
  1359. case ':':
  1360. {
  1361. char * end;
  1362. size32_t subLength = strtoul(src+1, &end, 10);
  1363. if (*end != '=')
  1364. UNIMPLEMENTED_X("Expected =");
  1365. //Created a truncated type
  1366. FieldTypeInfoStruct info;
  1367. info.fieldType = (type.fieldType & ~RFTMunknownsize);
  1368. info.length = subLength;
  1369. Owned<SharedRtlTypeInfo> subType(new SharedRtlTypeInfo(info.createRtlTypeInfo(nullptr)));
  1370. //The serialized set is already truncated to the appropriate length.
  1371. Owned<IValueSet> values = createValueSet(*subType->type);
  1372. deserializeSet(*values, end+1);
  1373. if (type.isFixedSize())
  1374. {
  1375. return new FixedSubStringFieldFilter(fieldId, type, subType, values);
  1376. }
  1377. return new VariableSubStringFieldFilter(fieldId, type, subType, values);
  1378. }
  1379. }
  1380. UNIMPLEMENTED_X("Unknown Field Filter");
  1381. }
  1382. IFieldFilter * deserializeFieldFilter(const RtlRecord & record, const char * src)
  1383. {
  1384. StringBuffer fieldText;
  1385. readFieldFromFieldFilter(fieldText, src);
  1386. unsigned fieldNum;
  1387. if (isdigit(fieldText.str()[0]))
  1388. fieldNum = atoi(fieldText.str());
  1389. else
  1390. fieldNum = record.getFieldNum(fieldText);
  1391. return deserializeFieldFilter(fieldNum, *record.queryType(fieldNum), src);
  1392. }
  1393. IFieldFilter * deserializeFieldFilter(unsigned fieldId, const RtlTypeInfo & type, MemoryBuffer & in)
  1394. {
  1395. char kind;
  1396. in.read(kind);
  1397. switch (kind)
  1398. {
  1399. case '*':
  1400. return createWildFieldFilter(fieldId, type);
  1401. case '=':
  1402. {
  1403. Owned<IValueSet> values = createValueSet(type, in);
  1404. return createFieldFilter(fieldId, values);
  1405. }
  1406. case ':':
  1407. {
  1408. size32_t subLength;
  1409. in.read(subLength);
  1410. //Created a truncated type
  1411. FieldTypeInfoStruct info;
  1412. info.fieldType = (type.fieldType & ~RFTMunknownsize);
  1413. info.length = subLength;
  1414. Owned<SharedRtlTypeInfo> subType(new SharedRtlTypeInfo(info.createRtlTypeInfo(nullptr)));
  1415. //The serialized set is already truncated to the appropriate length.
  1416. Owned<IValueSet> values = createValueSet(*subType->type, in);
  1417. if (type.isFixedSize())
  1418. {
  1419. return new FixedSubStringFieldFilter(fieldId, type, subType, values);
  1420. }
  1421. return new VariableSubStringFieldFilter(fieldId, type, subType, values);
  1422. }
  1423. }
  1424. throwUnexpectedX("Unknown Field Filter");
  1425. }
  1426. IFieldFilter * deserializeFieldFilter(const RtlRecord & searchRecord, MemoryBuffer & in)
  1427. {
  1428. unsigned fieldNum;
  1429. in.readPacked(fieldNum);
  1430. return deserializeFieldFilter(fieldNum, *searchRecord.queryType(fieldNum), in);
  1431. }
  1432. //---------------------------------------------------------------------------------------------------------------------
  1433. static int compareFieldFilters(IInterface * const * left, IInterface * const * right)
  1434. {
  1435. IFieldFilter * leftFilter = static_cast<IFieldFilter *>(*left);
  1436. IFieldFilter * rightFilter = static_cast<IFieldFilter *>(*right);
  1437. return leftFilter->queryFieldIndex() - rightFilter->queryFieldIndex();
  1438. }
  1439. void RowFilter::addFilter(const IFieldFilter & filter)
  1440. {
  1441. filters.append(filter);
  1442. unsigned fieldNum = filter.queryFieldIndex();
  1443. if (fieldNum >= numFieldsRequired)
  1444. numFieldsRequired = fieldNum+1;
  1445. }
  1446. void RowFilter::addFilter(const RtlRecord & record, const char * filterText)
  1447. {
  1448. IFieldFilter & filter = *deserializeFieldFilter(record, filterText);
  1449. filters.append(filter);
  1450. unsigned fieldNum = filter.queryFieldIndex();
  1451. if (fieldNum >= numFieldsRequired)
  1452. numFieldsRequired = fieldNum+1;
  1453. }
  1454. bool RowFilter::matches(const RtlRow & row) const
  1455. {
  1456. row.lazyCalcOffsets(numFieldsRequired);
  1457. ForEachItemIn(i, filters)
  1458. {
  1459. if (!filters.item(i).matches(row))
  1460. return false;
  1461. }
  1462. return true;
  1463. }
  1464. void RowFilter::appendFilters(IConstArrayOf<IFieldFilter> & _filters)
  1465. {
  1466. ForEachItemIn(i, _filters)
  1467. {
  1468. addFilter(OLINK(_filters.item(i)));
  1469. }
  1470. }
  1471. void RowFilter::createSegmentMonitors(IIndexReadContext *irc)
  1472. {
  1473. ForEachItemIn(i, filters)
  1474. irc->append(FFkeyed, LINK(&filters.item(i)));
  1475. }
  1476. void RowFilter::extractKeyFilter(const RtlRecord & record, IConstArrayOf<IFieldFilter> & keyFilters) const
  1477. {
  1478. if (!filters)
  1479. return;
  1480. // for an index must be in field order, and all values present
  1481. IConstArrayOf<IFieldFilter> temp;
  1482. ForEachItemIn(i, filters)
  1483. temp.append(OLINK(filters.item(i)));
  1484. temp.sort(compareFieldFilters);
  1485. unsigned maxField = temp.tos().queryFieldIndex();
  1486. unsigned curIdx=0;
  1487. for (unsigned field = 0; field <= maxField; field++)
  1488. {
  1489. const IFieldFilter & cur = temp.item(curIdx);
  1490. if (field == cur.queryFieldIndex())
  1491. {
  1492. keyFilters.append(OLINK(cur));
  1493. curIdx++;
  1494. }
  1495. else
  1496. keyFilters.append(*createWildFieldFilter(field, *record.queryType(field)));
  1497. }
  1498. }
  1499. void RowFilter::extractMemKeyFilter(const RtlRecord & record, const UnsignedArray &sortOrder, IConstArrayOf<IFieldFilter> & keyFilters) const
  1500. {
  1501. if (!filters)
  1502. return;
  1503. // for in-memory index, we want filters in the same order as the sort fields, with wilds added
  1504. ForEachItemIn(idx, sortOrder)
  1505. {
  1506. unsigned sortField = sortOrder.item(idx);
  1507. bool needWild = true;
  1508. ForEachItemIn(fidx, filters)
  1509. {
  1510. const IFieldFilter &filter = filters.item(fidx);
  1511. if (filter.queryFieldIndex()==sortField)
  1512. {
  1513. keyFilters.append(OLINK(filter));
  1514. needWild = false;
  1515. break;
  1516. }
  1517. }
  1518. if (needWild)
  1519. keyFilters.append(*createWildFieldFilter(sortField, *record.queryType(sortField)));
  1520. }
  1521. }
  1522. const IFieldFilter *RowFilter::findFilter(unsigned fieldNum) const
  1523. {
  1524. ForEachItemIn(i, filters)
  1525. {
  1526. const IFieldFilter &field = filters.item(i);
  1527. if (field.queryFieldIndex() == fieldNum)
  1528. return &field;
  1529. }
  1530. return nullptr;
  1531. }
  1532. const IFieldFilter *RowFilter::extractFilter(unsigned fieldNum)
  1533. {
  1534. ForEachItemIn(i, filters)
  1535. {
  1536. const IFieldFilter &field = filters.item(i);
  1537. if (field.queryFieldIndex() == fieldNum)
  1538. {
  1539. filters.remove(i, true);
  1540. return &field;
  1541. }
  1542. }
  1543. return nullptr;
  1544. }
  1545. void RowFilter::remove(unsigned idx)
  1546. {
  1547. filters.remove(idx);
  1548. }
  1549. void RowFilter::clear()
  1550. {
  1551. filters.kill();
  1552. numFieldsRequired = 0;
  1553. }
  1554. void RowFilter::recalcFieldsRequired()
  1555. {
  1556. numFieldsRequired = 0;
  1557. ForEachItemIn(i, filters)
  1558. {
  1559. const IFieldFilter &field = filters.item(i);
  1560. if (field.queryFieldIndex() >= numFieldsRequired)
  1561. numFieldsRequired = field.queryFieldIndex()+1;
  1562. }
  1563. }
  1564. void RowFilter::remapField(unsigned filterIdx, unsigned newFieldNum)
  1565. {
  1566. filters.replace(*filters.item(filterIdx).remap(newFieldNum), filterIdx);
  1567. }
  1568. //---------------------------------------------------------------------------------------------------------------------
  1569. bool RowCursor::setRowForward(const byte * row)
  1570. {
  1571. currentRow.setRow(row, numFieldsRequired);
  1572. unsigned field = 0;
  1573. //Now check which of the fields matches, and update matchedRanges to indicate
  1574. //MORE: Add an optimization:
  1575. //First of all check all of the fields that were previously matched. If the previous matches are in the same range,
  1576. //then the next field must either be in the same range, or a following range.
  1577. /*
  1578. for (; field < numMatched; field++)
  1579. {
  1580. const IFieldFilter & filter = queryFilter(field);
  1581. if (!filter.withinUpperRange(currentRow, matchPos(field)))
  1582. {
  1583. //This field now either matches a later range, or doesn't match at all.
  1584. //Find the new range for the current field that could include the row
  1585. cur.checkNextCandidateRange(currentRow, matchPos(i));
  1586. if (isValid(i))
  1587. return 0;
  1588. //Finished processing
  1589. if (i == 0)
  1590. return UINT_MAX;
  1591. //caller needs to find a new row that is larger that the current values for fields 0..i
  1592. //Now need to search for a value if
  1593. //Search for a new candidate value from this filter
  1594. return i+1;
  1595. }
  1596. //if (!filter.withinUpperRange(currentRow,
  1597. }
  1598. */
  1599. for (; field < filters.ordinality(); field++)
  1600. {
  1601. const IFieldFilter & filter = queryFilter(field);
  1602. //If the field is within a range return true and the range. If outside the range return the next range.
  1603. unsigned matchRange;
  1604. bool matched = filter.findForwardMatchRange(currentRow, matchRange);
  1605. if (!matched)
  1606. {
  1607. if (matchRange >= filter.numRanges())
  1608. return findNextRange(field);
  1609. nextUnmatchedRange = matchRange;
  1610. break;
  1611. }
  1612. matchedRanges.replace(matchRange, field);
  1613. }
  1614. numMatched = field;
  1615. return numMatched == filters.ordinality();
  1616. }
  1617. //The filter for field "field" has been exhausted, work out which value should be compared next
  1618. bool RowCursor::findNextRange(unsigned field)
  1619. {
  1620. unsigned matchRange;
  1621. for (;;)
  1622. {
  1623. if (field == 0)
  1624. {
  1625. eos = true;
  1626. return false;
  1627. }
  1628. field = field-1;
  1629. matchRange = matchedRanges.item(field);
  1630. const IFieldFilter & filter = queryFilter(field);
  1631. //If the field value is less than the upper bound of the current range, search for the next value above
  1632. //the current value
  1633. if (filter.compareHighest(currentRow, matchRange) < 0)
  1634. {
  1635. numMatched = field;
  1636. //MORE: Optimize the case where the field can be incremented - if so other fields can compare against lowest
  1637. //if (filter.incrementValue(currentRow))
  1638. // nextUnmatchedRange = 0;
  1639. //else
  1640. nextUnmatchedRange = -1U;
  1641. return false;
  1642. }
  1643. matchRange++;
  1644. if (matchRange < filter.numRanges())
  1645. break;
  1646. field--;
  1647. }
  1648. nextUnmatchedRange = matchRange;
  1649. numMatched = field-1;
  1650. return false;
  1651. }
  1652. //---------------------------------------------------------------------------------------------
  1653. class InMemoryRows
  1654. {
  1655. public:
  1656. InMemoryRows(size_t _countRows, const byte * * _rows, const RtlRecord & _record)
  1657. : countRows(_countRows), rows(_rows), record(_record)
  1658. {
  1659. }
  1660. const byte * queryRow(unsigned i) const { return rows[i]; }
  1661. size_t numRows() const { return countRows; }
  1662. const RtlRecord & queryRecord() const { return record; }
  1663. protected:
  1664. size_t countRows;
  1665. const byte * * rows;
  1666. const RtlRecord & record;
  1667. };
  1668. //Always has an even number of transitions
  1669. //Null transitions can be used at the start and end of the ranges to map anything
  1670. //equality conditions repeat the transition
  1671. class InMemoryRowCursor : public ISourceRowCursor
  1672. {
  1673. public:
  1674. InMemoryRowCursor(InMemoryRows & _source) : source(_source), seekRow(_source.queryRecord())
  1675. {
  1676. }
  1677. virtual const byte * findNext(const RowCursor & search) override
  1678. {
  1679. size_t numRows = source.numRows();
  1680. if (numRows == 0)
  1681. return nullptr;
  1682. size_t high = numRows;
  1683. size_t low = 0; // Could be cur
  1684. bool scanOnNext = false;
  1685. if (cur != 0 && scanOnNext)
  1686. {
  1687. //MORE: The next match is likely to be close, so first of all look for a match in the next few rows
  1688. //An always searching forwards, so can guarantee that it follows cur > low
  1689. }
  1690. //Find the value of low,high where all rows 0..low-1 are < search and rows low..max are >= search
  1691. while (low<high)
  1692. {
  1693. size_t mid = low + (high - low) / 2;
  1694. seekRow.setRow(source.queryRow(mid), search.numFilterFields());
  1695. int rc = search.compareNext(seekRow); // compare seekRow with the row we are hoping to find
  1696. if (rc < 0)
  1697. low = mid + 1; // if this row is lower than the seek row, exclude mid from the potential positions
  1698. else
  1699. high = mid; // otherwise exclude all above mid from the potential positions.
  1700. }
  1701. cur = low;
  1702. if (low == numRows)
  1703. return nullptr;
  1704. return source.queryRow(cur);
  1705. }
  1706. virtual const byte * next() override
  1707. {
  1708. cur++;
  1709. if (cur == source.numRows())
  1710. return nullptr;
  1711. return source.queryRow(cur);
  1712. }
  1713. virtual void reset() override
  1714. {
  1715. cur = 0;
  1716. seekRow.setRow(nullptr);
  1717. }
  1718. protected:
  1719. size_t cur = 0;
  1720. InMemoryRows & source;
  1721. RtlDynRow seekRow;
  1722. };
  1723. /*
  1724. Conclusions:
  1725. * Need compareLowest to be able to implement first()/ next with wildcards. Could implement with a typed lowest transition....
  1726. * Is it actually any different from start transition for most cases -
  1727. * index read is very efficient using a single memcmp when finding the next.
  1728. * Moving the compare into the transition makes the memcmp harder - although could be optimized + allow combining.
  1729. * The string sets should work on a field. The segmonitor should map row->field
  1730. * Could have multiple adjacent field fields once have variable length.
  1731. * Moving the compare into the transition makes index formats without decompression very tricky. Could possibly work around it by having a byte provider interface which could be called to get the next value.
  1732. *
  1733. *
  1734. */
  1735. #ifdef _USE_CPPUNIT
  1736. #include <cppunit/extensions/HelperMacros.h>
  1737. /*
  1738. class IStdException : extends std::exception
  1739. {
  1740. Owned<IException> jException;
  1741. public:
  1742. IStdException(IException *E) : jException(E) {};
  1743. };
  1744. */
  1745. //Scan a set of rows to find the matches - used to check that the keyed operations are correct
  1746. class RowScanner
  1747. {
  1748. public:
  1749. RowScanner(const RtlRecord & _info, RowFilter & _filter, const PointerArray & _rows) : rows(_rows), curRow(_info, nullptr), filter(_filter)
  1750. {
  1751. }
  1752. bool first()
  1753. {
  1754. return resolveNext(0);
  1755. }
  1756. bool next()
  1757. {
  1758. return resolveNext(curIndex+1);
  1759. }
  1760. bool resolveNext(unsigned next)
  1761. {
  1762. while (next < rows.ordinality())
  1763. {
  1764. curRow.setRow(rows.item(next));
  1765. if (filter.matches(curRow))
  1766. {
  1767. curIndex = next;
  1768. return true;
  1769. }
  1770. next++;
  1771. }
  1772. curIndex = next;
  1773. return false;
  1774. }
  1775. const RtlRow & queryRow() const { return curRow; }
  1776. protected:
  1777. const PointerArray & rows;
  1778. RtlDynRow curRow;
  1779. RowFilter & filter;
  1780. unsigned curIndex = 0;
  1781. };
  1782. static void addRange(IValueSet * set, const char * lower, const char * upper)
  1783. {
  1784. Owned<IValueTransition> lowerBound = lower ? set->createUtf8Transition(CMPge, rtlUtf8Length(strlen(lower), lower), lower) : nullptr;
  1785. Owned<IValueTransition> upperBound = upper ? set->createUtf8Transition(CMPle, rtlUtf8Length(strlen(upper), upper), upper) : nullptr;
  1786. set->addRange(lowerBound, upperBound);
  1787. };
  1788. class RawRowCompare : public ICompare
  1789. {
  1790. public:
  1791. RawRowCompare(const RtlRecord & _record) : record(_record) {}
  1792. virtual int docompare(const void * left,const void * right) const
  1793. {
  1794. return record.compare((const byte *)left, (const byte *)right);
  1795. }
  1796. const RtlRecord & record;
  1797. };
  1798. class ValueSetTest : public CppUnit::TestFixture
  1799. {
  1800. CPPUNIT_TEST_SUITE(ValueSetTest);
  1801. CPPUNIT_TEST(testKeyed2);
  1802. CPPUNIT_TEST(testRange);
  1803. CPPUNIT_TEST(testSerialize);
  1804. CPPUNIT_TEST(testUnion);
  1805. CPPUNIT_TEST(testExclude);
  1806. CPPUNIT_TEST(testInverse);
  1807. CPPUNIT_TEST(testIntersect);
  1808. CPPUNIT_TEST(testStr2);
  1809. CPPUNIT_TEST(testFilter);
  1810. CPPUNIT_TEST(testKeyed1);
  1811. CPPUNIT_TEST_SUITE_END();
  1812. protected:
  1813. void checkSet(const IValueSet * set, const char * expected)
  1814. {
  1815. StringBuffer temp;
  1816. set->serialize(temp);
  1817. if (!streq(expected, temp))
  1818. CPPUNIT_ASSERT_EQUAL(expected, temp.str());
  1819. }
  1820. void testRange(RtlTypeInfo & type, const char * low, const char * high, const char * expected)
  1821. {
  1822. Owned<IValueSet> set = createValueSet(type);
  1823. addRange(set, low, high);
  1824. checkSet(set, expected);
  1825. }
  1826. void testRangeStr1(const char * low, const char * high, const char * expected)
  1827. {
  1828. RtlStringTypeInfo str1(type_string, 1);
  1829. testRange(str1, low, high, expected);
  1830. }
  1831. void testRangeInt2(const char * low, const char * high, const char * expected)
  1832. {
  1833. RtlIntTypeInfo int2(type_int, 2);
  1834. testRange(int2, low, high, expected);
  1835. }
  1836. void testRangeStrX(const char * low, const char * high, const char * expected)
  1837. {
  1838. RtlStringTypeInfo type(type_string|RFTMunknownsize, 0);
  1839. testRange(type, low, high, expected);
  1840. }
  1841. void testRangeUniX(const char * low, const char * high, const char * expected)
  1842. {
  1843. RtlUnicodeTypeInfo type(type_string|RFTMunknownsize, 0, "");
  1844. testRange(type, low, high, expected);
  1845. }
  1846. void testRange()
  1847. {
  1848. testRangeStr1("A","Z","['A','Z']");
  1849. testRangeStr1("X","z","['X','z']");
  1850. testRangeStr1("Z","X","");
  1851. testRangeStr1(nullptr, "z","(,'z']");
  1852. testRangeStr1("Z", nullptr,"['Z',)");
  1853. testRangeStr1("A", "A","['A']");
  1854. testRangeStr1(nullptr, nullptr,"(,)");
  1855. testRangeStr1("é", "é","['é']"); // Test utf8 translation
  1856. testRangeStr1("AB", "ZX","['A','Z']");
  1857. testRangeInt2("0","1","[0,1]");
  1858. testRangeInt2("-1","1","[-1,1]");
  1859. testRangeInt2("-32768","32767","[-32768,32767]");
  1860. testRangeInt2("32768","0","[-32768,0]");
  1861. testRangeStrX("A", "Z","['A','Z']");
  1862. testRangeStrX("AB", "ZX","['AB','ZX']");
  1863. testRangeStrX("éèabc", "ab","");
  1864. testRangeStrX("a'b", "éèabc", "['a\\'b','éèabc']");
  1865. testRangeUniX("A", "Z","['A','Z']");
  1866. testRangeUniX("AB", "ZX","['AB','ZX']");
  1867. testRangeUniX("éèabc", "ab","");
  1868. testRangeUniX("a'b", "éèabc", "['a\\'b','éèabc']");
  1869. }
  1870. void testSerialize(RtlTypeInfo & type, const char * filter, const char * expected = nullptr)
  1871. {
  1872. Owned<IValueSet> set = createValueSet(type);
  1873. deserializeSet(*set, filter);
  1874. checkSet(set, expected ? expected : filter);
  1875. MemoryBuffer mb;
  1876. set->serialize(mb);
  1877. Owned<IValueSet> newset = createValueSet(type, mb);
  1878. checkSet(newset, expected ? expected : filter);
  1879. CPPUNIT_ASSERT(set->equals(*newset));
  1880. StringBuffer s;
  1881. set->serialize(s);
  1882. Owned<IValueSet> newset2 = createValueSet(type);
  1883. deserializeSet(*newset2, s);
  1884. CPPUNIT_ASSERT(set->equals(*newset2));
  1885. }
  1886. void testUnion(RtlTypeInfo & type, const char * filter, const char * next, const char * expected)
  1887. {
  1888. Owned<IValueSet> set = createValueSet(type);
  1889. deserializeSet(*set, filter);
  1890. deserializeSet(*set, next);
  1891. checkSet(set, expected);
  1892. //test the arguments in the opposite order
  1893. Owned<IValueSet> set2 = createValueSet(type);
  1894. deserializeSet(*set2, next);
  1895. deserializeSet(*set2, filter);
  1896. checkSet(set, expected);
  1897. //test the arguments in the opposite order
  1898. Owned<IValueSet> set3a = createValueSet(type);
  1899. Owned<IValueSet> set3b = createValueSet(type);
  1900. deserializeSet(*set3a, next);
  1901. deserializeSet(*set3b, filter);
  1902. set3a->unionSet(set3b);
  1903. checkSet(set3a, expected);
  1904. }
  1905. void testSerialize()
  1906. {
  1907. RtlStringTypeInfo str1(type_string, 1);
  1908. RtlIntTypeInfo int2(type_int, 2);
  1909. RtlStringTypeInfo strx(type_string|RFTMunknownsize, 0);
  1910. RtlUtf8TypeInfo utf8(type_utf8|RFTMunknownsize, 0, nullptr);
  1911. testSerialize(int2, "[123]");
  1912. testSerialize(int2, "(123,234]");
  1913. testSerialize(int2, "[123,234)");
  1914. testSerialize(int2, "(123,234)");
  1915. testSerialize(int2, "(,234)");
  1916. testSerialize(int2, "(128,)");
  1917. testSerialize(int2, "(,)");
  1918. testSerialize(int2, "(123,234),(456,567)");
  1919. testSerialize(int2, "(456,567),(123,234)", "(123,234),(456,567)");
  1920. testSerialize(str1, "['A']");
  1921. testSerialize(str1, "[',']");
  1922. testSerialize(str1, "['\\'']");
  1923. testSerialize(str1, "['\\u0041']", "['A']");
  1924. testSerialize(str1, "['\\n']");
  1925. testSerialize(utf8, "['\\u611b']", "['愛']");
  1926. testSerialize(strx, "['\\'\\'','}']");
  1927. testSerialize(str1, "[A]", "['A']");
  1928. testSerialize(int2, "(123]", "");
  1929. testSerialize(int2, "[123)", "");
  1930. testSerialize(int2, "[1,0]", "");
  1931. }
  1932. void testUnion()
  1933. {
  1934. RtlIntTypeInfo int2(type_int, 2);
  1935. testSerialize(int2, "[3,5],[5,7]", "[3,7]");
  1936. testSerialize(int2, "[3,5],(5,7]", "[3,7]");
  1937. testSerialize(int2, "[3,5),[5,7]", "[3,7]");
  1938. testSerialize(int2, "[3,5),(5,7]");
  1939. testSerialize(int2, "[4],[4]", "[4]");
  1940. testSerialize(int2, "[4,5],[4]", "[4,5]");
  1941. testSerialize(int2, "[4,5],[5]", "[4,5]");
  1942. testUnion(int2, "[3,5]", "[,1]", "(,1],[3,5]");
  1943. testUnion(int2, "[3,5]", "[,3]", "(,5]");
  1944. testUnion(int2, "[3,5]", "[,4]", "(,5]");
  1945. testUnion(int2, "[3,5]", "[,]", "(,)");
  1946. testUnion(int2, "[3,5]", "[1,)", "[1,)");
  1947. testUnion(int2, "[3,5]", "[3,)", "[3,)");
  1948. testUnion(int2, "[3,5]", "[5,)", "[3,)");
  1949. testUnion(int2, "[3,5]", "(5,)", "[3,)");
  1950. testUnion(int2, "[3,5]", "[6,)", "[3,5],[6,)");
  1951. testUnion(int2, "[3,5]", "(6,)", "[3,5],(6,)");
  1952. testUnion(int2, "[4,7],[12,15]", "[1,1]", "[1],[4,7],[12,15]");
  1953. testUnion(int2, "[4,7],[12,15]", "[1,4)", "[1,7],[12,15]");
  1954. testUnion(int2, "[4,7],[12,15]", "[1,4]", "[1,7],[12,15]");
  1955. testUnion(int2, "[4,7],[12,15]", "[1,5)", "[1,7],[12,15]");
  1956. testUnion(int2, "[4,7],[12,15]", "[1,7)", "[1,7],[12,15]");
  1957. testUnion(int2, "[4,7],[12,15]", "[1,7]", "[1,7],[12,15]");
  1958. testUnion(int2, "[4,7],[12,15]", "[1,8]", "[1,8],[12,15]");
  1959. testUnion(int2, "[4,7],[12,15]", "[1,12)", "[1,15]");
  1960. testUnion(int2, "[4,7],[12,15]", "[1,12]", "[1,15]");
  1961. testUnion(int2, "[4,7],[12,15]", "[1,14]", "[1,15]");
  1962. testUnion(int2, "[4,7],[12,15]", "[1,15]", "[1,15]");
  1963. testUnion(int2, "[4,7],[12,15]", "[1,16]", "[1,16]");
  1964. testUnion(int2, "[4,7],[12,15]", "[1,17]", "[1,17]");
  1965. testUnion(int2, "[4,7],[12,15]", "(4,5)", "[4,7],[12,15]");
  1966. testUnion(int2, "[4,7],[12,15]", "(4,7)", "[4,7],[12,15]");
  1967. testUnion(int2, "[4,7],[12,15]", "(4,7]", "[4,7],[12,15]");
  1968. testUnion(int2, "[4,7],[12,15]", "(4,8]", "[4,8],[12,15]");
  1969. testUnion(int2, "[4,7],[12,15]", "(4,12)", "[4,15]");
  1970. testUnion(int2, "[4,7],[12,15]", "(4,12]", "[4,15]");
  1971. testUnion(int2, "[4,7],[12,15]", "[4,4]", "[4,7],[12,15]");
  1972. testUnion(int2, "[4,7],[12,15]", "[4,5)", "[4,7],[12,15]");
  1973. testUnion(int2, "[4,7],[12,15]", "[4,7)", "[4,7],[12,15]");
  1974. testUnion(int2, "[4,7],[12,15]", "[4,7]", "[4,7],[12,15]");
  1975. testUnion(int2, "[4,7],[12,15]", "[4,8]", "[4,8],[12,15]");
  1976. testUnion(int2, "[4,7],[12,15]", "[4,12)", "[4,15]");
  1977. testUnion(int2, "[4,7],[12,15]", "[4,12]", "[4,15]");
  1978. testUnion(int2, "[4,7],[12,15]", "[4,14]", "[4,15]");
  1979. testUnion(int2, "[4,7],[12,15]", "[4,15]", "[4,15]");
  1980. testUnion(int2, "[4,7],[12,15]", "[4,16]", "[4,16]");
  1981. testUnion(int2, "[4,7],[12,15]", "[4,17]", "[4,17]");
  1982. testUnion(int2, "[4,7],[12,15]", "(5,7)", "[4,7],[12,15]");
  1983. testUnion(int2, "[4,7],[12,15]", "(5,7]", "[4,7],[12,15]");
  1984. testUnion(int2, "[4,7],[12,15]", "(5,8]", "[4,8],[12,15]");
  1985. testUnion(int2, "[4,7],[12,15]", "(5,12)", "[4,15]");
  1986. testUnion(int2, "[4,7],[12,15]", "(5,12]", "[4,15]");
  1987. testUnion(int2, "[4,7],[12,15]", "(5,14]", "[4,15]");
  1988. testUnion(int2, "[4,7],[12,15]", "(5,15]", "[4,15]");
  1989. testUnion(int2, "[4,7],[12,15]", "(5,17]", "[4,17]");
  1990. testUnion(int2, "[4,7],[12,15]", "(7,8]", "[4,8],[12,15]");
  1991. testUnion(int2, "[4,7],[12,15]", "(7,8)", "[4,8),[12,15]");
  1992. testUnion(int2, "[4,7],[12,15]", "(7,12)", "[4,15]");
  1993. testUnion(int2, "[4,7],[12,15]", "(7,12]", "[4,15]");
  1994. testUnion(int2, "[4,7],[12,15]", "(7,14]", "[4,15]");
  1995. testUnion(int2, "[4,7],[12,15]", "(7,15]", "[4,15]");
  1996. testUnion(int2, "[4,7],[12,15]", "(7,17]", "[4,17]");
  1997. testUnion(int2, "[4,7],[12,15]", "[7,7]", "[4,7],[12,15]");
  1998. testUnion(int2, "[4,7],[12,15]", "[7,8]", "[4,8],[12,15]");
  1999. testUnion(int2, "[4,7],[12,15]", "[7,12)", "[4,15]");
  2000. testUnion(int2, "[4,7],[12,15]", "[7,17]", "[4,17]");
  2001. testUnion(int2, "[4,7],[12,15]", "[8,8]", "[4,7],[8],[12,15]");
  2002. testUnion(int2, "[4,7],[12,15]", "[8,12)", "[4,7],[8,15]");
  2003. testUnion(int2, "[4,7],[12,15]", "[8,12]", "[4,7],[8,15]");
  2004. testUnion(int2, "[4,7],[12,15]", "[8,14]", "[4,7],[8,15]");
  2005. testUnion(int2, "[4,7],[12,15]", "[8,15]", "[4,7],[8,15]");
  2006. testUnion(int2, "[4,7],[12,15]", "[8,16]", "[4,7],[8,16]");
  2007. testUnion(int2, "[4,7],[12,15]", "[8,17]", "[4,7],[8,17]");
  2008. testUnion(int2, "[4,7],[12,15]", "(8,11)", "[4,7],(8,11),[12,15]");
  2009. testUnion(int2, "[4,7],[12,15]", "(8,12)", "[4,7],(8,15]");
  2010. testUnion(int2, "[4,7],[12,15]", "(8,12]", "[4,7],(8,15]");
  2011. testUnion(int2, "[4,7],[12,15]", "(8,14]", "[4,7],(8,15]");
  2012. testUnion(int2, "[4,7],[12,15]", "(8,15]", "[4,7],(8,15]");
  2013. testUnion(int2, "[4,7],[12,15]", "(8,16]", "[4,7],(8,16]");
  2014. testUnion(int2, "[4,7],[12,15]", "(8,17]", "[4,7],(8,17]");
  2015. testUnion(int2, "[4,7],[12,15]", "(12,14]", "[4,7],[12,15]");
  2016. testUnion(int2, "[4,7],[12,15]", "(12,15]", "[4,7],[12,15]");
  2017. testUnion(int2, "[4,7],[12,15]", "(12,16]", "[4,7],[12,16]");
  2018. testUnion(int2, "[4,7],[12,15]", "(12,17]", "[4,7],[12,17]");
  2019. testUnion(int2, "[4,7],[12,15]", "[12,12]", "[4,7],[12,15]");
  2020. testUnion(int2, "[4,7],[12,15]", "[12,14]", "[4,7],[12,15]");
  2021. testUnion(int2, "[4,7],[12,15]", "[12,15]", "[4,7],[12,15]");
  2022. testUnion(int2, "[4,7],[12,15]", "[12,16]", "[4,7],[12,16]");
  2023. testUnion(int2, "[4,7],[12,15]", "[12,17]", "[4,7],[12,17]");
  2024. testUnion(int2, "[4,7],[12,15]", "[14,14]", "[4,7],[12,15]");
  2025. testUnion(int2, "[4,7],[12,15]", "[14,15]", "[4,7],[12,15]");
  2026. testUnion(int2, "[4,7],[12,15]", "[14,16]", "[4,7],[12,16]");
  2027. testUnion(int2, "[4,7],[12,15]", "[14,17]", "[4,7],[12,17]");
  2028. testUnion(int2, "[4,7],[12,15]", "[15]", "[4,7],[12,15]");
  2029. testUnion(int2, "[4,7],[12,15]", "[15,16]", "[4,7],[12,16]");
  2030. testUnion(int2, "[4,7],[12,15]", "[15,17]", "[4,7],[12,17]");
  2031. testUnion(int2, "[4,7],[12,15]", "[15,17)", "[4,7],[12,17)");
  2032. testUnion(int2, "[4,7],[12,15]", "[16]", "[4,7],[12,15],[16]");
  2033. testUnion(int2, "[4,7],[12,15]", "[16,17]", "[4,7],[12,15],[16,17]");
  2034. testUnion(int2, "[4,7],[12,15]", "[17]", "[4,7],[12,15],[17]");
  2035. testUnion(int2, "(4,7),(12,15)", "[1,1]", "[1],(4,7),(12,15)");
  2036. testUnion(int2, "(4,7),(12,15)", "[1,4)", "[1,4),(4,7),(12,15)");
  2037. testUnion(int2, "(4,7),(12,15)", "[1,4]", "[1,7),(12,15)");
  2038. testUnion(int2, "(4,7),(12,15)", "[1,5)", "[1,7),(12,15)");
  2039. testUnion(int2, "(4,7),(12,15)", "[1,7)", "[1,7),(12,15)");
  2040. testUnion(int2, "(4,7),(12,15)", "[1,7]", "[1,7],(12,15)");
  2041. testUnion(int2, "(4,7),(12,15)", "[1,8]", "[1,8],(12,15)");
  2042. testUnion(int2, "(4,7),(12,15)", "[1,12)", "[1,12),(12,15)");
  2043. testUnion(int2, "(4,7),(12,15)", "[1,12]", "[1,15)");
  2044. testUnion(int2, "(4,7),(12,15)", "[1,14]", "[1,15)");
  2045. testUnion(int2, "(4,7),(12,15)", "[1,15]", "[1,15]");
  2046. testUnion(int2, "(4,7),(12,15)", "[1,16]", "[1,16]");
  2047. testUnion(int2, "(4,7),(12,15)", "[1,17]", "[1,17]");
  2048. testUnion(int2, "(4,7),(12,15)", "(4,5)", "(4,7),(12,15)");
  2049. testUnion(int2, "(4,7),(12,15)", "(4,7)", "(4,7),(12,15)");
  2050. testUnion(int2, "(4,7),(12,15)", "(4,7]", "(4,7],(12,15)");
  2051. testUnion(int2, "(4,7),(12,15)", "(4,8]", "(4,8],(12,15)");
  2052. testUnion(int2, "(4,7),(12,15)", "(4,12)", "(4,12),(12,15)");
  2053. testUnion(int2, "(4,7),(12,15)", "(4,12]", "(4,15)");
  2054. testUnion(int2, "(4,7),(12,15)", "[4,4]", "[4,7),(12,15)");
  2055. testUnion(int2, "(4,7),(12,15)", "[4,5)", "[4,7),(12,15)");
  2056. testUnion(int2, "(4,7),(12,15)", "[4,7)", "[4,7),(12,15)");
  2057. testUnion(int2, "(4,7),(12,15)", "[4,7]", "[4,7],(12,15)");
  2058. testUnion(int2, "(4,7),(12,15)", "[4,8]", "[4,8],(12,15)");
  2059. testUnion(int2, "(4,7),(12,15)", "[4,12)", "[4,12),(12,15)");
  2060. testUnion(int2, "(4,7),(12,15)", "[4,12]", "[4,15)");
  2061. testUnion(int2, "(4,7),(12,15)", "[4,14]", "[4,15)");
  2062. testUnion(int2, "(4,7),(12,15)", "[4,15]", "[4,15]");
  2063. testUnion(int2, "(4,7),(12,15)", "[4,16]", "[4,16]");
  2064. testUnion(int2, "(4,7),(12,15)", "[4,17]", "[4,17]");
  2065. testUnion(int2, "(4,7),(12,15)", "(5,7)", "(4,7),(12,15)");
  2066. testUnion(int2, "(4,7),(12,15)", "(5,7]", "(4,7],(12,15)");
  2067. testUnion(int2, "(4,7),(12,15)", "(5,8]", "(4,8],(12,15)");
  2068. testUnion(int2, "(4,7),(12,15)", "(5,12)", "(4,12),(12,15)");
  2069. testUnion(int2, "(4,7),(12,15)", "(5,12]", "(4,15)");
  2070. testUnion(int2, "(4,7),(12,15)", "(5,14]", "(4,15)");
  2071. testUnion(int2, "(4,7),(12,15)", "(5,15]", "(4,15]");
  2072. testUnion(int2, "(4,7),(12,15)", "(5,17]", "(4,17]");
  2073. testUnion(int2, "(4,7),(12,15)", "(7,8]", "(4,7),(7,8],(12,15)");
  2074. testUnion(int2, "(4,7),(12,15)", "(7,8)", "(4,7),(7,8),(12,15)");
  2075. testUnion(int2, "(4,7),(12,15)", "(7,12)", "(4,7),(7,12),(12,15)");
  2076. testUnion(int2, "(4,7),(12,15)", "(7,12]", "(4,7),(7,15)");
  2077. testUnion(int2, "(4,7),(12,15)", "(7,14]", "(4,7),(7,15)");
  2078. testUnion(int2, "(4,7),(12,15)", "(7,15]", "(4,7),(7,15]");
  2079. testUnion(int2, "(4,7),(12,15)", "(7,17]", "(4,7),(7,17]");
  2080. testUnion(int2, "(4,7),(12,15)", "[7,7]", "(4,7],(12,15)");
  2081. testUnion(int2, "(4,7),(12,15)", "[7,8]", "(4,8],(12,15)");
  2082. testUnion(int2, "(4,7),(12,15)", "[7,12)", "(4,12),(12,15)");
  2083. testUnion(int2, "(4,7),(12,15)", "[7,17]", "(4,17]");
  2084. testUnion(int2, "(4,7),(12,15)", "[8,8]", "(4,7),[8],(12,15)");
  2085. testUnion(int2, "(4,7),(12,15)", "[8,12)", "(4,7),[8,12),(12,15)");
  2086. testUnion(int2, "(4,7),(12,15)", "[8,12]", "(4,7),[8,15)");
  2087. testUnion(int2, "(4,7),(12,15)", "[8,14]", "(4,7),[8,15)");
  2088. testUnion(int2, "(4,7),(12,15)", "[8,15]", "(4,7),[8,15]");
  2089. testUnion(int2, "(4,7),(12,15)", "[8,16]", "(4,7),[8,16]");
  2090. testUnion(int2, "(4,7),(12,15)", "[8,17]", "(4,7),[8,17]");
  2091. testUnion(int2, "(4,7),(12,15)", "(8,11)", "(4,7),(8,11),(12,15)");
  2092. testUnion(int2, "(4,7),(12,15)", "(8,12)", "(4,7),(8,12),(12,15)");
  2093. testUnion(int2, "(4,7),(12,15)", "(8,12]", "(4,7),(8,15)");
  2094. testUnion(int2, "(4,7),(12,15)", "(8,14]", "(4,7),(8,15)");
  2095. testUnion(int2, "(4,7),(12,15)", "(8,15]", "(4,7),(8,15]");
  2096. testUnion(int2, "(4,7),(12,15)", "(8,16]", "(4,7),(8,16]");
  2097. testUnion(int2, "(4,7),(12,15)", "(8,17]", "(4,7),(8,17]");
  2098. testUnion(int2, "(4,7),(12,15)", "(12,14]", "(4,7),(12,15)");
  2099. testUnion(int2, "(4,7),(12,15)", "(12,15]", "(4,7),(12,15]");
  2100. testUnion(int2, "(4,7),(12,15)", "(12,16]", "(4,7),(12,16]");
  2101. testUnion(int2, "(4,7),(12,15)", "(12,17]", "(4,7),(12,17]");
  2102. testUnion(int2, "(4,7),(12,15)", "[12,12]", "(4,7),[12,15)");
  2103. testUnion(int2, "(4,7),(12,15)", "[12,14]", "(4,7),[12,15)");
  2104. testUnion(int2, "(4,7),(12,15)", "[12,15]", "(4,7),[12,15]");
  2105. testUnion(int2, "(4,7),(12,15)", "[12,16]", "(4,7),[12,16]");
  2106. testUnion(int2, "(4,7),(12,15)", "[12,17]", "(4,7),[12,17]");
  2107. testUnion(int2, "(4,7),(12,15)", "[14,14]", "(4,7),(12,15)");
  2108. testUnion(int2, "(4,7),(12,15)", "[14,15]", "(4,7),(12,15]");
  2109. testUnion(int2, "(4,7),(12,15)", "[14,16]", "(4,7),(12,16]");
  2110. testUnion(int2, "(4,7),(12,15)", "[14,17]", "(4,7),(12,17]");
  2111. testUnion(int2, "(4,7),(12,15)", "[15]", "(4,7),(12,15]");
  2112. testUnion(int2, "(4,7),(12,15)", "[15,16]", "(4,7),(12,16]");
  2113. testUnion(int2, "(4,7),(12,15)", "(15,16]", "(4,7),(12,15),(15,16]");
  2114. testUnion(int2, "(4,7),(12,15)", "[15,17]", "(4,7),(12,17]");
  2115. testUnion(int2, "(4,7),(12,15)", "[15,17)", "(4,7),(12,17)");
  2116. testUnion(int2, "(4,7),(12,15)", "[16]", "(4,7),(12,15),[16]");
  2117. testUnion(int2, "(4,7),(12,15)", "[16,17]", "(4,7),(12,15),[16,17]");
  2118. testUnion(int2, "(4,7),(12,15)", "[17]", "(4,7),(12,15),[17]");
  2119. }
  2120. void testExclude(RtlTypeInfo & type, const char * filter, const char * next, const char * expected)
  2121. {
  2122. Owned<IValueSet> set = createValueSet(type);
  2123. deserializeSet(*set, filter);
  2124. Owned<IValueSet> set2 = createValueSet(type);
  2125. deserializeSet(*set2, next);
  2126. set->excludeSet(set2);
  2127. checkSet(set, expected);
  2128. }
  2129. //Tests killRange which is used by excludeSet()
  2130. void testExclude()
  2131. {
  2132. RtlIntTypeInfo int2(type_int, 2);
  2133. testExclude(int2, "[4]", "(4,5]", "[4]");
  2134. testExclude(int2, "[4,7],[12,15]", "[1,1]", "[4,7],[12,15]");
  2135. testExclude(int2, "[4,7],[12,15]", "[1,4)", "[4,7],[12,15]");
  2136. testExclude(int2, "[4,7],[12,15]", "[1,4]", "(4,7],[12,15]");
  2137. testExclude(int2, "[4,7],[12,15]", "[1,5)", "[5,7],[12,15]");
  2138. testExclude(int2, "[4,7],[12,15]", "[1,7)", "[7],[12,15]");
  2139. testExclude(int2, "[4,7],[12,15]", "[1,7]", "[12,15]");
  2140. testExclude(int2, "[4,7],[12,15]", "(,)", "");
  2141. testExclude(int2, "[4,7],[12,15]", "(,12]", "(12,15]");
  2142. testExclude(int2, "[4,7],[12,15]", "(6,)", "[4,6]");
  2143. testExclude(int2, "[4,7],[12,15]", "[1,8]", "[12,15]");
  2144. testExclude(int2, "[4,7],[12,15]", "[1,12)", "[12,15]");
  2145. testExclude(int2, "[4,7],[12,15]", "[1,12]", "(12,15]");
  2146. testExclude(int2, "[4,7],[12,15]", "[1,14]", "(14,15]");
  2147. testExclude(int2, "[4,7],[12,15]", "[1,15]", "");
  2148. testExclude(int2, "[4,7],[12,15]", "[1,16]", "");
  2149. testExclude(int2, "[4,7],[12,15]", "(4,5)", "[4],[5,7],[12,15]");
  2150. testExclude(int2, "[4,7],[12,15]", "(4,7)", "[4],[7],[12,15]");
  2151. testExclude(int2, "[4,7],[12,15]", "(4,7]", "[4],[12,15]");
  2152. testExclude(int2, "[4,7],[12,15]", "(4,8]", "[4],[12,15]");
  2153. testExclude(int2, "[4,7],[12,15]", "(4,12)", "[4],[12,15]");
  2154. testExclude(int2, "[4,7],[12,15]", "(4,12]", "[4],(12,15]");
  2155. testExclude(int2, "[4,7],[12,15]", "[4,4]", "(4,7],[12,15]");
  2156. testExclude(int2, "[4,7],[12,15]", "[4,5)", "[5,7],[12,15]");
  2157. testExclude(int2, "[4,7],[12,15]", "[4,7)", "[7],[12,15]");
  2158. testExclude(int2, "[4,7],[12,15]", "[4,7]", "[12,15]");
  2159. testExclude(int2, "[4,7],[12,15]", "[4,8]", "[12,15]");
  2160. testExclude(int2, "[4,7],[12,15]", "[4,12)", "[12,15]");
  2161. testExclude(int2, "[4,7],[12,15]", "[4,12]", "(12,15]");
  2162. testExclude(int2, "[4,7],[12,15]", "[4,14]", "(14,15]");
  2163. testExclude(int2, "[4,7],[12,15]", "[4,15]", "");
  2164. testExclude(int2, "[4,7],[12,15]", "[4,16]", "");
  2165. testExclude(int2, "[4,7],[12,15]", "(5,7)", "[4,5],[7],[12,15]");
  2166. testExclude(int2, "[4,7],[12,15]", "(5,7]", "[4,5],[12,15]");
  2167. testExclude(int2, "[4,7],[12,15]", "(5,8]", "[4,5],[12,15]");
  2168. testExclude(int2, "[4,7],[12,15]", "(5,12)", "[4,5],[12,15]");
  2169. testExclude(int2, "[4,7],[12,15]", "(5,12]", "[4,5],(12,15]");
  2170. testExclude(int2, "[4,7],[12,15]", "(5,14]", "[4,5],(14,15]");
  2171. testExclude(int2, "[4,7],[12,15]", "(5,15)", "[4,5],[15]");
  2172. testExclude(int2, "[4,7],[12,15]", "(5,15]", "[4,5]");
  2173. testExclude(int2, "[4,7],[12,15]", "(5,17]", "[4,5]");
  2174. testExclude(int2, "[4,7],[12,15]", "(7,8]", "[4,7],[12,15]");
  2175. testExclude(int2, "[4,7],[12,15]", "(7,8)", "[4,7],[12,15]");
  2176. testExclude(int2, "[4,7],[12,15]", "(7,12)", "[4,7],[12,15]");
  2177. testExclude(int2, "[4,7],[12,15]", "(7,12]", "[4,7],(12,15]");
  2178. testExclude(int2, "[4,7],[12,15]", "(7,14]", "[4,7],(14,15]");
  2179. testExclude(int2, "[4,7],[12,15]", "(7,15]", "[4,7]");
  2180. testExclude(int2, "[4,7],[12,15]", "(7,17]", "[4,7]");
  2181. testExclude(int2, "[4,7],[12,15]", "[7,7]", "[4,7),[12,15]");
  2182. testExclude(int2, "[4,7],[12,15]", "[7,8]", "[4,7),[12,15]");
  2183. testExclude(int2, "[4,7],[12,15]", "[7,12)", "[4,7),[12,15]");
  2184. testExclude(int2, "[4,7],[12,15]", "[7,17]", "[4,7)");
  2185. testExclude(int2, "[4,7],[12,15]", "[8,8]", "[4,7],[12,15]");
  2186. testExclude(int2, "[4,7],[12,15]", "[8,12)", "[4,7],[12,15]");
  2187. testExclude(int2, "[4,7],[12,15]", "[8,12]", "[4,7],(12,15]");
  2188. testExclude(int2, "[4,7],[12,15]", "[8,14]", "[4,7],(14,15]");
  2189. testExclude(int2, "[4,7],[12,15]", "[8,15]", "[4,7]");
  2190. testExclude(int2, "[4,7],[12,15]", "[8,16]", "[4,7]");
  2191. testExclude(int2, "[4,7],[12,15]", "[8,17]", "[4,7]");
  2192. testExclude(int2, "[4,7],[12,15]", "(8,11)", "[4,7],[12,15]");
  2193. testExclude(int2, "[4,7],[12,15]", "(8,12)", "[4,7],[12,15]");
  2194. testExclude(int2, "[4,7],[12,15]", "(8,12]", "[4,7],(12,15]");
  2195. testExclude(int2, "[4,7],[12,15]", "(12,14]", "[4,7],[12],(14,15]");
  2196. testExclude(int2, "[4,7],[12,15]", "(12,15]", "[4,7],[12]");
  2197. testExclude(int2, "[4,7],[12,15]", "(12,16]", "[4,7],[12]");
  2198. testExclude(int2, "[4,7],[12,15]", "[12,12]", "[4,7],(12,15]");
  2199. testExclude(int2, "[4,7],[12,15]", "[12,14]", "[4,7],(14,15]");
  2200. testExclude(int2, "[4,7],[12,15]", "[12,15]", "[4,7]");
  2201. testExclude(int2, "[4,7],[12,15]", "[12,16]", "[4,7]");
  2202. testExclude(int2, "[4,7],[12,15]", "[14,14]", "[4,7],[12,14),(14,15]");
  2203. testExclude(int2, "[4,7],[12,15]", "[14,15]", "[4,7],[12,14)");
  2204. testExclude(int2, "[4,7],[12,15]", "[14,16]", "[4,7],[12,14)");
  2205. testExclude(int2, "[4,7],[12,15]", "[14,17]", "[4,7],[12,14)");
  2206. testExclude(int2, "[4,7],[12,15]", "[15]", "[4,7],[12,15)");
  2207. testExclude(int2, "[4,7],[12,15]", "[15,16]", "[4,7],[12,15)");
  2208. testExclude(int2, "[4,7],[12,15]", "[15,17]", "[4,7],[12,15)");
  2209. testExclude(int2, "[4,7],[12,15]", "[15,17)", "[4,7],[12,15)");
  2210. testExclude(int2, "[4,7],[12,15]", "[16]", "[4,7],[12,15]");
  2211. testExclude(int2, "(4,7),(12,15)", "[1,1]", "(4,7),(12,15)");
  2212. testExclude(int2, "(4,7),(12,15)", "[1,4)", "(4,7),(12,15)");
  2213. testExclude(int2, "(4,7),(12,15)", "[1,4]", "(4,7),(12,15)");
  2214. testExclude(int2, "(4,7),(12,15)", "[1,5)", "[5,7),(12,15)");
  2215. testExclude(int2, "(4,7),(12,15)", "[1,7)", "(12,15)");
  2216. testExclude(int2, "(4,7),(12,15)", "[1,7]", "(12,15)");
  2217. testExclude(int2, "(4,7),(12,15)", "[1,8]", "(12,15)");
  2218. testExclude(int2, "(4,7),(12,15)", "[1,12)", "(12,15)");
  2219. testExclude(int2, "(4,7),(12,15)", "[1,12]", "(12,15)");
  2220. testExclude(int2, "(4,7),(12,15)", "[1,14]", "(14,15)");
  2221. testExclude(int2, "(4,7),(12,15)", "[1,15]", "");
  2222. testExclude(int2, "(4,7),(12,15)", "[1,16]", "");
  2223. testExclude(int2, "(4,7),(12,15)", "(4,5)", "[5,7),(12,15)");
  2224. testExclude(int2, "(4,7),(12,15)", "(4,7)", "(12,15)");
  2225. testExclude(int2, "(4,7),(12,15)", "(4,7]", "(12,15)");
  2226. testExclude(int2, "(4,7),(12,15)", "(4,8]", "(12,15)");
  2227. testExclude(int2, "(4,7),(12,15)", "(4,12)", "(12,15)");
  2228. testExclude(int2, "(4,7),(12,15)", "(4,12]", "(12,15)");
  2229. testExclude(int2, "(4,7),(12,15)", "[4,4]", "(4,7),(12,15)");
  2230. testExclude(int2, "(4,7),(12,15)", "[4,5)", "[5,7),(12,15)");
  2231. testExclude(int2, "(4,7),(12,15)", "[4,7)", "(12,15)");
  2232. testExclude(int2, "(4,7),(12,15)", "[4,7]", "(12,15)");
  2233. testExclude(int2, "(4,7),(12,15)", "[4,8]", "(12,15)");
  2234. testExclude(int2, "(4,7),(12,15)", "[4,12)", "(12,15)");
  2235. testExclude(int2, "(4,7),(12,15)", "[4,12]", "(12,15)");
  2236. testExclude(int2, "(4,7),(12,15)", "[4,14]", "(14,15)");
  2237. testExclude(int2, "(4,7),(12,15)", "[4,15]", "");
  2238. testExclude(int2, "(4,7),(12,15)", "(5,6)", "(4,5],[6,7),(12,15)");
  2239. testExclude(int2, "(4,7),(12,15)", "(5,7)", "(4,5],(12,15)");
  2240. testExclude(int2, "(4,7),(12,15)", "(5,7]", "(4,5],(12,15)");
  2241. testExclude(int2, "(4,7),(12,15)", "(5,8]", "(4,5],(12,15)");
  2242. testExclude(int2, "(4,7),(12,15)", "(5,12)", "(4,5],(12,15)");
  2243. testExclude(int2, "(4,7),(12,15)", "(5,12]", "(4,5],(12,15)");
  2244. testExclude(int2, "(4,7),(12,15)", "(5,14]", "(4,5],(14,15)");
  2245. testExclude(int2, "(4,7),(12,15)", "(5,15]", "(4,5]");
  2246. testExclude(int2, "(4,7),(12,15)", "(5,17]", "(4,5]");
  2247. //return;
  2248. testExclude(int2, "(4,7),(12,15)", "(7,8]", "(4,7),(12,15)");
  2249. testExclude(int2, "(4,7),(12,15)", "(7,8)", "(4,7),(12,15)");
  2250. testExclude(int2, "(4,7),(12,15)", "(7,12)", "(4,7),(12,15)");
  2251. testExclude(int2, "(4,7),(12,15)", "(7,12]", "(4,7),(12,15)");
  2252. testExclude(int2, "(4,7),(12,15)", "(7,14]", "(4,7),(14,15)");
  2253. testExclude(int2, "(4,7),(12,15)", "(7,15]", "(4,7)");
  2254. testExclude(int2, "(4,7),(12,15)", "(7,17]", "(4,7)");
  2255. testExclude(int2, "(4,7),(12,15)", "[7,7]", "(4,7),(12,15)");
  2256. testExclude(int2, "(4,7),(12,15)", "[7,8]", "(4,7),(12,15)");
  2257. testExclude(int2, "(4,7),(12,15)", "[7,12)", "(4,7),(12,15)");
  2258. testExclude(int2, "(4,7),(12,15)", "[7,17]", "(4,7)");
  2259. testExclude(int2, "(4,7),(12,15)", "[8,8]", "(4,7),(12,15)");
  2260. testExclude(int2, "(4,7),(12,15)", "[8,12)", "(4,7),(12,15)");
  2261. testExclude(int2, "(4,7),(12,15)", "[8,12]", "(4,7),(12,15)");
  2262. testExclude(int2, "(4,7),(12,15)", "[8,14]", "(4,7),(14,15)");
  2263. testExclude(int2, "(4,7),(12,15)", "[8,15]", "(4,7)");
  2264. testExclude(int2, "(4,7),(12,15)", "[8,16]", "(4,7)");
  2265. testExclude(int2, "(4,7),(12,15)", "[8,17]", "(4,7)");
  2266. testExclude(int2, "(4,7),(12,15)", "(8,11)", "(4,7),(12,15)");
  2267. testExclude(int2, "(4,7),(12,15)", "(8,12)", "(4,7),(12,15)");
  2268. testExclude(int2, "(4,7),(12,15)", "(8,12]", "(4,7),(12,15)");
  2269. testExclude(int2, "(4,7),(12,15)", "(8,14]", "(4,7),(14,15)");
  2270. testExclude(int2, "(4,7),(12,15)", "(8,15]", "(4,7)");
  2271. testExclude(int2, "(4,7),(12,15)", "(8,16]", "(4,7)");
  2272. testExclude(int2, "(4,7),(12,15)", "(8,17]", "(4,7)");
  2273. testExclude(int2, "(4,7),(12,15)", "(12,14]", "(4,7),(14,15)");
  2274. testExclude(int2, "(4,7),(12,15)", "(12,15]", "(4,7)");
  2275. testExclude(int2, "(4,7),(12,15)", "(12,16]", "(4,7)");
  2276. testExclude(int2, "(4,7),(12,15)", "[12,12]", "(4,7),(12,15)");
  2277. testExclude(int2, "(4,7),(12,15)", "[13]", "(4,7),(12,13),(13,15)");
  2278. testExclude(int2, "(4,7),(12,15)", "[12,14)", "(4,7),[14,15)");
  2279. testExclude(int2, "(4,7),(12,15)", "[12,15)", "(4,7)");
  2280. testExclude(int2, "(4,7),(12,15)", "[12,16)", "(4,7)");
  2281. testExclude(int2, "(4,7),(12,15)", "[14,14]", "(4,7),(12,14),(14,15)");
  2282. testExclude(int2, "(4,7),(12,15)", "[14,15]", "(4,7),(12,14)");
  2283. testExclude(int2, "(4,7),(12,15)", "[14,16]", "(4,7),(12,14)");
  2284. testExclude(int2, "(4,7),(12,15)", "[15]", "(4,7),(12,15)");
  2285. }
  2286. void testInverse(RtlTypeInfo & type, const char * filter, const char * expected)
  2287. {
  2288. Owned<IValueSet> set = createValueSet(type);
  2289. deserializeSet(*set, filter);
  2290. set->invertSet();
  2291. checkSet(set, expected);
  2292. }
  2293. //Tests killRange which is used by excludeSet()
  2294. void testInverse()
  2295. {
  2296. RtlIntTypeInfo int2(type_int, 2);
  2297. testInverse(int2, "[4]", "(,4),(4,)");
  2298. testInverse(int2, "[4,5]", "(,4),(5,)");
  2299. testInverse(int2, "(4,5)", "(,4],[5,)");
  2300. testInverse(int2, "(,5)", "[5,)");
  2301. testInverse(int2, "[6,)", "(,6)");
  2302. testInverse(int2, "", "(,)");
  2303. testInverse(int2, "(,)", "");
  2304. testInverse(int2, "[4,5],(8,9),[12,14)", "(,4),(5,8],[9,12),[14,)");
  2305. }
  2306. void testIntersect(RtlTypeInfo & type, const char * filter, const char * next, const char * expected)
  2307. {
  2308. Owned<IValueSet> set = createValueSet(type);
  2309. deserializeSet(*set, filter);
  2310. Owned<IValueSet> set2 = createValueSet(type);
  2311. deserializeSet(*set2, next);
  2312. set->intersectSet(set2);
  2313. checkSet(set, expected);
  2314. //Test the opposite way around
  2315. Owned<IValueSet> seta = createValueSet(type);
  2316. deserializeSet(*seta, filter);
  2317. Owned<IValueSet> setb = createValueSet(type);
  2318. deserializeSet(*setb, next);
  2319. setb->intersectSet(seta);
  2320. checkSet(set, expected);
  2321. }
  2322. void testIntersect()
  2323. {
  2324. RtlIntTypeInfo int2(type_int, 2);
  2325. testIntersect(int2, "", "[1,2],(3,6)", "");
  2326. testIntersect(int2, "(,)", "[1,2],(3,6)", "[1,2],(3,6)");
  2327. testIntersect(int2, "(,)", "", "");
  2328. testIntersect(int2, "", "", "");
  2329. testIntersect(int2, "(,)", "(,)", "(,)");
  2330. testIntersect(int2, "(3,7),[10,20]", "[2]", "");
  2331. testIntersect(int2, "(3,7),[10,20]", "[3]", "");
  2332. testIntersect(int2, "(3,7),[10,20]", "[4]", "[4]");
  2333. testIntersect(int2, "(3,7),[10,20]", "[6]", "[6]");
  2334. testIntersect(int2, "(3,7),[10,20]", "[7]", "");
  2335. testIntersect(int2, "(3,7),[10,20]", "[10]", "[10]");
  2336. testIntersect(int2, "(3,7),[10,20]", "[20]", "[20]");
  2337. testIntersect(int2, "(3,7),[10,20]", "[21]", "");
  2338. testIntersect(int2, "(3,7),[10,20]", "[2,3]", "");
  2339. testIntersect(int2, "(3,7),[10,20]", "[2,5]", "(3,5]");
  2340. testIntersect(int2, "(3,7),[10,20]", "[2,7]", "(3,7)");
  2341. testIntersect(int2, "(3,7),[10,20]", "[2,8]", "(3,7)");
  2342. testIntersect(int2, "(3,7),[10,20]", "[2,10]", "(3,7),[10]");
  2343. testIntersect(int2, "(3,7),[10,20]", "[2,15]", "(3,7),[10,15]");
  2344. testIntersect(int2, "(3,7),[10,20]", "[2,20]", "(3,7),[10,20]");
  2345. testIntersect(int2, "(3,7),[10,20]", "[2,25]", "(3,7),[10,20]");
  2346. testIntersect(int2, "(3,7),[10,20]", "[3,3]", "");
  2347. testIntersect(int2, "(3,7),[10,20]", "[3,5]", "(3,5]");
  2348. testIntersect(int2, "(3,7),[10,20]", "[3,7]", "(3,7)");
  2349. testIntersect(int2, "(3,7),[10,20]", "[3,8]", "(3,7)");
  2350. testIntersect(int2, "(3,7),[10,20]", "[3,10]", "(3,7),[10]");
  2351. testIntersect(int2, "(3,7),[10,20]", "[3,15]", "(3,7),[10,15]");
  2352. testIntersect(int2, "(3,7),[10,20]", "[3,20]", "(3,7),[10,20]");
  2353. testIntersect(int2, "(3,7),[10,20]", "[3,25]", "(3,7),[10,20]");
  2354. testIntersect(int2, "(3,7),[10,20]", "[5,7]", "[5,7)");
  2355. testIntersect(int2, "(3,7),[10,20]", "[5,8]", "[5,7)");
  2356. testIntersect(int2, "(3,7),[10,20]", "[5,10]", "[5,7),[10]");
  2357. testIntersect(int2, "(3,7),[10,20]", "[5,15]", "[5,7),[10,15]");
  2358. testIntersect(int2, "(3,7),[10,20]", "[5,20]", "[5,7),[10,20]");
  2359. testIntersect(int2, "(3,7),[10,20]", "[5,25]", "[5,7),[10,20]");
  2360. testIntersect(int2, "(3,7),[10,20]", "[7,8]", "");
  2361. testIntersect(int2, "(3,7),[10,20]", "[7,10]", "[10]");
  2362. testIntersect(int2, "(3,7),[10,20]", "[7,15]", "[10,15]");
  2363. testIntersect(int2, "(3,7),[10,20]", "[7,20]", "[10,20]");
  2364. testIntersect(int2, "(3,7),[10,20]", "[7,25]", "[10,20]");
  2365. testIntersect(int2, "(3,7),[10,20]", "[10,15]", "[10,15]");
  2366. testIntersect(int2, "(3,7),[10,20]", "[10,20]", "[10,20]");
  2367. testIntersect(int2, "(3,7),[10,20]", "[10,25]", "[10,20]");
  2368. testIntersect(int2, "(3,7),[10,20]", "[15,20]", "[15,20]");
  2369. testIntersect(int2, "(3,7),[10,20]", "[15,25]", "[15,20]");
  2370. testIntersect(int2, "(3,7),[10,20]", "[20,25]", "[20]");
  2371. testIntersect(int2, "(3,7),[10,20]", "(2,3)", "");
  2372. testIntersect(int2, "(3,7),[10,20]", "(2,5)", "(3,5)");
  2373. testIntersect(int2, "(3,7),[10,20]", "(2,7)", "(3,7)");
  2374. testIntersect(int2, "(3,7),[10,20]", "(2,8)", "(3,7)");
  2375. testIntersect(int2, "(3,7),[10,20]", "(2,10)", "(3,7)");
  2376. testIntersect(int2, "(3,7),[10,20]", "(2,15)", "(3,7),[10,15)");
  2377. testIntersect(int2, "(3,7),[10,20]", "(2,20)", "(3,7),[10,20)");
  2378. testIntersect(int2, "(3,7),[10,20]", "(2,25)", "(3,7),[10,20]");
  2379. testIntersect(int2, "(3,7),[10,20]", "(3,5)", "(3,5)");
  2380. testIntersect(int2, "(3,7),[10,20]", "(3,7)", "(3,7)");
  2381. testIntersect(int2, "(3,7),[10,20]", "(3,8)", "(3,7)");
  2382. testIntersect(int2, "(3,7),[10,20]", "(3,10)", "(3,7)");
  2383. testIntersect(int2, "(3,7),[10,20]", "(3,15)", "(3,7),[10,15)");
  2384. testIntersect(int2, "(3,7),[10,20]", "(3,20)", "(3,7),[10,20)");
  2385. testIntersect(int2, "(3,7),[10,20]", "(3,25)", "(3,7),[10,20]");
  2386. testIntersect(int2, "(3,7),[10,20]", "(5,7)", "(5,7)");
  2387. testIntersect(int2, "(3,7),[10,20]", "(5,8)", "(5,7)");
  2388. testIntersect(int2, "(3,7),[10,20]", "(5,10)", "(5,7)");
  2389. testIntersect(int2, "(3,7),[10,20]", "(5,15)", "(5,7),[10,15)");
  2390. testIntersect(int2, "(3,7),[10,20]", "(5,20)", "(5,7),[10,20)");
  2391. testIntersect(int2, "(3,7),[10,20]", "(5,25)", "(5,7),[10,20]");
  2392. testIntersect(int2, "(3,7),[10,20]", "(7,8)", "");
  2393. testIntersect(int2, "(3,7),[10,20]", "(7,10)", "");
  2394. testIntersect(int2, "(3,7),[10,20]", "(7,15)", "[10,15)");
  2395. testIntersect(int2, "(3,7),[10,20]", "(7,20)", "[10,20)");
  2396. testIntersect(int2, "(3,7),[10,20]", "(7,25)", "[10,20]");
  2397. testIntersect(int2, "(3,7),[10,20]", "(10,15)", "(10,15)");
  2398. testIntersect(int2, "(3,7),[10,20]", "(10,20)", "(10,20)");
  2399. testIntersect(int2, "(3,7),[10,20]", "(15,20)", "(15,20)");
  2400. testIntersect(int2, "(3,7),[10,20]", "(15,25)", "(15,20]");
  2401. testIntersect(int2, "(3,7),[10,20]", "(20,25)", "");
  2402. testIntersect(int2, "(3,5),[7,10),[15,20),(30,32),[37]", "(4,7],(9,12),[13,31],(36,)", "(4,5),[7],(9,10),[15,20),(30,31],[37]");
  2403. }
  2404. void testStr2()
  2405. {
  2406. RtlStringTypeInfo str1(type_string, 1);
  2407. Owned<IValueSet> az = createValueSet(str1);
  2408. addRange(az, "A", "Z");
  2409. checkSet(az, "['A','Z']");
  2410. Owned<IValueSet> dj = createValueSet(str1);
  2411. addRange(dj, "D", "J");
  2412. checkSet(dj, "['D','J']");
  2413. Owned<IValueSet> hz = createValueSet(str1);
  2414. addRange(hz, "H", "Z");
  2415. Owned<IValueSet> jk = createValueSet(str1);
  2416. addRange(jk, "J", "K");
  2417. Owned<IValueSet> kj = createValueSet(str1);
  2418. addRange(kj, "K", "J");
  2419. checkSet(kj, "");
  2420. }
  2421. // id:int2 extra:string padding:! name:string2
  2422. // Keep in sorted order so they can be reused for index testing
  2423. const char *testRows[6] = {
  2424. "\001\000\004\000\000\000MARK!GH",
  2425. "\002\000\000\000\000\000!AB",
  2426. "\000\001\003\000\000\000FRY!JH",
  2427. "\001\001\003\000\000\000MAR!AC",
  2428. "\002\001\003\000\000\000MAS!JH",
  2429. "\003\002\004\000\000\000MASK!JH",
  2430. };
  2431. const RtlIntTypeInfo int2 = RtlIntTypeInfo(type_int, 2);
  2432. const RtlIntTypeInfo int4 = RtlIntTypeInfo(type_int, 4);
  2433. const RtlStringTypeInfo str1 = RtlStringTypeInfo(type_string, 1);
  2434. const RtlStringTypeInfo str2 = RtlStringTypeInfo(type_string, 2);
  2435. const RtlStringTypeInfo str4 = RtlStringTypeInfo(type_string, 4);
  2436. const RtlStringTypeInfo strx = RtlStringTypeInfo(type_string|RFTMunknownsize, 0);
  2437. const RtlFieldInfo id = RtlFieldInfo("id", nullptr, &int2);
  2438. const RtlFieldInfo extra = RtlFieldInfo("extra", nullptr, &strx);
  2439. const RtlFieldInfo padding = RtlFieldInfo("padding", nullptr, &str1);
  2440. const RtlFieldInfo name = RtlFieldInfo("name", nullptr, &str2);
  2441. const RtlFieldInfo * const fields[5] = { &id, &extra, &padding, &name, nullptr };
  2442. const RtlRecordTypeInfo recordType = RtlRecordTypeInfo(type_record, 4, fields);
  2443. const RtlRecord record = RtlRecord(recordType, true);
  2444. void verifyFilter(const RtlRecord & searchRecord, IFieldFilter * filter)
  2445. {
  2446. StringBuffer str1, str2;
  2447. filter->serialize(str1);
  2448. Owned<IFieldFilter> clone1 = deserializeFieldFilter(searchRecord, str1);
  2449. clone1->serialize(str2);
  2450. MemoryBuffer mem1, mem2;
  2451. filter->serialize(mem1);
  2452. Owned<IFieldFilter> clone2 = deserializeFieldFilter(searchRecord, mem1);
  2453. clone2->serialize(mem2);
  2454. if (!streq(str1, str2))
  2455. CPPUNIT_ASSERT_EQUAL(str1.str(), str2.str());
  2456. if ((mem1.length() != mem2.length()) || memcmp(mem1.bytes(), mem2.bytes(), mem1.length()) != 0)
  2457. {
  2458. printf("Filter %s failed\n", str1.str());
  2459. CPPUNIT_ASSERT_MESSAGE("Binary filter deserialize failed", false);
  2460. }
  2461. }
  2462. void processFilter(RowFilter & cursor, const char * originalFilter, const RtlRecord & searchRecord)
  2463. {
  2464. const char * filter = originalFilter;
  2465. while (filter && *filter)
  2466. {
  2467. StringBuffer next;
  2468. const char * semi = strchr(filter, ';');
  2469. if (semi)
  2470. {
  2471. next.append(semi-filter, filter);
  2472. filter = semi+1;
  2473. }
  2474. else
  2475. {
  2476. next.append(filter);
  2477. filter = nullptr;
  2478. }
  2479. const char * equal = strchr(next, '=');
  2480. assertex(equal);
  2481. const char * colon = strchr(next, ':');
  2482. if (colon && colon > equal)
  2483. colon = nullptr;
  2484. StringBuffer fieldName(colon ? colon - next : equal-next, next);
  2485. unsigned fieldNum = searchRecord.getFieldNum(fieldName);
  2486. assertex(fieldNum != (unsigned) -1);
  2487. const RtlTypeInfo *fieldType = searchRecord.queryType(fieldNum);
  2488. Owned<IValueSet> set = createValueSet(*fieldType);
  2489. deserializeSet(*set, equal+1);
  2490. IFieldFilter * filter;
  2491. if (colon)
  2492. filter = createSubStringFieldFilter(fieldNum, atoi(colon+1), set);
  2493. else
  2494. filter = new SetFieldFilter(fieldNum, set);
  2495. cursor.addFilter(*filter);
  2496. verifyFilter(searchRecord, filter);
  2497. }
  2498. }
  2499. //testFilter("id=[1,3];name=(,GH)", { false, true, false, false, false });
  2500. void testFilter(const char * originalFilter, const std::initializer_list<bool> & expected)
  2501. {
  2502. const byte * * rows = reinterpret_cast<const byte * *>(testRows);
  2503. RowFilter cursor;
  2504. processFilter(cursor, originalFilter, record);
  2505. RtlDynRow row(record, nullptr);
  2506. assertex((expected.end() - expected.begin()) == (unsigned)_elements_in(testRows));
  2507. const bool * curExpected = expected.begin();
  2508. for (unsigned i= 0; i < _elements_in(testRows); i++)
  2509. {
  2510. row.setRow(rows[i]);
  2511. if (cursor.matches(row) != curExpected[i])
  2512. {
  2513. printf("Failure to match row %u filter '%s'\n", i, originalFilter);
  2514. CPPUNIT_ASSERT_EQUAL(curExpected[i], cursor.matches(row));
  2515. }
  2516. }
  2517. };
  2518. void testFilter()
  2519. {
  2520. testFilter("", { true, true, true, true, true, true });
  2521. testFilter("id=[1]", { true, false, false, false, false, false });
  2522. testFilter("id=[1],[2],[4],[6],[12],[23],[255],[256],[300],[301],[320]", { true, true, true, false, false, false });
  2523. testFilter("id=[1,2]", { true, true, false, false, false, false });
  2524. testFilter("id=(1,2]", { false, true, false, false, false, false });
  2525. testFilter("id=[1,3];name=(,GH)", { false, true, false, false, false, false });
  2526. testFilter("id=[1,3];name=(,GH]", { true, true, false, false, false, false });
  2527. testFilter("extra=['MAR','MAS']", { true, false, false, true, true, false });
  2528. testFilter("extra=('MAR','MAS')", { true, false, false, false, false, false });
  2529. testFilter("id=(,257]", { true, true, true, true, false, false });
  2530. testFilter("extra:2=['MA']", { true, false, false, true, true, true });
  2531. testFilter("extra:2=[' ']", { false, true, false, false, false, false });
  2532. testFilter("extra:0=['XX']", { false, false, false, false, false, false });
  2533. testFilter("extra:0=['']", { true, true, true, true, true, true });
  2534. testFilter("name:1=['A']", { false, true, false, true, false, false });
  2535. //Check substring ranges are correctly truncated
  2536. testFilter("extra:3=['MARK','MAST']", { false, false, false, false, true, true });
  2537. testFilter("name:1=['AB','JA']", { true, false, true, false, true, true });
  2538. }
  2539. void testKeyed(const char * originalFilter, const char * expected)
  2540. {
  2541. const byte * * rows = reinterpret_cast<const byte * *>(testRows);
  2542. RowFilter filter;
  2543. processFilter(filter, originalFilter, record);
  2544. InMemoryRows source(_elements_in(testRows), rows, record);
  2545. InMemoryRowCursor sourceCursor(source); // could be created by source.createCursor()
  2546. KeySearcher searcher(source.queryRecord(), filter, &sourceCursor);
  2547. StringBuffer matches;
  2548. while (searcher.next())
  2549. {
  2550. searcher.queryRow().lazyCalcOffsets(1); // In unkeyed case we may not have calculated field 0 offset (though it is always going to be 0).
  2551. matches.append(searcher.queryRow().getInt(0)).append("|");
  2552. }
  2553. if (!streq(matches, expected))
  2554. {
  2555. printf("Failure to match expected keyed filter '%s' (%s, %s)\n", originalFilter, expected, matches.str());
  2556. CPPUNIT_ASSERT(streq(matches, expected));
  2557. }
  2558. }
  2559. void testKeyed1()
  2560. {
  2561. testKeyed("extra=['MAR','MAS']", "1|257|258|");
  2562. testKeyed("","1|2|256|257|258|515|");
  2563. testKeyed("id=[1,2]","1|2|");
  2564. testKeyed("id=[1],[256]","1|256|");
  2565. testKeyed("id=[1],[256,280]","1|256|257|258|");
  2566. testKeyed("id=[1],[256,280],[1000],[1023]","1|256|257|258|");
  2567. testKeyed("id=[1],[2],[4],[6],[12],[23],[255],[256],[300],[301],[320]","1|2|256|");
  2568. testKeyed("extra=['MAR','MAS']", "1|257|258|");
  2569. testKeyed("extra=('MAR','MAS')", "1|");
  2570. testKeyed("name=['AB','AC']", "2|257|");
  2571. }
  2572. void generateOrderedRows(PointerArray & rows, const RtlRecord & rowRecord)
  2573. {
  2574. //Generate rows with 3 fields. Try and ensure:
  2575. // each trailing field starts with 0, non zero.
  2576. // the third field has significant distribution in the number of elements for each value of field2
  2577. // duplicates occur in the full keyed values.
  2578. // sometimes the next value in sequence happens to match a trailing filter condition e.g. field3=1
  2579. //Last field First field x ranges from 0 to n1
  2580. //Second field
  2581. //Second field y ranges from 0 .. n2, and is included if (x + y) % 3 != 0 and (x + y) % 5 != 0
  2582. //Third field is sparse from 0..n3. m = ((x + y) % 11 ^2 + 1; if (n3 + x *2 + y) % m = 0 then it is included
  2583. unsigned n = 100000;
  2584. unsigned f1 = 0;
  2585. unsigned f2 = 0;
  2586. unsigned f3 = 0;
  2587. unsigned numf2 = 1;
  2588. unsigned countf2 = 0;
  2589. unsigned numf3 = 1;
  2590. unsigned countf3 = 0;
  2591. MemoryBuffer buff;
  2592. for (unsigned i = 0; i < n; i++)
  2593. {
  2594. buff.setLength(0);
  2595. MemoryBufferBuilder builder(buff, 0);
  2596. size32_t offset = 0;
  2597. offset = rowRecord.queryType(0)->buildInt(builder, offset, nullptr, f1);
  2598. offset = rowRecord.queryType(1)->buildInt(builder, offset, nullptr, f2);
  2599. offset = rowRecord.queryType(2)->buildInt(builder, offset, nullptr, f3);
  2600. byte * row = new byte[offset];
  2601. memcpy(row, buff.bufferBase(), offset);
  2602. rows.append(row);
  2603. unsigned pf2 = f2;
  2604. unsigned pf3 = f3;
  2605. if (++countf3 == numf3)
  2606. {
  2607. f2++;
  2608. if (++countf2 == numf2)
  2609. {
  2610. f1++;
  2611. f2 = i % 2;
  2612. numf2 = i % 23;
  2613. if (numf2 == 0)
  2614. {
  2615. f1++;
  2616. numf2 = (i % 21) + 1;
  2617. }
  2618. countf2 = 0;
  2619. }
  2620. f3 = i % 7;
  2621. countf3 = 0;
  2622. numf3 = i % 9;
  2623. if (numf3 == 0)
  2624. {
  2625. f3++;
  2626. numf3 = (i % 11) + 1;
  2627. }
  2628. }
  2629. if (i % 5)
  2630. f3++;
  2631. }
  2632. //Sort the rows - to allow different field types to be used.
  2633. RawRowCompare compareRow(rowRecord);
  2634. qsortvec(rows.getArray(), rows.ordinality(), compareRow);
  2635. }
  2636. void traceRow(const RtlRow & row)
  2637. {
  2638. printf("%u %u %u", (unsigned)row.getInt(0), (unsigned)row.getInt(1), (unsigned)row.getInt(2));
  2639. }
  2640. const RtlFieldInfo f1 = RtlFieldInfo("f1", nullptr, &int2);
  2641. const RtlFieldInfo f2 = RtlFieldInfo("f2", nullptr, &int2);
  2642. const RtlFieldInfo f3 = RtlFieldInfo("f3", nullptr, &int2);
  2643. const RtlFieldInfo * const testFields[4] = { &f1, &f2, &f3, nullptr };
  2644. const RtlRecordTypeInfo testRecordType = RtlRecordTypeInfo(type_record, 6, testFields);
  2645. const RtlRecord testRecord = RtlRecord(testRecordType, true);
  2646. const RtlFieldInfo f1s = RtlFieldInfo("f1", nullptr, &strx);
  2647. const RtlFieldInfo f2s = RtlFieldInfo("f2", nullptr, &str4);
  2648. const RtlFieldInfo f3s = RtlFieldInfo("f3", nullptr, &str2);
  2649. const RtlFieldInfo * const testFieldsB[4] = { &f1s, &f2s, &f3s, nullptr };
  2650. const RtlRecordTypeInfo testRecordTypeB = RtlRecordTypeInfo(type_record, 10, testFieldsB);
  2651. const RtlRecord testRecordB = RtlRecord(testRecordTypeB, true);
  2652. void timeKeyedScan(const PointerArray & rows, const RtlRecord & searchRecord, const char * filterText)
  2653. {
  2654. RowFilter filter;
  2655. processFilter(filter, filterText, searchRecord);
  2656. CCycleTimer timeKeyed;
  2657. unsigned countKeyed = 0;
  2658. {
  2659. InMemoryRows source(rows.ordinality(), (const byte * *)rows.getArray(), searchRecord);
  2660. InMemoryRowCursor sourceCursor(source); // could be created by source.createCursor()
  2661. KeySearcher searcher(source.queryRecord(), filter, &sourceCursor);
  2662. while (searcher.next())
  2663. {
  2664. countKeyed++;
  2665. }
  2666. }
  2667. unsigned __int64 keyedMs = timeKeyed.elapsedNs();
  2668. CCycleTimer timeScan;
  2669. unsigned countScan = 0;
  2670. {
  2671. RowScanner scanner(searchRecord, filter, rows);
  2672. bool hasSearch = scanner.first();
  2673. while (hasSearch)
  2674. {
  2675. countScan++;
  2676. hasSearch = scanner.next();
  2677. }
  2678. }
  2679. unsigned __int64 scanMs = timeScan.elapsedNs();
  2680. CPPUNIT_ASSERT_EQUAL(countScan, countKeyed);
  2681. printf("[%s] %u matches keyed(%" I64F "u) scan(%" I64F "u) (%.3f)\n", filterText, countScan, keyedMs, scanMs, (double)keyedMs/scanMs);
  2682. }
  2683. void testKeyed(const PointerArray & rows, const RtlRecord & searchRecord, const char * filterText)
  2684. {
  2685. RowFilter filter;
  2686. processFilter(filter, filterText, searchRecord);
  2687. InMemoryRows source(rows.ordinality(), (const byte * *)rows.getArray(), searchRecord);
  2688. InMemoryRowCursor sourceCursor(source); // could be created by source.createCursor()
  2689. KeySearcher searcher(source.queryRecord(), filter, &sourceCursor);
  2690. RowScanner scanner(source.queryRecord(), filter, rows);
  2691. unsigned count = 0;
  2692. bool hasSearch = searcher.next();
  2693. bool hasScan = scanner.first();
  2694. while (hasSearch && hasScan)
  2695. {
  2696. count++;
  2697. if (searchRecord.compare(searcher.queryRow().queryRow(), scanner.queryRow().queryRow()) != 0)
  2698. break;
  2699. hasSearch = searcher.next();
  2700. hasScan = scanner.next();
  2701. }
  2702. if (hasSearch || hasScan)
  2703. {
  2704. printf("[%s] Keyed: ", filterText);
  2705. if (hasSearch)
  2706. traceRow(searcher.queryRow());
  2707. else
  2708. printf("<missing>");
  2709. printf(" Scan: ");
  2710. if (hasScan)
  2711. traceRow(scanner.queryRow());
  2712. else
  2713. printf("<missing>");
  2714. printf("\n");
  2715. }
  2716. else
  2717. {
  2718. const bool compareTiming = true;
  2719. if (compareTiming)
  2720. timeKeyedScan(rows, searchRecord, filterText);
  2721. else
  2722. printf("[%s] %u matches\n", filterText, count);
  2723. }
  2724. }
  2725. void testKeyed2(const RtlRecord & record, bool testSubString)
  2726. {
  2727. PointerArray rows;
  2728. generateOrderedRows(rows, record);
  2729. testKeyed(rows, record, "");
  2730. testKeyed(rows, record, "f1=[5]");
  2731. testKeyed(rows, record, "f1=[0]");
  2732. testKeyed(rows, record, "f2=[1]");
  2733. testKeyed(rows, record, "f3=[1]");
  2734. testKeyed(rows, record, "f3=[4]");
  2735. testKeyed(rows, record, "f3=[1,3]");
  2736. testKeyed(rows, record, "f3=[1],[2],[3]");
  2737. testKeyed(rows, record, "f1=[21];f2=[20];f3=[4]");
  2738. testKeyed(rows, record, "f1=[7];f3=[5]");
  2739. testKeyed(rows, record, "f1=[7,];f3=[,5]");
  2740. if (testSubString)
  2741. {
  2742. testKeyed(rows, record, "f1:1=['1']");
  2743. testKeyed(rows, record, "f1:2=['10']");
  2744. testKeyed(rows, record, "f1:30=['5']");
  2745. testKeyed(rows, record, "f3:1=['1']");
  2746. testKeyed(rows, record, "f3:2=['10']");
  2747. testKeyed(rows, record, "f3:2=['123']");
  2748. testKeyed(rows, record, "f3:2=['123','126']");
  2749. }
  2750. ForEachItemIn(i, rows)
  2751. delete [] (byte *)rows.item(i);
  2752. }
  2753. void testKeyed2()
  2754. {
  2755. testKeyed2(testRecord, false);
  2756. testKeyed2(testRecordB, true);
  2757. }
  2758. };
  2759. CPPUNIT_TEST_SUITE_REGISTRATION(ValueSetTest);
  2760. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ValueSetTest, "ValueSetTest");
  2761. #endif