hqlsource.cpp 271 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jliball.hpp"
  14. #include "hql.hpp"
  15. #include "platform.h"
  16. #include "jlib.hpp"
  17. #include "jmisc.hpp"
  18. #include "jstream.ipp"
  19. #include "jdebug.hpp"
  20. #include "eclrtl_imp.hpp"
  21. #include "hql.hpp"
  22. #include "hqlattr.hpp"
  23. #include "hqlmeta.hpp"
  24. #include "hqlthql.hpp"
  25. #include "hqlhtcpp.ipp"
  26. #include "hqlttcpp.ipp"
  27. #include "hqlutil.hpp"
  28. #include "hqlthql.hpp"
  29. #include "hqlwcpp.hpp"
  30. #include "hqlcpputil.hpp"
  31. #include "hqltcppc.ipp"
  32. #include "hqlopt.hpp"
  33. #include "hqlfold.hpp"
  34. #include "hqlcerrors.hpp"
  35. #include "hqlcatom.hpp"
  36. #include "hqltrans.ipp"
  37. #include "hqlpmap.hpp"
  38. #include "hqlttcpp.ipp"
  39. #include "hqlsource.ipp"
  40. #include "hqlcse.ipp"
  41. #include "hqliter.ipp"
  42. #include "thorcommon.hpp"
  43. #include "hqlinline.hpp"
  44. //#define FLATTEN_DATASETS
  45. //#define HACK_TO_IGNORE_TABLE
  46. //#define TraceExprPrintLog(x, expr) PrintLog(x ": %s", expr->toString(StringBuffer()).str());
  47. #define TraceExprPrintLog(x, expr)
  48. //#define TraceTableFields
  49. inline bool needToSerializeRecord(node_operator mode)
  50. {
  51. return (mode == no_thor || mode == no_flat);
  52. }
  53. inline bool needToSerializeRecord(IHqlExpression * mode)
  54. {
  55. return needToSerializeRecord(mode->getOperator());
  56. }
  57. //---------------------------------------------------------------------------
  58. void HqlCppTranslator::addGlobalOnWarning(IHqlExpression * setMetaExpr)
  59. {
  60. globalOnWarnings->addOnWarning(setMetaExpr);
  61. }
  62. unsigned HqlCppTranslator::getSourceAggregateOptimizeFlags() const
  63. {
  64. const bool insideChildQuery = false; // value does not currently matter
  65. return getOptimizeFlags(insideChildQuery)|HOOfold|HOOinsidecompound;
  66. }
  67. void HqlCppTranslator::doBuildExprFilepos(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  68. {
  69. if (buildExprInCorrectContext(ctx, expr, tgt, false))
  70. return;
  71. throwError(HQLERR_CouldNotResolveFileposition); // internal error: fileposition should have been available.
  72. }
  73. void HqlCppTranslator::doBuildExprFileLogicalName(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  74. {
  75. if (buildExprInCorrectContext(ctx, expr, tgt, false))
  76. return;
  77. throwError(HQLERR_CouldNotResolveFileposition); // internal error: fileposition should have been available.
  78. }
  79. //---------------------------------------------------------------------------
  80. node_operator getDatasetKind(IHqlExpression * dataset)
  81. {
  82. dataset = queryPhysicalRootTable(dataset);
  83. if (dataset)
  84. {
  85. IHqlExpression * mode = dataset->queryChild(2);
  86. if (mode)
  87. return mode->getOperator();
  88. }
  89. return no_none;
  90. }
  91. unsigned getProjectCount(IHqlExpression * expr)
  92. {
  93. unsigned projectCount = 0;
  94. while (expr->getOperator() != no_table)
  95. {
  96. switch (expr->getOperator())
  97. {
  98. case no_hqlproject:
  99. case no_usertable:
  100. case no_newusertable:
  101. case no_selectfields:
  102. projectCount++;
  103. break;
  104. }
  105. expr = expr->queryChild(0);
  106. }
  107. return projectCount;
  108. }
  109. IHqlExpression * queryFetch(IHqlExpression * expr)
  110. {
  111. for (;;)
  112. {
  113. switch (expr->getOperator())
  114. {
  115. case no_fetch:
  116. return expr;
  117. case no_filter:
  118. case no_compound_fetch:
  119. case no_limit:
  120. case no_keyedlimit:
  121. case no_choosen:
  122. break;
  123. default:
  124. UNIMPLEMENTED;
  125. }
  126. expr = expr->queryChild(0);
  127. }
  128. }
  129. bool isSimpleSource(IHqlExpression * expr)
  130. {
  131. for (;;)
  132. {
  133. switch (expr->getOperator())
  134. {
  135. case no_keyindex:
  136. case no_newkeyindex:
  137. case no_table:
  138. case no_temptable:
  139. case no_inlinetable:
  140. case no_workunit_dataset:
  141. case no_xmlproject:
  142. case no_null:
  143. case no_datasetfromrow:
  144. case no_datasetfromdictionary:
  145. case no_getgraphresult:
  146. case no_getgraphloopresult:
  147. case no_rows:
  148. return true;
  149. case no_choosen:
  150. case no_limit:
  151. case no_keyedlimit:
  152. case no_sorted:
  153. case no_stepped:
  154. case no_distributed:
  155. case no_preservemeta:
  156. case no_unordered:
  157. case no_grouped:
  158. case no_compound_diskread:
  159. case no_compound_disknormalize:
  160. case no_compound_diskaggregate:
  161. case no_compound_diskcount:
  162. case no_compound_diskgroupaggregate:
  163. case no_compound_indexread:
  164. case no_compound_indexnormalize:
  165. case no_compound_indexaggregate:
  166. case no_compound_indexcount:
  167. case no_compound_indexgroupaggregate:
  168. case no_compound_childread:
  169. case no_compound_childnormalize:
  170. case no_compound_childaggregate:
  171. case no_compound_childcount:
  172. case no_compound_childgroupaggregate:
  173. case no_compound_selectnew:
  174. case no_compound_inline:
  175. case no_section:
  176. case no_sectioninput:
  177. case no_nofold:
  178. case no_nohoist:
  179. case no_nocombine:
  180. case no_dataset_alias:
  181. break;
  182. default:
  183. return false;
  184. }
  185. expr = expr->queryChild(0);
  186. }
  187. }
  188. IHqlExpression * getVirtualSelector(IHqlExpression * dataset)
  189. {
  190. IHqlExpression * table = queryPhysicalRootTable(dataset);
  191. if (!table)
  192. table = dataset;
  193. return LINK(table->queryNormalizedSelector());
  194. }
  195. IHqlExpression * getFilepos(IHqlExpression * dataset, bool isLocal)
  196. {
  197. IHqlExpression * attr = isLocal ? createLocalAttribute() : NULL;
  198. return createValue(no_filepos, LINK(fposType), getVirtualSelector(dataset), attr);
  199. }
  200. IHqlExpression * getFileLogicalName(IHqlExpression * dataset)
  201. {
  202. return createValue(no_file_logicalname, makeVarStringType(UNKNOWN_LENGTH, NULL, NULL), getVirtualSelector(dataset));
  203. }
  204. IHqlExpression * getVirtualReplacement(IHqlExpression * field, IHqlExpression * virtualDef, IHqlExpression * dataset)
  205. {
  206. IAtom * virtualKind = virtualDef->queryName();
  207. if (virtualKind == filepositionAtom)
  208. return getFilepos(dataset, false);
  209. else if (virtualKind == localFilePositionAtom)
  210. return getFilepos(dataset, true);
  211. else if (virtualKind == sizeofAtom)
  212. return createValue(no_sizeof, LINK(sizetType), getVirtualSelector(dataset));
  213. else if (virtualKind == logicalFilenameAtom)
  214. return createValue(no_implicitcast, field->getType(), getFileLogicalName(dataset));
  215. throwError1(HQLERR_UnknownVirtualAttr, str(virtualKind));
  216. return NULL;
  217. }
  218. static IHqlExpression * getExplicitlyPromotedCompare(IHqlExpression * filter)
  219. {
  220. switch (filter->getOperator())
  221. {
  222. case no_in:
  223. case no_notin:
  224. return LINK(filter);
  225. }
  226. IHqlExpression * l = filter->queryChild(0);
  227. IHqlExpression * r = filter->queryChild(1);
  228. ITypeInfo * lType = queryUnqualifiedType(l->queryType());
  229. ITypeInfo * rType = queryUnqualifiedType(r->queryType());
  230. if (lType == rType)
  231. return LINK(filter);
  232. //Add explicit casts to the type. ensureExprType won't add a (string) to a string2 field.
  233. Owned<ITypeInfo> promotedType = getPromotedECLType(lType, rType);
  234. HqlExprArray args;
  235. if (lType == promotedType)
  236. args.append(*LINK(l));
  237. else
  238. args.append(*createValue(no_implicitcast, LINK(promotedType), LINK(l)));
  239. args.append(*ensureExprType(r, promotedType));
  240. return filter->clone(args);
  241. }
  242. static IHqlExpression * createFileposCall(HqlCppTranslator & translator, IIdAtom * name, const char * provider, const char * rowname)
  243. {
  244. HqlExprArray args;
  245. args.append(*createVariable(provider, makeBoolType()));
  246. args.append(*createVariable(rowname, makeBoolType())); // really a row
  247. return translator.bindFunctionCall(name, args);
  248. }
  249. //---------------------------------------------------------------------------
  250. void VirtualFieldsInfo::gatherVirtualFields(IHqlExpression * _record, bool ignoreVirtuals, bool ensureSerialized)
  251. {
  252. OwnedHqlExpr record = ensureSerialized ? getSerializedForm(_record, diskAtom) : LINK(_record);
  253. if (record != _record)
  254. requiresDeserialize = true;
  255. //MORE: This should really recurse through records to check for nested virtual fields.
  256. // e.g., inside ifblocks, or even records....
  257. ForEachChild(idx, record)
  258. {
  259. IHqlExpression * cur = record->queryChild(idx);
  260. IHqlExpression * virtualAttr = NULL;
  261. if (!ignoreVirtuals)
  262. virtualAttr = cur->queryAttribute(virtualAtom);
  263. if (virtualAttr)
  264. {
  265. selects.append(*LINK(cur));
  266. if (isUnknownSize(cur->queryType()))
  267. simpleVirtualsAtEnd = false;
  268. if (virtuals.find(*virtualAttr) == NotFound)
  269. virtuals.append(*LINK(virtualAttr));
  270. }
  271. else
  272. {
  273. //Also adds attributes...
  274. physicalFields.append(*LINK(cur));
  275. if (virtuals.ordinality())
  276. simpleVirtualsAtEnd = false;
  277. }
  278. }
  279. }
  280. IHqlExpression * VirtualFieldsInfo::createPhysicalRecord()
  281. {
  282. if (physicalFields.ordinality() == 1)
  283. if (physicalFields.item(0).getOperator() == no_record)
  284. return LINK(&physicalFields.item(0));
  285. return createRecord(physicalFields);
  286. }
  287. //---------------------------------------------------------------------------
  288. class VirtualRecordTransformCreator : public RecordTransformCreator
  289. {
  290. public:
  291. VirtualRecordTransformCreator(IHqlExpression * _dataset) { dataset = _dataset; }
  292. virtual IHqlExpression * getMissingAssignValue(IHqlExpression * expr)
  293. {
  294. IHqlExpression * virtualAttr = expr->queryAttribute(virtualAtom);
  295. assertex(virtualAttr);
  296. return getVirtualReplacement(expr, virtualAttr->queryChild(0), dataset);
  297. }
  298. protected:
  299. IHqlExpression * dataset;
  300. };
  301. IHqlExpression * createTableWithoutVirtuals(VirtualFieldsInfo & info, IHqlExpression * tableExpr)
  302. {
  303. IHqlExpression * record = tableExpr->queryChild(1);
  304. OwnedHqlExpr diskRecord = info.createPhysicalRecord();
  305. //Clone the annotations to improve the regenerated text in the graph
  306. OwnedHqlExpr diskRecordWithMeta = record->cloneAllAnnotations(diskRecord);
  307. HqlExprArray args;
  308. unwindChildren(args, tableExpr);
  309. args.replace(*LINK(diskRecordWithMeta), 1);
  310. IHqlExpression * newDataset = tableExpr->queryBody()->clone(args);
  311. VirtualRecordTransformCreator mapper(newDataset);
  312. IHqlExpression * newTransform = mapper.createMappingTransform(no_newtransform, record, newDataset);
  313. OwnedHqlExpr projected = createDatasetF(no_newusertable, newDataset, LINK(record), newTransform, createAttribute(_internal_Atom), NULL);
  314. return tableExpr->cloneAllAnnotations(projected);
  315. }
  316. IHqlExpression * buildTableWithoutVirtuals(VirtualFieldsInfo & info, IHqlExpression * expr)
  317. {
  318. IHqlExpression * tableExpr = queryPhysicalRootTable(expr);
  319. OwnedHqlExpr projected = createTableWithoutVirtuals(info, tableExpr);
  320. return replaceExpression(expr, tableExpr, projected);
  321. }
  322. static IHqlExpression * nextDiskField(IHqlExpression * diskRecord, unsigned & diskIndex)
  323. {
  324. for (;;)
  325. {
  326. IHqlExpression * cur = diskRecord->queryChild(diskIndex++);
  327. if (!cur || !cur->isAttribute())
  328. return cur;
  329. }
  330. }
  331. static void createPhysicalLogicalAssigns(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * diskRecord, IHqlExpression * record, IHqlExpression * diskDataset, bool allowTranslate, unsigned fileposIndex)
  332. {
  333. unsigned numFields = record->numChildren();
  334. unsigned diskIndex = 0;
  335. for (unsigned idx2=0; idx2 < numFields; idx2++)
  336. {
  337. IHqlExpression * cur = record->queryChild(idx2);
  338. switch (cur->getOperator())
  339. {
  340. case no_ifblock:
  341. {
  342. IHqlExpression * ifblock = nextDiskField(diskRecord, diskIndex);
  343. assertex(ifblock && ifblock->getOperator() == no_ifblock);
  344. createPhysicalLogicalAssigns(assigns, self, ifblock->queryChild(1), cur->queryChild(1), diskDataset, false, NotFound);
  345. break;
  346. }
  347. case no_record:
  348. {
  349. IHqlExpression * srcRecord = nextDiskField(diskRecord, diskIndex);
  350. assertex(srcRecord && srcRecord->getOperator() == no_record);
  351. createPhysicalLogicalAssigns(assigns, self, srcRecord, cur, diskDataset, allowTranslate, NotFound);
  352. break;
  353. }
  354. case no_field:
  355. {
  356. OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(cur));
  357. OwnedHqlExpr newValue;
  358. if (idx2 == fileposIndex)
  359. newValue.setown(getFilepos(diskDataset, false));
  360. else
  361. {
  362. IHqlExpression * curPhysical = nextDiskField(diskRecord, diskIndex);
  363. OwnedHqlExpr physicalSelect = createSelectExpr(LINK(diskDataset), LINK(curPhysical));
  364. if (cur->isDatarow() && !cur->hasAttribute(blobAtom) && (!isInPayload() || (physicalSelect->queryType() != target->queryType())))
  365. {
  366. HqlExprArray subassigns;
  367. OwnedHqlExpr childSelf = createSelector(no_self, cur, NULL);
  368. createPhysicalLogicalAssigns(subassigns, childSelf, curPhysical->queryRecord(), cur->queryRecord(), physicalSelect, false, NotFound);
  369. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(cur->queryRecord()->getType()), subassigns);
  370. newValue.setown(createRow(no_createrow, transform.getClear()));
  371. }
  372. else
  373. newValue.setown(convertIndexPhysical2LogicalValue(cur, physicalSelect, allowTranslate));
  374. }
  375. if (newValue)
  376. assigns.append(*createAssign(target.getClear(), newValue.getClear()));
  377. break;
  378. }
  379. }
  380. }
  381. }
  382. static void createPhysicalLogicalAssigns(HqlExprArray & assigns, IHqlExpression * diskDataset, IHqlExpression * tableExpr, bool hasFilePosition)
  383. {
  384. IHqlExpression * record = tableExpr->queryRecord();
  385. unsigned fileposIndex = (hasFilePosition ? record->numChildren() - 1 : NotFound);
  386. OwnedHqlExpr self = getSelf(record);
  387. createPhysicalLogicalAssigns(assigns, self, diskDataset->queryRecord(), record, diskDataset, true, fileposIndex);
  388. }
  389. static IHqlExpression * mapIfBlock(HqlMapTransformer & mapper, IHqlExpression * cur);
  390. static IHqlExpression * mapIfBlockRecord(HqlMapTransformer & mapper, IHqlExpression * record)
  391. {
  392. HqlExprArray mapped;
  393. ForEachChild(i, record)
  394. {
  395. IHqlExpression * cur = record->queryChild(i);
  396. if (cur->getOperator() == no_ifblock)
  397. mapped.append(*mapIfBlock(mapper, cur));
  398. else
  399. mapped.append(*LINK(cur));
  400. }
  401. return record->clone(mapped);
  402. }
  403. static IHqlExpression * mapIfBlock(HqlMapTransformer & mapper, IHqlExpression * cur)
  404. {
  405. HqlExprArray args;
  406. unwindChildren(args, cur);
  407. args.replace(*mapper.transformRoot(&args.item(0)), 0);
  408. args.replace(*mapIfBlockRecord(mapper, &args.item(1)), 1);
  409. return cur->clone(args);
  410. }
  411. static IHqlExpression * createPhysicalIndexRecord(HqlMapTransformer & mapper, IHqlExpression * tableExpr, IHqlExpression * record, bool hasInternalFileposition, bool allowTranslate)
  412. {
  413. HqlExprArray physicalFields;
  414. unsigned max = record->numChildren() - (hasInternalFileposition ? 1 : 0);
  415. for (unsigned idx=0; idx < max; idx++)
  416. {
  417. IHqlExpression * cur = record->queryChild(idx);
  418. IHqlExpression * newField = NULL;
  419. if (cur->isAttribute())
  420. physicalFields.append(*LINK(cur));
  421. else if (cur->getOperator() == no_ifblock)
  422. physicalFields.append(*mapIfBlock(mapper, cur));
  423. else if (cur->getOperator() == no_record)
  424. physicalFields.append(*createPhysicalIndexRecord(mapper, tableExpr, cur, false, allowTranslate));
  425. else if (cur->hasAttribute(blobAtom))
  426. {
  427. newField = createField(cur->queryId(), makeIntType(8, false), NULL, NULL);
  428. }
  429. else
  430. {
  431. OwnedHqlExpr select = createSelectExpr(LINK(tableExpr), LINK(cur));
  432. if (!allowTranslate)
  433. newField = LINK(cur);
  434. else if (cur->isDatarow() && !isInPayload())
  435. {
  436. //MORE: Mappings for ifblocks using self.a.b (!)
  437. HqlMapTransformer childMapper;
  438. OwnedHqlExpr newRecord = createPhysicalIndexRecord(childMapper, select, cur->queryRecord(), false, allowTranslate);
  439. HqlExprArray args;
  440. unwindChildren(args, cur);
  441. newField = createField(cur->queryId(), newRecord->getType(), args);
  442. }
  443. else
  444. {
  445. //This should support other non serialized formats. E.g., link counted strings.
  446. //Simplest would be to move getSerializedForm code + call that first.
  447. if (cur->hasAttribute(_linkCounted_Atom) || cur->isDatarow())
  448. {
  449. newField = getSerializedForm(cur, diskAtom);
  450. assertex(newField != cur || cur->isDatarow());
  451. }
  452. else
  453. {
  454. OwnedHqlExpr hozed = getHozedKeyValue(select);
  455. if (hozed->queryType() == select->queryType())
  456. newField = LINK(cur);
  457. else
  458. newField = createField(cur->queryId(), hozed->getType(), extractFieldAttrs(cur));
  459. }
  460. }
  461. }
  462. if (newField)
  463. {
  464. physicalFields.append(*newField);
  465. if (cur != newField)
  466. {
  467. IHqlExpression * self = querySelfReference();
  468. OwnedHqlExpr select = createSelectExpr(LINK(self), LINK(cur));
  469. OwnedHqlExpr physicalSelect = createSelectExpr(LINK(self), LINK(newField));
  470. OwnedHqlExpr newValue = convertIndexPhysical2LogicalValue(cur, physicalSelect, true);
  471. mapper.setMapping(select, newValue);
  472. }
  473. }
  474. }
  475. return createRecord(physicalFields);
  476. }
  477. IHqlExpression * HqlCppTranslator::convertToPhysicalIndex(IHqlExpression * tableExpr)
  478. {
  479. LinkedHqlExpr * match = physicalIndexCache.getValue(tableExpr);
  480. if (match)
  481. return LINK(*match);
  482. if (tableExpr->hasAttribute(_original_Atom))
  483. return LINK(tableExpr);
  484. assertex(tableExpr->getOperator() == no_newkeyindex);
  485. IHqlExpression * record = tableExpr->queryRecord();
  486. HqlMapTransformer mapper;
  487. bool hasFileposition = getBoolAttribute(tableExpr, filepositionAtom, true);
  488. IHqlExpression * diskRecord = createPhysicalIndexRecord(mapper, tableExpr, record, hasFileposition, true);
  489. unsigned payload = numPayloadFields(tableExpr);
  490. assertex(payload || !hasFileposition);
  491. unsigned newPayload = hasFileposition ? payload-1 : payload;
  492. HqlExprArray args;
  493. unwindChildren(args, tableExpr);
  494. args.replace(*diskRecord, 1);
  495. removeAttribute(args, _payload_Atom);
  496. args.append(*createAttribute(_payload_Atom, getSizetConstant(newPayload)));
  497. args.append(*createAttribute(_original_Atom, LINK(tableExpr)));
  498. //remove the preload attribute and replace with correct value
  499. IHqlExpression * newDataset = createDataset(tableExpr->getOperator(), args);
  500. HqlExprArray assigns;
  501. createPhysicalLogicalAssigns(assigns, newDataset, tableExpr, hasFileposition);
  502. OwnedHqlExpr projectedTable = createDataset(no_newusertable, newDataset, createComma(LINK(record), createValue(no_newtransform, makeTransformType(record->getType()), assigns)));
  503. physicalIndexCache.setValue(tableExpr, projectedTable);
  504. return projectedTable.getClear();
  505. }
  506. IHqlExpression * convertToPhysicalTable(IHqlExpression * tableExpr, bool ensureSerialized)
  507. {
  508. VirtualFieldsInfo fieldInfo;
  509. fieldInfo.gatherVirtualFields(tableExpr->queryRecord(), tableExpr->hasAttribute(_noVirtual_Atom), ensureSerialized);
  510. if (fieldInfo.hasVirtualsOrDeserialize())
  511. return createTableWithoutVirtuals(fieldInfo, tableExpr);
  512. return LINK(tableExpr);
  513. }
  514. IHqlExpression * HqlCppTranslator::buildIndexFromPhysical(IHqlExpression * expr)
  515. {
  516. IHqlExpression * tableExpr = queryPhysicalRootTable(expr);
  517. OwnedHqlExpr newProject = convertToPhysicalIndex(tableExpr);
  518. return replaceExpression(expr, tableExpr, newProject);
  519. }
  520. //---------------------------------------------------------------------------
  521. class SourceSteppingInfo
  522. {
  523. public:
  524. inline bool exists() { return rawStepping.exists(); }
  525. IHqlExpression * firstStepped()
  526. {
  527. if (rawStepping.exists())
  528. return rawStepping.fields->queryChild(0);
  529. return NULL;
  530. }
  531. void extractRaw()
  532. {
  533. rawSteppingProject.extractFields(rawStepping);
  534. }
  535. void checkKeyable(MonitorExtractor & monitors)
  536. {
  537. if (!rawStepping.exists())
  538. return;
  539. unsigned prev = NotFound;
  540. ForEachChild(i, rawStepping.fields)
  541. {
  542. IHqlExpression * cur = rawStepping.fields->queryChild(i);
  543. unsigned thisMatch = monitors.queryKeySelectIndex(cur);
  544. if (thisMatch == NotFound)
  545. throwError1(HQLERR_StepFieldNotKeyed, str(cur->queryChild(1)->queryName()));
  546. if ((prev != NotFound) && (thisMatch != prev+1))
  547. throwError1(HQLERR_StepFieldNotContiguous, str(cur->queryChild(1)->queryName()));
  548. prev = thisMatch;
  549. }
  550. }
  551. void generateMembers(HqlCppTranslator & translator, BuildCtx & ctx)
  552. {
  553. rawStepping.generateSteppingMetaMember(translator, ctx, "RawSteppingMeta");
  554. if (outputStepping.exists())
  555. {
  556. if (outputStepping.exists() && outputStepping.ds != rawStepping.ds)
  557. {
  558. outputStepping.generateSteppingMetaMember(translator, ctx, "ProjectedSteppingMeta");
  559. BuildCtx transformctx(ctx);
  560. transformctx.addQuotedCompoundLiteral("virtual void mapOutputToInput(ARowBuilder & crSelf, const void * _projected, unsigned numFields)");
  561. translator.ensureRowAllocated(transformctx, "crSelf");
  562. transformctx.addQuotedLiteral("const byte * pr = (const byte *)_projected;");
  563. translator.bindTableCursor(transformctx, rawStepping.ds, "crSelf.row()");
  564. translator.bindTableCursor(transformctx, outputStepping.ds, "pr");
  565. StringBuffer s;
  566. ForEachChild(i, outputStepping.fields)
  567. {
  568. IHqlExpression * curOutput = outputStepping.fields->queryChild(i);
  569. IHqlExpression * curRawExpr = rawSteppingProject.fields->queryChild(i);
  570. IHqlExpression * curRawSelect = rawStepping.fields->queryChild(i);
  571. OwnedHqlExpr original = outputStepping.invertTransform(curRawExpr, curOutput);
  572. transformctx.addQuoted(s.clear().append("if (numFields < ").append(i+1).append(") return;"));
  573. translator.buildAssign(transformctx, curRawSelect, original);
  574. }
  575. }
  576. }
  577. else
  578. {
  579. OwnedHqlExpr fail = createValue(no_fail, makeVoidType(), createConstant("Cannot step output of index read"));
  580. BuildCtx transformctx(ctx);
  581. transformctx.addQuotedCompoundLiteral("virtual void mapOutputToInput(void * _original, const void * _projected, unsigned numFields)");
  582. translator.buildStmt(transformctx, fail);
  583. }
  584. }
  585. public:
  586. SteppingFieldSelection outputStepping;
  587. SteppingFieldSelection rawSteppingProject;
  588. SteppingFieldSelection rawStepping;
  589. };
  590. //---------------------------------------------------------------------------
  591. class SourceBuilder
  592. {
  593. public:
  594. SourceBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  595. : tableExpr(_tableExpr), translator(_translator)
  596. {
  597. nameExpr.setown(foldHqlExpression(_nameExpr));
  598. needDefaultTransform = true;
  599. needToCallTransform = false;
  600. isPreloaded = false;
  601. isCompoundCount = false;
  602. transformCanFilter = false;
  603. IHqlExpression * preload = tableExpr ? tableExpr->queryAttribute(preloadAtom) : NULL;
  604. if (preload)
  605. {
  606. isPreloaded = true;
  607. preloadSize.set(preload->queryChild(0));
  608. }
  609. failedFilterValue.set(queryZero());
  610. isNormalize = false;
  611. aggregation = false;
  612. instance = NULL;
  613. returnIfFilterFails = true;
  614. useFilterMappings = true;
  615. generateUnfilteredTransform = false;
  616. allowDynamicFormatChange = tableExpr && !tableExpr->hasAttribute(fixedAtom);
  617. onlyExistsAggreate = false;
  618. monitorsForGrouping = false;
  619. useImplementationClass = false;
  620. isUnfilteredCount = false;
  621. isVirtualLogicalFilenameUsed = false;
  622. requiresOrderedMerge = false;
  623. rootSelfRow = NULL;
  624. activityKind = TAKnone;
  625. }
  626. virtual ~SourceBuilder() {}
  627. virtual void buildMembers(IHqlExpression * expr) = 0;
  628. virtual void buildTransformFpos(BuildCtx & transformCtx) = 0;
  629. virtual void extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds);
  630. virtual void buildTransformElements(BuildCtx & ctx, IHqlExpression * expr, bool ignoreFilters);
  631. virtual void buildTransform(IHqlExpression * expr) = 0;
  632. virtual void analyse(IHqlExpression * expr);
  633. void buildFilenameMember();
  634. void appendFilter(SharedHqlExpr & unkeyedFilter, IHqlExpression * expr);
  635. void buildKeyedLimitHelper(IHqlExpression * expr);
  636. void buildLimits(BuildCtx & classctx, IHqlExpression * expr, unique_id_t id);
  637. void buildReadMembers( IHqlExpression * expr);
  638. void buildSteppingMeta(IHqlExpression * expr, MonitorExtractor * monitors);
  639. void buildTransformBody(BuildCtx & transformCtx, IHqlExpression * expr, bool returnSize, bool ignoreFilters, bool bindInputRow);
  640. void checkDependencies(BuildCtx & ctx, IHqlExpression * expr);
  641. bool containsStepping(IHqlExpression * expr);
  642. ABoundActivity * buildActivity(BuildCtx & ctx, IHqlExpression * expr, ThorActivityKind activityKind, const char *kind, ABoundActivity *input);
  643. void gatherVirtualFields(bool ignoreVirtuals, bool ensureSerialized);
  644. bool recordHasVirtuals() { return fieldInfo.hasVirtuals(); }
  645. bool recordHasVirtualsOrDeserialize() { return fieldInfo.hasVirtualsOrDeserialize(); }
  646. bool isSourceInvariant(IHqlExpression * dataset, IHqlExpression * expr);
  647. bool hasExistChoosenLimit() { return (choosenValue && getIntValue(choosenValue) == 1); }
  648. protected:
  649. void assignLocalExtract(BuildCtx & ctx, ParentExtract * extractBuilder, IHqlExpression * dataset, const char * argName);
  650. void associateFilePositions(BuildCtx & ctx, const char * provider, const char * rowname);
  651. void buildSteppedHelpers();
  652. void doBuildAggregateSelectIterator(BuildCtx & ctx, IHqlExpression * expr);
  653. void doBuildNormalizeIterators(BuildCtx & ctx, IHqlExpression * expr, bool isChildIterator);
  654. void buildAggregateHelpers(IHqlExpression * expr);
  655. void buildCountHelpers(IHqlExpression * expr, bool allowMultiple);
  656. virtual void buildFlagsMember(IHqlExpression * expr) {}
  657. void buildGlobalGroupAggregateHelpers(IHqlExpression * expr);
  658. void buildGroupAggregateHelpers(ParentExtract * extractBuilder, IHqlExpression * aggregate);
  659. void buildGroupAggregateCompareHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, HqlExprArray & recordFields, HqlExprArray & agrgegateFields);
  660. void buildGroupAggregateHashHelper(ParentExtract * extractBuilder, IHqlExpression * dataset, IHqlExpression * fields);
  661. void buildGroupAggregateProcessHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, const char * name, bool doneAny);
  662. void buildGroupingMonitors(IHqlExpression * expr, MonitorExtractor & monitors);
  663. void buildGroupAggregateTransformBody(BuildCtx & transformctx, IHqlExpression * expr, bool useExtract, bool bindInputRow);
  664. void buildNormalizeHelpers(IHqlExpression * expr);
  665. void buildTargetCursor(Shared<BoundRow> & tempRow, Shared<BoundRow> & rowBuilder, BuildCtx & ctx, IHqlExpression * expr);
  666. void associateTargetCursor(BuildCtx & subctx, BuildCtx & ctx, BoundRow * tempRow, BoundRow * rowBuilder, IHqlExpression * expr);
  667. IHqlExpression * ensureAggregateGroupingAliased(IHqlExpression * aggregate);
  668. void gatherSteppingMeta(IHqlExpression * expr, SourceSteppingInfo & info);
  669. void gatherSteppingMeta(IHqlExpression * expr, SteppingFieldSelection & outputStepping, SteppingFieldSelection & rawStepping);
  670. void gatherFieldUsage(SourceFieldUsage * fieldUsage, IHqlExpression * expr);
  671. void rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq, bool isLocal);
  672. void rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq);
  673. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr);
  674. virtual void analyseGraph(IHqlExpression * expr);
  675. virtual bool isExplicitExists() { return false; }
  676. public:
  677. VirtualFieldsInfo fieldInfo;
  678. ActivityInstance * instance;
  679. BoundRow * rootSelfRow;
  680. HqlExprAttr tableExpr;
  681. HqlExprAttr nameExpr;
  682. HqlExprAttr fpos;
  683. HqlExprAttr lfpos;
  684. HqlExprAttr limitExpr;
  685. HqlExprAttr keyedLimitExpr;
  686. HqlExprAttr choosenValue;
  687. HqlExprAttr preloadSize;
  688. HqlExprAttr lastTransformer;
  689. HqlExprAttr alreadyDoneFlag;
  690. HqlExprArray originalFilters;
  691. HqlExprArray mappedFilters;
  692. HqlExprArray removedFilters;
  693. HqlExprAttr failedFilterValue;
  694. HqlExprAttr compoundCountVar;
  695. HqlExprAttr physicalRecord;
  696. HqlExprAttr steppedExpr;
  697. Linked<BuildCtx> globaliterctx;
  698. HqlExprCopyArray parentCursors;
  699. HqlExprAttr logicalFilenameMarker;
  700. ThorActivityKind activityKind;
  701. bool useFilterMappings;
  702. bool needDefaultTransform;
  703. bool needToCallTransform;
  704. bool isPreloaded;
  705. bool transformCanFilter;
  706. bool isCompoundCount;
  707. bool isNormalize;
  708. bool aggregation;
  709. bool returnIfFilterFails;
  710. bool allowDynamicFormatChange;
  711. bool onlyExistsAggreate;
  712. bool monitorsForGrouping;
  713. bool generateUnfilteredTransform;
  714. bool useImplementationClass;
  715. bool isUnfilteredCount;
  716. bool isVirtualLogicalFilenameUsed;
  717. bool requiresOrderedMerge;
  718. protected:
  719. HqlCppTranslator & translator;
  720. };
  721. struct HQLCPP_API HqlFilePositionDefinedValue : public HqlSimpleDefinedValue
  722. {
  723. public:
  724. HqlFilePositionDefinedValue(SourceBuilder & _builder, IHqlExpression * _original, IHqlExpression * _expr)
  725. : HqlSimpleDefinedValue(_original, _expr), builder(_builder)
  726. { }
  727. virtual IHqlExpression * queryExpr() const
  728. {
  729. builder.isVirtualLogicalFilenameUsed = true;
  730. return HqlSimpleDefinedValue::queryExpr();
  731. }
  732. public:
  733. SourceBuilder & builder;
  734. };
  735. bool SourceBuilder::isSourceInvariant(IHqlExpression * dataset, IHqlExpression * expr)
  736. {
  737. if (containsAssertKeyed(expr))
  738. return false;
  739. if (!containsActiveDataset(expr))
  740. return true;
  741. HqlExprCopyArray inScope;
  742. expr->gatherTablesUsed(NULL, &inScope);
  743. if (!canEvaluateInScope(parentCursors, inScope))
  744. return false;
  745. //Carefull.... It looks ok, but it is possible that the same dataset occurs at multiple levels (sqfilt.hql)
  746. //So need to be careful that the datasets being referenced aren't newly in scope for this activity...
  747. for (;;)
  748. {
  749. if (inScope.contains(*dataset->queryNormalizedSelector()))
  750. return false;
  751. //To be strictly correct we need to walk no_select chain of root datasets!
  752. dataset = queryNextMultiLevelDataset(dataset, true);
  753. if (!dataset)
  754. return true;
  755. }
  756. }
  757. void SourceBuilder::analyse(IHqlExpression * expr)
  758. {
  759. IHqlExpression * body = expr->queryBody(true);
  760. if (expr != body)
  761. {
  762. switch (expr->getAnnotationKind())
  763. {
  764. case annotate_meta:
  765. //the onwarning state will be restored by the scope held in HqlCppTranslator::buildActivity
  766. translator.localOnWarnings->processMetaAnnotation(expr);
  767. break;
  768. case annotate_location:
  769. instance->addLocationAttribute(expr);
  770. break;
  771. case annotate_symbol:
  772. //don't clear onWarnings when we hit a symbol because the warnings within a compound activity aren't generated at the correct point
  773. instance->addNameAttribute(expr);
  774. break;
  775. }
  776. analyse(body);
  777. return;
  778. }
  779. node_operator op = expr->getOperator();
  780. switch (op)
  781. {
  782. case no_cachealias:
  783. analyse(expr->queryChild(1));
  784. return;
  785. case no_newkeyindex:
  786. case no_table:
  787. case no_fetch:
  788. case no_select: // handled below
  789. case no_null:
  790. case no_anon:
  791. case no_pseudods:
  792. case no_workunit_dataset:
  793. case no_call:
  794. case no_externalcall:
  795. case no_rows:
  796. case no_libraryinput:
  797. break;
  798. default:
  799. analyse(expr->queryChild(0));
  800. break;
  801. }
  802. switch (op)
  803. {
  804. case no_table:
  805. case no_newkeyindex:
  806. if (fieldInfo.hasVirtuals())
  807. {
  808. assertex(fieldInfo.simpleVirtualsAtEnd);
  809. needToCallTransform = true;
  810. needDefaultTransform = false;
  811. }
  812. break;
  813. case no_null:
  814. case no_anon:
  815. case no_pseudods:
  816. case no_workunit_dataset:
  817. case no_getgraphresult:
  818. case no_call:
  819. case no_externalcall:
  820. case no_rows:
  821. case no_libraryinput:
  822. break;
  823. case no_filter:
  824. {
  825. OwnedHqlExpr unkeyedFilter;
  826. HqlExprArray conds;
  827. unwindFilterConditions(conds, expr);
  828. extractMonitors(expr, unkeyedFilter, conds);
  829. if (unkeyedFilter)
  830. {
  831. transformCanFilter = true;
  832. originalFilters.append(*LINK(expr));
  833. mappedFilters.append(*unkeyedFilter.getClear());
  834. }
  835. else
  836. removedFilters.append(*LINK(expr));
  837. break;
  838. }
  839. case no_select:
  840. {
  841. bool isNew;
  842. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  843. if (isNew && isMultiLevelDatasetSelector(expr, false))
  844. {
  845. if (!translator.resolveSelectorDataset(instance->startctx, ds))
  846. {
  847. analyse(ds);
  848. isNormalize = true;
  849. }
  850. }
  851. break;
  852. }
  853. case no_stepped:
  854. if (steppedExpr)
  855. throwError(HQLERR_MultipleStepped);
  856. steppedExpr.set(expr);
  857. break;
  858. case no_sorted:
  859. case no_distributed:
  860. case no_preservemeta:
  861. case no_unordered:
  862. case no_grouped:
  863. case no_alias_scope:
  864. case no_section:
  865. case no_sectioninput:
  866. case no_nofold:
  867. case no_nohoist:
  868. case no_nocombine:
  869. case no_dataset_alias:
  870. break;
  871. case no_preload:
  872. isPreloaded = true;
  873. preloadSize.set(queryRealChild(expr, 1));
  874. break;
  875. case no_limit:
  876. limitExpr.set(expr);
  877. break;
  878. case no_keyedlimit:
  879. keyedLimitExpr.set(expr);
  880. break;
  881. case no_choosen:
  882. {
  883. choosenValue.set(expr->queryChild(1));
  884. IHqlExpression * first = queryRealChild(expr, 2);
  885. if (first)
  886. {
  887. Owned<ITypeInfo> type = makeIntType(8, true);
  888. choosenValue.setown(createValue(no_sub, LINK(type), createValue(no_add, LINK(type), ensureExprType(choosenValue, type), ensureExprType(first, type)), createConstant(I64C(1))));
  889. }
  890. choosenValue.setown(foldHqlExpression(choosenValue));
  891. }
  892. break;
  893. case no_hqlproject:
  894. needToCallTransform = true;
  895. needDefaultTransform = false;
  896. lastTransformer.set(expr);
  897. break;
  898. case no_newusertable:
  899. needToCallTransform = true;
  900. needDefaultTransform = false;
  901. lastTransformer.set(expr);
  902. break;
  903. case no_aggregate:
  904. {
  905. needToCallTransform = true;
  906. needDefaultTransform = false;
  907. aggregation = true;
  908. lastTransformer.set(expr);
  909. break;
  910. }
  911. case no_newaggregate:
  912. {
  913. needToCallTransform = true;
  914. needDefaultTransform = false;
  915. aggregation = true;
  916. lastTransformer.set(expr);
  917. IHqlExpression * transform = expr->queryChild(2);
  918. node_operator aggOp = queryTransformSingleAggregate(transform);
  919. onlyExistsAggreate = ((aggOp == no_existsgroup) || (aggOp == no_none)); // The implicit project code can remove all the aggregate() operators....
  920. if (isCompoundCount)
  921. {
  922. IHqlExpression * rhs = transform->queryChild(0)->queryChild(1);
  923. IHqlExpression * filter = queryRealChild(rhs, 0);
  924. if (filter)
  925. transformCanFilter = true;
  926. }
  927. break;
  928. }
  929. case no_usertable:
  930. case no_selectfields:
  931. UNIMPLEMENTED;
  932. break;
  933. case no_fetch:
  934. needToCallTransform = true;
  935. needDefaultTransform = false;
  936. lastTransformer.set(expr);
  937. break;
  938. case no_compound_diskread:
  939. case no_compound_disknormalize:
  940. case no_compound_diskaggregate:
  941. case no_compound_diskcount:
  942. case no_compound_diskgroupaggregate:
  943. case no_compound_indexread:
  944. case no_compound_indexnormalize:
  945. case no_compound_indexaggregate:
  946. case no_compound_indexcount:
  947. case no_compound_indexgroupaggregate:
  948. case no_compound_childread:
  949. case no_compound_childnormalize:
  950. case no_compound_childaggregate:
  951. case no_compound_childcount:
  952. case no_compound_childgroupaggregate:
  953. case no_compound_fetch:
  954. case no_compound_selectnew:
  955. break;
  956. default:
  957. throwUnexpectedOp(op);
  958. }
  959. }
  960. void SourceBuilder::appendFilter(SharedHqlExpr & unkeyedFilter, IHqlExpression * expr)
  961. {
  962. if (expr)
  963. {
  964. if (expr->queryValue())
  965. {
  966. if (!expr->queryValue()->getBoolValue())
  967. unkeyedFilter.set(expr);
  968. }
  969. else
  970. {
  971. if (unkeyedFilter)
  972. unkeyedFilter.setown(createValue(no_and, unkeyedFilter.getClear(), LINK(expr)));
  973. else
  974. unkeyedFilter.set(expr);
  975. }
  976. }
  977. }
  978. void SourceBuilder::associateFilePositions(BuildCtx & ctx, const char * provider, const char * rowname)
  979. {
  980. if (fpos)
  981. {
  982. Owned<IHqlExpression> fposExpr = createFileposCall(translator, getFilePositionId, provider, rowname);
  983. ctx.associateExpr(fpos, fposExpr);
  984. }
  985. if (lfpos)
  986. {
  987. Owned<IHqlExpression> fposExpr = createFileposCall(translator, getLocalFilePositionId, provider, rowname);
  988. ctx.associateExpr(lfpos, fposExpr);
  989. }
  990. if (logicalFilenameMarker)
  991. {
  992. Owned<IHqlExpression> nameExpr = createFileposCall(translator, queryLogicalFilenameId, provider, rowname);
  993. ctx.associateOwn(*new HqlFilePositionDefinedValue(*this, logicalFilenameMarker, nameExpr));
  994. }
  995. }
  996. void SourceBuilder::rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq, bool isLocal)
  997. {
  998. if (!tableExpr)
  999. return;
  1000. OwnedHqlExpr searchPos = getFilepos(tableExpr, isLocal);
  1001. HqlExprAssociation * match = ctx.queryMatchExpr(searchPos);
  1002. if (match)
  1003. {
  1004. OwnedHqlExpr selector = createSelector(side, dataset, selSeq);
  1005. OwnedHqlExpr selectorFpos = getFilepos(selector, isLocal);
  1006. ctx.associateExpr(selectorFpos, match->queryExpr());
  1007. }
  1008. }
  1009. void SourceBuilder::rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq)
  1010. {
  1011. bool savedIsVirtualLogicalFilenameUsed = isVirtualLogicalFilenameUsed; // don't allow the rebinding to set the flag.
  1012. rebindFilepositons(ctx, dataset, side, selSeq, true);
  1013. rebindFilepositons(ctx, dataset, side, selSeq, false);
  1014. OwnedHqlExpr searchLogicalFilename = getFileLogicalName(dataset);
  1015. HqlExprAssociation * match = ctx.queryMatchExpr(searchLogicalFilename);
  1016. if (match)
  1017. {
  1018. OwnedHqlExpr selector = createSelector(side, dataset, selSeq);
  1019. OwnedHqlExpr selectorLogicalFilename = getFileLogicalName(dataset);
  1020. ctx.associateOwn(*new HqlFilePositionDefinedValue(*this, selectorLogicalFilename, match->queryExpr()));
  1021. }
  1022. isVirtualLogicalFilenameUsed = savedIsVirtualLogicalFilenameUsed;
  1023. }
  1024. void SourceBuilder::buildFilenameMember()
  1025. {
  1026. //---- virtual const char * getFileName() { return "x.d00"; } ----
  1027. translator.buildFilenameFunction(*instance, instance->startctx, "getFileName", nameExpr, translator.hasDynamicFilename(tableExpr));
  1028. }
  1029. void SourceBuilder::buildReadMembers(IHqlExpression * expr)
  1030. {
  1031. buildFilenameMember();
  1032. //---- virtual bool needTransform() { return <bool>; } ----
  1033. if (needToCallTransform || transformCanFilter)
  1034. translator.doBuildBoolFunction(instance->classctx, "needTransform", true);
  1035. //---- virtual bool needTransform() { return <bool>; } ----
  1036. if (transformCanFilter)
  1037. translator.doBuildBoolFunction(instance->classctx, "transformMayFilter", true);
  1038. }
  1039. void SourceBuilder::buildLimits(BuildCtx & classctx, IHqlExpression * expr, unique_id_t id)
  1040. {
  1041. if (limitExpr)
  1042. translator.buildLimitHelpers(classctx, limitExpr, nameExpr, id);
  1043. if (choosenValue)
  1044. {
  1045. BuildCtx funcctx(classctx);
  1046. funcctx.addQuotedCompoundLiteral("virtual unsigned __int64 getChooseNLimit()");
  1047. OwnedHqlExpr newLimit = ensurePositiveOrZeroInt64(choosenValue);
  1048. translator.buildReturn(funcctx, newLimit);
  1049. }
  1050. }
  1051. void SourceBuilder::buildTransformBody(BuildCtx & transformCtx, IHqlExpression * expr, bool returnSize, bool ignoreFilters, bool bindInputRow)
  1052. {
  1053. if (tableExpr && bindInputRow)
  1054. {
  1055. IHqlExpression * mode = (tableExpr->getOperator() == no_table) ? tableExpr->queryChild(2) : NULL;
  1056. if (mode && mode->getOperator() == no_csv)
  1057. {
  1058. translator.bindCsvTableCursor(transformCtx, tableExpr, "Src", no_none, NULL, true, queryCsvEncoding(mode));
  1059. }
  1060. else
  1061. {
  1062. //NOTE: The source is not link counted - it comes from a prefetched row, and does not include any virtual file position field.
  1063. OwnedHqlExpr boundSrc = createVariable("left", makeRowReferenceType(physicalRecord));
  1064. transformCtx.associateOwn(*new BoundRow(tableExpr->queryNormalizedSelector(), boundSrc, translator.queryRecordOffsetMap(physicalRecord), no_none, NULL));
  1065. }
  1066. transformCtx.addGroup();
  1067. }
  1068. rootSelfRow = translator.bindSelf(transformCtx, expr, "crSelf");
  1069. buildTransformFpos(transformCtx);
  1070. buildTransformElements(transformCtx, expr, ignoreFilters);
  1071. if (returnSize)
  1072. {
  1073. CHqlBoundExpr boundTargetSize;
  1074. if (needDefaultTransform)
  1075. {
  1076. IHqlExpression * left = expr->queryNormalizedSelector();
  1077. OwnedHqlExpr source = ensureActiveRow(left);
  1078. translator.buildAssign(transformCtx, rootSelfRow->querySelector(), source);
  1079. }
  1080. translator.getRecordSize(transformCtx, rootSelfRow->querySelector(), boundTargetSize);
  1081. transformCtx.setNextDestructor();
  1082. transformCtx.addReturn(boundTargetSize.expr);
  1083. }
  1084. rootSelfRow = NULL;
  1085. }
  1086. void SourceBuilder::buildTargetCursor(Shared<BoundRow> & tempRow, Shared<BoundRow> & rowBuilder, BuildCtx & ctx, IHqlExpression * expr)
  1087. {
  1088. assertex(lastTransformer != NULL);
  1089. if (expr == lastTransformer)
  1090. {
  1091. rowBuilder.set(rootSelfRow);
  1092. }
  1093. else
  1094. {
  1095. tempRow.setown(translator.declareTempAnonRow(ctx, ctx, expr));
  1096. ctx.addGroup();
  1097. // group is important, otherwise sizeof(self.x) gets cached incorrectly
  1098. // not so sure, but references to LEFT(x) may be misresolved
  1099. rowBuilder.setown(translator.createRowBuilder(ctx, tempRow));
  1100. }
  1101. }
  1102. void SourceBuilder::associateTargetCursor(BuildCtx & subctx, BuildCtx & ctx, BoundRow * tempRow, BoundRow * rowBuilder, IHqlExpression * expr)
  1103. {
  1104. //First remove the old active dataset
  1105. //This is not strictly necessary, but it avoids the redundant row being serialized to any child queries
  1106. BoundRow * oldCursor = translator.resolveSelectorDataset(ctx, expr->queryChild(0));
  1107. ctx.removeAssociation(oldCursor);
  1108. //And add an association for expr
  1109. if (tempRow)
  1110. {
  1111. translator.finalizeTempRow(subctx, tempRow, rowBuilder);
  1112. translator.bindTableCursor(ctx, expr, tempRow->queryBound());
  1113. }
  1114. else
  1115. translator.bindTableCursor(ctx, expr, rowBuilder->queryBound());
  1116. }
  1117. void SourceBuilder::buildTransformElements(BuildCtx & ctx, IHqlExpression * expr, bool ignoreFilters)
  1118. {
  1119. //This function can be called again for the unfiltered tranform. Don't process annotations again.
  1120. if ((expr != instance->dataset) && !ignoreFilters)
  1121. instance->processAnnotations(expr);
  1122. expr = expr->queryBody();
  1123. node_operator op = expr->getOperator();
  1124. switch (op)
  1125. {
  1126. case no_cachealias:
  1127. buildTransformElements(ctx, expr->queryChild(1), ignoreFilters);
  1128. return;
  1129. case no_newkeyindex:
  1130. case no_table:
  1131. case no_fetch:
  1132. case no_select: // handled below
  1133. case no_null:
  1134. case no_anon:
  1135. case no_pseudods:
  1136. case no_workunit_dataset:
  1137. case no_getgraphresult:
  1138. case no_call:
  1139. case no_externalcall:
  1140. case no_rows:
  1141. case no_libraryinput:
  1142. break;
  1143. default:
  1144. buildTransformElements(ctx, expr->queryChild(0), ignoreFilters);
  1145. break;
  1146. }
  1147. switch (op)
  1148. {
  1149. case no_newkeyindex:
  1150. case no_table:
  1151. if (fieldInfo.hasVirtuals())
  1152. {
  1153. IHqlExpression * record = expr->queryRecord();
  1154. assertex(fieldInfo.simpleVirtualsAtEnd);
  1155. assertex(!recordRequiresSerialization(record, diskAtom));
  1156. CHqlBoundExpr bound;
  1157. StringBuffer s;
  1158. translator.getRecordSize(ctx, expr, bound);
  1159. size32_t virtualSize = 0;
  1160. ForEachChild(idx, record)
  1161. {
  1162. IHqlExpression * field = record->queryChild(idx);
  1163. IHqlExpression * virtualAttr = field->queryAttribute(virtualAtom);
  1164. if (virtualAttr)
  1165. {
  1166. size32_t fieldSize = field->queryType()->getSize();
  1167. assertex(fieldSize != UNKNOWN_LENGTH);
  1168. virtualSize += fieldSize;
  1169. }
  1170. }
  1171. if (!isFixedSizeRecord(record))
  1172. {
  1173. OwnedHqlExpr ensureSize = adjustValue(bound.expr, virtualSize);
  1174. s.clear().append("crSelf.ensureCapacity(");
  1175. translator.generateExprCpp(s, ensureSize).append(", NULL);");
  1176. ctx.addQuoted(s);
  1177. }
  1178. s.clear().append("memcpy(crSelf.row(), left, ");
  1179. translator.generateExprCpp(s, bound.expr).append(");");
  1180. ctx.addQuoted(s);
  1181. ForEachChild(idx2, record)
  1182. {
  1183. IHqlExpression * field = record->queryChild(idx2);
  1184. IHqlExpression * virtualAttr = field->queryAttribute(virtualAtom);
  1185. if (virtualAttr)
  1186. {
  1187. IHqlExpression * self = rootSelfRow->querySelector();
  1188. OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(field));
  1189. OwnedHqlExpr value = getVirtualReplacement(field, virtualAttr->queryChild(0), expr);
  1190. translator.buildAssign(ctx, target, value);
  1191. }
  1192. }
  1193. }
  1194. break;
  1195. case no_null:
  1196. case no_anon:
  1197. case no_pseudods:
  1198. break;
  1199. case no_workunit_dataset:
  1200. case no_getgraphresult:
  1201. case no_call:
  1202. case no_externalcall:
  1203. case no_rows:
  1204. case no_libraryinput:
  1205. throwUnexpectedOp(op);
  1206. break;
  1207. case no_select:
  1208. processTransformSelect(ctx, expr);
  1209. break;
  1210. case no_sorted:
  1211. case no_stepped:
  1212. case no_distributed:
  1213. case no_preservemeta:
  1214. case no_unordered:
  1215. case no_grouped:
  1216. case no_preload:
  1217. case no_limit:
  1218. case no_keyedlimit:
  1219. case no_choosen:
  1220. case no_alias_scope:
  1221. case no_section:
  1222. case no_sectioninput:
  1223. case no_nofold:
  1224. case no_nohoist:
  1225. case no_nocombine:
  1226. break;
  1227. case no_filter:
  1228. {
  1229. if (!ignoreFilters)
  1230. {
  1231. LinkedHqlExpr cond;
  1232. if (useFilterMappings)
  1233. {
  1234. unsigned match = originalFilters.find(*expr);
  1235. if (match != NotFound)
  1236. cond.set(&mappedFilters.item(match));
  1237. }
  1238. else
  1239. {
  1240. HqlExprArray args;
  1241. unwindRealChildren(args, expr, 1);
  1242. cond.setown(createBalanced(no_and, queryBoolType(), args));
  1243. }
  1244. if (cond)
  1245. {
  1246. IHqlExpression * ds = expr->queryChild(0);
  1247. OwnedHqlExpr test = returnIfFilterFails ? getInverse(cond) : LINK(cond);
  1248. if (translator.queryOptions().foldFilter)
  1249. test.setown(foldScopedHqlExpression(translator.queryErrorProcessor(), ds->queryNormalizedSelector(), test));
  1250. if (translator.options.spotCSE)
  1251. test.setown(spotScalarCSE(test, ds, translator.queryOptions().spotCseInIfDatasetConditions));
  1252. if (!returnIfFilterFails)
  1253. translator.buildFilter(ctx, test);
  1254. else
  1255. {
  1256. LinkedHqlExpr mismatchReturnValue = failedFilterValue;
  1257. //If the output row has already been generated, then returning at this point will leak any
  1258. //child datasets. To avoid that we explicitly call the destructor on the output row.
  1259. if (recordRequiresDestructor(expr->queryRecord()))
  1260. {
  1261. if (lastTransformer && lastTransformer->queryNormalizedSelector() == expr->queryNormalizedSelector())
  1262. {
  1263. StringBuffer s;
  1264. translator.buildMetaForRecord(s, expr->queryRecord());
  1265. s.append(".destruct(crSelf.row())");
  1266. OwnedHqlExpr cleanupAction = createQuoted(s.str(), makeVoidType());
  1267. //Create a compound expression (destroy-old, return-value)
  1268. mismatchReturnValue.setown(createCompound(LINK(cleanupAction), LINK(mismatchReturnValue)));
  1269. }
  1270. }
  1271. translator.buildFilteredReturn(ctx, test, mismatchReturnValue);
  1272. }
  1273. }
  1274. }
  1275. }
  1276. break;
  1277. case no_hqlproject:
  1278. {
  1279. IHqlExpression * dataset = expr->queryChild(0);
  1280. IHqlExpression * selSeq = querySelSeq(expr);
  1281. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, querySelSeq(expr));
  1282. //Following is a bit nasty....
  1283. //Converting the no_hqlproject to a no_newusertable means that some of the expressions
  1284. //are commoned up with expressions calculated by a previous filter, reducing the code.
  1285. //However, it isn't valid if transform contains an instance of newSelect -
  1286. //e.g. project(i(x), transform(exists(i....))) - see jholt25.xhql
  1287. //And unfortunately it fails silently.
  1288. //So we use queryReplaceSelector which fails if an ambiguity is introduced by the replacement
  1289. OwnedHqlExpr newSelect = ensureActiveRow(dataset->queryNormalizedSelector());
  1290. OwnedHqlExpr transform = queryNewReplaceSelector(expr->queryChild(1), leftSelect, newSelect);
  1291. BuildCtx subctx(ctx); // buildTargetCursor adds group if necessary
  1292. Linked<BoundRow> tempRow;
  1293. Linked<BoundRow> rowBuilder;
  1294. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1295. if (!transform)
  1296. {
  1297. //The replace introduced an ambiguity => need to use the unmapped expression.
  1298. BoundRow * prevCursor = translator.resolveSelectorDataset(ctx, dataset->queryNormalizedSelector());
  1299. transform.set(expr->queryChild(1));
  1300. translator.rebindTableCursor(subctx, dataset, prevCursor, no_left, selSeq);
  1301. rebindFilepositons(subctx, dataset, no_left, selSeq);
  1302. }
  1303. if (returnIfFilterFails)
  1304. {
  1305. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL); // failedFilterValue already handles clearing the result
  1306. }
  1307. else
  1308. {
  1309. //MORE: Probably not implementable, should try and prevent this happening!
  1310. //translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL);
  1311. }
  1312. translator.doTransform(subctx, transform, rowBuilder);
  1313. ctx.addGroup();
  1314. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1315. }
  1316. break;
  1317. case no_newusertable:
  1318. {
  1319. BuildCtx subctx(ctx);
  1320. Linked<BoundRow> tempRow;
  1321. Linked<BoundRow> rowBuilder;
  1322. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1323. IHqlExpression * transform = expr->queryChild(2);
  1324. if (returnIfFilterFails)
  1325. {
  1326. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL); // failedFilterValue already handles clearing the result
  1327. }
  1328. else
  1329. {
  1330. //MORE: Probably not implementable
  1331. //translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL);
  1332. }
  1333. translator.doTransform(subctx, transform, rowBuilder);
  1334. ctx.addGroup();
  1335. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1336. }
  1337. break;
  1338. case no_aggregate:
  1339. {
  1340. if (alreadyDoneFlag)
  1341. {
  1342. IHqlExpression * dataset = expr->queryChild(0);
  1343. IHqlExpression * selSeq = querySelSeq(expr);
  1344. IHqlExpression * transform = expr->queryChild(2);
  1345. BuildCtx subctx(ctx);
  1346. //Similar code to no_hqlproject. Should possibly try and do a similar mapping to the transforms
  1347. //(but complicated by having merge/first)
  1348. BoundRow * prevCursor = translator.resolveSelectorDataset(ctx, dataset);
  1349. translator.rebindTableCursor(subctx, dataset, prevCursor, no_left, selSeq);
  1350. rebindFilepositons(subctx, dataset, no_left, selSeq);
  1351. Linked<BoundRow> tempRow;
  1352. Linked<BoundRow> rowBuilder;
  1353. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1354. translator.doBuildUserAggregateProcessTransform(subctx, rowBuilder, expr, transform, alreadyDoneFlag);
  1355. subctx.addAssign(alreadyDoneFlag, queryBoolExpr(true));
  1356. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1357. }
  1358. }
  1359. break;
  1360. case no_newaggregate:
  1361. {
  1362. IHqlExpression * transform = expr->queryChild(2);
  1363. if (isCompoundCount)
  1364. {
  1365. //This should really be special cased in a count() baseclass, but can't be bothered at the moment.
  1366. IHqlExpression * rhs = transform->queryChild(0)->queryChild(1);
  1367. IHqlExpression * filter = queryRealChild(rhs, 0);
  1368. if (filter)
  1369. {
  1370. if (!returnIfFilterFails)
  1371. translator.buildFilter(ctx, filter);
  1372. else
  1373. {
  1374. OwnedHqlExpr test = getInverse(filter);
  1375. translator.buildFilteredReturn(ctx, test, failedFilterValue);
  1376. }
  1377. }
  1378. if (compoundCountVar)
  1379. {
  1380. OwnedHqlExpr inc = adjustValue(compoundCountVar, 1);
  1381. ctx.addAssign(compoundCountVar, inc);
  1382. }
  1383. }
  1384. else if (alreadyDoneFlag)
  1385. {
  1386. BuildCtx subctx(ctx);
  1387. Linked<BoundRow> tempRow;
  1388. Linked<BoundRow> rowBuilder;
  1389. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1390. translator.doBuildAggregateProcessTransform(subctx, rowBuilder, expr, alreadyDoneFlag);
  1391. subctx.addAssign(alreadyDoneFlag, queryBoolExpr(true));
  1392. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1393. }
  1394. }
  1395. break;
  1396. case no_usertable:
  1397. case no_selectfields:
  1398. UNIMPLEMENTED;
  1399. break;
  1400. case no_fetch:
  1401. {
  1402. BuildCtx subctx(ctx);
  1403. Linked<BoundRow> tempRow;
  1404. Linked<BoundRow> rowBuilder;
  1405. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1406. // MORE - don't understand why this is required here but not in hqlproject above
  1407. IHqlExpression * dataset = expr->queryChild(0);
  1408. BoundRow * leftCursor;
  1409. switch (getDatasetKind(tableExpr))
  1410. {
  1411. case no_csv:
  1412. leftCursor = translator.bindCsvTableCursor(subctx, dataset, "Left", no_left, querySelSeq(expr), true, queryCsvTableEncoding(tableExpr));
  1413. break;
  1414. case no_xml:
  1415. case no_json:
  1416. leftCursor = translator.bindXmlTableCursor(subctx, dataset, "xmlLeft", no_left, querySelSeq(expr), true);
  1417. break;
  1418. default:
  1419. leftCursor = translator.bindTableCursor(subctx, dataset, "left", no_left, querySelSeq(expr));
  1420. break;
  1421. }
  1422. BoundRow * rightCursor = NULL;
  1423. LinkedHqlExpr transform = expr->queryChild(3);
  1424. if (!containsOnlyLeft(transform, true))
  1425. {
  1426. IHqlExpression * rhs = expr->queryChild(1);
  1427. IHqlExpression * memoryRhsRecord = rhs->queryRecord();
  1428. //RIGHT is the input data row.
  1429. //a) In hthor the remote file is read locally, so RIGHT is a deserialized unmodified row.
  1430. //b) in roxie it is serialized, and accessed in its serialized form.
  1431. //c) in thor it is serialized, but also (inefficiently) deserialized, so use the deserialized form.
  1432. //NOTE: Currently extractJoinFields either does nothing, or sends the entire row. Needless to say that could be improved -
  1433. //and would mean the roxie/thor code required changing
  1434. if (translator.targetRoxie())
  1435. {
  1436. OwnedHqlExpr serializedRhsRecord = getSerializedForm(memoryRhsRecord, diskAtom);
  1437. OwnedHqlExpr serializedRhs = createDataset(no_null, LINK(serializedRhsRecord));
  1438. rightCursor = translator.bindTableCursor(subctx, serializedRhs, "right", no_right, querySelSeq(expr));
  1439. transform.setown(replaceMemorySelectorWithSerializedSelector(transform, memoryRhsRecord, no_right, querySelSeq(expr), diskAtom));
  1440. }
  1441. else
  1442. {
  1443. rightCursor = translator.bindTableCursor(subctx, rhs, "right", no_right, querySelSeq(expr));
  1444. }
  1445. }
  1446. buildTransformFpos(subctx); // unusual, but this must occur after the row cursor is bound
  1447. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL); // failedFilterValue already handles clearing the result
  1448. translator.doTransform(subctx, transform, rowBuilder);
  1449. subctx.removeAssociation(leftCursor);
  1450. subctx.removeAssociation(rightCursor);
  1451. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1452. }
  1453. break;
  1454. case no_compound_diskread:
  1455. case no_compound_disknormalize:
  1456. case no_compound_diskaggregate:
  1457. case no_compound_diskcount:
  1458. case no_compound_diskgroupaggregate:
  1459. case no_compound_indexread:
  1460. case no_compound_indexnormalize:
  1461. case no_compound_indexaggregate:
  1462. case no_compound_indexcount:
  1463. case no_compound_indexgroupaggregate:
  1464. case no_compound_childread:
  1465. case no_compound_childnormalize:
  1466. case no_compound_childaggregate:
  1467. case no_compound_childcount:
  1468. case no_compound_childgroupaggregate:
  1469. case no_compound_fetch:
  1470. case no_compound_selectnew:
  1471. break;
  1472. default:
  1473. throwUnexpectedOp(op);
  1474. }
  1475. }
  1476. void SourceBuilder::doBuildAggregateSelectIterator(BuildCtx & ctx, IHqlExpression * expr)
  1477. {
  1478. IHqlExpression * ds = expr->queryChild(0);
  1479. if (isNewSelector(expr))
  1480. buildTransformElements(ctx, ds, false);
  1481. Owned<IHqlCppDatasetCursor> cursor = translator.createDatasetSelector(ctx, expr->queryNormalizedSelector());
  1482. cursor->buildIterateLoop(ctx, false);
  1483. }
  1484. void SourceBuilder::processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  1485. {
  1486. throwUnexpected();
  1487. }
  1488. void SourceBuilder::doBuildNormalizeIterators(BuildCtx & ctx, IHqlExpression * expr, bool isChildIterator)
  1489. {
  1490. HqlExprArray iterators;
  1491. IHqlExpression * root = gatherSelectorLevels(iterators, expr);
  1492. //MORE: transform also needs to be inside this iterctx
  1493. BuildCtx iterctx(*globaliterctx);
  1494. BuildCtx firstctx(instance->startctx);
  1495. CursorArray cursors;
  1496. if (isChildIterator)
  1497. {
  1498. assertex(!root);
  1499. firstctx.addQuotedCompoundLiteral("virtual bool first()");
  1500. }
  1501. else
  1502. {
  1503. assertex(root);
  1504. firstctx.addQuotedCompoundLiteral("virtual bool first(const void * _src)");
  1505. bool isProjected = (root->queryNormalizedSelector() != tableExpr->queryNormalizedSelector());
  1506. if (!isProjected)
  1507. {
  1508. iterctx.addQuotedLiteral("byte * src;");
  1509. associateFilePositions(iterctx, "activity->fpp", "activity->src"); // in case no projection in first()
  1510. translator.associateBlobHelper(iterctx, tableExpr, "fpp");
  1511. firstctx.addQuotedLiteral("src = (byte *)_src;");
  1512. }
  1513. else
  1514. {
  1515. firstctx.addQuotedLiteral("byte * src = (byte *)_src;");
  1516. }
  1517. translator.associateBlobHelper(firstctx, tableExpr, "fpp");
  1518. BoundRow * tableCursor = translator.bindTableCursor(firstctx, tableExpr, "src");
  1519. associateFilePositions(firstctx, "fpp", "src");
  1520. TransformSequenceBuilder builder(translator, queryBoolExpr(false));
  1521. builder.buildSequence(firstctx, &iterctx, root);
  1522. if (!isProjected)
  1523. cursors.append(*LINK(tableCursor));
  1524. else
  1525. {
  1526. BoundRow * match = translator.resolveSelectorDataset(firstctx, root);
  1527. assertex(match);
  1528. cursors.append(*LINK(match));
  1529. }
  1530. }
  1531. CompoundIteratorBuilder iterBuilder(translator, instance->nestedctx, iterctx);
  1532. if (iterators.ordinality() == 1)
  1533. {
  1534. StringBuffer s, iterName, cursorName;
  1535. iterBuilder.createSingleLevelIterator(iterName, cursorName, &iterators.item(0), cursors);
  1536. firstctx.addQuoted(s.clear().append("return (").append(cursorName).append(" = (byte *)").append(iterName).append(".first()) != 0;"));
  1537. BuildCtx nextctx(instance->startctx);
  1538. nextctx.addQuotedCompoundLiteral("virtual bool next()");
  1539. nextctx.addQuoted(s.clear().append("return (").append(cursorName).append(" = (byte *)").append(iterName).append(".next()) != 0;"));
  1540. }
  1541. else
  1542. {
  1543. iterBuilder.buildCompoundIterator(instance->onlyEvalOnceContext(), iterators, cursors);
  1544. firstctx.addQuotedLiteral("return iter.first();");
  1545. BuildCtx nextctx(instance->startctx);
  1546. nextctx.addQuotedCompoundLiteral("virtual bool next()");
  1547. nextctx.addQuotedLiteral("return iter.next();");
  1548. }
  1549. ForEachItemIn(i, cursors)
  1550. ctx.associate(cursors.item(i));
  1551. }
  1552. void SourceBuilder::checkDependencies(BuildCtx & ctx, IHqlExpression * expr)
  1553. {
  1554. //Add dependency information
  1555. Owned<ABoundActivity> bound = instance->getBoundActivity();
  1556. translator.addFileDependency(nameExpr, bound);
  1557. }
  1558. void SourceBuilder::extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds)
  1559. {
  1560. ForEachItemIn(i, conds)
  1561. {
  1562. IHqlExpression * filter = &conds.item(i);
  1563. #ifdef ALLOW_CHILD_ITERATORS_TO_CALL_CANMATCHANY
  1564. if (isSourceInvariant(ds, filter)) // more actually isSourceInvariant.
  1565. extendAndCondition(globalGuard, filter);
  1566. else
  1567. #endif
  1568. appendFilter(unkeyedFilter, filter);
  1569. }
  1570. }
  1571. void SourceBuilder::analyseGraph(IHqlExpression * expr)
  1572. {
  1573. analyse(expr);
  1574. SourceFieldUsage * fieldUsage = translator.querySourceFieldUsage(tableExpr);
  1575. if (fieldUsage && !fieldUsage->seenAll())
  1576. {
  1577. if (expr->queryNormalizedSelector() == tableExpr->queryNormalizedSelector())
  1578. fieldUsage->noteAll();
  1579. else
  1580. gatherFieldUsage(fieldUsage, expr);
  1581. }
  1582. }
  1583. void SourceBuilder::gatherFieldUsage(SourceFieldUsage * fieldUsage, IHqlExpression * expr)
  1584. {
  1585. for (;;)
  1586. {
  1587. if (expr->queryBody() == tableExpr->queryBody())
  1588. return;
  1589. if (fieldUsage->seenAll())
  1590. return;
  1591. IHqlExpression * ds = expr->queryChild(0);
  1592. switch (expr->getOperator())
  1593. {
  1594. case no_fetch:
  1595. {
  1596. assertex(ds->queryBody() == tableExpr->queryBody());
  1597. IHqlExpression * selSeq = querySelSeq(expr);
  1598. OwnedHqlExpr left = createSelector(no_left, ds, selSeq);
  1599. ::gatherFieldUsage(fieldUsage, expr, left);
  1600. return;
  1601. }
  1602. }
  1603. assertex(getNumChildTables(expr) == 1);
  1604. if (ds->queryNormalizedSelector() == tableExpr->queryNormalizedSelector())
  1605. gatherParentFieldUsage(fieldUsage, expr);
  1606. expr = ds;
  1607. }
  1608. }
  1609. inline bool useDescriptiveGraphLabel(ThorActivityKind kind)
  1610. {
  1611. switch (kind)
  1612. {
  1613. case TAKcsvfetch:
  1614. case TAKxmlfetch:
  1615. case TAKjsonfetch:
  1616. case TAKfetch:
  1617. return false;
  1618. }
  1619. return true;
  1620. }
  1621. static bool expandGraphLabel(ThorActivityKind kind)
  1622. {
  1623. switch (kind)
  1624. {
  1625. case TAKdiskread:
  1626. case TAKcsvread:
  1627. case TAKxmlread:
  1628. case TAKjsonread:
  1629. case TAKdiskcount:
  1630. case TAKdiskexists:
  1631. return true;
  1632. default:
  1633. return false;
  1634. }
  1635. }
  1636. ABoundActivity * SourceBuilder::buildActivity(BuildCtx & ctx, IHqlExpression * expr, ThorActivityKind _activityKind, const char *kind, ABoundActivity *input)
  1637. {
  1638. activityKind = _activityKind;
  1639. translator.gatherActiveCursors(ctx, parentCursors);
  1640. bool isSpill = tableExpr && tableExpr->hasAttribute(_spill_Atom);
  1641. useImplementationClass = translator.queryOptions().minimizeActivityClasses && translator.targetRoxie() && isSpill;
  1642. Owned<ActivityInstance> localInstance = new ActivityInstance(translator, ctx, activityKind, expr, kind);
  1643. if (useImplementationClass)
  1644. localInstance->setImplementationClass(newMemorySpillReadArgId);
  1645. if ((activityKind >= TAKdiskread) && (activityKind <= TAKdiskgroupaggregate))
  1646. {
  1647. IHqlExpression * seq = querySequence(tableExpr);
  1648. translator.noteResultAccessed(ctx, seq, nameExpr);
  1649. }
  1650. instance = localInstance;
  1651. StringBuffer graphLabel;
  1652. graphLabel.append(getActivityText(activityKind));
  1653. bool isFiltered = false;
  1654. double filterLikelihood = 1.0;
  1655. if (expandGraphLabel(activityKind))
  1656. {
  1657. graphLabel.clear();
  1658. if (expr != tableExpr)
  1659. {
  1660. IHqlExpression * cur = expr;
  1661. bool isProjected = false;
  1662. for (;;)
  1663. {
  1664. switch (cur->getOperator())
  1665. {
  1666. case no_filter:
  1667. if (isKnownLikelihood(filterLikelihood))
  1668. {
  1669. double likelihood = queryActivityLikelihood(cur);
  1670. if (isKnownLikelihood(likelihood))
  1671. // Combine the likelihood of the 2 filter conditions
  1672. // N.B. this only works if the filter probability are independent
  1673. filterLikelihood *= likelihood;
  1674. else
  1675. // One of the filter probability is unknown, so the overall probability is unknown
  1676. setUnknownLikelihood(filterLikelihood);
  1677. }
  1678. isFiltered = true;
  1679. break;
  1680. case no_hqlproject:
  1681. case no_newusertable:
  1682. case no_transformascii:
  1683. case no_transformebcdic:
  1684. if (!cur->hasAttribute(_internal_Atom))
  1685. isProjected = true;
  1686. break;
  1687. case no_table:
  1688. cur = NULL;
  1689. break;
  1690. }
  1691. if (!cur)
  1692. break;
  1693. cur = cur->queryChild(0);
  1694. }
  1695. if (isFiltered)
  1696. {
  1697. graphLabel.append("Filtered\n");
  1698. }
  1699. if (isProjected)
  1700. graphLabel.append("Projected\n");
  1701. }
  1702. if ((translator.getTargetClusterType() == RoxieCluster) && isSpill)
  1703. graphLabel.append("Read");
  1704. else if (isExplicitExists() && (activityKind == TAKdiskcount))
  1705. graphLabel.append("Disk Exists");
  1706. else
  1707. graphLabel.append(getActivityText(activityKind));
  1708. }
  1709. if (isExplicitExists())
  1710. {
  1711. if (activityKind == TAKindexcount)
  1712. graphLabel.clear().append("Index Exists");
  1713. }
  1714. if (useDescriptiveGraphLabel(activityKind))
  1715. {
  1716. StringBuffer eclChunk;
  1717. bool isLimited = false;
  1718. bool isStepped = false;
  1719. IHqlExpression * cur = expr;
  1720. instance->graphEclText.clear();
  1721. for (;;)
  1722. {
  1723. eclChunk.clear();
  1724. switch (cur->getOperator())
  1725. {
  1726. case no_hqlproject:
  1727. case no_newusertable:
  1728. case no_transformascii:
  1729. case no_transformebcdic:
  1730. break;
  1731. case no_filter:
  1732. toECL(cur->queryBody(), eclChunk, false, true);
  1733. break;
  1734. case no_table:
  1735. case no_newkeyindex:
  1736. case no_select:
  1737. toECL(cur->queryBody(), eclChunk, false, true);
  1738. cur = NULL;
  1739. break;
  1740. case no_stepped:
  1741. isStepped = true;
  1742. break;
  1743. case no_limit:
  1744. case no_keyedlimit:
  1745. isLimited = true;
  1746. break;
  1747. default:
  1748. if (getNumChildTables(cur) == 0)
  1749. {
  1750. toECL(cur->queryBody(), eclChunk, false, true);
  1751. cur = NULL;
  1752. }
  1753. break;
  1754. }
  1755. instance->graphEclText.insert(0, eclChunk);
  1756. if (!cur)
  1757. break;
  1758. cur = cur->queryChild(0);
  1759. }
  1760. if (isLimited)
  1761. graphLabel.insert(0, "Limited\n");
  1762. if (isStepped)
  1763. graphLabel.insert(0, "Stepped\n");
  1764. if (localInstance->isLocal && !isSpill)
  1765. graphLabel.insert(0, "Local ");
  1766. }
  1767. if (nameExpr && nameExpr->queryValue())
  1768. {
  1769. if (isSpill)
  1770. graphLabel.append("\nSpill");
  1771. else
  1772. {
  1773. StringBuffer filename;
  1774. //Call getStringValue() rather than generateECL() to avoid 't quote \ etc. in the string
  1775. getStringValue(filename.append("'"), nameExpr).append("'");
  1776. const char * coloncolon = strstr(filename, "::");
  1777. if (coloncolon)
  1778. {
  1779. for (;;)
  1780. {
  1781. const char * next = strstr(coloncolon+2, "::");
  1782. if (!next)
  1783. break;
  1784. coloncolon = next;
  1785. }
  1786. graphLabel.newline().append("'...").append(coloncolon);
  1787. }
  1788. else
  1789. graphLabel.newline().append(filename);
  1790. }
  1791. }
  1792. instance->graphLabel.set(graphLabel.str());
  1793. translator.buildActivityFramework(localInstance);
  1794. translator.buildInstancePrefix(localInstance);
  1795. analyseGraph(expr);
  1796. if (!useImplementationClass)
  1797. {
  1798. buildMembers(expr);
  1799. buildTransform(expr);
  1800. buildFlagsMember(expr);
  1801. if (tableExpr)
  1802. {
  1803. if (fieldInfo.hasVirtualsOrDeserialize())
  1804. {
  1805. OwnedHqlExpr diskTable = createDataset(no_anon, LINK(physicalRecord));
  1806. translator.buildMetaMember(instance->classctx, diskTable, false, "queryDiskRecordSize");
  1807. }
  1808. else
  1809. translator.buildMetaMember(instance->classctx, tableExpr, isGrouped(tableExpr), "queryDiskRecordSize");
  1810. }
  1811. }
  1812. else
  1813. {
  1814. assertex(!hasDynamic(tableExpr));
  1815. bool matched = translator.registerGlobalUsage(nameExpr);
  1816. if (!matched)
  1817. {
  1818. StringBuffer spillName;
  1819. getExprECL(nameExpr, spillName);
  1820. if (translator.queryOptions().allowThroughSpill)
  1821. throwError1(HQLERR_ReadSpillBeforeWriteFix, spillName.str());
  1822. else
  1823. throwError1(HQLERR_ReadSpillBeforeWrite, spillName.str());
  1824. }
  1825. translator.addFilenameConstructorParameter(*instance, "getFileName", nameExpr);
  1826. }
  1827. if (steppedExpr)
  1828. buildSteppedHelpers();
  1829. if (translator.targetRoxie())
  1830. instance->addAttributeBool("_isSpill", isSpill);
  1831. else if (needToCallTransform || transformCanFilter)
  1832. instance->addAttributeBool("_isTransformSpill", isSpill);
  1833. else
  1834. instance->addAttributeBool("_isSpill", isSpill);
  1835. if (isFiltered)
  1836. {
  1837. if (isKnownLikelihood(filterLikelihood))
  1838. {
  1839. StringBuffer text;
  1840. filterLikelihood *= 100;
  1841. text.setf("%3.2f%%", filterLikelihood);
  1842. instance->addAttribute("matchLikelihood", text);
  1843. }
  1844. }
  1845. IHqlExpression * spillReason = tableExpr ? queryAttributeChild(tableExpr, _spillReason_Atom, 0) : NULL;
  1846. if (spillReason && !translator.queryOptions().obfuscateOutput)
  1847. {
  1848. StringBuffer text;
  1849. getStringValue(text, spillReason);
  1850. instance->addAttribute("spillReason", text.str());
  1851. }
  1852. if (tableExpr)
  1853. instance->addSignedAttribute(tableExpr->queryAttribute(_signed_Atom));
  1854. checkDependencies(ctx, expr);
  1855. translator.buildInstanceSuffix(localInstance);
  1856. if (input)
  1857. translator.buildConnectInputOutput(ctx, localInstance, input, 0, 0);
  1858. instance = NULL;
  1859. return localInstance->getBoundActivity();
  1860. }
  1861. void SourceBuilder::buildKeyedLimitHelper(IHqlExpression * self)
  1862. {
  1863. if (keyedLimitExpr)
  1864. {
  1865. IHqlExpression * limitValue = keyedLimitExpr->queryChild(1);
  1866. BuildCtx func1ctx(instance->startctx);
  1867. func1ctx.addQuotedCompoundLiteral("virtual unsigned __int64 getKeyedLimit()");
  1868. translator.buildReturn(func1ctx, limitValue);
  1869. if (isZero(limitValue))
  1870. translator.WARNING(CategoryUnusual, HQLWRN_KeyedLimitIsZero);
  1871. LinkedHqlExpr fail = keyedLimitExpr->queryChild(2);
  1872. if (!fail || fail->isAttribute())
  1873. fail.setown(translator.createFailAction("Keyed limit exceeded", limitValue, NULL, instance->activityId));
  1874. BuildCtx func2ctx(instance->startctx);
  1875. func2ctx.addQuotedCompoundLiteral("virtual void onKeyedLimitExceeded()");
  1876. translator.buildStmt(func2ctx, fail);
  1877. IHqlExpression * transform = queryAttributeChild(keyedLimitExpr, onFailAtom, 0);
  1878. if (transform)
  1879. {
  1880. BuildCtx transformctx(instance->startctx);
  1881. transformctx.addQuotedCompoundLiteral("virtual size32_t transformOnKeyedLimitExceeded(ARowBuilder & crSelf)");
  1882. translator.ensureRowAllocated(transformctx, "crSelf");
  1883. translator.buildTransformBody(transformctx, transform, NULL, NULL, self, NULL);
  1884. }
  1885. }
  1886. }
  1887. void SourceBuilder::buildSteppedHelpers()
  1888. {
  1889. StringBuffer steppedFlags;
  1890. IHqlExpression * priority = steppedExpr->queryAttribute(priorityAtom);
  1891. if (priority)
  1892. {
  1893. steppedFlags.append("|SSFhaspriority");
  1894. translator.doBuildFunction(instance->startctx, doubleType, "getPriority", priority->queryChild(0));
  1895. }
  1896. IHqlExpression * prefetch = steppedExpr->queryAttribute(prefetchAtom);
  1897. if (prefetch)
  1898. {
  1899. steppedFlags.append("|SSFhasprefetch");
  1900. translator.doBuildUnsignedFunction(instance->startctx, "getPrefetchSize", prefetch->queryChild(0));
  1901. }
  1902. IHqlExpression * filtered = steppedExpr->queryAttribute(filteredAtom);
  1903. if (filtered)
  1904. steppedFlags.append("|SSFalwaysfilter");
  1905. if (steppedFlags.length())
  1906. translator.doBuildUnsignedFunction(instance->classctx, "getSteppedFlags", steppedFlags.str()+1);
  1907. }
  1908. void SourceBuilder::assignLocalExtract(BuildCtx & ctx, ParentExtract * extractBuilder, IHqlExpression * dataset, const char * argName)
  1909. {
  1910. if (extractBuilder)
  1911. {
  1912. StringBuffer s;
  1913. s.append("byte * ");
  1914. translator.generateExprCpp(s, extractBuilder->queryExtractName());
  1915. s.append(" = (byte *) ").append(argName).append(";");
  1916. ctx.addQuoted(s);
  1917. }
  1918. else
  1919. {
  1920. StringBuffer s;
  1921. ctx.addQuoted(s.append("unsigned char * left = (unsigned char *) ").append(argName).append(";"));
  1922. translator.bindTableCursor(ctx, dataset, "left");
  1923. }
  1924. }
  1925. void SourceBuilder::buildGroupAggregateHashHelper(ParentExtract * extractBuilder, IHqlExpression * dataset, IHqlExpression * fields)
  1926. {
  1927. instance->classctx.addQuotedLiteral("virtual IHash * queryHash() { return &hash; }");
  1928. BuildCtx classctx(instance->nestedctx);
  1929. translator.beginNestedClass(classctx, "hash", "IHash", NULL, extractBuilder);
  1930. BuildCtx funcctx(classctx);
  1931. funcctx.addQuotedCompoundLiteral("virtual unsigned hash(const void * _self)");
  1932. assignLocalExtract(funcctx, extractBuilder, dataset, "_self");
  1933. OwnedHqlExpr hash = createValue(no_hash32, LINK(unsignedType), LINK(fields), createAttribute(internalAtom));
  1934. translator.buildReturn(funcctx, hash);
  1935. translator.endNestedClass();
  1936. }
  1937. void SourceBuilder::buildGroupAggregateCompareHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, HqlExprArray & recordFields, HqlExprArray & aggregateFields)
  1938. {
  1939. //Special case comparison of IF(<global-bool>, value, some-constant), so that the order expression only compares if <global-bool> is true
  1940. //specifically to improve david's BIRPs code.
  1941. HqlExprArray optimizedLeft, optimizedRight;
  1942. ForEachItemIn(i, recordFields)
  1943. {
  1944. IHqlExpression & curLeft = recordFields.item(i);
  1945. IHqlExpression & curRight = aggregateFields.item(i);
  1946. IHqlExpression * newLeft = NULL;
  1947. IHqlExpression * newRight = NULL;
  1948. if (curLeft.getOperator() == no_if)
  1949. {
  1950. IHqlExpression * cond = curLeft.queryChild(0);
  1951. if (isIndependentOfScope(cond))
  1952. {
  1953. IHqlExpression * elseValue = curLeft.queryChild(2);
  1954. if (elseValue->getOperator() == no_constant)
  1955. {
  1956. newLeft = LINK(&curLeft);
  1957. newRight = createValue(no_if, curRight.getType(), LINK(cond), LINK(&curRight), LINK(elseValue));
  1958. }
  1959. }
  1960. }
  1961. if (newLeft)
  1962. {
  1963. optimizedLeft.append(*newLeft);
  1964. optimizedRight.append(*newRight);
  1965. }
  1966. else
  1967. {
  1968. optimizedLeft.append(OLINK(curLeft));
  1969. optimizedRight.append(OLINK(curRight));
  1970. }
  1971. }
  1972. OwnedHqlExpr leftList = createSortList(optimizedLeft);
  1973. DatasetReference datasetRight(aggregate, no_activetable, NULL);
  1974. OwnedHqlExpr selSeq = createDummySelectorSequence();
  1975. OwnedHqlExpr rightList = createSortList(optimizedRight);
  1976. OwnedHqlExpr rightSelect = datasetRight.getSelector(no_right, selSeq);
  1977. OwnedHqlExpr rightResolved = datasetRight.mapCompound(rightList, rightSelect);
  1978. OwnedHqlExpr order = createValue(no_order, makeIntType(sizeof(signed), true), LINK(leftList), LINK(rightResolved));
  1979. //Now generate the nested class
  1980. instance->classctx.addQuotedLiteral("virtual ICompare * queryCompareRowElement() { return &compareRowElement; }");
  1981. BuildCtx classctx(instance->nestedctx);
  1982. translator.beginNestedClass(classctx, "compareRowElement", "ICompare", NULL, extractBuilder);
  1983. BuildCtx funcctx(classctx);
  1984. funcctx.addQuotedCompoundLiteral("virtual int docompare(const void * _left, const void * _right) const");
  1985. assignLocalExtract(funcctx, extractBuilder, aggregate->queryChild(0), "_left");
  1986. funcctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  1987. funcctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  1988. translator.bindTableCursor(funcctx, aggregate, "right", no_right, selSeq);
  1989. translator.doBuildReturnCompare(funcctx, order, no_eq, false, false);
  1990. translator.endNestedClass();
  1991. }
  1992. void SourceBuilder::buildGroupAggregateProcessHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, const char * name, bool doneAny)
  1993. {
  1994. StringBuffer s;
  1995. IHqlExpression * dataset = aggregate->queryChild(0);
  1996. IHqlExpression * tgtRecord = aggregate->queryChild(1);
  1997. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  1998. BuildCtx funcctx(instance->nestedctx);
  1999. funcctx.addQuotedCompound(s.clear().append("virtual size32_t ").append(name).append("(ARowBuilder & crSelf, const void * _src)"));
  2000. translator.ensureRowAllocated(funcctx, "crSelf");
  2001. assignLocalExtract(funcctx, extractBuilder, dataset, "_src");
  2002. BoundRow * selfRow = translator.bindSelf(funcctx, resultDataset, "crSelf");
  2003. if (extractBuilder)
  2004. {
  2005. MemberEvalContext * evalContext = new MemberEvalContext(translator, extractBuilder, translator.queryEvalContext(funcctx), funcctx);
  2006. funcctx.associateOwn(*evalContext);
  2007. evalContext->initContext();
  2008. }
  2009. if (aggregate->getOperator() == no_aggregate)
  2010. {
  2011. //It is inefficient to call processUserAggregateTransform() twice, but this is an unusual construct, so leave as it
  2012. //is for the moment.
  2013. OwnedHqlExpr firstTransform;
  2014. OwnedHqlExpr nextTransform;
  2015. translator.processUserAggregateTransform(aggregate, aggregate->queryChild(2), firstTransform, nextTransform);
  2016. IHqlExpression * transform = doneAny ? nextTransform : firstTransform;
  2017. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(aggregate));
  2018. OwnedHqlExpr mappedTransform = replaceSelector(transform, left, dataset);
  2019. translator.doBuildUserAggregateProcessTransform(funcctx, selfRow, aggregate, mappedTransform, queryBoolExpr(doneAny));
  2020. }
  2021. else
  2022. translator.doBuildAggregateProcessTransform(funcctx, selfRow, aggregate, queryBoolExpr(doneAny));
  2023. translator.buildReturnRecordSize(funcctx, selfRow);
  2024. }
  2025. void SourceBuilder::buildGroupAggregateHelpers(ParentExtract * extractBuilder, IHqlExpression * aggregate)
  2026. {
  2027. IHqlExpression * dataset = aggregate->queryChild(0);
  2028. LinkedHqlExpr transform = aggregate->queryChild(2);
  2029. LinkedHqlExpr grouping = aggregate->queryChild(3);
  2030. if (aggregate->getOperator() == no_aggregate)
  2031. {
  2032. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(aggregate));
  2033. grouping.setown(replaceSelector(grouping, left, dataset));
  2034. transform.setown(replaceSelector(transform, left, dataset));
  2035. }
  2036. HqlExprArray recordFields, aggregateFields;
  2037. grouping->unwindList(recordFields, no_sortlist);
  2038. getMappedFields(aggregateFields, transform, recordFields, queryActiveTableSelector());
  2039. OwnedHqlExpr allRecordFields = createValueSafe(no_sortlist, makeSortListType(NULL), recordFields);
  2040. OwnedHqlExpr allAggregateFields = createValueSafe(no_sortlist, makeSortListType(NULL), aggregateFields);
  2041. //virtual size32_t processFirst(void * target, const void * src)
  2042. buildGroupAggregateProcessHelper(extractBuilder, aggregate, "processFirst", false);
  2043. //virtual size32_t processNext(void * target, const void * src)
  2044. buildGroupAggregateProcessHelper(extractBuilder, aggregate, "processNext", true);
  2045. //virtual IHash * queryHash()
  2046. buildGroupAggregateHashHelper(extractBuilder, dataset, allRecordFields);
  2047. //virtual ICompare * queryCompareElements()
  2048. DatasetReference outRef(aggregate, no_activetable, NULL);
  2049. translator.buildCompareMember(instance->nestedctx, "CompareElements", allAggregateFields, outRef); // compare transformed elements
  2050. //virtual ICompare * queryCompareRowElement()
  2051. buildGroupAggregateCompareHelper(extractBuilder, aggregate, recordFields, aggregateFields);
  2052. //virtual IHash * queryHashElement()
  2053. translator.buildHashOfExprsClass(instance->nestedctx, "HashElement", allAggregateFields, outRef, true);
  2054. }
  2055. IHqlExpression * SourceBuilder::ensureAggregateGroupingAliased(IHqlExpression * aggregate)
  2056. {
  2057. IHqlExpression * dataset = aggregate->queryChild(0);
  2058. IHqlExpression * grouping = aggregate->queryChild(3);
  2059. //Force complex grouping fields into aliases to reduce processing...
  2060. HqlMapTransformer transformer;
  2061. transformer.setMapping(dataset, dataset);
  2062. ForEachChild(i, grouping)
  2063. {
  2064. IHqlExpression * cur = grouping->queryChild(i);
  2065. if (translator.requiresTemp(instance->nestedctx, cur, true) && (cur->getOperator() != no_alias))
  2066. {
  2067. OwnedHqlExpr alias = createAliasOwn(LINK(cur), createAttribute(internalAtom));
  2068. transformer.setMapping(cur, alias);
  2069. }
  2070. }
  2071. return transformer.transformRoot(aggregate);
  2072. }
  2073. void SourceBuilder::buildGlobalGroupAggregateHelpers(IHqlExpression * expr)
  2074. {
  2075. IHqlExpression * aggregate = expr->queryChild(0);
  2076. node_operator op = aggregate->getOperator();
  2077. assertex(op == no_newaggregate || op == no_aggregate);
  2078. StringBuffer s;
  2079. //virtual size32_t clearAggregate(void * self) = 0;
  2080. translator.doBuildAggregateClearFunc(instance->startctx, aggregate);
  2081. //virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) = 0; //only call if transform called at least once on src.
  2082. translator.doBuildAggregateMergeFunc(instance->startctx, aggregate, requiresOrderedMerge);
  2083. //virtual void processRow(void * self, const void * src) = 0;
  2084. BuildCtx rowctx(instance->startctx);
  2085. rowctx.addQuotedCompoundLiteral("virtual void processRow(const void * src, IHThorGroupAggregateCallback * callback)");
  2086. rowctx.addQuotedLiteral("doProcessRow((byte *)src, callback);");
  2087. //virtual void processRows(void * self, size32_t srcLen, const void * src) = 0;
  2088. BuildCtx rowsctx(instance->startctx);
  2089. rowsctx.addQuotedCompoundLiteral("virtual void processRows(size32_t srcLen, const void * _left, IHThorGroupAggregateCallback * callback)");
  2090. rowsctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2091. OwnedHqlExpr ds = createVariable("left", makeReferenceModifier(tableExpr->getType()));
  2092. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  2093. OwnedHqlExpr fullDs = createTranslated(ds, len);
  2094. BoundRow * curRow = translator.buildDatasetIterate(rowsctx, fullDs, false);
  2095. s.clear().append("doProcessRow(");
  2096. translator.generateExprCpp(s, curRow->queryBound());
  2097. s.append(", callback);");
  2098. rowsctx.addQuoted(s);
  2099. }
  2100. void SourceBuilder::buildGroupingMonitors(IHqlExpression * expr, MonitorExtractor & monitors)
  2101. {
  2102. IHqlExpression * aggregate = expr->queryChild(0);
  2103. node_operator op = aggregate->getOperator();
  2104. assertex(op == no_newaggregate || op == no_aggregate);
  2105. IHqlExpression * dataset = aggregate->queryChild(0);
  2106. IHqlExpression * grouping = aggregate->queryChild(3);
  2107. //virtual void createGroupSegmentMonitors(IIndexReadContext *ctx) = 0;
  2108. BuildCtx groupctx(instance->startctx);
  2109. IHqlStmt * group = groupctx.addQuotedCompoundLiteral("virtual bool createGroupSegmentMonitors(IIndexReadContext * irc)");
  2110. monitorsForGrouping = true;
  2111. if (op == no_newaggregate)
  2112. translator.bindTableCursor(groupctx, dataset, "_dummy");
  2113. else
  2114. translator.bindTableCursor(groupctx, dataset, "_dummy", no_left, querySelSeq(aggregate));
  2115. unsigned maxOffset = 0;
  2116. ForEachChild(i, grouping)
  2117. {
  2118. unsigned nextOffset = 0;
  2119. if (!monitors.createGroupingMonitor(groupctx, "irc", grouping->queryChild(i), nextOffset))
  2120. {
  2121. monitorsForGrouping = false;
  2122. group->setIncluded(false);
  2123. break;
  2124. }
  2125. if (maxOffset < nextOffset)
  2126. maxOffset = nextOffset;
  2127. }
  2128. if (monitorsForGrouping)
  2129. groupctx.addReturn(queryBoolExpr(true));
  2130. if (monitorsForGrouping)
  2131. translator.doBuildUnsignedFunction(instance->classctx, "getGroupSegmentMonitorsSize", maxOffset);
  2132. }
  2133. void SourceBuilder::buildAggregateHelpers(IHqlExpression * expr)
  2134. {
  2135. IHqlExpression * aggregate = expr->queryChild(0);
  2136. node_operator op = aggregate->getOperator();
  2137. assertex(op == no_newaggregate || op == no_aggregate);
  2138. StringBuffer s;
  2139. alreadyDoneFlag.setown(instance->startctx.getTempDeclare(queryBoolType(), NULL));
  2140. instance->onstartctx.addAssign(alreadyDoneFlag, queryBoolExpr(false));
  2141. //virtual bool processedAnyRows() = 0;
  2142. translator.doBuildBoolFunction(instance->startctx, "processedAnyRows", alreadyDoneFlag);
  2143. //virtual size32_t clearAggregate(ARowBuilder & crSelf) = 0;
  2144. translator.doBuildAggregateClearFunc(instance->startctx, aggregate);
  2145. //virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) = 0; //only call if transform called at least once on src.
  2146. translator.doBuildAggregateMergeFunc(instance->startctx, aggregate, requiresOrderedMerge);
  2147. }
  2148. void SourceBuilder::buildCountHelpers(IHqlExpression * expr, bool allowMultiple)
  2149. {
  2150. StringBuffer s;
  2151. //---- virtual bool hasFilter() { return <bool>; } ----
  2152. if (transformCanFilter||isNormalize)
  2153. translator.doBuildBoolFunction(instance->classctx, "hasFilter", true);
  2154. if (allowMultiple)
  2155. {
  2156. bool isExists = hasExistChoosenLimit();
  2157. OwnedHqlExpr one = getSizetConstant(1);
  2158. if (transformCanFilter||isNormalize)
  2159. {
  2160. //virtual size32_t numValid(const void * src) = 0;
  2161. BuildCtx rowctx(instance->startctx);
  2162. rowctx.addQuotedCompoundLiteral("virtual size32_t numValid(const void * src)");
  2163. rowctx.addQuotedLiteral("return valid((byte *)src);");
  2164. //virtual size32_t numValid(size32_t srcLen, const void * src);
  2165. BuildCtx rowsctx(instance->startctx);
  2166. rowsctx.addQuotedCompoundLiteral("virtual size32_t numValid(size32_t srcLen, const void * _src)");
  2167. rowsctx.addQuotedLiteral("unsigned char * src = (unsigned char *)_src;");
  2168. OwnedHqlExpr ds = createVariable("src", makeReferenceModifier(tableExpr->getType()));
  2169. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  2170. OwnedHqlExpr fullDs = createTranslated(ds, len);
  2171. if (isExists)
  2172. {
  2173. BuildCtx iterctx(rowsctx);
  2174. BoundRow * curRow = translator.buildDatasetIterate(iterctx, fullDs, false);
  2175. s.clear().append("if (valid(");
  2176. translator.generateExprCpp(s, curRow->queryBound());
  2177. s.append("))");
  2178. iterctx.addQuotedCompound(s);
  2179. iterctx.addReturn(one);
  2180. rowsctx.addQuotedLiteral("return 0;");
  2181. }
  2182. else
  2183. {
  2184. rowsctx.addQuotedLiteral("size32_t cnt = 0;");
  2185. BuildCtx iterctx(rowsctx);
  2186. BoundRow * curRow = translator.buildDatasetIterate(iterctx, fullDs, false);
  2187. s.clear().append("cnt += valid(");
  2188. translator.generateExprCpp(s, curRow->queryBound());
  2189. s.append(");");
  2190. iterctx.addQuoted(s);
  2191. rowsctx.addQuotedLiteral("return cnt;");
  2192. }
  2193. }
  2194. else
  2195. {
  2196. //virtual size32_t numValid(size32_t srcLen, const void * src);
  2197. BuildCtx rowsctx(instance->startctx);
  2198. rowsctx.addQuotedCompoundLiteral("virtual size32_t numValid(size32_t srcLen, const void * _src)");
  2199. if (isExists)
  2200. rowsctx.addReturn(one);
  2201. else
  2202. {
  2203. rowsctx.addQuotedLiteral("unsigned char * src = (unsigned char *)_src;");
  2204. CHqlBoundExpr bound;
  2205. bound.length.setown(createVariable("srcLen", LINK(sizetType)));
  2206. bound.expr.setown(createVariable("src", makeReferenceModifier(tableExpr->getType())));
  2207. OwnedHqlExpr count = translator.getBoundCount(bound);
  2208. rowsctx.addReturn(count);
  2209. }
  2210. }
  2211. }
  2212. }
  2213. void SourceBuilder::buildNormalizeHelpers(IHqlExpression * expr)
  2214. {
  2215. }
  2216. void SourceBuilder::buildGroupAggregateTransformBody(BuildCtx & transformCtx, IHqlExpression * expr, bool useExtract, bool bindInputRow)
  2217. {
  2218. buildTransformBody(transformCtx, expr, false, false, bindInputRow);
  2219. IHqlExpression * aggregate = expr->queryChild(0);
  2220. OwnedHqlExpr mappedAggregate = ensureAggregateGroupingAliased(aggregate);
  2221. Owned<ParentExtract> extractBuilder;
  2222. if (useExtract || (aggregate != mappedAggregate))
  2223. {
  2224. extractBuilder.setown(translator.createExtractBuilder(transformCtx, PETcallback, NULL, GraphCoLocal, true));
  2225. if (!translator.queryOptions().serializeRowsetInExtract)
  2226. extractBuilder->setAllowDestructor();
  2227. translator.beginExtract(transformCtx, extractBuilder);
  2228. buildGroupAggregateHelpers(extractBuilder, mappedAggregate);
  2229. translator.endExtract(transformCtx, extractBuilder);
  2230. }
  2231. else
  2232. buildGroupAggregateHelpers(NULL, mappedAggregate);
  2233. HqlExprArray args;
  2234. args.append(*createVariable("callback", makeBoolType()));
  2235. if (extractBuilder)
  2236. {
  2237. CHqlBoundExpr boundExtract;
  2238. extractBuilder->endCreateExtract(boundExtract);
  2239. args.append(*boundExtract.getTranslatedExpr());
  2240. }
  2241. else
  2242. {
  2243. BoundRow * match = translator.resolveDatasetRequired(transformCtx, aggregate->queryChild(0));
  2244. Owned<ITypeInfo> rowType = makeReferenceModifier(makeRowType(queryNullRecord()->getType()));
  2245. OwnedHqlExpr rowAddr = getPointer(match->queryBound());
  2246. OwnedHqlExpr castBound = createValue(no_typetransfer, LINK(rowType), LINK(rowAddr));
  2247. args.append(*createTranslated(castBound));
  2248. }
  2249. OwnedHqlExpr call = translator.bindFunctionCall(addAggregateRowId, args);
  2250. translator.buildStmt(transformCtx, call);
  2251. }
  2252. void SourceBuilder::gatherVirtualFields(bool ignoreVirtuals, bool ensureSerialized)
  2253. {
  2254. IHqlExpression * record = tableExpr->queryRecord();
  2255. fieldInfo.gatherVirtualFields(record, ignoreVirtuals, ensureSerialized);
  2256. if (fieldInfo.hasVirtuals())
  2257. physicalRecord.setown(fieldInfo.createPhysicalRecord());
  2258. else
  2259. physicalRecord.set(record);
  2260. }
  2261. /*
  2262. interface ICompoundSourceSteppingMeta : extends ISteppingMeta
  2263. {
  2264. virtual ISteppingMeta * queryRawSteppingMeta() = 0;
  2265. virtual ISteppingMeta * queryProjectedSteppingMeta() = 0; // if null no projection takes place
  2266. virtual void mapOutputToIInput(void * originalRow, const void * projectedRow, unsigned firstField, unsigned numFields) = 0;
  2267. };
  2268. */
  2269. bool SourceBuilder::containsStepping(IHqlExpression * expr)
  2270. {
  2271. for (;;)
  2272. {
  2273. switch (expr->getOperator())
  2274. {
  2275. case no_stepped:
  2276. return true;
  2277. default:
  2278. {
  2279. if (expr->queryBody() == tableExpr)
  2280. return false;
  2281. unsigned numChildren = getNumChildTables(expr);
  2282. if (numChildren == 0)
  2283. return false;
  2284. assertex(numChildren == 1);
  2285. }
  2286. }
  2287. expr = expr->queryChild(0);
  2288. }
  2289. }
  2290. void SourceBuilder::gatherSteppingMeta(IHqlExpression * expr, SteppingFieldSelection & outputStepping, SteppingFieldSelection & rawStepping)
  2291. {
  2292. for (;;)
  2293. {
  2294. switch (expr->getOperator())
  2295. {
  2296. case no_newusertable:
  2297. case no_hqlproject:
  2298. if (rawStepping.exists())
  2299. {
  2300. rawStepping.expandTransform(expr);
  2301. }
  2302. else
  2303. {
  2304. gatherSteppingMeta(expr->queryChild(0), outputStepping, rawStepping);
  2305. outputStepping.clear();
  2306. return;
  2307. //throwError(HQLERR_CantProjectStepping);
  2308. //gatherSteppingMeta(expr->queryChild(0), outputStepping, rawStepping);
  2309. //apply projection to the output fields and inverse to the raw fields.
  2310. }
  2311. break;
  2312. case no_stepped:
  2313. {
  2314. outputStepping.setStepping(expr);
  2315. rawStepping.setStepping(expr);
  2316. break;
  2317. }
  2318. default:
  2319. {
  2320. if (expr->queryBody() == tableExpr)
  2321. return;
  2322. unsigned numChildren = getNumChildTables(expr);
  2323. if (numChildren == 0)
  2324. return;
  2325. assertex(numChildren == 1);
  2326. }
  2327. }
  2328. expr = expr->queryChild(0);
  2329. }
  2330. }
  2331. void SourceBuilder::gatherSteppingMeta(IHqlExpression * expr, SourceSteppingInfo & info)
  2332. {
  2333. if (!steppedExpr)
  2334. return;
  2335. gatherSteppingMeta(expr, info.outputStepping, info.rawSteppingProject);
  2336. if (info.rawSteppingProject.exists())
  2337. info.extractRaw();
  2338. }
  2339. //-----------------------------------------------------------------------------------------------
  2340. //-- Disk file processing
  2341. //-----------------------------------------------------------------------------------------------
  2342. class DiskReadBuilderBase : public SourceBuilder
  2343. {
  2344. public:
  2345. DiskReadBuilderBase(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2346. : SourceBuilder(_translator, _tableExpr, _nameExpr), monitors(_tableExpr, _translator, 0, true)
  2347. {
  2348. fpos.setown(getFilepos(tableExpr, false));
  2349. lfpos.setown(getFilepos(tableExpr, true));
  2350. logicalFilenameMarker.setown(getFileLogicalName(tableExpr));
  2351. mode = tableExpr->queryChild(2);
  2352. modeOp = mode->getOperator();
  2353. includeFormatCrc = (modeOp != no_csv);
  2354. }
  2355. virtual void buildMembers(IHqlExpression * expr);
  2356. virtual void buildTransformFpos(BuildCtx & transformCtx);
  2357. virtual void extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds);
  2358. protected:
  2359. virtual void buildFlagsMember(IHqlExpression * expr);
  2360. protected:
  2361. MonitorExtractor monitors;
  2362. OwnedHqlExpr globalGuard;
  2363. IHqlExpression * mode;
  2364. node_operator modeOp;
  2365. bool includeFormatCrc;
  2366. };
  2367. void DiskReadBuilderBase::buildMembers(IHqlExpression * expr)
  2368. {
  2369. StringBuffer s;
  2370. //Process any KEYED() information
  2371. if (monitors.isFiltered())
  2372. {
  2373. BuildCtx createSegmentCtx(instance->startctx);
  2374. createSegmentCtx.addQuotedCompoundLiteral("virtual void createSegmentMonitors(IIndexReadContext *irc)");
  2375. monitors.buildSegments(createSegmentCtx, "irc", true);
  2376. }
  2377. instance->addAttributeBool("_isKeyed", monitors.isFiltered());
  2378. //---- virtual unsigned getFlags()
  2379. instance->addAttributeBool("preload", isPreloaded);
  2380. bool matched = translator.registerGlobalUsage(tableExpr->queryChild(0));
  2381. if (translator.getTargetClusterType() == RoxieCluster)
  2382. {
  2383. instance->addAttributeBool("_isOpt", tableExpr->hasAttribute(optAtom));
  2384. instance->addAttributeBool("_isSpillGlobal", tableExpr->hasAttribute(jobTempAtom));
  2385. if (tableExpr->hasAttribute(jobTempAtom) && !matched)
  2386. throwUnexpected();
  2387. }
  2388. if (!matched && expr->hasAttribute(_spill_Atom))
  2389. {
  2390. StringBuffer spillName;
  2391. getExprECL(tableExpr->queryChild(0), spillName);
  2392. if (translator.queryOptions().allowThroughSpill)
  2393. throwError1(HQLERR_ReadSpillBeforeWriteFix, spillName.str());
  2394. else
  2395. throwError1(HQLERR_ReadSpillBeforeWrite, spillName.str());
  2396. }
  2397. //---- virtual bool canMatchAny() { return <value>; } ----
  2398. LinkedHqlExpr guard = globalGuard.get();
  2399. extendConditionOwn(guard, no_and, LINK(monitors.queryGlobalGuard()));
  2400. if (guard)
  2401. translator.doBuildBoolFunction(instance->startctx, "canMatchAny", guard);
  2402. translator.buildEncryptHelper(instance->startctx, tableExpr->queryAttribute(encryptAtom));
  2403. //---- virtual size32_t getPreloadSize() { return <value>; } ----
  2404. if (preloadSize)
  2405. {
  2406. BuildCtx subctx(instance->classctx);
  2407. subctx.addQuotedCompoundLiteral("virtual size32_t getPreloadSize()");
  2408. translator.buildReturn(subctx, preloadSize, sizetType);
  2409. instance->addAttributeInt("_preloadSize", preloadSize->queryValue()->getIntValue());
  2410. }
  2411. if (includeFormatCrc)
  2412. {
  2413. //Spill files can still have virtual attributes in their physical records => remove them.
  2414. OwnedHqlExpr noVirtualRecord = removeVirtualAttributes(physicalRecord);
  2415. translator.buildFormatCrcFunction(instance->classctx, "getFormatCrc", noVirtualRecord, NULL, 0);
  2416. }
  2417. buildLimits(instance->startctx, expr, instance->activityId);
  2418. buildKeyedLimitHelper(expr);
  2419. //Note the helper base class contains code like the following
  2420. //IThorDiskCallback * fpp;");
  2421. //virtual void setCallback(IThorDiskCallback * _tc) { fpp = _tc; }");
  2422. }
  2423. void DiskReadBuilderBase::buildFlagsMember(IHqlExpression * expr)
  2424. {
  2425. StringBuffer flags;
  2426. if (tableExpr->hasAttribute(_spill_Atom)) flags.append("|TDXtemporary");
  2427. if (tableExpr->hasAttribute(jobTempAtom)) flags.append("|TDXjobtemp");
  2428. if (tableExpr->hasAttribute(groupedAtom)) flags.append("|TDXgrouped");
  2429. if (tableExpr->hasAttribute(__compressed__Atom)) flags.append("|TDXcompress");
  2430. if (tableExpr->hasAttribute(unsortedAtom)) flags.append("|TDRunsorted");
  2431. if (tableExpr->hasAttribute(optAtom)) flags.append("|TDRoptional");
  2432. if (tableExpr->hasAttribute(_workflowPersist_Atom)) flags.append("|TDXupdateaccessed");
  2433. if (isPreloaded) flags.append("|TDRpreload");
  2434. if (monitors.isFiltered()) flags.append("|TDRkeyed");
  2435. if (limitExpr)
  2436. {
  2437. if (limitExpr->hasAttribute(onFailAtom))
  2438. flags.append("|TDRlimitcreates");
  2439. else if (limitExpr->hasAttribute(skipAtom))
  2440. flags.append("|TDRlimitskips");
  2441. }
  2442. if (keyedLimitExpr)
  2443. {
  2444. if (keyedLimitExpr->hasAttribute(onFailAtom))
  2445. flags.append("|TDRkeyedlimitcreates|TDRcountkeyedlimit"); // is count correct?
  2446. else if (keyedLimitExpr->hasAttribute(skipAtom))
  2447. flags.append("|TDRkeyedlimitskips|TDRcountkeyedlimit");
  2448. else if (keyedLimitExpr->hasAttribute(countAtom))
  2449. flags.append("|TDRcountkeyedlimit");
  2450. }
  2451. if (onlyExistsAggreate) flags.append("|TDRaggregateexists");
  2452. if (monitorsForGrouping) flags.append("|TDRgroupmonitors");
  2453. if (!nameExpr->isConstant()) flags.append("|TDXvarfilename");
  2454. if (translator.hasDynamicFilename(tableExpr)) flags.append("|TDXdynamicfilename");
  2455. if (isUnfilteredCount) flags.append("|TDRunfilteredcount");
  2456. if (isVirtualLogicalFilenameUsed) flags.append("|TDRfilenamecallback");
  2457. if (requiresOrderedMerge) flags.append("|TDRorderedmerge");
  2458. if (flags.length())
  2459. translator.doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  2460. }
  2461. void DiskReadBuilderBase::buildTransformFpos(BuildCtx & transformCtx)
  2462. {
  2463. if (modeOp == no_csv)
  2464. associateFilePositions(transformCtx, "fpp", "dataSrc[0]");
  2465. else
  2466. associateFilePositions(transformCtx, "fpp", "left");
  2467. }
  2468. void DiskReadBuilderBase::extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds)
  2469. {
  2470. ForEachItemIn(i, conds)
  2471. {
  2472. IHqlExpression * filter = &conds.item(i);
  2473. if (isSourceInvariant(ds, filter)) // more actually isSourceInvariant.
  2474. extendConditionOwn(globalGuard, no_and, LINK(filter));
  2475. else
  2476. {
  2477. node_operator op = filter->getOperator();
  2478. switch (op)
  2479. {
  2480. case no_assertkeyed:
  2481. case no_assertwild:
  2482. {
  2483. //MORE: This needs to test that the fields are at fixed offsets, fixed length, and collatable.
  2484. OwnedHqlExpr extraFilter;
  2485. monitors.extractFilters(filter, extraFilter);
  2486. //NB: Even if it is keyed then (part of) the test condition might be duplicated.
  2487. appendFilter(unkeyedFilter, extraFilter);
  2488. break;
  2489. }
  2490. default:
  2491. // Add this condition to the catchall filter
  2492. appendFilter(unkeyedFilter, filter);
  2493. break;
  2494. }
  2495. }
  2496. }
  2497. }
  2498. //---------------------------------------------------------------------------
  2499. class DiskReadBuilder : public DiskReadBuilderBase
  2500. {
  2501. public:
  2502. DiskReadBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2503. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr)
  2504. {
  2505. }
  2506. virtual void buildTransform(IHqlExpression * expr);
  2507. virtual void buildMembers(IHqlExpression * expr);
  2508. };
  2509. void DiskReadBuilder::buildMembers(IHqlExpression * expr)
  2510. {
  2511. buildReadMembers(expr);
  2512. DiskReadBuilderBase::buildMembers(expr);
  2513. //---- virtual const char * getPipeProgram() { return "grep"; } ----
  2514. if (modeOp==no_pipe)
  2515. {
  2516. if (expr->hasAttribute(_disallowed_Atom))
  2517. throwError(HQLERR_PipeNotAllowed);
  2518. BuildCtx pipeCtx(instance->startctx);
  2519. pipeCtx.addQuotedCompoundLiteral("virtual const char * getPipeProgram()");
  2520. translator.buildReturn(pipeCtx, mode->queryChild(0), unknownVarStringType);
  2521. IHqlExpression * csvFromPipe = tableExpr->queryAttribute(csvAtom);
  2522. IHqlExpression * xmlFromPipe = tableExpr->queryAttribute(xmlAtom);
  2523. bool usesContents = false;
  2524. if (csvFromPipe)
  2525. {
  2526. if (isValidCsvRecord(tableExpr->queryRecord()))
  2527. {
  2528. StringBuffer csvInstanceName;
  2529. translator.buildCsvReadTransformer(tableExpr, csvInstanceName, csvFromPipe);
  2530. StringBuffer s;
  2531. s.append("virtual ICsvToRowTransformer * queryCsvTransformer() { return &").append(csvInstanceName).append("; }");
  2532. instance->classctx.addQuoted(s);
  2533. }
  2534. else
  2535. {
  2536. throwUnexpected(); // should be caught earlier
  2537. }
  2538. }
  2539. else if (xmlFromPipe)
  2540. {
  2541. translator.doBuildXmlReadMember(*instance, expr, "queryXmlTransformer", usesContents);
  2542. translator.doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryAttributeChild(xmlFromPipe, rowAtom, 0));
  2543. }
  2544. StringBuffer flags;
  2545. if (tableExpr->hasAttribute(groupAtom)) // not supported in parser?
  2546. flags.append("|TPFgroupeachrow");
  2547. if (tableExpr->hasAttribute(optAtom)) // not supported in parser?
  2548. flags.append("|TPFnofail");
  2549. if (csvFromPipe)
  2550. flags.append("|TPFreadcsvfrompipe");
  2551. if (xmlFromPipe)
  2552. flags.append("|TPFreadxmlfrompipe");
  2553. if (usesContents)
  2554. flags.append("|TPFreadusexmlcontents");
  2555. if (flags.length())
  2556. translator.doBuildUnsignedFunction(instance->classctx, "getPipeFlags", flags.str()+1);
  2557. }
  2558. }
  2559. void DiskReadBuilder::buildTransform(IHqlExpression * expr)
  2560. {
  2561. if (modeOp == no_pipe)
  2562. {
  2563. assertex(!(needToCallTransform || transformCanFilter));
  2564. return;
  2565. }
  2566. if (modeOp == no_csv)
  2567. {
  2568. translator.buildCsvParameters(instance->nestedctx, mode, NULL, true);
  2569. BuildCtx funcctx(instance->startctx);
  2570. funcctx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenSrc, const char * * dataSrc)");
  2571. translator.ensureRowAllocated(funcctx, "crSelf");
  2572. //associateVirtualCallbacks(*this, funcctx, tableExpr);
  2573. buildTransformBody(funcctx, expr, true, false, true);
  2574. rootSelfRow = NULL;
  2575. unsigned maxColumns = countTotalFields(tableExpr->queryRecord(), false);
  2576. translator.doBuildUnsignedFunction(instance->classctx, "getMaxColumns", maxColumns);
  2577. return;
  2578. }
  2579. BuildCtx transformCtx(instance->startctx);
  2580. if (instance->kind == TAKdiskread)
  2581. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  2582. else
  2583. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IFilePositionProvider * fpp)");
  2584. translator.ensureRowAllocated(transformCtx, "crSelf");
  2585. transformCtx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2586. buildTransformBody(transformCtx, expr, true, false, true);
  2587. }
  2588. //---------------------------------------------------------------------------
  2589. ABoundActivity * HqlCppTranslator::doBuildActivityDiskRead(BuildCtx & ctx, IHqlExpression * expr)
  2590. {
  2591. // assertex(!isGroupedActivity(expr));
  2592. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  2593. if (!tableExpr)
  2594. return buildCachedActivity(ctx, expr->queryChild(0)); // Somehow a null appeared.
  2595. HqlExprAttr mode = tableExpr->queryChild(2);
  2596. node_operator modeOp = mode->getOperator();
  2597. bool isPiped = modeOp==no_pipe;
  2598. DiskReadBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  2599. info.gatherVirtualFields(tableExpr->hasAttribute(_noVirtual_Atom) || isPiped, needToSerializeRecord(modeOp));
  2600. unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
  2601. if (!info.fieldInfo.simpleVirtualsAtEnd || info.fieldInfo.requiresDeserialize ||
  2602. (info.recordHasVirtuals() && (modeOp == no_csv || !isSimpleSource(expr))))
  2603. {
  2604. OwnedHqlExpr transformed = buildTableWithoutVirtuals(info.fieldInfo, expr);
  2605. //Need to wrap a possible no_usertable, otherwise the localisation can go wrong.
  2606. if (expr->getOperator() == no_table)
  2607. transformed.setown(createDataset(no_compound_diskread, LINK(transformed)));
  2608. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  2609. traceExpression("after disk optimize", optimized);
  2610. return doBuildActivityDiskRead(ctx, optimized);
  2611. }
  2612. OwnedHqlExpr optimized;
  2613. if (expr->getOperator() == no_table)
  2614. optimized.set(expr);
  2615. else
  2616. optimized.setown(optimizeHqlExpression(queryErrorProcessor(), expr, optFlags));
  2617. if (optimized != expr)
  2618. return buildActivity(ctx, optimized, false);
  2619. if (optimized->getOperator() != no_compound_diskread)
  2620. optimized.setown(createDataset(no_compound_diskread, LINK(optimized)));
  2621. if (isPiped)
  2622. return info.buildActivity(ctx, expr, TAKpiperead, "PipeRead", NULL);
  2623. ensureDiskAccessAllowed(tableExpr);
  2624. if (modeOp == no_csv)
  2625. return info.buildActivity(ctx, expr, TAKcsvread, "CsvRead", NULL);
  2626. return info.buildActivity(ctx, expr, TAKdiskread, "DiskRead", NULL);
  2627. }
  2628. //---------------------------------------------------------------------------
  2629. class DiskNormalizeBuilder : public DiskReadBuilderBase
  2630. {
  2631. public:
  2632. DiskNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2633. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr)
  2634. {
  2635. }
  2636. virtual void buildTransform(IHqlExpression * expr);
  2637. virtual void buildMembers(IHqlExpression * expr);
  2638. protected:
  2639. virtual void analyseGraph(IHqlExpression * expr);
  2640. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2641. {
  2642. doBuildNormalizeIterators(ctx, expr, false);
  2643. }
  2644. };
  2645. void DiskNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  2646. {
  2647. DiskReadBuilderBase::analyseGraph(expr);
  2648. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  2649. }
  2650. void DiskNormalizeBuilder::buildMembers(IHqlExpression * expr)
  2651. {
  2652. buildFilenameMember();
  2653. DiskReadBuilderBase::buildMembers(expr);
  2654. buildNormalizeHelpers(expr);
  2655. }
  2656. void DiskNormalizeBuilder::buildTransform(IHqlExpression * expr)
  2657. {
  2658. globaliterctx.setown(new BuildCtx(instance->startctx));
  2659. globaliterctx->addGroup();
  2660. BuildCtx transformCtx(instance->startctx);
  2661. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf)");
  2662. translator.ensureRowAllocated(transformCtx, "crSelf");
  2663. buildTransformBody(transformCtx, expr, true, false, false);
  2664. }
  2665. //---------------------------------------------------------------------------
  2666. ABoundActivity * HqlCppTranslator::doBuildActivityDiskNormalize(BuildCtx & ctx, IHqlExpression * expr)
  2667. {
  2668. assertex(!isGroupedActivity(expr));
  2669. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  2670. ensureDiskAccessAllowed(tableExpr);
  2671. HqlExprAttr mode = tableExpr->queryChild(2);
  2672. assertex(mode->getOperator()!=no_pipe);
  2673. DiskNormalizeBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  2674. info.gatherVirtualFields(tableExpr->hasAttribute(_noVirtual_Atom), needToSerializeRecord(mode));
  2675. LinkedHqlExpr transformed = expr;
  2676. if (info.recordHasVirtualsOrDeserialize())
  2677. transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
  2678. unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
  2679. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  2680. if (optimized != expr)
  2681. return buildActivity(ctx, optimized, false);
  2682. return info.buildActivity(ctx, expr, TAKdisknormalize, "DiskNormalize", NULL);
  2683. }
  2684. //---------------------------------------------------------------------------
  2685. class DiskAggregateBuilder : public DiskReadBuilderBase
  2686. {
  2687. public:
  2688. DiskAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2689. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr)
  2690. {
  2691. failedFilterValue.clear();
  2692. }
  2693. virtual void buildTransform(IHqlExpression * expr);
  2694. virtual void buildMembers(IHqlExpression * expr);
  2695. protected:
  2696. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2697. {
  2698. doBuildAggregateSelectIterator(ctx, expr);
  2699. }
  2700. virtual void analyseGraph(IHqlExpression * expr)
  2701. {
  2702. DiskReadBuilderBase::analyseGraph(expr);
  2703. returnIfFilterFails = !isNormalize;
  2704. }
  2705. };
  2706. void DiskAggregateBuilder::buildMembers(IHqlExpression * expr)
  2707. {
  2708. StringBuffer s;
  2709. buildFilenameMember();
  2710. DiskReadBuilderBase::buildMembers(expr);
  2711. buildAggregateHelpers(expr);
  2712. //virtual void processRow(void * self, const void * src) = 0;
  2713. BuildCtx rowctx(instance->startctx);
  2714. rowctx.addQuotedCompoundLiteral("virtual void processRow(ARowBuilder & crSelf, const void * src)");
  2715. rowctx.addQuotedLiteral("doProcessRow(crSelf, (byte *)src);");
  2716. //virtual void processRows(void * self, size32_t srcLen, const void * src) = 0;
  2717. BuildCtx rowsctx(instance->startctx);
  2718. rowsctx.addQuotedCompoundLiteral("virtual void processRows(ARowBuilder & crSelf, size32_t srcLen, const void * _left)");
  2719. rowsctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2720. OwnedHqlExpr ds = createVariable("left", makeReferenceModifier(tableExpr->getType()));
  2721. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  2722. OwnedHqlExpr fullDs = createTranslated(ds, len);
  2723. Owned<IHqlCppDatasetCursor> iter = translator.createDatasetSelector(rowsctx, fullDs);
  2724. BoundRow * curRow = iter->buildIterateLoop(rowsctx, false);
  2725. s.clear().append("doProcessRow(crSelf, ");
  2726. translator.generateExprCpp(s, curRow->queryBound());
  2727. s.append(");");
  2728. rowsctx.addQuoted(s);
  2729. }
  2730. void DiskAggregateBuilder::buildTransform(IHqlExpression * expr)
  2731. {
  2732. BuildCtx transformCtx(instance->startctx);
  2733. transformCtx.addQuotedCompoundLiteral("void doProcessRow(ARowBuilder & crSelf, byte * left)");
  2734. translator.ensureRowAllocated(transformCtx, "crSelf");
  2735. buildTransformBody(transformCtx, expr, false, false, true);
  2736. }
  2737. //---------------------------------------------------------------------------
  2738. class DiskCountBuilder : public DiskReadBuilderBase
  2739. {
  2740. public:
  2741. DiskCountBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, node_operator _aggOp)
  2742. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr)
  2743. {
  2744. aggOp = _aggOp;
  2745. isCompoundCount = true;
  2746. failedFilterValue.set(queryZero());
  2747. }
  2748. virtual void buildTransform(IHqlExpression * expr);
  2749. virtual void buildMembers(IHqlExpression * expr);
  2750. virtual bool isExplicitExists() { return (aggOp == no_existsgroup); }
  2751. protected:
  2752. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2753. {
  2754. doBuildAggregateSelectIterator(ctx, expr);
  2755. }
  2756. virtual void analyseGraph(IHqlExpression * expr)
  2757. {
  2758. DiskReadBuilderBase::analyseGraph(expr);
  2759. returnIfFilterFails = !isNormalize;
  2760. if (aggOp == no_existsgroup)
  2761. choosenValue.setown(getSizetConstant(1));
  2762. }
  2763. protected:
  2764. node_operator aggOp;
  2765. };
  2766. void DiskCountBuilder::buildMembers(IHqlExpression * expr)
  2767. {
  2768. isUnfilteredCount = !(transformCanFilter||isNormalize);
  2769. buildFilenameMember();
  2770. DiskReadBuilderBase::buildMembers(expr);
  2771. buildCountHelpers(expr, true);
  2772. }
  2773. void DiskCountBuilder::buildTransform(IHqlExpression * expr)
  2774. {
  2775. if (transformCanFilter||isNormalize)
  2776. {
  2777. BuildCtx transformCtx(instance->startctx);
  2778. transformCtx.addQuotedCompoundLiteral("size32_t valid(byte * _left)");
  2779. transformCtx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2780. OwnedHqlExpr cnt;
  2781. if (isNormalize)
  2782. {
  2783. compoundCountVar.setown(transformCtx.getTempDeclare(sizetType, queryZero()));
  2784. cnt.set(compoundCountVar);
  2785. }
  2786. else
  2787. cnt.setown(getSizetConstant(1));
  2788. BuildCtx subctx(transformCtx);
  2789. buildTransformBody(subctx, expr, false, false, true);
  2790. transformCtx.addReturn(cnt);
  2791. }
  2792. }
  2793. //---------------------------------------------------------------------------
  2794. ABoundActivity * HqlCppTranslator::doBuildActivityDiskAggregate(BuildCtx & ctx, IHqlExpression * expr)
  2795. {
  2796. assertex(!isGroupedActivity(expr));
  2797. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  2798. ensureDiskAccessAllowed(tableExpr);
  2799. HqlExprAttr mode = tableExpr->queryChild(2);
  2800. assertex(mode->getOperator()!=no_pipe);
  2801. DiskAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  2802. info.gatherVirtualFields(tableExpr->hasAttribute(_noVirtual_Atom), needToSerializeRecord(mode));
  2803. LinkedHqlExpr transformed = expr;
  2804. if (info.recordHasVirtualsOrDeserialize())
  2805. transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
  2806. transformed.setown(optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags()));
  2807. if (transformed != expr)
  2808. return buildActivity(ctx, transformed, false);
  2809. node_operator aggOp = querySimpleAggregate(expr, true, false);
  2810. if (aggOp == no_countgroup || aggOp == no_existsgroup)
  2811. {
  2812. DiskCountBuilder info(*this, tableExpr, tableExpr->queryChild(0), aggOp);
  2813. info.gatherVirtualFields(tableExpr->hasAttribute(_noVirtual_Atom), needToSerializeRecord(mode));
  2814. return info.buildActivity(ctx, expr, TAKdiskcount, "DiskCount", NULL);
  2815. }
  2816. else
  2817. return info.buildActivity(ctx, expr, TAKdiskaggregate, "DiskAggregate", NULL);
  2818. }
  2819. //---------------------------------------------------------------------------
  2820. class DiskGroupAggregateBuilder : public DiskReadBuilderBase
  2821. {
  2822. public:
  2823. DiskGroupAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2824. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr)
  2825. {
  2826. failedFilterValue.clear();
  2827. }
  2828. virtual void buildTransform(IHqlExpression * expr);
  2829. virtual void buildMembers(IHqlExpression * expr);
  2830. protected:
  2831. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2832. {
  2833. doBuildAggregateSelectIterator(ctx, expr);
  2834. }
  2835. virtual void analyseGraph(IHqlExpression * expr)
  2836. {
  2837. DiskReadBuilderBase::analyseGraph(expr);
  2838. returnIfFilterFails = !isNormalize;
  2839. }
  2840. };
  2841. void DiskGroupAggregateBuilder::buildMembers(IHqlExpression * expr)
  2842. {
  2843. buildFilenameMember();
  2844. buildGroupingMonitors(expr, monitors);
  2845. DiskReadBuilderBase::buildMembers(expr);
  2846. buildGlobalGroupAggregateHelpers(expr);
  2847. }
  2848. void DiskGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
  2849. {
  2850. BuildCtx transformCtx(instance->startctx);
  2851. transformCtx.addQuotedCompoundLiteral("void doProcessRow(byte * left, IHThorGroupAggregateCallback * callback)");
  2852. bool accessesCallback = containsOperator(expr, no_filepos) || containsOperator(expr, no_file_logicalname);
  2853. buildGroupAggregateTransformBody(transformCtx, expr, isNormalize || accessesCallback, true);
  2854. }
  2855. //---------------------------------------------------------------------------
  2856. ABoundActivity * HqlCppTranslator::doBuildActivityDiskGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
  2857. {
  2858. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  2859. ensureDiskAccessAllowed(tableExpr);
  2860. HqlExprAttr mode = tableExpr->queryChild(2);
  2861. assertex(mode->getOperator()!=no_pipe);
  2862. DiskGroupAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  2863. info.gatherVirtualFields(tableExpr->hasAttribute(_noVirtual_Atom), needToSerializeRecord(mode));
  2864. LinkedHqlExpr transformed = expr;
  2865. if (info.recordHasVirtualsOrDeserialize())
  2866. transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
  2867. transformed.setown(optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags()));
  2868. if (transformed != expr)
  2869. return buildActivity(ctx, transformed, false);
  2870. return info.buildActivity(ctx, expr, TAKdiskgroupaggregate, "DiskGroupAggregate", NULL);
  2871. }
  2872. //-----------------------------------------------------------------------------------------------
  2873. //-- Child dataset processing
  2874. //-----------------------------------------------------------------------------------------------
  2875. class ChildBuilderBase : public SourceBuilder
  2876. {
  2877. public:
  2878. ChildBuilderBase(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2879. : SourceBuilder(_translator, _tableExpr, _nameExpr)
  2880. {
  2881. }
  2882. virtual void buildMembers(IHqlExpression * expr) {}
  2883. virtual void buildTransformFpos(BuildCtx & transformCtx) {}
  2884. };
  2885. class ChildNormalizeBuilder : public ChildBuilderBase
  2886. {
  2887. public:
  2888. ChildNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2889. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  2890. {
  2891. }
  2892. virtual void buildTransform(IHqlExpression * expr);
  2893. virtual void buildMembers(IHqlExpression * expr);
  2894. protected:
  2895. virtual void analyseGraph(IHqlExpression * expr);
  2896. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2897. {
  2898. doBuildNormalizeIterators(ctx, expr, true);
  2899. }
  2900. };
  2901. void ChildNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  2902. {
  2903. ChildBuilderBase::analyseGraph(expr);
  2904. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  2905. }
  2906. void ChildNormalizeBuilder::buildMembers(IHqlExpression * expr)
  2907. {
  2908. ChildBuilderBase::buildMembers(expr);
  2909. buildNormalizeHelpers(expr);
  2910. }
  2911. void ChildNormalizeBuilder::buildTransform(IHqlExpression * expr)
  2912. {
  2913. globaliterctx.setown(new BuildCtx(instance->startctx));
  2914. globaliterctx->addGroup();
  2915. BuildCtx transformCtx(instance->startctx);
  2916. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf)");
  2917. translator.ensureRowAllocated(transformCtx, "crSelf");
  2918. buildTransformBody(transformCtx, expr, true, false, false);
  2919. }
  2920. //---------------------------------------------------------------------------
  2921. ABoundActivity * HqlCppTranslator::doBuildActivityChildNormalize(BuildCtx & ctx, IHqlExpression * expr)
  2922. {
  2923. ChildNormalizeBuilder info(*this, NULL, NULL);
  2924. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, HOOfold);
  2925. if (optimized != expr)
  2926. return buildActivity(ctx, optimized, false);
  2927. return info.buildActivity(ctx, expr, TAKchildnormalize, "ChildNormalize", NULL);
  2928. }
  2929. //---------------------------------------------------------------------------
  2930. class ChildAggregateBuilder : public ChildBuilderBase
  2931. {
  2932. public:
  2933. ChildAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2934. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  2935. {
  2936. failedFilterValue.clear();
  2937. }
  2938. virtual void buildTransform(IHqlExpression * expr);
  2939. virtual void buildMembers(IHqlExpression * expr);
  2940. protected:
  2941. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2942. {
  2943. doBuildAggregateSelectIterator(ctx, expr);
  2944. }
  2945. virtual void analyseGraph(IHqlExpression * expr)
  2946. {
  2947. ChildBuilderBase::analyseGraph(expr);
  2948. returnIfFilterFails = false;
  2949. }
  2950. };
  2951. void ChildAggregateBuilder::buildMembers(IHqlExpression * expr)
  2952. {
  2953. ChildBuilderBase::buildMembers(expr);
  2954. buildAggregateHelpers(expr);
  2955. }
  2956. void ChildAggregateBuilder::buildTransform(IHqlExpression * expr)
  2957. {
  2958. BuildCtx transformCtx(instance->startctx);
  2959. transformCtx.addQuotedCompoundLiteral("virtual void processRows(ARowBuilder & crSelf)");
  2960. translator.ensureRowAllocated(transformCtx, "crSelf");
  2961. buildTransformBody(transformCtx, expr, false, false, false);
  2962. }
  2963. //---------------------------------------------------------------------------
  2964. ABoundActivity * HqlCppTranslator::doBuildActivityChildAggregate(BuildCtx & ctx, IHqlExpression * expr)
  2965. {
  2966. ChildAggregateBuilder info(*this, NULL, NULL);
  2967. OwnedHqlExpr transformed = optimizeHqlExpression(queryErrorProcessor(), expr, getSourceAggregateOptimizeFlags());
  2968. if (transformed != expr)
  2969. return buildActivity(ctx, transformed, false);
  2970. return info.buildActivity(ctx, expr, TAKchildaggregate, "ChildAggregate", NULL);
  2971. }
  2972. //---------------------------------------------------------------------------
  2973. class ChildGroupAggregateBuilder : public ChildBuilderBase
  2974. {
  2975. public:
  2976. ChildGroupAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2977. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  2978. {
  2979. failedFilterValue.clear();
  2980. }
  2981. virtual void buildTransform(IHqlExpression * expr);
  2982. virtual void buildMembers(IHqlExpression * expr);
  2983. protected:
  2984. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2985. {
  2986. doBuildAggregateSelectIterator(ctx, expr);
  2987. }
  2988. virtual void analyseGraph(IHqlExpression * expr)
  2989. {
  2990. ChildBuilderBase::analyseGraph(expr);
  2991. returnIfFilterFails = false;
  2992. }
  2993. };
  2994. void ChildGroupAggregateBuilder::buildMembers(IHqlExpression * expr)
  2995. {
  2996. ChildBuilderBase::buildMembers(expr);
  2997. IHqlExpression * aggregate = expr->queryChild(0);
  2998. assertex(aggregate->getOperator() == no_newaggregate);
  2999. StringBuffer s;
  3000. //virtual size32_t clearAggregate(void * self) = 0;
  3001. translator.doBuildAggregateClearFunc(instance->startctx, aggregate);
  3002. //virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) - never actually called.
  3003. instance->startctx.addQuotedLiteral("virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) { return 0; }");
  3004. }
  3005. void ChildGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
  3006. {
  3007. BuildCtx transformCtx(instance->startctx);
  3008. transformCtx.addQuotedCompoundLiteral("void processRows(IHThorGroupAggregateCallback * callback)");
  3009. buildGroupAggregateTransformBody(transformCtx, expr, true, false);
  3010. }
  3011. //---------------------------------------------------------------------------
  3012. ABoundActivity * HqlCppTranslator::doBuildActivityChildGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3013. {
  3014. ChildGroupAggregateBuilder info(*this, NULL, NULL);
  3015. OwnedHqlExpr transformed = optimizeHqlExpression(queryErrorProcessor(), expr, getSourceAggregateOptimizeFlags());
  3016. if (transformed != expr)
  3017. return buildActivity(ctx, transformed, false);
  3018. return info.buildActivity(ctx, expr, TAKchildgroupaggregate, "ChildGroupAggregate", NULL);
  3019. }
  3020. //---------------------------------------------------------------------------
  3021. class ChildThroughNormalizeBuilder : public ChildBuilderBase
  3022. {
  3023. public:
  3024. ChildThroughNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3025. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  3026. {
  3027. }
  3028. virtual void buildTransform(IHqlExpression * expr);
  3029. virtual void buildMembers(IHqlExpression * expr);
  3030. protected:
  3031. virtual void analyseGraph(IHqlExpression * expr);
  3032. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3033. {
  3034. translator.bindTableCursor(ctx, expr, "left");
  3035. doBuildNormalizeIterators(ctx, expr, false);
  3036. }
  3037. };
  3038. void ChildThroughNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  3039. {
  3040. ChildBuilderBase::analyseGraph(expr);
  3041. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  3042. }
  3043. void ChildThroughNormalizeBuilder::buildMembers(IHqlExpression * expr)
  3044. {
  3045. ChildBuilderBase::buildMembers(expr);
  3046. buildNormalizeHelpers(expr);
  3047. }
  3048. void ChildThroughNormalizeBuilder::buildTransform(IHqlExpression * expr)
  3049. {
  3050. globaliterctx.setown(new BuildCtx(instance->startctx));
  3051. globaliterctx->addGroup();
  3052. BuildCtx transformCtx(instance->startctx);
  3053. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf)");
  3054. translator.ensureRowAllocated(transformCtx, "crSelf");
  3055. buildTransformBody(transformCtx, expr, true, false, false);
  3056. }
  3057. ABoundActivity * HqlCppTranslator::doBuildActivityCompoundSelectNew(BuildCtx & ctx, IHqlExpression * expr)
  3058. {
  3059. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, HOOfold);
  3060. if (optimized->getOperator() == no_null)
  3061. return buildCachedActivity(ctx, optimized);
  3062. IHqlExpression * select = queryRoot(optimized);
  3063. if (!(select && select->getOperator() == no_select && select->hasAttribute(newAtom)))
  3064. {
  3065. if (optimized->getOperator() == no_compound_selectnew)
  3066. return buildCachedActivity(ctx, optimized->queryChild(0));
  3067. return buildCachedActivity(ctx, optimized);
  3068. }
  3069. IHqlExpression * ds = select->queryChild(0);
  3070. Owned<ABoundActivity> childActivity = buildCachedActivity(ctx, ds);
  3071. OwnedHqlExpr fakeDataset = createDataset(no_anon, LINK(ds->queryRecord()));
  3072. OwnedHqlExpr fakeSelect = createNewSelectExpr(LINK(fakeDataset), LINK(select->queryChild(1)));
  3073. OwnedHqlExpr activityExpr = replaceExpression(optimized, select, fakeSelect);
  3074. ChildThroughNormalizeBuilder info(*this, fakeDataset, NULL);
  3075. info.gatherVirtualFields(true, true); // ,false?
  3076. return info.buildActivity(ctx, activityExpr, TAKchildthroughnormalize, "ChildThroughNormalize", childActivity);
  3077. }
  3078. //-----------------------------------------------------------------------------------------------
  3079. //-- Index processing
  3080. //-----------------------------------------------------------------------------------------------
  3081. /*
  3082. Note on generating segment monitors for conditions (ty)x = Y
  3083. 1) casting from Tx to Ty loses information. E.g., (int1)string2field = int1value.
  3084. In this case it is almost impossible to generate a segment monitor because we would need to work out all
  3085. the possibly values for x which could generate the value y.
  3086. The only exception is an inequality (and no_notin), which we can use to remove some of the candidates. The test will always need
  3087. duplicating since we cannot remove all the expected values.
  3088. 2) Casting from Ty to Tx loses information. E.g., (string)string2field = stringvalue
  3089. In this case we can process the filter without prefiltering by testing whether isExact: (Ty)(Tx)Y == Y, and following the following rules:
  3090. a) no_eq. If isExact, add value else nothing.
  3091. b) no_ne. If isExtact, remove value else nothing.
  3092. c) no_gt. Always add > value
  3093. d) no_ge. If isExact add >= value else add > value
  3094. e) no_lt. If isExact add < value else add <= value
  3095. f) no_le. Always add <= value
  3096. 3) Note casts must be present on both sides to indicate exactly what type the comparison will be done as. This includes (string)which would
  3097. normally be missing if the field was of type string<n>.
  3098. */
  3099. static node_operator getModifiedOp(node_operator op, bool duplicate)
  3100. {
  3101. if (!duplicate)
  3102. return op;
  3103. switch (op)
  3104. {
  3105. case no_eq:
  3106. case no_le:
  3107. case no_ge:
  3108. case no_in:
  3109. return op;
  3110. //err on the side of caution for the segment monitors -
  3111. //the test later which check it more accurately.
  3112. case no_gt:
  3113. return no_ge;
  3114. case no_lt:
  3115. return no_le;
  3116. case no_ne:
  3117. case no_notin:
  3118. return no_none;
  3119. default:
  3120. UNIMPLEMENTED;
  3121. }
  3122. }
  3123. void KeyFailureInfo::merge(const KeyFailureInfo & other)
  3124. {
  3125. if (code < other.code)
  3126. set(other.code, other.field);
  3127. }
  3128. void KeyFailureInfo::reportError(HqlCppTranslator & translator, IHqlExpression * condition)
  3129. {
  3130. StringBuffer ecl;
  3131. getExprECL(condition, ecl);
  3132. switch (code)
  3133. {
  3134. case KFRunknown:
  3135. translator.throwError1(HQLERR_KeyedJoinTooComplex, ecl.str());
  3136. case KFRnokey:
  3137. translator.throwError1(HQLERR_KeyAccessNoKeyField, ecl.str());
  3138. case KFRtoocomplex:
  3139. translator.throwError1(HQLERR_KeyedJoinTooComplex, ecl.str());
  3140. case KFRcast:
  3141. translator.throwError2(HQLERR_KeyAccessNeedCast, ecl.str(), str(field->queryName()));
  3142. case KFRor:
  3143. translator.throwError1(HQLERR_OrMultipleKeyfields, ecl.str());
  3144. }
  3145. }
  3146. const char * BuildMonitorState::getSetName()
  3147. {
  3148. if (!setNames.isItem(numActiveSets))
  3149. {
  3150. StringBuffer name;
  3151. getUniqueId(name.append("set"));
  3152. setNames.append(*new StringAttrItem(name.str()));
  3153. StringBuffer s;
  3154. funcctx.setNextConstructor();
  3155. funcctx.addQuoted(s.append("Owned<IStringSet> ").append(name).append(";"));
  3156. }
  3157. return setNames.item(numActiveSets++).text;
  3158. }
  3159. void BuildMonitorState::popSetName()
  3160. {
  3161. numActiveSets--;
  3162. }
  3163. IHqlExpression * KeyConditionInfo::createConjunction()
  3164. {
  3165. LinkedHqlExpr result = preFilter;
  3166. ForEachItemIn(i, conditions)
  3167. extendAndCondition(result, conditions.item(i).expr);
  3168. extendAndCondition(result, postFilter);
  3169. return result.getClear();
  3170. }
  3171. MonitorExtractor::MonitorExtractor(IHqlExpression * _tableExpr, HqlCppTranslator & _translator, int _numKeyableFields, bool _allowTranslatedConds) : translator(_translator)
  3172. {
  3173. tableExpr = _tableExpr;
  3174. allowTranslatedConds = _allowTranslatedConds;
  3175. if (_numKeyableFields <= 0)
  3176. {
  3177. //-ve number means remove a certain number of fields from the record
  3178. IHqlExpression * record = tableExpr->queryRecord();
  3179. numKeyableFields = 0;
  3180. ForEachChild(i, record)
  3181. if (!record->queryChild(i)->isAttribute())
  3182. numKeyableFields++;
  3183. numKeyableFields += _numKeyableFields; // remove payload fields.
  3184. }
  3185. else
  3186. numKeyableFields = (unsigned)_numKeyableFields;
  3187. onlyHozedCompares = !allowTranslatedConds;
  3188. expandKeyableFields();
  3189. cleanlyKeyedExplicitly = false;
  3190. keyedExplicitly = false;
  3191. allowDynamicFormatChange = !tableExpr->hasAttribute(fixedAtom);
  3192. }
  3193. void MonitorExtractor::callAddAll(BuildCtx & ctx, IHqlExpression * targetVar)
  3194. {
  3195. HqlExprArray args;
  3196. args.append(*LINK(targetVar));
  3197. translator.callProcedure(ctx, addAllId, args);
  3198. }
  3199. static IHqlExpression * createExpandedRecord(IHqlExpression * expr);
  3200. static ITypeInfo * getExpandedFieldType(ITypeInfo * type, IHqlExpression * expr)
  3201. {
  3202. Linked<ITypeInfo> expandedType = type;
  3203. if (type->getSize() == UNKNOWN_LENGTH)
  3204. expandedType.clear();
  3205. switch (type->getTypeCode())
  3206. {
  3207. case type_packedint:
  3208. expandedType.setown(makeIntType(type->queryPromotedType()->getSize(), type->isSigned()));
  3209. break;
  3210. case type_bitfield:
  3211. expandedType.set(type->queryPromotedType());
  3212. break;
  3213. case type_varstring:
  3214. case type_varunicode:
  3215. #if 0
  3216. if (type->getSize() != UNKNOWN_LENGTH)
  3217. {
  3218. unsigned len = type->getStringLen();
  3219. switch (type->getTypeCode())
  3220. {
  3221. case type_varstring:
  3222. expandedType.setown(makeStringType(len, LINK(type->queryCharset()), LINK(type->queryCollation())));
  3223. break;
  3224. case type_varunicode:
  3225. expandedType.setown(makeUnicodeType(len, type->queryLocale()));
  3226. break;
  3227. }
  3228. break;
  3229. }
  3230. #endif //fall through
  3231. case type_data:
  3232. case type_qstring:
  3233. case type_string:
  3234. case type_unicode:
  3235. case type_utf8:
  3236. if (type->getSize() == UNKNOWN_LENGTH)
  3237. {
  3238. unsigned maxLength = UNKNOWN_LENGTH;
  3239. IHqlExpression * maxSizeExpr = expr ? queryAttributeChild(expr, maxSizeAtom, 0) : NULL;
  3240. if (maxSizeExpr)
  3241. {
  3242. unsigned maxSize = (unsigned)maxSizeExpr->queryValue()->getIntValue();
  3243. switch (type->getTypeCode())
  3244. {
  3245. case type_data:
  3246. case type_string:
  3247. maxLength = maxSize - sizeof(size32_t);
  3248. break;
  3249. case type_qstring:
  3250. maxLength = rtlQStrLength(maxSize - sizeof(size32_t));
  3251. break;
  3252. case type_unicode:
  3253. maxLength = (maxSize-sizeof(size32_t))/sizeof(UChar);
  3254. break;
  3255. case type_utf8:
  3256. maxLength = (maxSize-sizeof(size32_t))/4;
  3257. break;
  3258. case type_varstring:
  3259. maxLength = maxSize - 1;
  3260. break;
  3261. case type_varunicode:
  3262. maxLength = (maxSize/sizeof(UChar)) - 1;
  3263. break;
  3264. }
  3265. }
  3266. else
  3267. {
  3268. IHqlExpression * maxLengthExpr = expr ? queryAttributeChild(expr, maxLengthAtom, 0) : NULL;
  3269. if (maxLengthExpr)
  3270. maxLength = (unsigned)maxLengthExpr->queryValue()->getIntValue();
  3271. }
  3272. if (maxLength != UNKNOWN_LENGTH)
  3273. {
  3274. switch (type->getTypeCode())
  3275. {
  3276. case type_data:
  3277. expandedType.setown(makeDataType(maxLength));
  3278. break;
  3279. case type_qstring:
  3280. expandedType.setown(makeQStringType(maxLength));
  3281. break;
  3282. case type_string:
  3283. expandedType.setown(makeStringType(maxLength, LINK(type->queryCharset()), LINK(type->queryCollation())));
  3284. break;
  3285. case type_unicode:
  3286. expandedType.setown(makeUnicodeType(maxLength, type->queryLocale()));
  3287. break;
  3288. case type_utf8:
  3289. expandedType.setown(makeUtf8Type(maxLength, type->queryLocale()));
  3290. break;
  3291. case type_varstring:
  3292. expandedType.setown(makeVarStringType(maxLength, LINK(type->queryCharset()), LINK(type->queryCollation())));
  3293. break;
  3294. case type_varunicode:
  3295. expandedType.setown(makeVarUnicodeType(maxLength, type->queryLocale()));
  3296. break;
  3297. }
  3298. }
  3299. }
  3300. else
  3301. {
  3302. //This could ensure the strings are ascii, but the ebcdic strings are still comparable, and the order will be more logical
  3303. //if they remain as ebcdic.
  3304. }
  3305. break;
  3306. case type_table:
  3307. case type_groupedtable:
  3308. case type_set:
  3309. expandedType.clear();
  3310. break;
  3311. case type_row:
  3312. {
  3313. OwnedHqlExpr newRecord = createExpandedRecord(queryRecord(type));
  3314. if (isEmptyRecord(newRecord))
  3315. expandedType.clear();
  3316. else
  3317. expandedType.setown(makeRowType(LINK(newRecord->queryRecordType())));
  3318. break;
  3319. }
  3320. case type_alien:
  3321. {
  3322. IHqlAlienTypeInfo * alien = queryAlienType(type);
  3323. expandedType.set(alien->queryLogicalType());
  3324. break;
  3325. }
  3326. }
  3327. return expandedType.getClear();
  3328. }
  3329. static void createExpanded(HqlExprArray & fields, IHqlExpression * expr)
  3330. {
  3331. switch (expr->getOperator())
  3332. {
  3333. case no_ifblock:
  3334. //if blocks need to generate translated segment monitors to be keyed, so don't expand them
  3335. break;
  3336. case no_record:
  3337. {
  3338. ForEachChild(i, expr)
  3339. createExpanded(fields, expr->queryChild(i));
  3340. break;
  3341. }
  3342. case no_field:
  3343. {
  3344. ITypeInfo * type = expr->queryType();
  3345. Owned<ITypeInfo> expandedType = getExpandedFieldType(type, expr);
  3346. if (expandedType)
  3347. {
  3348. if (expandedType == type)
  3349. fields.append(*LINK(expr));
  3350. else
  3351. {
  3352. HqlExprArray attrs;
  3353. unwindChildren(attrs, expr);
  3354. //MORE: Any default will now have the wrong type => remove it for the moment (ideally it would be projected)
  3355. removeAttribute(attrs, defaultAtom);
  3356. fields.append(*createField(expr->queryId(), LINK(expandedType), attrs));
  3357. }
  3358. }
  3359. break;
  3360. }
  3361. case no_attr:
  3362. case no_attr_link:
  3363. case no_attr_expr:
  3364. fields.append(*LINK(expr));
  3365. break;
  3366. }
  3367. }
  3368. static IHqlExpression * createExpandedRecord(IHqlExpression * expr)
  3369. {
  3370. HqlExprArray fields;
  3371. createExpanded(fields, expr);
  3372. return cloneOrLink(expr, fields);
  3373. }
  3374. bool MonitorExtractor::createGroupingMonitor(BuildCtx ctx, const char * listName, IHqlExpression * expr, unsigned & maxOffset)
  3375. {
  3376. switch (expr->getOperator())
  3377. {
  3378. case no_if:
  3379. {
  3380. IHqlExpression * cond = expr->queryChild(0);
  3381. if (expr->queryChild(2)->isConstant() && isIndependentOfScope(cond))
  3382. {
  3383. BuildCtx subctx(ctx);
  3384. translator.buildFilter(subctx, expr->queryChild(0));
  3385. createGroupingMonitor(subctx, listName, expr->queryChild(1), maxOffset);
  3386. return true; // may still be keyed
  3387. }
  3388. break;
  3389. }
  3390. case no_select:
  3391. {
  3392. size32_t offset = 0;
  3393. ForEachItemIn(i, keyableSelects)
  3394. {
  3395. IHqlExpression & cur = keyableSelects.item(i);
  3396. size32_t curSize = cur.queryType()->getSize();
  3397. if (curSize == UNKNOWN_LENGTH)
  3398. break;
  3399. if (expr == &cur)
  3400. {
  3401. //MORE: Check the type of the field is legal.
  3402. ctx.addQuotedF("%s->append(createWildKeySegmentMonitor(%u, %u));", listName, offset, curSize);
  3403. maxOffset = offset+curSize;
  3404. return true;
  3405. }
  3406. offset += curSize;
  3407. }
  3408. break;
  3409. }
  3410. case no_constant:
  3411. return true;
  3412. }
  3413. ctx.addReturn(queryBoolExpr(false));
  3414. return false;
  3415. }
  3416. void MonitorExtractor::expandKeyableFields()
  3417. {
  3418. HqlExprArray fields;
  3419. IHqlExpression * tableRecord = tableExpr->queryRecord();
  3420. unsigned cnt = 0;
  3421. ForEachChild(i, tableRecord)
  3422. {
  3423. if (cnt == numKeyableFields)
  3424. break;
  3425. IHqlExpression * cur = tableRecord->queryChild(i);
  3426. if (!cur->isAttribute())
  3427. {
  3428. fields.append(*LINK(cur));
  3429. cnt++;
  3430. }
  3431. }
  3432. keyableRecord.setown(createRecord(fields));
  3433. expandedRecord.setown(createExpandedRecord(keyableRecord));
  3434. IHqlExpression * selector = tableExpr->queryNormalizedSelector();
  3435. OwnedHqlExpr expandedSelector = createDataset(no_anon, LINK(expandedRecord), createUniqueId());
  3436. firstOffsetField = NotFound;
  3437. expandSelects(keyableRecord, expandedRecord->querySimpleScope(), selector, expandedSelector);
  3438. if (firstOffsetField == NotFound)
  3439. firstOffsetField = keyableSelects.ordinality();
  3440. }
  3441. void MonitorExtractor::expandSelects(IHqlExpression * expr, IHqlSimpleScope * expandedScope, IHqlExpression * keySelector, IHqlExpression * expandedSelector)
  3442. {
  3443. switch (expr->getOperator())
  3444. {
  3445. case no_record:
  3446. {
  3447. ForEachChild(i, expr)
  3448. expandSelects(expr->queryChild(i), expandedScope, keySelector, expandedSelector);
  3449. break;
  3450. }
  3451. case no_ifblock:
  3452. expandSelects(expr->queryChild(1), expandedScope, keySelector, expandedSelector);
  3453. break;
  3454. case no_field:
  3455. {
  3456. OwnedHqlExpr match = expandedScope->lookupSymbol(expr->queryId());
  3457. if (match)
  3458. {
  3459. OwnedHqlExpr keySelected = createSelectExpr(LINK(keySelector), LINK(expr));
  3460. OwnedHqlExpr expandedSelected = createSelectExpr(LINK(expandedSelector), LINK(match));
  3461. IHqlExpression * record = expr->queryRecord();
  3462. if (record)
  3463. expandSelects(record, match->queryRecord()->querySimpleScope(), keySelected, expandedSelected);
  3464. else
  3465. {
  3466. if ((expr != match) && (firstOffsetField == NotFound))
  3467. {
  3468. ITypeInfo * exprType = expr->queryType();
  3469. ITypeInfo * matchType = match->queryType();
  3470. if ((exprType->getSize() != matchType->getSize()) ||
  3471. (exprType->getTypeCode() == type_bitfield || exprType->getTypeCode() == type_bitfield))
  3472. firstOffsetField = keyableSelects.ordinality();
  3473. }
  3474. keyableSelects.append(*LINK(keySelected));
  3475. expandedSelects.append(*LINK(expandedSelected));
  3476. }
  3477. }
  3478. else
  3479. {
  3480. if (firstOffsetField == NotFound)
  3481. firstOffsetField = keyableSelects.ordinality();
  3482. }
  3483. break;
  3484. }
  3485. }
  3486. }
  3487. void MonitorExtractor::buildKeySegmentInExpr(BuildMonitorState & buildState, KeySelectorInfo & selectorInfo, BuildCtx & ctx, const char * target, IHqlExpression & thisKey, MonitorFilterKind filterKind)
  3488. {
  3489. //Generally this slightly increases the code size, but reduces the number of
  3490. //temporary sets which is generally more efficient.
  3491. OwnedHqlExpr simplified = querySimplifyInExpr(&thisKey);
  3492. if (simplified)
  3493. {
  3494. OwnedHqlExpr folded = foldHqlExpression(simplified);
  3495. buildKeySegmentExpr(buildState, selectorInfo, ctx, target, *folded, filterKind);
  3496. return;
  3497. }
  3498. IHqlExpression * expandedSelector = selectorInfo.expandedSelector;
  3499. ITypeInfo * fieldType = expandedSelector->queryType();
  3500. unsigned curSize = fieldType->getSize();
  3501. createStringSet(ctx, target, curSize, fieldType);
  3502. OwnedHqlExpr targetVar = createVariable(target, makeVoidType());
  3503. IHqlExpression * lhs = thisKey.queryChild(0);
  3504. OwnedHqlExpr values = normalizeListCasts(thisKey.queryChild(1));
  3505. IIdAtom * func = addRangeId;
  3506. if (thisKey.getOperator() == no_notin)
  3507. {
  3508. callAddAll(ctx, targetVar);
  3509. func = killRangeId;
  3510. }
  3511. if (values->getOperator() != no_list)
  3512. {
  3513. //iterate through the set
  3514. BuildCtx subctx(ctx);
  3515. CHqlBoundExpr boundCurElement;
  3516. Owned<IHqlCppSetCursor> cursor = translator.createSetSelector(ctx, values);
  3517. bool done = false;
  3518. CHqlBoundExpr isAll;
  3519. cursor->buildIsAll(subctx, isAll);
  3520. if (isAll.expr->queryValue())
  3521. {
  3522. if (isAll.expr->queryValue()->getBoolValue())
  3523. {
  3524. callAddAll(subctx, targetVar);
  3525. done = true;
  3526. //If ALL allowed exceptions then we would need to do more....
  3527. }
  3528. }
  3529. else
  3530. {
  3531. IHqlStmt * stmt = subctx.addFilter(isAll.expr);
  3532. callAddAll(subctx, targetVar);
  3533. subctx.selectElse(stmt);
  3534. }
  3535. if (!done)
  3536. {
  3537. cursor->buildIterateLoop(subctx, boundCurElement, false);
  3538. OwnedHqlExpr curValue = boundCurElement.getTranslatedExpr();
  3539. OwnedHqlExpr test = createBoolExpr(no_eq, LINK(lhs), LINK(curValue));
  3540. OwnedHqlExpr promoted = getExplicitlyPromotedCompare(test);
  3541. OwnedHqlExpr compare, normalized;
  3542. extractCompareInformation(subctx, promoted, compare, normalized, expandedSelector, selectorInfo.isComputed);
  3543. if (compare)
  3544. translator.buildFilter(subctx, compare);
  3545. HqlExprArray args;
  3546. args.append(*LINK(targetVar));
  3547. unsigned srcSize = normalized->queryType()->getSize();
  3548. if (srcSize < curSize)
  3549. {
  3550. OwnedHqlExpr lengthExpr = getSizetConstant(srcSize);
  3551. OwnedHqlExpr rangeLower = getRangeLimit(fieldType, lengthExpr, normalized, -1);
  3552. OwnedHqlExpr rangeUpper = getRangeLimit(fieldType, lengthExpr, normalized, +1);
  3553. CHqlBoundExpr boundLower, boundUpper;
  3554. translator.buildExpr(subctx, rangeLower, boundLower);
  3555. translator.buildExpr(subctx, rangeUpper, boundUpper);
  3556. args.append(*getPointer(boundLower.expr));
  3557. args.append(*getPointer(boundUpper.expr));
  3558. }
  3559. else
  3560. {
  3561. OwnedHqlExpr address = getMonitorValueAddress(subctx, normalized);
  3562. args.append(*LINK(address));
  3563. args.append(*LINK(address));
  3564. }
  3565. translator.callProcedure(subctx, func, args);
  3566. }
  3567. }
  3568. else
  3569. {
  3570. ForEachChild(idx2, values)
  3571. {
  3572. BuildCtx subctx(ctx);
  3573. IHqlExpression * cur = values->queryChild(idx2);
  3574. OwnedHqlExpr test = createBoolExpr(no_eq, LINK(lhs), LINK(cur));
  3575. OwnedHqlExpr promoted = getExplicitlyPromotedCompare(test);
  3576. OwnedHqlExpr compare, normalized;
  3577. extractCompareInformation(subctx, promoted, compare, normalized, expandedSelector, selectorInfo.isComputed);
  3578. if (compare)
  3579. translator.buildFilter(subctx, compare);
  3580. OwnedHqlExpr address = getMonitorValueAddress(subctx, normalized);
  3581. HqlExprArray args;
  3582. args.append(*LINK(targetVar));
  3583. args.append(*LINK(address));
  3584. args.append(*LINK(address));
  3585. translator.callProcedure(subctx, func, args);
  3586. }
  3587. }
  3588. }
  3589. static IHqlExpression * createCompareRecast(node_operator op, IHqlExpression * value, IHqlExpression * recastValue)
  3590. {
  3591. if (recastValue->queryValue())
  3592. return LINK(queryBoolExpr(op == no_ne));
  3593. return createValue(op, makeBoolType(), LINK(value), LINK(recastValue));
  3594. }
  3595. void MonitorExtractor::extractCompareInformation(BuildCtx & ctx, IHqlExpression * expr, SharedHqlExpr & compare, SharedHqlExpr & normalized, IHqlExpression * expandedSelector, bool isComputed)
  3596. {
  3597. extractCompareInformation(ctx, expr->queryChild(0), expr->queryChild(1), compare, normalized, expandedSelector, isComputed);
  3598. }
  3599. void MonitorExtractor::extractCompareInformation(BuildCtx & ctx, IHqlExpression * lhs, IHqlExpression * value, SharedHqlExpr & compare, SharedHqlExpr & normalized, IHqlExpression * expandedSelector, bool isComputed)
  3600. {
  3601. LinkedHqlExpr compareValue = value->queryBody();
  3602. OwnedHqlExpr recastValue;
  3603. if (isComputed)
  3604. normalized.setown(ensureExprType(compareValue, expandedSelector->queryType()));
  3605. else
  3606. {
  3607. if ((lhs->getOperator() != no_select) || (lhs->queryType() != compareValue->queryType()))
  3608. {
  3609. OwnedHqlExpr temp = castToFieldAndBack(lhs, compareValue);
  3610. if (temp != compareValue)
  3611. {
  3612. //Force into a temporary variable since it will be used more than once, and reapply the field casting/
  3613. compareValue.setown(translator.buildSimplifyExpr(ctx, compareValue));
  3614. //cast to promoted type because sometimes evaluating can convert string to string<n>
  3615. Owned<ITypeInfo> promotedType = getPromotedECLType(lhs->queryType(), compareValue->queryType());
  3616. compareValue.setown(ensureExprType(compareValue, promotedType));
  3617. recastValue.setown(castToFieldAndBack(lhs, compareValue));
  3618. }
  3619. }
  3620. normalized.setown(invertTransforms(lhs, compareValue));
  3621. }
  3622. normalized.setown(foldHqlExpression(normalized));
  3623. if (recastValue && recastValue != compareValue)
  3624. compare.setown(createCompareRecast(no_eq, compareValue, recastValue));
  3625. }
  3626. void MonitorExtractor::createStringSet(BuildCtx & ctx, const char * target, unsigned size, ITypeInfo * type)
  3627. {
  3628. if (onlyHozedCompares)
  3629. ctx.addQuotedF("%s.setown(createRtlStringSet(%u));", target, size);
  3630. else
  3631. {
  3632. bool isBigEndian = !type->isInteger() || !isLittleEndian(type);
  3633. ctx.addQuotedF("%s.setown(createRtlStringSetEx(%u,%d,%d));", target, size, isBigEndian, type->isSigned());
  3634. }
  3635. }
  3636. void MonitorExtractor::buildKeySegmentCompareExpr(BuildMonitorState & buildState, KeySelectorInfo & selectorInfo, BuildCtx & ctx, const char * targetSet, IHqlExpression & thisKey)
  3637. {
  3638. OwnedHqlExpr targetVar = createVariable(targetSet, makeVoidType());
  3639. createStringSet(ctx, targetSet, selectorInfo.size, selectorInfo.expandedSelector->queryType());
  3640. if (!exprReferencesDataset(&thisKey, tableExpr))
  3641. {
  3642. BuildCtx subctx(ctx);
  3643. translator.buildFilter(subctx, &thisKey);
  3644. callAddAll(subctx, targetVar);
  3645. return;
  3646. }
  3647. OwnedHqlExpr compare;
  3648. OwnedHqlExpr normalized;
  3649. BuildCtx subctx(ctx);
  3650. extractCompareInformation(subctx, &thisKey, compare, normalized, selectorInfo.expandedSelector, selectorInfo.isComputed);
  3651. OwnedHqlExpr address = getMonitorValueAddress(subctx, normalized);
  3652. HqlExprArray args;
  3653. args.append(*LINK(targetVar));
  3654. node_operator op = thisKey.getOperator();
  3655. switch (op)
  3656. {
  3657. case no_eq:
  3658. if (compare)
  3659. translator.buildFilter(subctx, compare);
  3660. args.append(*LINK(address));
  3661. args.append(*LINK(address));
  3662. translator.callProcedure(subctx, addRangeId, args);
  3663. break;
  3664. case no_ne:
  3665. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  3666. if (compare)
  3667. translator.buildFilter(subctx, compare);
  3668. args.append(*LINK(address));
  3669. args.append(*LINK(address));
  3670. translator.callProcedure(subctx, killRangeId, args);
  3671. break;
  3672. case no_le:
  3673. args.append(*createValue(no_nullptr, makeVoidType()));
  3674. args.append(*LINK(address));
  3675. translator.callProcedure(subctx, addRangeId, args);
  3676. break;
  3677. case no_lt:
  3678. // e) no_lt. If isExact add < value else add <= value
  3679. if (compare)
  3680. {
  3681. OwnedHqlExpr invCompare = getInverse(compare);
  3682. IHqlStmt * cond = translator.buildFilterViaExpr(subctx, invCompare);
  3683. //common this up...
  3684. args.append(*createValue(no_nullptr, makeVoidType()));
  3685. args.append(*LINK(address));
  3686. translator.callProcedure(subctx, addRangeId, args);
  3687. subctx.selectElse(cond);
  3688. args.append(*LINK(targetVar));
  3689. }
  3690. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  3691. args.append(*LINK(address));
  3692. args.append(*createValue(no_nullptr, makeVoidType()));
  3693. translator.callProcedure(subctx, killRangeId, args);
  3694. break;
  3695. case no_ge:
  3696. // d) no_ge. If isExact add >= value else add > value
  3697. if (compare)
  3698. {
  3699. OwnedHqlExpr invCompare = getInverse(compare);
  3700. IHqlStmt * cond = translator.buildFilterViaExpr(subctx, invCompare);
  3701. //common this up...
  3702. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  3703. args.append(*createValue(no_nullptr, makeVoidType()));
  3704. args.append(*LINK(address));
  3705. translator.callProcedure(subctx, killRangeId, args);
  3706. subctx.selectElse(cond);
  3707. args.append(*LINK(targetVar));
  3708. }
  3709. args.append(*LINK(address));
  3710. args.append(*createValue(no_nullptr, makeVoidType()));
  3711. translator.callProcedure(subctx, addRangeId, args);
  3712. break;
  3713. case no_gt:
  3714. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  3715. args.append(*createValue(no_nullptr, makeVoidType()));
  3716. args.append(*LINK(address));
  3717. translator.callProcedure(subctx, killRangeId, args);
  3718. break;
  3719. case no_between:
  3720. case no_notbetween:
  3721. {
  3722. //NB: This should only be generated for substring queries. User betweens are converted
  3723. //to two separate comparisons to cope with range issues.
  3724. args.append(*LINK(address));
  3725. CHqlBoundExpr rhs2;
  3726. OwnedHqlExpr adjustedUpper = invertTransforms(thisKey.queryChild(0), thisKey.queryChild(2));
  3727. OwnedHqlExpr foldedUpper = foldHqlExpression(adjustedUpper);
  3728. OwnedHqlExpr hozedValue = getHozedKeyValue(foldedUpper);
  3729. IIdAtom * name = hozedValue->queryId();
  3730. if ((name != createRangeHighId) && (name != createQStrRangeHighId))
  3731. hozedValue.setown(ensureExprType(hozedValue, selectorInfo.expandedSelector->queryType()));
  3732. translator.buildExpr(subctx, hozedValue, rhs2);
  3733. translator.ensureHasAddress(subctx, rhs2);
  3734. args.append(*getPointer(rhs2.expr));
  3735. if (op == no_between)
  3736. translator.callProcedure(subctx, addRangeId, args);
  3737. else
  3738. {
  3739. subctx.addQuoted(StringBuffer().appendf("%s->addAll();", targetSet));
  3740. translator.callProcedure(subctx, killRangeId, args);
  3741. }
  3742. break;
  3743. }
  3744. default:
  3745. throwUnexpectedOp(op);
  3746. }
  3747. }
  3748. IHqlExpression * MonitorExtractor::unwindConjunction(HqlExprArray & matches, IHqlExpression * expr)
  3749. {
  3750. node_operator op = expr->getOperator();
  3751. expr->unwindList(matches, op);
  3752. OwnedHqlExpr invariant;
  3753. ForEachItemInRev(i, matches)
  3754. {
  3755. IHqlExpression & cur = matches.item(i);
  3756. if (isIndexInvariant(&cur, false))
  3757. {
  3758. invariant.setown(extendConditionOwn(op, LINK(&cur), invariant.getClear()));
  3759. matches.remove(i);
  3760. }
  3761. }
  3762. return invariant.getClear();
  3763. }
  3764. //Note this function may change the incoming ctx if filterKind is not NoMonitorFilter
  3765. void MonitorExtractor::buildKeySegmentExpr(BuildMonitorState & buildState, KeySelectorInfo & selectorInfo, BuildCtx & ctx, const char * requiredSet, IHqlExpression & thisKey, MonitorFilterKind filterKind)
  3766. {
  3767. const char * targetSet = requiredSet;
  3768. StringBuffer s;
  3769. unsigned curSize = selectorInfo.size;
  3770. node_operator op = thisKey.getOperator();
  3771. BuildCtx subctx(ctx);
  3772. BuildCtx * appendCtx = &ctx;
  3773. StringBuffer createMonitorText;
  3774. switch (op)
  3775. {
  3776. case no_in:
  3777. case no_notin:
  3778. {
  3779. if (!targetSet)
  3780. targetSet = buildState.getSetName();
  3781. buildKeySegmentInExpr(buildState, selectorInfo, ctx, targetSet, thisKey, filterKind);
  3782. break;
  3783. }
  3784. case no_if:
  3785. {
  3786. MonitorFilterKind childFilter = targetSet ? NoMonitorFilter : filterKind;
  3787. IHqlStmt * ifStmt = translator.buildFilterViaExpr(subctx, thisKey.queryChild(0));
  3788. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, *thisKey.queryChild(1), childFilter);
  3789. subctx.selectElse(ifStmt);
  3790. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, *thisKey.queryChild(2), childFilter);
  3791. break;
  3792. }
  3793. case no_and:
  3794. {
  3795. HqlExprArray matches;
  3796. OwnedHqlExpr invariant = unwindConjunction(matches, &thisKey);
  3797. unsigned numMatches = matches.ordinality();
  3798. if (!targetSet && numMatches > 1)
  3799. targetSet = buildState.getSetName();
  3800. IHqlStmt * ifStmt = NULL;
  3801. if (invariant)
  3802. {
  3803. ifStmt = translator.buildFilterViaExpr(subctx, invariant);
  3804. if (filterKind == MonitorFilterSkipEmpty)
  3805. ctx.set(subctx);
  3806. }
  3807. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, matches.item(0), NoMonitorFilter);
  3808. for (unsigned i=1; i< numMatches; i++)
  3809. {
  3810. IHqlExpression & cur = matches.item(i);
  3811. const char * curTarget = buildState.getSetName();
  3812. BuildCtx childctx(subctx);
  3813. buildKeySegmentExpr(buildState, selectorInfo, childctx, curTarget, cur, MonitorFilterSkipAll);
  3814. childctx.addQuotedF("%s.setown(rtlIntersectSet(%s,%s));", targetSet, targetSet, curTarget);
  3815. buildState.popSetName();
  3816. }
  3817. if (invariant && (filterKind != MonitorFilterSkipEmpty))
  3818. {
  3819. subctx.selectElse(ifStmt);
  3820. if (targetSet)
  3821. createStringSet(subctx, targetSet, curSize, selectorInfo.selector->queryType());
  3822. else
  3823. buildEmptyKeySegment(buildState, subctx, selectorInfo);
  3824. }
  3825. break;
  3826. }
  3827. case no_or:
  3828. {
  3829. HqlExprArray matches;
  3830. OwnedHqlExpr invariant = unwindConjunction(matches, &thisKey);
  3831. unsigned numMatches = matches.ordinality();
  3832. if (invariant)
  3833. {
  3834. if (filterKind == MonitorFilterSkipAll)
  3835. {
  3836. OwnedHqlExpr test = getInverse(invariant);
  3837. translator.buildFilter(subctx, test);
  3838. ctx.set(subctx);
  3839. }
  3840. else
  3841. {
  3842. IHqlStmt * ifStmt = translator.buildFilterViaExpr(subctx, invariant);
  3843. if (targetSet)
  3844. {
  3845. createStringSet(subctx, targetSet, curSize, selectorInfo.selector->queryType());
  3846. OwnedHqlExpr targetVar = createVariable(targetSet, makeVoidType());
  3847. callAddAll(subctx, targetVar);
  3848. }
  3849. else
  3850. buildWildKeySegment(buildState, subctx, selectorInfo);
  3851. subctx.selectElse(ifStmt);
  3852. }
  3853. }
  3854. appendCtx = &subctx;
  3855. if (!targetSet && numMatches > 1)
  3856. targetSet = buildState.getSetName();
  3857. buildKeySegmentExpr(buildState, selectorInfo, subctx, targetSet, matches.item(0), NoMonitorFilter);
  3858. for (unsigned i=1; i < numMatches; i++)
  3859. {
  3860. IHqlExpression & cur = matches.item(i);
  3861. const char * curTarget = buildState.getSetName();
  3862. BuildCtx childctx(subctx);
  3863. buildKeySegmentExpr(buildState, selectorInfo, childctx, curTarget, cur, MonitorFilterSkipEmpty);
  3864. childctx.addQuotedF("%s.setown(rtlUnionSet(%s, %s));", targetSet, targetSet, curTarget);
  3865. buildState.popSetName();
  3866. }
  3867. break;
  3868. }
  3869. case no_eq:
  3870. {
  3871. if (!targetSet)
  3872. {
  3873. if (buildSingleKeyMonitor(createMonitorText, selectorInfo, subctx, thisKey))
  3874. break;
  3875. targetSet = buildState.getSetName();
  3876. }
  3877. buildKeySegmentCompareExpr(buildState, selectorInfo, ctx, targetSet, thisKey);
  3878. break;
  3879. }
  3880. default:
  3881. {
  3882. if (!targetSet)
  3883. targetSet = buildState.getSetName();
  3884. buildKeySegmentCompareExpr(buildState, selectorInfo, ctx, targetSet, thisKey);
  3885. break;
  3886. }
  3887. }
  3888. if (targetSet && !requiredSet)
  3889. {
  3890. unsigned offset = (selectorInfo.isComputed || selectorInfo.mapOffset) ? 0 : selectorInfo.offset;
  3891. createMonitorText.appendf("createKeySegmentMonitor(%s, %s.getClear(), %u, %u)",
  3892. boolToText(selectorInfo.keyedKind != KeyedYes), targetSet, offset, selectorInfo.size);
  3893. buildState.popSetName();
  3894. }
  3895. if (createMonitorText.length())
  3896. {
  3897. if (selectorInfo.expandNeeded || selectorInfo.isComputed)
  3898. generateFormatWrapping(createMonitorText, selectorInfo.selector, selectorInfo.expandedSelector, buildState.curOffset);
  3899. else if (selectorInfo.mapOffset)
  3900. generateOffsetWrapping(createMonitorText, selectorInfo.selector, buildState.curOffset);
  3901. appendCtx->addQuotedF("%s->append(%s);", buildState.listName, createMonitorText.str());
  3902. }
  3903. }
  3904. IHqlExpression * MonitorExtractor::getMonitorValueAddress(BuildCtx & ctx, IHqlExpression * _value)
  3905. {
  3906. LinkedHqlExpr value = _value;
  3907. CHqlBoundExpr bound;
  3908. ITypeInfo * type = value->queryType();
  3909. switch (type->getTypeCode())
  3910. {
  3911. case type_varstring: case type_varunicode:
  3912. {
  3913. assertex(type->getSize() != UNKNOWN_LENGTH);
  3914. CHqlBoundTarget tempTarget;
  3915. translator.createTempFor(ctx, type, tempTarget, typemod_none, FormatNatural);
  3916. //clear the variable.
  3917. HqlExprArray args;
  3918. args.append(*getPointer(tempTarget.expr));
  3919. args.append(*getZero());
  3920. args.append(*getSizetConstant(type->getSize()));
  3921. OwnedHqlExpr call = translator.bindTranslatedFunctionCall(memsetId, args);
  3922. ctx.addExpr(call);
  3923. //then assign over the top
  3924. translator.buildExprAssign(ctx, tempTarget, value);
  3925. bound.setFromTarget(tempTarget);
  3926. break;
  3927. }
  3928. default:
  3929. translator.buildExpr(ctx, value, bound);
  3930. translator.ensureHasAddress(ctx, bound);
  3931. break;
  3932. }
  3933. return getPointer(bound.expr);
  3934. }
  3935. /*
  3936. interface IKeySegmentOffsetTranslator : public IInterface
  3937. {
  3938. virtual const void * getSegmentBase(const void * row) const = 0;
  3939. };
  3940. interface IKeySegmentFormatTranslator : public IInterface
  3941. {
  3942. virtual void extractField(void * target, const void * row) const = 0;
  3943. };
  3944. */
  3945. void MonitorExtractor::generateOffsetWrapping(StringBuffer & createMonitorText, IHqlExpression * selector, unsigned curOffset)
  3946. {
  3947. //MORE: Common up classes if same field filtered more than once.
  3948. OwnedHqlExpr key = createAttribute(wrapperAtom, LINK(selector));
  3949. BuildCtx declarectx(*translator.code, declareAtom);
  3950. StringBuffer s, suffix, instanceName, className, factoryName;
  3951. unique_id_t id = translator.getUniqueId();
  3952. appendUniqueId(className.append("c"), id);
  3953. appendUniqueId(instanceName.append("i"), id);
  3954. appendUniqueId(factoryName.append("f"), id);
  3955. declarectx.setPriority(SegMonitorPrio);
  3956. BuildCtx classctx(declarectx);
  3957. //MORE: Use a base class for implementing this to save Link()/Release()
  3958. s.clear().append("struct ").append(className).append(" : public RtlCInterface, public IKeySegmentOffsetTranslator");
  3959. suffix.append(instanceName).append(";");
  3960. classctx.addQuotedCompound(s, suffix);
  3961. classctx.addQuotedLiteral("virtual void Link() const { RtlCInterface::Link(); }");
  3962. classctx.addQuotedLiteral("virtual bool Release() const { return RtlCInterface::Release(); }");
  3963. classctx.addQuoted(s.clear().append("virtual const char * queryFactoryName() const { return \"").append(factoryName).append("\"; }"));
  3964. classctx.addQuotedCompoundLiteral("virtual const void * getSegmentBase(const void * _row) const");
  3965. classctx.addQuotedLiteral("const byte * row = (const byte *)_row;");
  3966. classctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  3967. translator.bindTableCursor(classctx, tableExpr, "row");
  3968. CHqlBoundExpr bound;
  3969. Owned<IReferenceSelector> ds = translator.buildReference(classctx, selector);
  3970. ds->buildAddress(classctx, bound);
  3971. classctx.addReturn(bound.expr);
  3972. declarectx.addQuoted(s.clear().append("IKeySegmentOffsetTranslator * ").append(factoryName).append("() { return new ").append(className).append("; }"));
  3973. if (translator.options.spanMultipleCpp)
  3974. {
  3975. s.clear().append("extern IKeySegmentOffsetTranslator * ").append(factoryName).append("();");
  3976. BuildCtx protoctx(*translator.code, mainprototypesAtom);
  3977. protoctx.addQuoted(s);
  3978. }
  3979. //TAKE NOTE: Child activities are only colocal if whole graph is colocal, or targeting roxie and activity is colocal.
  3980. //Email Richard if any objections to changing parameters so byte * not void *. Would save quite a lot of generated boilerplate code.
  3981. s.clear().append("createVarOffsetKeySegmentMonitor(").append(createMonitorText).append(",").append(curOffset).append(",").append(factoryName).append("())");
  3982. createMonitorText.swapWith(s);
  3983. }
  3984. void MonitorExtractor::generateFormatWrapping(StringBuffer & createMonitorText, IHqlExpression * selector, IHqlExpression * expandedSelector, unsigned curOffset)
  3985. {
  3986. BuildCtx declarectx(*translator.code, declareAtom);
  3987. StringBuffer s, suffix, instanceName, className, factoryName;
  3988. unique_id_t id = translator.getUniqueId();
  3989. appendUniqueId(className.append("c"), id);
  3990. appendUniqueId(instanceName.append("i"), id);
  3991. appendUniqueId(factoryName.append("f"), id);
  3992. declarectx.setNextPriority(SegMonitorPrio);
  3993. BuildCtx classctx(declarectx);
  3994. //MORE: Use a base class for implementing this to save Link()/Release()
  3995. s.clear().append("struct ").append(className).append(" : public RtlCInterface, public IKeySegmentFormatTranslator");
  3996. suffix.append(instanceName).append(";");
  3997. classctx.addQuotedCompound(s, suffix);
  3998. classctx.addQuotedLiteral("virtual void Link() const { RtlCInterface::Link(); }");
  3999. classctx.addQuotedLiteral("virtual bool Release() const { return RtlCInterface::Release(); }");
  4000. classctx.addQuoted(s.clear().append("virtual const char * queryFactoryName() const { return \"").append(factoryName).append("\"; }"));
  4001. classctx.addQuoted(s.clear().append("virtual unsigned queryHashCode() const { return ").append(getExpressionCRC(selector)).append("; }"));
  4002. classctx.addQuotedCompoundLiteral("virtual void extractField(void * _target, const void * _row) const");
  4003. classctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4004. classctx.addQuotedLiteral("const byte * row = (const byte *)_row;");
  4005. classctx.addQuotedLiteral("byte * target = (byte *)_target;");
  4006. OwnedHqlExpr castValue = ensureExprType(selector, expandedSelector->queryType());
  4007. LinkedHqlExpr targetField = expandedSelector->queryChild(1);
  4008. OwnedHqlExpr simpleRecord = createRecord(targetField);
  4009. OwnedHqlExpr targetDataset = createDataset(no_anon, LINK(simpleRecord));
  4010. OwnedHqlExpr target = createSelectExpr(LINK(targetDataset), LINK(targetField));
  4011. translator.bindTableCursor(classctx, tableExpr, "row");
  4012. translator.bindTableCursor(classctx, targetDataset, "target");
  4013. translator.buildAssign(classctx, target, castValue);
  4014. declarectx.setNextPriority(SegMonitorPrio);
  4015. declarectx.addQuoted(s.clear().append("IKeySegmentFormatTranslator * ").append(factoryName).append("() { return new ").append(className).append("; }"));
  4016. if (translator.spanMultipleCppFiles())
  4017. {
  4018. s.clear().append("extern IKeySegmentFormatTranslator * ").append(factoryName).append("();");
  4019. BuildCtx protoctx(*translator.code, mainprototypesAtom);
  4020. protoctx.addQuoted(s);
  4021. }
  4022. //Now generate the key segment monitor...
  4023. s.clear().append("createTranslatedKeySegmentMonitor(").append(createMonitorText).append(",").append(curOffset).append(",").append(factoryName).append("())");
  4024. createMonitorText.swapWith(s);
  4025. }
  4026. bool MonitorExtractor::buildSingleKeyMonitor(StringBuffer & createMonitorText, KeySelectorInfo & selectorInfo, BuildCtx & ctx, IHqlExpression & thisKey)
  4027. {
  4028. BuildCtx subctx(ctx);
  4029. OwnedHqlExpr compare, normalized;
  4030. StringBuffer funcName;
  4031. extractCompareInformation(subctx, &thisKey, compare, normalized, selectorInfo.expandedSelector, selectorInfo.isComputed);
  4032. if (compare)
  4033. return false;
  4034. ITypeInfo * type = selectorInfo.expandedSelector->queryType();
  4035. type_t tc = type->getTypeCode();
  4036. if ((tc == type_int) || (tc == type_swapint))
  4037. {
  4038. if (isLittleEndian(type))
  4039. {
  4040. if (type->isSigned())
  4041. funcName.append("createSingleLittleSignedKeySegmentMonitor");
  4042. else if (type->getSize() != 1)
  4043. funcName.append("createSingleLittleKeySegmentMonitor");
  4044. }
  4045. else
  4046. {
  4047. if (type->isSigned())
  4048. funcName.append("createSingleBigSignedKeySegmentMonitor");
  4049. else
  4050. funcName.append("createSingleKeySegmentMonitor");
  4051. }
  4052. }
  4053. if (!funcName.length())
  4054. funcName.append("createSingleKeySegmentMonitor");
  4055. OwnedHqlExpr address = getMonitorValueAddress(subctx, normalized);
  4056. StringBuffer addrText;
  4057. translator.generateExprCpp(addrText, address);
  4058. unsigned offset = (selectorInfo.isComputed || selectorInfo.mapOffset) ? 0 : selectorInfo.offset;
  4059. createMonitorText.append(funcName)
  4060. .appendf("(%s, %u, %u, %s)",
  4061. boolToText(selectorInfo.keyedKind != KeyedYes), offset, selectorInfo.size, addrText.str());
  4062. return true;
  4063. }
  4064. KeyedKind getKeyedKind(HqlCppTranslator & translator, KeyConditionArray & matches)
  4065. {
  4066. KeyedKind keyedKind = KeyedNo;
  4067. ForEachItemIn(i, matches)
  4068. {
  4069. KeyCondition & cur = matches.item(i);
  4070. if (cur.keyedKind != keyedKind)
  4071. {
  4072. if (keyedKind == KeyedNo)
  4073. keyedKind = cur.keyedKind;
  4074. else
  4075. translator.throwError1(HQLERR_InconsistentKeyedOpt, str(cur.selector->queryChild(1)->queryName()));
  4076. }
  4077. }
  4078. return keyedKind;
  4079. }
  4080. void MonitorExtractor::buildEmptyKeySegment(BuildMonitorState & buildState, BuildCtx & ctx, KeySelectorInfo & selectorInfo)
  4081. {
  4082. StringBuffer s;
  4083. ctx.addQuoted(s.appendf("%s->append(createEmptyKeySegmentMonitor(%s, %u, %u));", buildState.listName, boolToText(selectorInfo.keyedKind != KeyedYes), selectorInfo.offset, selectorInfo.size));
  4084. }
  4085. void MonitorExtractor::buildWildKeySegment(BuildMonitorState & buildState, BuildCtx & ctx, unsigned offset, unsigned size)
  4086. {
  4087. StringBuffer s;
  4088. ctx.addQuoted(s.appendf("%s->append(createWildKeySegmentMonitor(%u, %u));", buildState.listName, offset, size));
  4089. }
  4090. void MonitorExtractor::buildWildKeySegment(BuildMonitorState & buildState, BuildCtx & ctx, KeySelectorInfo & selectorInfo)
  4091. {
  4092. buildWildKeySegment(buildState, ctx, selectorInfo.offset, selectorInfo.size);
  4093. }
  4094. void MonitorExtractor::buildKeySegment(BuildMonitorState & buildState, BuildCtx & ctx, unsigned whichField, unsigned curSize)
  4095. {
  4096. IHqlExpression * selector = &keyableSelects.item(whichField);
  4097. IHqlExpression * expandedSelector = &expandedSelects.item(whichField);
  4098. IHqlExpression * field = selector->queryChild(1);
  4099. KeyConditionArray matches;
  4100. bool isImplicit = true;
  4101. bool prevWildWasKeyed = buildState.wildWasKeyed;
  4102. buildState.wildWasKeyed = false;
  4103. ForEachItemIn(cond, keyed.conditions)
  4104. {
  4105. KeyCondition & cur = keyed.conditions.item(cond);
  4106. if (cur.selector == selector)
  4107. {
  4108. cur.generated = true;
  4109. if (cur.isWild)
  4110. {
  4111. isImplicit = false;
  4112. if (cur.wasKeyed)
  4113. buildState.wildWasKeyed = true;
  4114. else if (buildState.implicitWildField && !ignoreUnkeyed)
  4115. {
  4116. StringBuffer s, keyname;
  4117. translator.throwError3(HQLERR_WildFollowsGap, getExprECL(field, s).str(), str(buildState.implicitWildField->queryChild(1)->queryName()), queryKeyName(keyname));
  4118. }
  4119. }
  4120. else
  4121. {
  4122. matches.append(OLINK(cur));
  4123. if (buildState.implicitWildField && !ignoreUnkeyed)
  4124. {
  4125. StringBuffer s,keyname;
  4126. if (cur.isKeyed())
  4127. translator.throwError3(HQLERR_KeyedFollowsGap, getExprECL(field, s).str(), str(buildState.implicitWildField->queryChild(1)->queryName()), queryKeyName(keyname));
  4128. else if (!buildState.doneImplicitWarning)
  4129. {
  4130. translator.WARNING3(CategoryEfficiency, HQLWRN_KeyedFollowsGap, getExprECL(field, s).str(), str(buildState.implicitWildField->queryChild(1)->queryName()), queryKeyName(keyname));
  4131. buildState.doneImplicitWarning = true;
  4132. }
  4133. }
  4134. }
  4135. }
  4136. }
  4137. if (buildState.wildWasKeyed && (matches.ordinality() == 0))
  4138. {
  4139. StringBuffer keyname;
  4140. translator.WARNING2(CategoryFolding, HQLWRN_FoldRemoveKeyed, str(field->queryName()), queryKeyName(keyname));
  4141. }
  4142. StringBuffer s;
  4143. KeyedKind keyedKind = getKeyedKind(translator, matches);
  4144. KeySelectorInfo selectorInfo(keyedKind, selector, expandedSelector, buildState.curOffset, curSize, (whichField >= firstOffsetField), false);
  4145. bool ignoreKeyedExtend = false;
  4146. if ((keyedKind == KeyedExtend) && buildState.wildPending() && !ignoreUnkeyed)
  4147. {
  4148. if (keyedKind == KeyedExtend)
  4149. {
  4150. if (prevWildWasKeyed)
  4151. buildState.wildWasKeyed = true;
  4152. else
  4153. {
  4154. StringBuffer keyname;
  4155. translator.WARNING2(CategoryEfficiency, HQLERR_OptKeyedFollowsWild, getExprECL(field, s).str(), queryKeyName(keyname));
  4156. }
  4157. }
  4158. //previous condition folded so always true, so keyed,opt will always be a wildcard.
  4159. if (!allowDynamicFormatChange)
  4160. ignoreKeyedExtend = true;
  4161. isImplicit = false;
  4162. }
  4163. if (matches.ordinality() && !ignoreKeyedExtend)
  4164. {
  4165. if (buildState.wildPending() && !ignoreUnkeyed)
  4166. {
  4167. buildWildKeySegment(buildState, ctx, buildState.wildOffset, buildState.curOffset-buildState.wildOffset);
  4168. buildState.clearWild();
  4169. }
  4170. HqlExprArray args;
  4171. ForEachItemIn(i, matches)
  4172. {
  4173. KeyCondition & cur = matches.item(i);
  4174. args.append(*LINK(cur.expr));
  4175. }
  4176. OwnedHqlExpr fullExpr = createBalanced(no_and, queryBoolType(), args);
  4177. BuildCtx subctx(ctx);
  4178. buildKeySegmentExpr(buildState, selectorInfo, subctx, NULL, *fullExpr, ignoreUnkeyed ? MonitorFilterSkipAll : NoMonitorFilter);
  4179. }
  4180. else
  4181. {
  4182. if (isImplicit)
  4183. {
  4184. buildState.implicitWildField.set(selector);
  4185. buildState.doneImplicitWarning = false;
  4186. }
  4187. if (buildState.wildPending() && noMergeSelects.contains(*selector))
  4188. {
  4189. buildWildKeySegment(buildState, ctx, buildState.wildOffset, buildState.curOffset-buildState.wildOffset);
  4190. buildState.clearWild();
  4191. }
  4192. if (!buildState.wildPending())
  4193. buildState.wildOffset = buildState.curOffset;
  4194. }
  4195. buildState.curOffset += selectorInfo.size;
  4196. }
  4197. void MonitorExtractor::buildArbitaryKeySegment(BuildMonitorState & buildState, BuildCtx & ctx, unsigned curSize, IHqlExpression * condition)
  4198. {
  4199. IHqlExpression * left = condition->queryChild(0);
  4200. node_operator op = condition->getOperator();
  4201. StringBuffer createMonitorText;
  4202. OwnedHqlExpr field = createField(unknownId, getExpandedFieldType(left->queryType(), NULL), NULL);
  4203. OwnedHqlExpr pseudoSelector = createSelectExpr(getActiveTableSelector(), LINK(field));
  4204. KeySelectorInfo selectorInfo(KeyedExtend, left, pseudoSelector, buildState.curOffset, curSize, false, true);
  4205. BuildCtx subctx(ctx);
  4206. buildKeySegmentExpr(buildState, selectorInfo, subctx, NULL, *condition, MonitorFilterSkipAll);
  4207. }
  4208. void MonitorExtractor::spotSegmentCSE(BuildCtx & ctx)
  4209. {
  4210. //This could make things much better, but needs some thought
  4211. HqlExprArray conditions;
  4212. ForEachItemIn(cond, keyed.conditions)
  4213. {
  4214. KeyCondition & cur = keyed.conditions.item(cond);
  4215. if (cur.expr)
  4216. conditions.append(*LINK(cur.expr));
  4217. }
  4218. HqlExprArray associated;
  4219. IHqlExpression * selector = tableExpr->queryNormalizedSelector();
  4220. translator.traceExpressions("before seg spot", conditions);
  4221. spotScalarCSE(conditions, associated, NULL, selector, translator.queryOptions().spotCseInIfDatasetConditions);
  4222. translator.traceExpressions("after seg spot", conditions);
  4223. unsigned curCond = 0;
  4224. ForEachItemIn(i, conditions)
  4225. {
  4226. IHqlExpression * cur = &conditions.item(i);
  4227. switch (cur->getOperator())
  4228. {
  4229. case no_alias:
  4230. translator.buildStmt(ctx, cur);
  4231. break;
  4232. case no_alias_scope:
  4233. translator.expandAliasScope(ctx, cur);
  4234. cur = cur->queryChild(0);
  4235. //fallthrough
  4236. default:
  4237. for (;;)
  4238. {
  4239. if (!keyed.conditions.isItem(curCond))
  4240. throwUnexpected();
  4241. KeyCondition & keyCond = keyed.conditions.item(curCond++);
  4242. if (keyCond.expr)
  4243. {
  4244. keyCond.expr.set(cur);
  4245. break;
  4246. }
  4247. }
  4248. break;
  4249. }
  4250. }
  4251. for (;;)
  4252. {
  4253. if (!keyed.conditions.isItem(curCond))
  4254. break;
  4255. KeyCondition & keyCond = keyed.conditions.item(curCond++);
  4256. assertex(!keyCond.expr);
  4257. }
  4258. }
  4259. void MonitorExtractor::buildSegments(BuildCtx & ctx, const char * listName, bool _ignoreUnkeyed)
  4260. {
  4261. translator.useInclude("rtlkey.hpp");
  4262. ignoreUnkeyed = _ignoreUnkeyed;
  4263. if (translator.queryOptions().spotCSE)
  4264. spotSegmentCSE(ctx);
  4265. BuildMonitorState buildState(ctx, listName);
  4266. ForEachItemIn(idx, keyableSelects)
  4267. {
  4268. IHqlExpression * selector = &keyableSelects.item(idx);
  4269. IHqlExpression * expandedSelector = &expandedSelects.item(idx);
  4270. IHqlExpression * field = selector->queryChild(1);
  4271. unsigned curSize = expandedSelector->queryType()->getSize();
  4272. assertex(curSize != UNKNOWN_LENGTH);
  4273. //MORE: Should also allow nested record structures, and allow keying on first elements.
  4274. // and field->queryType()->getSize() doesn't work for alien datatypes etc.
  4275. if(!field->hasAttribute(virtualAtom))
  4276. {
  4277. if (mergedSizes.isItem(idx))
  4278. curSize = mergedSizes.item(idx);
  4279. if (curSize)
  4280. buildKeySegment(buildState, ctx, idx, curSize);
  4281. else
  4282. {
  4283. ForEachItemIn(cond, keyed.conditions)
  4284. {
  4285. KeyCondition & cur = keyed.conditions.item(cond);
  4286. if (cur.selector == selector)
  4287. cur.generated = true;
  4288. }
  4289. }
  4290. }
  4291. }
  4292. if (buildState.wildPending() && !ignoreUnkeyed)
  4293. buildWildKeySegment(buildState, ctx, buildState.wildOffset, buildState.curOffset-buildState.wildOffset);
  4294. //These really don't work very sensibly - we would need an offset that was constant, possibly based on the crc of the expression.
  4295. //I suspect they need a complete rethink.
  4296. ForEachItemIn(i, keyed.conditions)
  4297. {
  4298. KeyCondition & cur = keyed.conditions.item(i);
  4299. if (cur.selector->isAttribute() && cur.selector->queryName() == _translated_Atom)
  4300. {
  4301. BuildCtx subctx(ctx);
  4302. IHqlExpression * curExpr = cur.expr;
  4303. unsigned curSize = curExpr->queryChild(0)->queryType()->getSize();
  4304. buildArbitaryKeySegment(buildState, subctx, curSize, curExpr);
  4305. buildState.curOffset += curSize;
  4306. cur.generated = true;
  4307. }
  4308. }
  4309. //check that all keyed entries have been matched
  4310. ForEachItemIn(cond, keyed.conditions)
  4311. {
  4312. KeyCondition & cur = keyed.conditions.item(cond);
  4313. if (!cur.generated)
  4314. translator.throwError(HQLERR_OnlyKeyFixedField);
  4315. }
  4316. }
  4317. static UniqueSequenceCounter translatedSequence;
  4318. KeyCondition * MonitorExtractor::createTranslatedCondition(IHqlExpression * cond, KeyedKind keyedKind)
  4319. {
  4320. OwnedHqlExpr seq = createSequence(no_attr, makeNullType(), _translated_Atom, translatedSequence.next());
  4321. return new KeyCondition(seq, cond, keyedKind);
  4322. }
  4323. bool MonitorExtractor::isKeySelect(IHqlExpression * select)
  4324. {
  4325. return (keyableSelects.find(*select) != NotFound);
  4326. }
  4327. bool MonitorExtractor::isEqualityFilter(IHqlExpression * search)
  4328. {
  4329. bool matched = false;
  4330. ForEachItemIn(cond, keyed.conditions)
  4331. {
  4332. KeyCondition & cur = keyed.conditions.item(cond);
  4333. if (cur.selector == search)
  4334. {
  4335. if (!cur.isWild)
  4336. {
  4337. if (matched)
  4338. return false;
  4339. matched = true;
  4340. IHqlExpression * matchExpr = cur.expr;
  4341. if (matchExpr->getOperator() != no_eq)
  4342. return false;
  4343. }
  4344. }
  4345. }
  4346. return matched;
  4347. }
  4348. bool MonitorExtractor::isEqualityFilterBefore(IHqlExpression * select)
  4349. {
  4350. ForEachItemIn(i, keyableSelects)
  4351. {
  4352. IHqlExpression & cur = keyableSelects.item(i);
  4353. if (select == &cur)
  4354. return true;
  4355. if (!isEqualityFilter(&cur))
  4356. return false;
  4357. }
  4358. throwUnexpected();
  4359. }
  4360. bool MonitorExtractor::isPrevSelectKeyed(IHqlExpression * select)
  4361. {
  4362. unsigned match = keyableSelects.find(*select);
  4363. assertex(match != NotFound);
  4364. if (match == 0)
  4365. return true;
  4366. IHqlExpression * prev = &keyableSelects.item(match-1);
  4367. ForEachItemIn(i, keyed.conditions)
  4368. {
  4369. KeyCondition & cur = keyed.conditions.item(i);
  4370. if (cur.selector == prev)
  4371. {
  4372. if (!cur.isWild && cur.isKeyed())
  4373. return true;
  4374. if (cur.wasKeyed)
  4375. return true;
  4376. }
  4377. }
  4378. return false;
  4379. }
  4380. bool MonitorExtractor::okToKey(IHqlExpression * select, KeyedKind keyedKind)
  4381. {
  4382. if (keyedKind == KeyedYes)
  4383. return true;
  4384. ForEachItemIn(i, keyed.conditions)
  4385. {
  4386. KeyCondition & cur = keyed.conditions.item(i);
  4387. if (cur.selector == select && cur.isWild)
  4388. return false;
  4389. }
  4390. return true;
  4391. }
  4392. bool MonitorExtractor::isIndexInvariant(IHqlExpression * expr, bool includeRoot)
  4393. {
  4394. if (containsAssertKeyed(expr))
  4395. return false;
  4396. HqlExprCopyArray scopeUsed;
  4397. expr->gatherTablesUsed(NULL, &scopeUsed);
  4398. IHqlExpression * search = tableExpr->queryNormalizedSelector();
  4399. ForEachItemIn(i, scopeUsed)
  4400. {
  4401. IHqlExpression * cur = &scopeUsed.item(i);
  4402. for (;;)
  4403. {
  4404. if (cur == search)
  4405. return false;
  4406. if (includeRoot && (queryRoot(cur) == search))
  4407. return false;
  4408. IHqlExpression * parent = queryNextMultiLevelDataset(cur, true);
  4409. if (!parent)
  4410. break;
  4411. cur = parent;
  4412. }
  4413. }
  4414. return true;
  4415. }
  4416. IHqlExpression * MonitorExtractor::castToFieldAndBack(IHqlExpression * left, IHqlExpression * right)
  4417. {
  4418. node_operator op = left->getOperator();
  4419. switch (op)
  4420. {
  4421. case no_cast:
  4422. case no_implicitcast:
  4423. {
  4424. IHqlExpression * uncast = left->queryChild(0);
  4425. ITypeInfo * castType = right->queryType();
  4426. ITypeInfo * uncastType = uncast->queryType();
  4427. OwnedHqlExpr castRight = ensureExprType(right, uncastType);
  4428. OwnedHqlExpr base = castToFieldAndBack(uncast, castRight);
  4429. //If this cast doesn't lose any information and child didn't change then don't bother
  4430. //casting back and forwards.
  4431. if ((base == castRight) && !castLosesInformation(uncastType, castType))
  4432. return LINK(right);
  4433. return ensureExprType(base, castType);
  4434. }
  4435. case no_select:
  4436. {
  4437. ITypeInfo * leftType = left->queryType();
  4438. ITypeInfo * rightType = right->queryType();
  4439. if (leftType == rightType || !castLosesInformation(leftType, rightType))
  4440. return LINK(right);
  4441. return ensureExprType(right, leftType);
  4442. }
  4443. case no_substring:
  4444. case no_add:
  4445. case no_sub:
  4446. return castToFieldAndBack(left->queryChild(0), right);
  4447. default:
  4448. UNIMPLEMENTED;
  4449. }
  4450. }
  4451. IHqlExpression * MonitorExtractor::invertTransforms(IHqlExpression * left, IHqlExpression * right)
  4452. {
  4453. node_operator op = left->getOperator();
  4454. switch (op)
  4455. {
  4456. case no_cast:
  4457. case no_implicitcast:
  4458. {
  4459. assertex(right->queryType()->getTypeCode() != type_set);
  4460. IHqlExpression * uncast = left->queryChild(0);
  4461. ITypeInfo * uncastType = uncast->queryType();
  4462. OwnedHqlExpr castRight = ensureExprType(right, uncastType);
  4463. return invertTransforms(uncast, castRight);
  4464. }
  4465. case no_select:
  4466. {
  4467. assertex(isKeySelect(left));
  4468. ITypeInfo * leftType = left->queryType();
  4469. ITypeInfo * rightType = right->queryType();
  4470. if (leftType == rightType || !castLosesInformation(leftType, rightType))
  4471. return LINK(right);
  4472. return ensureExprType(right, leftType);
  4473. }
  4474. case no_add:
  4475. case no_sub:
  4476. {
  4477. assertex(right->getOperator() != no_list);
  4478. OwnedHqlExpr adjusted = createValue(op == no_sub ? no_add : no_sub, right->getType(), LINK(right), LINK(left->queryChild(1)));
  4479. return invertTransforms(left->queryChild(0), adjusted);
  4480. }
  4481. case no_substring:
  4482. {
  4483. assertex(right->getOperator() != no_list);
  4484. return invertTransforms(left->queryChild(0), right);
  4485. }
  4486. default:
  4487. UNIMPLEMENTED;
  4488. }
  4489. }
  4490. IHqlExpression * MonitorExtractor::queryKeyableSelector(IHqlExpression * expr)
  4491. {
  4492. switch (expr->getOperator())
  4493. {
  4494. case no_cast:
  4495. case no_implicitcast:
  4496. case no_add:
  4497. case no_sub:
  4498. return queryKeyableSelector(expr->queryChild(0));
  4499. case no_select:
  4500. if (isKeySelect(expr))
  4501. return expr;
  4502. return NULL;
  4503. }
  4504. return NULL;
  4505. }
  4506. IHqlExpression * MonitorExtractor::isKeyableFilter(IHqlExpression * left, IHqlExpression * right, bool & duplicate, node_operator compareOp, KeyFailureInfo & reason, KeyedKind keyedKind)
  4507. {
  4508. node_operator op = left->getOperator();
  4509. switch (op)
  4510. {
  4511. case no_cast:
  4512. case no_implicitcast:
  4513. {
  4514. IHqlExpression * uncast = left->queryChild(0);
  4515. ITypeInfo * castType = left->queryType();
  4516. ITypeInfo * uncastType = uncast->queryType();
  4517. //(ty)x = y. E.g., (int1)string2field = int1value
  4518. //if more than one value of x[uncastType] corresponds to a single value in y[castType] then we can't sensibly create
  4519. //the key segment monitor. Because we will get false negatives. If it is an inverse then duplicate (see below)
  4520. bool canRemoveCast = true;
  4521. if (castLosesInformation(castType, uncastType))
  4522. {
  4523. if ((compareOp != no_ne) && (compareOp != no_notin))
  4524. canRemoveCast = false;
  4525. duplicate = true;
  4526. }
  4527. //if more than one value of y corresponds to a single value of x then need to duplicate the test condition.
  4528. //or pretest whether (ty)(tx)y == y.
  4529. //if (castLosesInformation(uncastType, castType))
  4530. //Now taken care of when the segment monitors are created
  4531. //If the comparison is non equality and the cast changes the collation sequence then you can't remove it.
  4532. switch (compareOp)
  4533. {
  4534. case no_eq:
  4535. case no_ne:
  4536. case no_in:
  4537. case no_notin:
  4538. break;
  4539. default:
  4540. if (!preservesOrder(castType, uncastType))
  4541. canRemoveCast = false;
  4542. break;
  4543. }
  4544. Linked<ITypeInfo> newType = uncastType;
  4545. if (right->queryType()->getTypeCode() == type_set)
  4546. newType.setown(makeSetType(newType.getLink()));
  4547. OwnedHqlExpr castRight = ensureExprType(right, newType);
  4548. IHqlExpression * ret = isKeyableFilter(uncast, castRight, duplicate, compareOp, reason, keyedKind);
  4549. if (canRemoveCast || !ret)
  4550. return ret;
  4551. reason.set(KFRcast, ret->queryChild(1));
  4552. return NULL;
  4553. }
  4554. case no_select:
  4555. if (isKeySelect(left) && okToKey(left, keyedKind))
  4556. {
  4557. if (isIndexInvariant(right, false))
  4558. return left;
  4559. reason.set(KFRtoocomplex, left);
  4560. }
  4561. else
  4562. reason.set(KFRnokey);
  4563. return NULL;
  4564. case no_substring:
  4565. {
  4566. IHqlExpression * range = left->queryChild(1);
  4567. if (range->getOperator() == no_rangeto)
  4568. {
  4569. IValue *end = range->queryChild(0)->queryValue();
  4570. if (!end)
  4571. break;
  4572. return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
  4573. }
  4574. else if (range->getOperator() == no_range)
  4575. {
  4576. IValue *start = range->queryChild(0)->queryValue();
  4577. IValue *end = range->queryChild(1)->queryValue();
  4578. if (!start || !end || start->getIntValue() != 1)
  4579. break;
  4580. return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
  4581. }
  4582. reason.set(KFRtoocomplex, right);
  4583. return NULL;
  4584. }
  4585. case no_add:
  4586. case no_sub:
  4587. if (isIndexInvariant(left->queryChild(1), false))
  4588. return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
  4589. reason.set(KFRtoocomplex, left);
  4590. return NULL;
  4591. }
  4592. reason.set(KFRnokey);
  4593. return NULL;
  4594. }
  4595. static IHqlExpression * getCompareValue(ITypeInfo * fieldType, unsigned subStringLen, IValue * value, int whichBoundary)
  4596. {
  4597. type_t ftc = fieldType->getTypeCode();
  4598. unsigned fieldLen = fieldType->getStringLen();
  4599. unsigned lenValue = value->queryType()->getStringLen();
  4600. const void * rawValue = value->queryValue();
  4601. size32_t resultLen;
  4602. rtlDataAttr result;
  4603. if (whichBoundary < 0)
  4604. {
  4605. switch (ftc)
  4606. {
  4607. case type_qstring:
  4608. rtlCreateQStrRangeLow(resultLen, result.refstr(), fieldLen, subStringLen, lenValue, static_cast<const char *>(rawValue));
  4609. break;
  4610. case type_string:
  4611. rtlCreateStrRangeLow(resultLen, result.refstr(), fieldLen, subStringLen, lenValue, static_cast<const char *>(rawValue));
  4612. break;
  4613. case type_data:
  4614. rtlCreateDataRangeLow(resultLen, result.refdata(), fieldLen, subStringLen, lenValue, rawValue);
  4615. break;
  4616. case type_unicode:
  4617. rtlCreateUnicodeRangeLow(resultLen, result.refustr(), fieldLen, subStringLen, lenValue, static_cast<const UChar *>(rawValue));
  4618. break;
  4619. default:
  4620. //should this generate a warning/error instead?
  4621. rtlCreateRange(resultLen, result.refstr(), fieldLen, subStringLen, fieldType->getSize(), static_cast<const char *>(rawValue), 0, 0);
  4622. break;
  4623. }
  4624. }
  4625. else
  4626. {
  4627. switch (ftc)
  4628. {
  4629. case type_qstring:
  4630. rtlCreateQStrRangeHigh(resultLen, result.refstr(), fieldLen, subStringLen, lenValue, static_cast<const char *>(rawValue));
  4631. break;
  4632. case type_string:
  4633. rtlCreateStrRangeHigh(resultLen, result.refstr(), fieldLen, subStringLen, lenValue, static_cast<const char *>(rawValue));
  4634. break;
  4635. case type_data:
  4636. rtlCreateDataRangeHigh(resultLen, result.refdata(), fieldLen, subStringLen, lenValue, rawValue);
  4637. break;
  4638. case type_unicode:
  4639. rtlCreateUnicodeRangeHigh(resultLen, result.refustr(), fieldLen, subStringLen, lenValue, static_cast<const UChar *>(rawValue));
  4640. break;
  4641. default:
  4642. rtlCreateRange(resultLen, result.refstr(), fieldLen, subStringLen, fieldType->getSize(), static_cast<const char *>(rawValue), 255, 0);
  4643. break;
  4644. }
  4645. }
  4646. assertex(resultLen == fieldLen);
  4647. return createConstant(createValueFromMem(LINK(fieldType), result.getdata()));
  4648. }
  4649. IHqlExpression * MonitorExtractor::getRangeLimit(ITypeInfo * fieldType, IHqlExpression * lengthExpr, IHqlExpression * value, int whichBoundary)
  4650. {
  4651. type_t ftc = fieldType->getTypeCode();
  4652. unsigned fieldLength = fieldType->getStringLen();
  4653. IValue * constValue = value->queryValue();
  4654. if (constValue && lengthExpr->queryValue())
  4655. {
  4656. unsigned subStringLen = (unsigned)lengthExpr->queryValue()->getIntValue();
  4657. if ((int)subStringLen < 0) subStringLen = 0;
  4658. if (subStringLen > fieldLength)
  4659. translator.throwError1(HQLERR_SubstringOutOfRange, subStringLen);
  4660. return getCompareValue(fieldType, subStringLen, constValue, whichBoundary);
  4661. }
  4662. IIdAtom * func;
  4663. if (whichBoundary < 0)
  4664. {
  4665. switch (ftc)
  4666. {
  4667. case type_qstring:
  4668. func = createQStrRangeLowId;
  4669. break;
  4670. case type_string:
  4671. func = createStrRangeLowId;
  4672. break;
  4673. case type_data:
  4674. func = createDataRangeLowId;
  4675. break;
  4676. case type_unicode:
  4677. func = createUnicodeRangeLowId;
  4678. break;
  4679. default:
  4680. func = createRangeLowId;
  4681. break;
  4682. }
  4683. }
  4684. else
  4685. {
  4686. switch (ftc)
  4687. {
  4688. case type_qstring:
  4689. func = createQStrRangeHighId;
  4690. break;
  4691. case type_string:
  4692. func = createStrRangeHighId;
  4693. break;
  4694. case type_data:
  4695. func = createDataRangeHighId;
  4696. break;
  4697. case type_unicode:
  4698. func = createUnicodeRangeHighId;
  4699. break;
  4700. default:
  4701. func = createRangeHighId;
  4702. break;
  4703. }
  4704. }
  4705. HqlExprArray args;
  4706. args.append(*getSizetConstant(fieldLength));
  4707. args.append(*LINK(lengthExpr));
  4708. args.append(*LINK(value));
  4709. //Note: I can't change the return type of the function - because if fixed length then wrong call is made, and variable length is worse code.
  4710. OwnedHqlExpr call = translator.bindFunctionCall(func, args);
  4711. return createValue(no_typetransfer, LINK(fieldType), LINK(call));
  4712. }
  4713. IHqlExpression * MonitorExtractor::createRangeCompare(IHqlExpression * selector, IHqlExpression * value, IHqlExpression * lengthExpr, bool compareEqual)
  4714. {
  4715. OwnedHqlExpr foldedValue = foldHqlExpression(value);
  4716. ITypeInfo * fieldType = selector->queryType();
  4717. IHqlExpression * lowExpr = getRangeLimit(fieldType, lengthExpr, foldedValue, -1);
  4718. IHqlExpression * highExpr = getRangeLimit(fieldType, lengthExpr, foldedValue, +1);
  4719. //Could convert to two separate tests, but code is worse, and boundary conditions aren't going to happen.
  4720. return createValue(compareEqual ? no_between : no_notbetween, makeBoolType(), LINK(selector), lowExpr, highExpr);
  4721. }
  4722. static IHqlExpression * removeCastTrim(IHqlExpression * expr)
  4723. {
  4724. for (;;)
  4725. {
  4726. if ((expr->getOperator() == no_trim) && !expr->queryChild(1))
  4727. expr = expr->queryChild(0);
  4728. else if (isLengthPreservingCast(expr))
  4729. expr = expr->queryChild(0);
  4730. else
  4731. return expr;
  4732. expr = queryNonAliased(expr);
  4733. }
  4734. }
  4735. static IHqlExpression * queryLengthFromRange(IHqlExpression * range)
  4736. {
  4737. switch (range->getOperator())
  4738. {
  4739. case no_rangefrom:
  4740. case no_rangecommon:
  4741. return NULL;
  4742. case no_rangeto:
  4743. return range->queryChild(0);
  4744. case no_range:
  4745. if (getIntValue(range->queryChild(0), 0) == 1)
  4746. return range->queryChild(1);
  4747. return NULL;
  4748. default:
  4749. if (getIntValue(range, 0) == 1)
  4750. return range;
  4751. return NULL;
  4752. }
  4753. }
  4754. static void extendRangeCheck(SharedHqlExpr & globalGuard, SharedHqlExpr & localCond, IHqlExpression * selector, IHqlExpression * lengthExpr, bool compareEqual)
  4755. {
  4756. #if 0
  4757. //This might be a good idea, but probably doesn't make a great deal of difference at runtime
  4758. //Optimize the case where you check zero length to use a wild carded range instead
  4759. //x[1..len=0] = y from x in range 0000000..FFFFFF to len==0 || x in range....
  4760. if (compareEqual)
  4761. {
  4762. if (!lengthExpr->queryValue())
  4763. {
  4764. OwnedHqlExpr testLength = createBoolExpr(no_eq, LINK(lengthExpr), ensureExprType(queryZero(), lengthExpr->queryType()));
  4765. localCond.setown(createBoolExpr(no_or, testLength.getClear(), LINK(localCond)));
  4766. }
  4767. }
  4768. #endif
  4769. //For a range check x[1..m] = y we generate
  4770. //x in range(sizeof(x), m, y, 0) and range(maxlength(x), m, y, 255)
  4771. //need to guard with condition len(trim(y)) <= m
  4772. //If x[1..length(trim(y))] == y then don't add a condition
  4773. IHqlExpression * cur = queryNonAliased(lengthExpr);
  4774. IHqlExpression * compare = removeCastTrim(queryNonAliased(selector));
  4775. if (cur->getOperator() == no_charlen)
  4776. {
  4777. cur = queryNonAliased(cur->queryChild(0));
  4778. if (cur->getOperator() == no_trim)
  4779. {
  4780. cur = queryNonAliased(cur->queryChild(0));
  4781. while (isLengthPreservingCast(cur))
  4782. cur = queryNonAliased(cur->queryChild(0));
  4783. IHqlExpression * compare = selector;
  4784. for (;;)
  4785. {
  4786. compare = removeCastTrim(queryNonAliased(compare));
  4787. if (cur->queryBody() == compare->queryBody())
  4788. return;
  4789. //Casts between strings that reduce/increase the number of characters don't matter as long as
  4790. //they eventually match the search string
  4791. if (!isCast(compare) || !isStringType(compare->queryType()))
  4792. break;
  4793. compare = compare->queryChild(0);
  4794. if (!isStringType(compare->queryType()))
  4795. break;
  4796. }
  4797. }
  4798. }
  4799. // if x[1..n] = z[1..n] then no need for a condition
  4800. if (compare->getOperator() == no_substring)
  4801. {
  4802. IHqlExpression * range = queryLengthFromRange(compare->queryChild(1));
  4803. if (range == lengthExpr)
  4804. return;
  4805. }
  4806. // if x[1..n] = (string<m>y) where m<n then no need for condition
  4807. unsigned selectorLength = selector->queryType()->getStringLen();
  4808. if (selectorLength <= getIntValue(lengthExpr, 0))
  4809. return;
  4810. //otherwise, if x[1..y] == z then add check length(trim(z)) <= y
  4811. OwnedHqlExpr trim = createTrimExpr(selector, NULL);
  4812. OwnedHqlExpr len = createValue(no_charlen, LINK(unsignedType), LINK(trim));
  4813. ITypeInfo * lengthType = lengthExpr->queryType();
  4814. Owned<ITypeInfo> compareType = getPromotedECLCompareType(unsignedType, lengthType);
  4815. node_operator compOp = compareEqual ? no_le : no_gt;
  4816. OwnedHqlExpr positiveLen = createValue(no_maxlist, lengthExpr->getType(), createValue(no_list, makeSetType(LINK(lengthType)), LINK(lengthExpr), createConstant(lengthType->castFrom(false, I64C(0)))));
  4817. OwnedHqlExpr test = createValue(no_le, makeBoolType(), ensureExprType(len, compareType), ensureExprType(positiveLen, compareType));
  4818. test.setown(foldHqlExpression(test));
  4819. if (compareEqual)
  4820. extendConditionOwn(globalGuard, no_and, test.getClear());
  4821. else
  4822. extendConditionOwn(localCond, no_or, getInverse(test));
  4823. }
  4824. bool MonitorExtractor::matchSubstringFilter(KeyConditionInfo & matches, node_operator op, IHqlExpression * left, IHqlExpression * right, KeyedKind keyedKind, bool & duplicate)
  4825. {
  4826. LinkedHqlExpr value = right;
  4827. duplicate = false;
  4828. OwnedHqlExpr guard;
  4829. ITypeInfo * guardCastType = NULL;
  4830. if ((left->getOperator() == no_cast) || (left->getOperator() == no_implicitcast))
  4831. {
  4832. //code is extracted and simplified from isKeyableFilter() above - should be commoned up.
  4833. IHqlExpression * uncast = left->queryChild(0);
  4834. ITypeInfo * castType = left->queryType();
  4835. ITypeInfo * uncastType = uncast->queryType();
  4836. //(ty)x = y.
  4837. //if more than one value of x[uncastType] corresponds to a single value in y[castType] then we can't sensibly create
  4838. //the key segment monitor. Because we will get false negatives. If it is an inverse then duplicate (see below)
  4839. bool canRemoveCast = true;
  4840. if (castLosesInformation(castType, uncastType))
  4841. canRemoveCast = false;
  4842. //if more than one value of y corresponds to a single value of x then need to duplicate the test condition.
  4843. if (!preservesOrder(castType, uncastType))
  4844. canRemoveCast = false;
  4845. if (!canRemoveCast)
  4846. {
  4847. // reason.set(KFRcast, ret->queryChild(1));
  4848. return false;
  4849. }
  4850. if ((op != no_in) && (op != no_notin))
  4851. {
  4852. value.setown(ensureExprType(right, uncastType));
  4853. //If a simple equality test then create a global guard to check that we aren't matching a false positive
  4854. if (castLosesInformation(uncastType, castType))
  4855. guard.setown(createBoolExpr(no_eq, ensureExprType(value, castType), LINK(right)));
  4856. }
  4857. else
  4858. {
  4859. //if an IN then add guards to each comparison - generated later...
  4860. if (castLosesInformation(uncastType, castType))
  4861. guardCastType = uncastType;
  4862. else
  4863. {
  4864. Owned<ITypeInfo> targetType = makeSetType(LINK(uncastType));
  4865. value.setown(ensureExprType(right, targetType));
  4866. }
  4867. }
  4868. left = uncast;
  4869. }
  4870. if (left->getOperator() != no_substring)
  4871. return false;
  4872. if ((op == no_in) || (op == no_notin))
  4873. {
  4874. value.setown(normalizeListCasts(value));
  4875. if (value->getOperator() != no_list)
  4876. return false;
  4877. }
  4878. IHqlExpression * selector = left->queryChild(0);
  4879. if (!isKeySelect(selector) || !okToKey(selector, keyedKind))
  4880. return false;
  4881. if (!isIndexInvariant(right, false))
  4882. return false;
  4883. ITypeInfo * fieldType = selector->queryType();
  4884. unsigned fieldLength = fieldType->getStringLen();
  4885. if (fieldLength == UNKNOWN_LENGTH)
  4886. return false;
  4887. OwnedHqlExpr range = foldHqlExpression(left->queryChild(1));
  4888. IHqlExpression * lengthExpr = queryLengthFromRange(range);
  4889. if (!lengthExpr)
  4890. return false;
  4891. OwnedHqlExpr newTest;
  4892. if ((op == no_eq) || (op == no_ne))
  4893. {
  4894. newTest.setown(createRangeCompare(selector, value, lengthExpr, op == no_eq));
  4895. extendRangeCheck(guard, newTest, right, lengthExpr, op == no_eq);
  4896. }
  4897. else //no_in, no_notin
  4898. {
  4899. HqlExprArray compares;
  4900. ForEachChild(i, value)
  4901. {
  4902. IHqlExpression * cur = value->queryChild(i);
  4903. LinkedHqlExpr castValue = cur;
  4904. OwnedHqlExpr valueGuard;
  4905. if (guardCastType)
  4906. {
  4907. castValue.setown(ensureExprType(castValue, guardCastType));
  4908. valueGuard.setown(createBoolExpr(no_eq, ensureExprType(castValue, cur->queryType()), LINK(cur)));
  4909. extendRangeCheck(valueGuard, valueGuard, cur, lengthExpr, (op == no_in));
  4910. }
  4911. OwnedHqlExpr cond = createRangeCompare(selector, castValue, lengthExpr, (op == no_in));
  4912. if (valueGuard)
  4913. cond.setown(createValue(no_and, makeBoolType(), valueGuard.getClear(), cond.getClear()));
  4914. compares.append(*cond.getClear());
  4915. }
  4916. node_operator combineOp = (op == no_in) ? no_or : no_and;
  4917. newTest.setown(createBalanced(combineOp, queryBoolType(), compares));
  4918. }
  4919. matches.appendCondition(*new KeyCondition(selector, newTest, keyedKind));
  4920. if (guard)
  4921. matches.appendPreFilter(guard);
  4922. return true;
  4923. }
  4924. bool MonitorExtractor::extractSimpleCompareFilter(KeyConditionInfo & matches, IHqlExpression * expr, KeyedKind keyedKind)
  4925. {
  4926. OwnedHqlExpr promoted = getExplicitlyPromotedCompare(expr);
  4927. IHqlExpression * l = promoted->queryChild(0);
  4928. IHqlExpression * r = promoted->queryChild(1);
  4929. bool duplicate = false;
  4930. KeyFailureInfo reasonl, reasonr;
  4931. node_operator op = expr->getOperator();
  4932. IHqlExpression * matchedSelector = isKeyableFilter(l, r, duplicate, op, reasonl, keyedKind);
  4933. Owned<KeyCondition> result;
  4934. if (matchedSelector)
  4935. {
  4936. node_operator newOp = getModifiedOp(op, duplicate);
  4937. if (newOp != no_none)
  4938. {
  4939. OwnedHqlExpr newFilter = createValue(newOp, expr->getType(), LINK(l), LINK(r));
  4940. result.setown(new KeyCondition(matchedSelector, newFilter, keyedKind));
  4941. }
  4942. }
  4943. else
  4944. {
  4945. duplicate = false;
  4946. matchedSelector = isKeyableFilter(r, l, duplicate, op, reasonr, keyedKind);
  4947. if (matchedSelector)
  4948. {
  4949. node_operator newOp = getModifiedOp(getReverseOp(op), duplicate);
  4950. if (newOp != no_none)
  4951. {
  4952. OwnedHqlExpr newFilter = createValue(newOp, expr->getType(), LINK(r), LINK(l));
  4953. result.setown(new KeyCondition(matchedSelector, newFilter, keyedKind));
  4954. }
  4955. }
  4956. }
  4957. if (!result && allowTranslatedConds)
  4958. {
  4959. duplicate = false;
  4960. ITypeInfo * type = l->queryType();
  4961. if (isKeyableType(type))
  4962. {
  4963. bool leftHasSelects = containsTableSelects(l);
  4964. bool rightHasSelects = containsTableSelects(r);
  4965. if (leftHasSelects && !rightHasSelects)
  4966. {
  4967. result.setown(createTranslatedCondition(expr, keyedKind));
  4968. }
  4969. else if (!leftHasSelects && rightHasSelects && (op != no_in) && (op != no_notin))
  4970. {
  4971. OwnedHqlExpr newFilter = createValue(getReverseOp(op), expr->getType(), LINK(r), LINK(l));
  4972. result.setown(createTranslatedCondition(newFilter, keyedKind));
  4973. }
  4974. }
  4975. }
  4976. bool extracted = (result != NULL);
  4977. if (extracted)
  4978. {
  4979. matches.appendCondition(*result.getClear());
  4980. }
  4981. else
  4982. {
  4983. failReason.merge(reasonl);
  4984. failReason.merge(reasonr);
  4985. }
  4986. if (duplicate || !extracted)
  4987. matches.appendPostFilter(expr);
  4988. return extracted;
  4989. }
  4990. bool MonitorExtractor::extractOrFilter(KeyConditionInfo & matches, IHqlExpression * expr, KeyedKind keyedKind)
  4991. {
  4992. HqlExprArray conds;
  4993. expr->unwindList(conds, no_or);
  4994. bool validOrFilter = true;
  4995. HqlExprAttr invariant;
  4996. CIArrayOf<KeyConditionInfo> branches;
  4997. ForEachItemIn(idx, conds)
  4998. {
  4999. IHqlExpression & cur = conds.item(idx);
  5000. if (isIndexInvariant(&cur, false))
  5001. extendOrCondition(invariant, &cur);
  5002. else
  5003. {
  5004. KeyConditionInfo & branch = * new KeyConditionInfo;
  5005. branches.append(branch);
  5006. //Can't generate an OR with a pure post-filter
  5007. if (!extractFilters(branch, &cur, keyedKind))
  5008. validOrFilter = false;
  5009. }
  5010. }
  5011. //check all the conditions that are ORd together don't contain references to multiple fields.
  5012. KeyCondition * firstBranch = NULL;
  5013. bool multipleBranches = branches.ordinality() > 1;
  5014. bool multipleSelectors = false;
  5015. bool multipleConditions = false;
  5016. bool hasPostFilter = false;
  5017. ForEachItemIn(i1, branches)
  5018. {
  5019. KeyConditionInfo & branch = branches.item(i1);
  5020. if (branch.postFilter)
  5021. hasPostFilter = true;
  5022. ForEachItemIn(i2, branch.conditions)
  5023. {
  5024. KeyCondition & cur = branch.conditions.item(i2);
  5025. if (!firstBranch)
  5026. firstBranch = &cur;
  5027. else
  5028. {
  5029. multipleConditions = true;
  5030. if (i1 == 0)
  5031. {
  5032. if (firstBranch->selector != cur.selector)
  5033. multipleSelectors = true;
  5034. }
  5035. else
  5036. {
  5037. if ((firstBranch->selector != cur.selector) || multipleSelectors)
  5038. validOrFilter = false;
  5039. }
  5040. }
  5041. }
  5042. }
  5043. if (multipleBranches && hasPostFilter)
  5044. validOrFilter = false;
  5045. if (validOrFilter && firstBranch)
  5046. {
  5047. bool optimizeSingleBranch = true;
  5048. if (multipleSelectors || hasPostFilter || (optimizeSingleBranch && !multipleConditions))
  5049. {
  5050. //Invariant ored with a conjunction
  5051. //X or (A and B) -> (X or A) AND (X or B)
  5052. assertex(branches.ordinality() == 1);
  5053. KeyConditionInfo & branch = branches.item(0);
  5054. OwnedHqlExpr preFilter = branch.preFilter ? extendCondition(no_or, invariant, branch.preFilter) : NULL;
  5055. OwnedHqlExpr postFilter = branch.postFilter ? extendCondition(no_or, invariant, branch.postFilter) : NULL;
  5056. matches.appendPreFilter(preFilter);
  5057. matches.appendPostFilter(postFilter);
  5058. ForEachItemIn(i2, branch.conditions)
  5059. {
  5060. KeyCondition & cur = branch.conditions.item(i2);
  5061. OwnedHqlExpr filter = extendCondition(no_or, invariant, cur.expr);
  5062. matches.conditions.append(*new KeyCondition(cur.selector, filter, keyedKind));
  5063. }
  5064. }
  5065. else
  5066. {
  5067. LinkedHqlExpr combinedCondition = invariant;
  5068. ForEachItemIn(i1, branches)
  5069. {
  5070. KeyConditionInfo & branch = branches.item(i1);
  5071. OwnedHqlExpr conjunction = branch.createConjunction();
  5072. extendOrCondition(combinedCondition, conjunction);
  5073. }
  5074. matches.conditions.append(*new KeyCondition(firstBranch->selector, combinedCondition, keyedKind));
  5075. }
  5076. return true;
  5077. }
  5078. else
  5079. {
  5080. matches.appendPostFilter(expr);
  5081. KeyFailureInfo reason;
  5082. reason.set(KFRor);
  5083. failReason.merge(reason);
  5084. return false;
  5085. }
  5086. }
  5087. bool MonitorExtractor::extractIfFilter(KeyConditionInfo & matches, IHqlExpression * expr, KeyedKind keyedKind)
  5088. {
  5089. //MORE: This could generate better code, but I don't think it is worth the effort at the moment.
  5090. //Really, I should analyse left and right. Iterate each selector referenced. If there are no post conditions then
  5091. //generate IF(a, X, Y) compound expression, otherwise generate the default below.
  5092. IHqlExpression * cond = expr->queryChild(0);
  5093. if ((keyedKind != KeyedNo) && isIndexInvariant(cond, false))
  5094. {
  5095. //Convert IF(a, X, Y) to... IF (a, X, true) AND IF (a, true, Y) to... (NOT a OR X) AND (a OR Y)
  5096. OwnedHqlExpr inverseCond = getInverse(cond);
  5097. OwnedHqlExpr trueValue = createBoolExpr(no_or, LINK(inverseCond), LINK(expr->queryChild(1)));
  5098. OwnedHqlExpr falseValue = createBoolExpr(no_or, LINK(cond), LINK(expr->queryChild(2)));
  5099. OwnedHqlExpr combined = createBoolExpr(no_and, LINK(trueValue), LINK(falseValue));
  5100. return extractFilters(matches, combined, keyedKind);
  5101. }
  5102. matches.appendPostFilter(expr);
  5103. return false;
  5104. }
  5105. static HqlTransformerInfo selectSpotterInfo("SelectSpotter");
  5106. MonitorExtractor::SelectSpotter::SelectSpotter(const HqlExprArray & _selects) : NewHqlTransformer(selectSpotterInfo), selects(_selects)
  5107. {
  5108. hasSelects = false;
  5109. }
  5110. void MonitorExtractor::SelectSpotter::analyseExpr(IHqlExpression * expr)
  5111. {
  5112. if (hasSelects || alreadyVisited(expr))
  5113. return;
  5114. if (selects.find(*expr) != NotFound)
  5115. {
  5116. hasSelects = true;
  5117. return;
  5118. }
  5119. NewHqlTransformer::analyseExpr(expr);
  5120. }
  5121. bool MonitorExtractor::containsTableSelects(IHqlExpression * expr)
  5122. {
  5123. HqlExprCopyArray inScope;
  5124. expr->gatherTablesUsed(NULL, &inScope);
  5125. //Check that cursors for all inScope tables are already bound in the start context
  5126. return inScope.find(*tableExpr->queryNormalizedSelector()) != NotFound;
  5127. }
  5128. void MonitorExtractor::extractFilters(IHqlExpression * expr, SharedHqlExpr & extraFilter)
  5129. {
  5130. HqlExprArray conds;
  5131. expr->unwindList(conds, no_and);
  5132. extractFilters(conds, extraFilter);
  5133. }
  5134. void MonitorExtractor::extractFilters(HqlExprArray & exprs, SharedHqlExpr & extraFilter)
  5135. {
  5136. OwnedHqlExpr savedFilter = keyed.postFilter.getClear();
  5137. ForEachItemIn(i1, exprs)
  5138. {
  5139. IHqlExpression & cur = exprs.item(i1);
  5140. switch (cur.getOperator())
  5141. {
  5142. case no_assertkeyed:
  5143. case no_assertwild:
  5144. extractFilters(keyed, &cur, KeyedNo);
  5145. break;
  5146. }
  5147. }
  5148. keyedExplicitly = (keyed.conditions.ordinality() != 0);
  5149. cleanlyKeyedExplicitly = keyedExplicitly && !keyed.postFilter;
  5150. ForEachItemIn(i2, exprs)
  5151. {
  5152. IHqlExpression & cur = exprs.item(i2);
  5153. switch (cur.getOperator())
  5154. {
  5155. case no_assertkeyed:
  5156. case no_assertwild:
  5157. break;
  5158. default:
  5159. if (!keyedExplicitly)
  5160. extractFilters(keyed, &cur, KeyedNo);
  5161. else if (!cur.isAttribute() && isIndexInvariant(&cur, true))
  5162. keyed.appendPreFilter(&cur);
  5163. else
  5164. keyed.appendPostFilter(&cur);
  5165. break;
  5166. }
  5167. }
  5168. extraFilter.set(keyed.postFilter);
  5169. keyed.postFilter.setown(extendConditionOwn(no_and, savedFilter.getClear(), LINK(extraFilter)));
  5170. }
  5171. void MonitorExtractor::extractFiltersFromFilterDs(IHqlExpression * expr)
  5172. {
  5173. HqlExprArray conds;
  5174. HqlExprAttr dummy;
  5175. unwindFilterConditions(conds, expr);
  5176. extractFilters(conds, dummy);
  5177. }
  5178. void MonitorExtractor::extractFoldedWildFields(IHqlExpression * expr)
  5179. {
  5180. node_operator op = expr->getOperator();
  5181. switch (op)
  5182. {
  5183. case no_cast:
  5184. case no_implicitcast:
  5185. case no_add:
  5186. case no_sub:
  5187. //fields may have been transformed since folding...
  5188. extractFoldedWildFields(expr->queryChild(0));
  5189. break;
  5190. case no_select:
  5191. if (isKeySelect(expr))
  5192. {
  5193. KeyCondition * condition = new KeyCondition;
  5194. condition->selector.set(expr);
  5195. condition->isWild = true;
  5196. condition->wasKeyed = true;
  5197. keyed.conditions.append(*condition);
  5198. }
  5199. break;
  5200. }
  5201. }
  5202. bool MonitorExtractor::extractBoolFieldFilter(KeyConditionInfo & matches, IHqlExpression * selector, KeyedKind keyedKind, bool compareValue)
  5203. {
  5204. if (selector->isBoolean())
  5205. {
  5206. if (isKeySelect(selector) && okToKey(selector, keyedKind))
  5207. {
  5208. OwnedHqlExpr newFilter = createValue(no_eq, makeBoolType(), LINK(selector), createConstant(compareValue));
  5209. matches.appendCondition(*new KeyCondition(selector, newFilter, keyedKind));
  5210. return true;
  5211. }
  5212. }
  5213. return false;
  5214. }
  5215. bool MonitorExtractor::extractFilters(KeyConditionInfo & matches, IHqlExpression * expr, KeyedKind keyedKind)
  5216. {
  5217. if (!expr->isAttribute() && isIndexInvariant(expr, true))
  5218. {
  5219. extendAndCondition(matches.preFilter, expr);
  5220. return true;
  5221. }
  5222. IHqlExpression *l = expr->queryChild(0);
  5223. IHqlExpression *r = expr->queryChild(1);
  5224. node_operator op = expr->getOperator();
  5225. switch (op)
  5226. {
  5227. case no_and:
  5228. {
  5229. bool extracted = extractFilters(matches, l, keyedKind);
  5230. if (!extractFilters(matches, r, keyedKind)) extracted = false;
  5231. return extracted;
  5232. }
  5233. case no_or:
  5234. return extractOrFilter(matches, expr, keyedKind);
  5235. case no_attr:
  5236. case no_attr_expr:
  5237. case no_attr_link:
  5238. return true;
  5239. case no_not:
  5240. {
  5241. IHqlExpression * arg = expr->queryChild(0);
  5242. OwnedHqlExpr inverse = getInverse(arg);
  5243. if (inverse->queryBody() != expr->queryBody())
  5244. return extractFilters(matches, inverse, keyedKind);
  5245. if ((arg->getOperator() == no_select) && arg->isBoolean() &&
  5246. extractBoolFieldFilter(matches, arg, keyedKind, false))
  5247. return true;
  5248. matches.appendPostFilter(expr);
  5249. return false;
  5250. }
  5251. case no_between:
  5252. case no_notbetween:
  5253. {
  5254. //Convert this into two comparisons because that will handle weird boundary conditions much better.
  5255. OwnedHqlExpr normalized = expandBetween(expr);
  5256. return extractFilters(matches, normalized, keyedKind);
  5257. }
  5258. case no_eq:
  5259. case no_ne:
  5260. {
  5261. bool duplicate = false;
  5262. if (matchSubstringFilter(matches, op, l, r, keyedKind, duplicate) || matchSubstringFilter(matches, op, r, l, keyedKind, duplicate))
  5263. {
  5264. if (duplicate)
  5265. matches.appendPostFilter(expr);
  5266. return true;
  5267. }
  5268. return extractSimpleCompareFilter(matches, expr, keyedKind);
  5269. }
  5270. case no_in:
  5271. case no_notin:
  5272. {
  5273. bool duplicate = false;
  5274. if (matchSubstringFilter(matches, op, l, r, keyedKind, duplicate))
  5275. {
  5276. if (duplicate)
  5277. matches.appendPostFilter(expr);
  5278. return true;
  5279. }
  5280. return extractSimpleCompareFilter(matches, expr, keyedKind);
  5281. }
  5282. case no_gt:
  5283. case no_lt:
  5284. case no_ge:
  5285. case no_le:
  5286. return extractSimpleCompareFilter(matches, expr, keyedKind);
  5287. case no_assertkeyed:
  5288. {
  5289. KeyFailureInfo reason;
  5290. reason.merge(failReason);
  5291. failReason.clear();
  5292. bool extend = expr->hasAttribute(extendAtom);
  5293. if (!extractFilters(matches, l, extend ? KeyedExtend : KeyedYes))
  5294. {
  5295. if (!extend)
  5296. failReason.reportError(translator, expr);
  5297. }
  5298. IHqlExpression * original = expr->queryAttribute(_selectors_Atom);
  5299. if (original)
  5300. {
  5301. ForEachChild(i, original)
  5302. extractFoldedWildFields(original->queryChild(i));
  5303. }
  5304. failReason.merge(reason);
  5305. return true;
  5306. }
  5307. case no_assertwild:
  5308. {
  5309. if (l->getOperator() == no_all)
  5310. {
  5311. IHqlExpression * original = expr->queryAttribute(_selectors_Atom);
  5312. assertex(original);
  5313. ForEachChild(i, original)
  5314. extractFoldedWildFields(original->queryChild(i));
  5315. }
  5316. else
  5317. {
  5318. IHqlExpression * selector = queryKeyableSelector(l);
  5319. if (!selector)
  5320. {
  5321. StringBuffer keyname;
  5322. translator.throwError1(HQLERR_WildNotReferenceIndex, queryKeyName(keyname));
  5323. }
  5324. KeyCondition * condition = new KeyCondition;
  5325. condition->selector.set(selector);
  5326. condition->isWild = true;
  5327. matches.appendCondition(*condition);
  5328. }
  5329. return true;
  5330. }
  5331. case no_if:
  5332. return extractIfFilter(matches, expr, keyedKind);
  5333. case no_select:
  5334. {
  5335. if (expr->isBoolean() && extractBoolFieldFilter(matches, expr, keyedKind, true))
  5336. return true;
  5337. matches.appendPostFilter(expr);
  5338. return false;
  5339. }
  5340. default:
  5341. // Add this condition to the catchall expr
  5342. matches.appendPostFilter(expr);
  5343. return false;
  5344. }
  5345. }
  5346. void MonitorExtractor::extractAllFilters(IHqlExpression * dataset)
  5347. {
  5348. for (;;)
  5349. {
  5350. switch (dataset->getOperator())
  5351. {
  5352. case no_newkeyindex:
  5353. return;
  5354. case no_filter:
  5355. extractAllFilters(dataset->queryChild(0));
  5356. extractFiltersFromFilterDs(dataset);
  5357. return;
  5358. case no_compound_indexread:
  5359. case no_newusertable:
  5360. case no_hqlproject:
  5361. case no_distributed:
  5362. case no_preservemeta:
  5363. case no_unordered:
  5364. case no_sorted:
  5365. case no_stepped:
  5366. case no_grouped:
  5367. case no_alias_scope:
  5368. case no_dataset_alias:
  5369. break;
  5370. default:
  5371. UNIMPLEMENTED;
  5372. }
  5373. dataset = dataset->queryChild(0);
  5374. }
  5375. }
  5376. bool MonitorExtractor::isKeyed()
  5377. {
  5378. ForEachItemIn(i, keyed.conditions)
  5379. {
  5380. if (!keyed.conditions.item(i).isWild)
  5381. return true;
  5382. }
  5383. return false;
  5384. }
  5385. bool expandFilename(StringBuffer & s, IHqlExpression * expr)
  5386. {
  5387. switch (expr->getOperator())
  5388. {
  5389. case no_constant:
  5390. expr->toString(s);
  5391. return true;
  5392. case no_getresult:
  5393. //more
  5394. break;
  5395. case no_concat:
  5396. {
  5397. bool hadString = expandFilename(s, expr->queryChild(0));
  5398. unsigned oldLength = s.length();
  5399. s.append("+");
  5400. if (expandFilename(s, expr->queryChild(1)) || hadString)
  5401. return true;
  5402. s.setLength(oldLength);
  5403. return false;
  5404. }
  5405. case no_alias:
  5406. case no_cast:
  5407. case no_implicitcast:
  5408. return expandFilename(s, expr->queryChild(0));
  5409. }
  5410. if (hasNamedSymbol(expr))
  5411. {
  5412. s.append(expr->queryName());
  5413. return true;
  5414. }
  5415. s.append("...");
  5416. return false;
  5417. }
  5418. const char * MonitorExtractor::queryKeyName(StringBuffer & s)
  5419. {
  5420. IAtom * name = tableExpr->queryName();
  5421. if (name)
  5422. s.append(" \'").append(name).append("'");
  5423. else
  5424. {
  5425. IHqlExpression * filename = queryTableFilename(tableExpr);
  5426. if (filename)
  5427. {
  5428. if (!expandFilename(s.append(' '), filename))
  5429. s.clear();
  5430. }
  5431. }
  5432. return s.str();
  5433. }
  5434. static bool isNextField(IHqlExpression * record, IHqlExpression * prevExpr, IHqlExpression * nextExpr)
  5435. {
  5436. if ((prevExpr->getOperator() != no_select) || (nextExpr->getOperator() != no_select))
  5437. return false;
  5438. IHqlExpression * prevSelect = prevExpr->queryChild(0);
  5439. if (prevSelect != nextExpr->queryChild(0))
  5440. return false;
  5441. if (!containsOnlyLeft(prevExpr))
  5442. return false;
  5443. if (prevSelect->getOperator() != no_left)
  5444. record = prevSelect->queryRecord();
  5445. IHqlExpression * prevField = prevExpr->queryChild(1);
  5446. IHqlExpression * nextField = nextExpr->queryChild(1);
  5447. //Slow, but probably doesn't matter...
  5448. ForEachChild(i, record)
  5449. {
  5450. IHqlExpression * cur = record->queryChild(i);
  5451. if (cur == prevField)
  5452. return (record->queryChild(i+1) == nextField);
  5453. }
  5454. return false;
  5455. }
  5456. IHqlExpression * MonitorExtractor::querySimpleJoinValue(IHqlExpression * selector)
  5457. {
  5458. IHqlExpression * matched = NULL;
  5459. ForEachItemIn(cond, keyed.conditions)
  5460. {
  5461. KeyCondition & cur = keyed.conditions.item(cond);
  5462. if (cur.selector == selector)
  5463. {
  5464. if (!cur.isWild)
  5465. {
  5466. if (matched)
  5467. return NULL;
  5468. IHqlExpression * matchExpr = cur.expr;
  5469. if (matchExpr->getOperator() != no_eq)
  5470. return NULL;
  5471. if (matchExpr->queryChild(0) != selector)
  5472. return NULL;
  5473. matched = matchExpr->queryChild(1);
  5474. }
  5475. }
  5476. }
  5477. return matched;
  5478. }
  5479. void MonitorExtractor::optimizeSegments(IHqlExpression * leftRecord)
  5480. {
  5481. //loop to see if we have matches for key.cpt[n] = x.field[n] and key.cpt[n+1] = x.field[n+1]
  5482. //where fields are fixed length, no casts and no modifiers.
  5483. //if so, mark the new total size,
  5484. //when generate, extend the size of the first monitor, and skip the others.
  5485. //MORE: Could also combine fixed constants, but less of an advantage.
  5486. //Don't process anything after a variable size field/something that is transformed.
  5487. unsigned i = 0;
  5488. for (; i < firstOffsetField; i++)
  5489. {
  5490. IHqlExpression * keySelector = &keyableSelects.item(i);
  5491. unsigned mergedSize = keySelector->queryType()->getSize();
  5492. IHqlExpression * prevValue = querySimpleJoinValue(keySelector);
  5493. unsigned best = i;
  5494. if (prevValue && isSameBasicType(keySelector->queryType(), prevValue->queryType()))
  5495. {
  5496. for (unsigned j = i+1; j < firstOffsetField; j++)
  5497. {
  5498. IHqlExpression * nextSelector = &keyableSelects.item(j);
  5499. if (noMergeSelects.contains(*nextSelector))
  5500. break;
  5501. IHqlExpression * nextValue = querySimpleJoinValue(nextSelector);
  5502. if (!nextValue || !isNextField(leftRecord, prevValue, nextValue) ||
  5503. !isSameBasicType(nextSelector->queryType(), nextValue->queryType()))
  5504. break;
  5505. prevValue = nextValue;
  5506. mergedSize += nextSelector->queryType()->getSize();
  5507. best = j;
  5508. }
  5509. }
  5510. mergedSizes.append(mergedSize);
  5511. for (;i < best;i++)
  5512. mergedSizes.append(0);
  5513. }
  5514. while ( i < numKeyableFields)
  5515. mergedSizes.append(expandedSelects.item(i).queryType()->getSize());
  5516. }
  5517. //---------------------------------------------------------------------------
  5518. static ABoundActivity * buildNullIndexActivity(HqlCppTranslator & translator, BuildCtx & ctx, IHqlExpression * expr)
  5519. {
  5520. while (isCompoundSource(expr))
  5521. expr = expr->queryChild(0);
  5522. return translator.buildCachedActivity(ctx, expr);
  5523. }
  5524. class IndexReadBuilderBase : public SourceBuilder
  5525. {
  5526. friend class MonitorRemovalTransformer;
  5527. public:
  5528. IndexReadBuilderBase(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  5529. : SourceBuilder(_translator, _tableExpr, _nameExpr), monitors(_tableExpr, _translator, -(int)numPayloadFields(_tableExpr), false)
  5530. {
  5531. fpos.setown(getFilepos(tableExpr, false));
  5532. lfpos.setown(getFilepos(tableExpr, true));
  5533. }
  5534. virtual void buildMembers(IHqlExpression * expr);
  5535. virtual void extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds);
  5536. protected:
  5537. virtual void buildFlagsMember(IHqlExpression * expr);
  5538. virtual void buildTransformFpos(BuildCtx & transformCtx)
  5539. {
  5540. associateFilePositions(transformCtx, "fpp", "left");
  5541. }
  5542. IHqlExpression * removeMonitors(IHqlExpression * expr);
  5543. protected:
  5544. MonitorExtractor monitors;
  5545. SourceSteppingInfo steppingInfo;
  5546. };
  5547. void IndexReadBuilderBase::buildMembers(IHqlExpression * expr)
  5548. {
  5549. //---- virtual void createSegmentMonitors(struct IIndexReadContext *) { ... } ----
  5550. BuildCtx createSegmentCtx(instance->startctx);
  5551. createSegmentCtx.addQuotedCompoundLiteral("virtual void createSegmentMonitors(IIndexReadContext *irc)");
  5552. monitors.buildSegments(createSegmentCtx, "irc", false);
  5553. buildLimits(instance->startctx, expr, instance->activityId);
  5554. if (!limitExpr && !keyedLimitExpr && !choosenValue && (instance->kind == TAKindexread || instance->kind == TAKindexnormalize) && !steppedExpr)
  5555. {
  5556. unsigned implicitLimit = translator.getDefaultImplicitIndexReadLimit();
  5557. if (translator.checkIndexReadLimit())
  5558. {
  5559. StringBuffer keyname;
  5560. if (implicitLimit)
  5561. translator.WARNINGAT2(CategoryLimit, queryLocation(expr), HQLWRN_ImplicitReadAddLimit, implicitLimit, monitors.queryKeyName(keyname));
  5562. else
  5563. translator.WARNINGAT1(CategoryLimit, queryLocation(expr), HQLWRN_ImplicitReadLimit, monitors.queryKeyName(keyname));
  5564. }
  5565. if (implicitLimit)
  5566. {
  5567. OwnedHqlExpr limit = getSizetConstant(implicitLimit);
  5568. translator.buildLimitHelpers(instance->startctx, limit, NULL, false, nameExpr, instance->activityId);
  5569. }
  5570. }
  5571. instance->addAttributeBool("preload", isPreloaded);
  5572. if (translator.getTargetClusterType() == RoxieCluster)
  5573. instance->addAttributeBool("_isIndexOpt", tableExpr->hasAttribute(optAtom));
  5574. if (monitors.queryGlobalGuard())
  5575. translator.doBuildBoolFunction(instance->startctx, "canMatchAny", monitors.queryGlobalGuard());
  5576. buildKeyedLimitHelper(expr);
  5577. translator.buildFormatCrcFunction(instance->classctx, "getFormatCrc", tableExpr, tableExpr, 1);
  5578. IHqlExpression * originalKey = queryAttributeChild(tableExpr, _original_Atom, 0);
  5579. translator.buildSerializedLayoutMember(instance->classctx, originalKey->queryRecord(), "getIndexLayout", numKeyedFields(originalKey));
  5580. //Note the helper base class contains code like the following
  5581. //IThorIndexCallback * fpp;");
  5582. //virtual void setCallback(IThorIndexCallback * _tc) { fpp = _tc; }");
  5583. }
  5584. void IndexReadBuilderBase::buildFlagsMember(IHqlExpression * expr)
  5585. {
  5586. StringBuffer flags;
  5587. if (tableExpr->hasAttribute(sortedAtom))
  5588. flags.append("|TIRsorted");
  5589. else if (!isOrdered(tableExpr))
  5590. flags.append("|TIRunordered");
  5591. if (!monitors.isFiltered())
  5592. flags.append("|TIRnofilter");
  5593. if (isPreloaded)
  5594. flags.append("|TIRpreload");
  5595. if (tableExpr->hasAttribute(optAtom))
  5596. flags.append("|TIRoptional");
  5597. if (limitExpr && limitExpr->hasAttribute(skipAtom))
  5598. flags.append("|TIRlimitskips");
  5599. if (limitExpr && limitExpr->hasAttribute(onFailAtom))
  5600. flags.append("|TIRlimitcreates");
  5601. if (generateUnfilteredTransform)
  5602. flags.append("|TIRunfilteredtransform");
  5603. if (keyedLimitExpr)
  5604. {
  5605. if (keyedLimitExpr->hasAttribute(onFailAtom))
  5606. flags.append("|TIRkeyedlimitcreates|TIRcountkeyedlimit");
  5607. else if (keyedLimitExpr->hasAttribute(skipAtom))
  5608. flags.append("|TIRkeyedlimitskips|TIRcountkeyedlimit");
  5609. else if (keyedLimitExpr->hasAttribute(countAtom))
  5610. flags.append("|TIRcountkeyedlimit");
  5611. }
  5612. IHqlExpression * firstStepped = steppingInfo.firstStepped();
  5613. if (firstStepped && monitors.isEqualityFilterBefore(firstStepped))
  5614. flags.append("|TIRstepleadequality");
  5615. if (onlyExistsAggreate) flags.append("|TIRaggregateexists");
  5616. if (monitorsForGrouping) flags.append("|TIRgroupmonitors");
  5617. if (!nameExpr->isConstant()) flags.append("|TIRvarfilename");
  5618. if (translator.hasDynamicFilename(tableExpr)) flags.append("|TIRdynamicfilename");
  5619. if (requiresOrderedMerge) flags.append("|TIRorderedmerge");
  5620. if (flags.length())
  5621. translator.doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  5622. }
  5623. void IndexReadBuilderBase::extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds)
  5624. {
  5625. OwnedHqlExpr extraFilter;
  5626. monitors.extractFilters(conds, extraFilter);
  5627. appendFilter(unkeyedFilter, extraFilter);
  5628. }
  5629. class MonitorRemovalTransformer : public HqlMapTransformer
  5630. {
  5631. public:
  5632. MonitorRemovalTransformer(IndexReadBuilderBase & _builder) : builder(_builder) {}
  5633. virtual IHqlExpression * createTransformed(IHqlExpression * expr);
  5634. protected:
  5635. IndexReadBuilderBase & builder;
  5636. };
  5637. IHqlExpression * MonitorRemovalTransformer::createTransformed(IHqlExpression * expr)
  5638. {
  5639. switch (expr->getOperator())
  5640. {
  5641. case no_filter:
  5642. {
  5643. IHqlExpression * ds = expr->queryChild(0);
  5644. IHqlExpression * body = expr->queryBody();
  5645. unsigned match = builder.originalFilters.find(*body);
  5646. if (match == NotFound)
  5647. {
  5648. if (builder.removedFilters.find(*body))
  5649. return transform(ds);
  5650. return NewHqlTransformer::createTransformed(expr);
  5651. }
  5652. IHqlExpression & newFilter = builder.mappedFilters.item(match);
  5653. HqlExprArray args;
  5654. args.append(*transform(ds));
  5655. args.append(*transform(&newFilter));
  5656. return expr->clone(args);
  5657. }
  5658. }
  5659. return NewHqlTransformer::createTransformed(expr);
  5660. }
  5661. IHqlExpression * IndexReadBuilderBase::removeMonitors(IHqlExpression * expr)
  5662. {
  5663. MonitorRemovalTransformer mapper(*this);
  5664. mapper.setMapping(tableExpr, tableExpr);
  5665. return mapper.transformRoot(expr);
  5666. }
  5667. //---------------------------------------------------------------------------
  5668. class NewIndexReadBuilder : public IndexReadBuilderBase
  5669. {
  5670. public:
  5671. NewIndexReadBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  5672. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  5673. {
  5674. }
  5675. virtual void analyseGraph(IHqlExpression * expr)
  5676. {
  5677. IndexReadBuilderBase::analyseGraph(expr);
  5678. gatherSteppingMeta(expr, steppingInfo);
  5679. if (steppedExpr && transformCanFilter && translator.queryOptions().optimizeSteppingPostfilter)
  5680. {
  5681. //If sorted, but can't step output no point in duplicating the transform
  5682. if (steppingInfo.outputStepping.exists())
  5683. generateUnfilteredTransform = true;
  5684. }
  5685. returnIfFilterFails = !isNormalize;
  5686. }
  5687. virtual void buildTransform(IHqlExpression * expr);
  5688. virtual void buildMembers(IHqlExpression * expr);
  5689. };
  5690. void NewIndexReadBuilder::buildMembers(IHqlExpression * expr)
  5691. {
  5692. if (steppingInfo.exists())
  5693. {
  5694. steppingInfo.checkKeyable(monitors);
  5695. monitors.preventMerge(steppingInfo.firstStepped());
  5696. }
  5697. buildReadMembers(expr);
  5698. if (steppingInfo.exists())
  5699. steppingInfo.generateMembers(translator, instance->classctx);
  5700. IndexReadBuilderBase::buildMembers(expr);
  5701. }
  5702. void NewIndexReadBuilder::buildTransform(IHqlExpression * expr)
  5703. {
  5704. if (true)
  5705. {
  5706. BuildCtx transformCtx(instance->startctx);
  5707. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  5708. translator.ensureRowAllocated(transformCtx, "crSelf");
  5709. transformCtx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  5710. translator.associateBlobHelper(transformCtx, tableExpr, "fpp");
  5711. buildTransformBody(transformCtx, expr, true, false, true);
  5712. }
  5713. if (generateUnfilteredTransform)
  5714. {
  5715. BuildCtx transformCtx(instance->startctx);
  5716. transformCtx.addQuotedCompoundLiteral("virtual size32_t unfilteredTransform(ARowBuilder & crSelf, const void * _left)");
  5717. translator.ensureRowAllocated(transformCtx, "crSelf");
  5718. transformCtx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  5719. translator.associateBlobHelper(transformCtx, tableExpr, "fpp");
  5720. buildTransformBody(transformCtx, expr, true, true, true);
  5721. }
  5722. }
  5723. //---------------------------------------------------------------------------
  5724. ABoundActivity * HqlCppTranslator::doBuildActivityIndexRead(BuildCtx & ctx, IHqlExpression * expr)
  5725. {
  5726. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  5727. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, HOOfold);
  5728. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  5729. //If the filter is false, then it may get reduced to a NULL operation!
  5730. if (!tableExpr)
  5731. return buildNullIndexActivity(*this, ctx, optimized);
  5732. ensureDiskAccessAllowed(tableExpr);
  5733. if (optimized->getOperator() != no_compound_indexread)
  5734. optimized.setown(createDataset(no_compound_indexread, LINK(optimized)));
  5735. traceExpression("before index read", optimized);
  5736. assertex(tableExpr->getOperator() == no_newkeyindex);
  5737. NewIndexReadBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  5738. info.gatherVirtualFields(true, true);
  5739. if (info.containsStepping(optimized))
  5740. return info.buildActivity(ctx, optimized, TAKindexread, "SteppedIndexRead", NULL);
  5741. return info.buildActivity(ctx, optimized, TAKindexread, "IndexRead", NULL);
  5742. }
  5743. //---------------------------------------------------------------------------
  5744. class IndexNormalizeBuilder : public IndexReadBuilderBase
  5745. {
  5746. public:
  5747. IndexNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  5748. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  5749. {
  5750. }
  5751. virtual void buildTransform(IHqlExpression * expr);
  5752. virtual void buildMembers(IHqlExpression * expr);
  5753. protected:
  5754. virtual void analyseGraph(IHqlExpression * expr);
  5755. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  5756. {
  5757. doBuildNormalizeIterators(ctx, expr, false);
  5758. }
  5759. };
  5760. void IndexNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  5761. {
  5762. IndexReadBuilderBase::analyseGraph(expr);
  5763. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  5764. }
  5765. void IndexNormalizeBuilder::buildMembers(IHqlExpression * expr)
  5766. {
  5767. buildFilenameMember();
  5768. IndexReadBuilderBase::buildMembers(expr);
  5769. buildNormalizeHelpers(expr);
  5770. }
  5771. void IndexNormalizeBuilder::buildTransform(IHqlExpression * expr)
  5772. {
  5773. globaliterctx.setown(new BuildCtx(instance->startctx));
  5774. globaliterctx->addGroup();
  5775. BuildCtx transformCtx(instance->startctx);
  5776. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf)");
  5777. translator.ensureRowAllocated(transformCtx, "crSelf");
  5778. //Because this transform creates iterator classes for the child iterators the expression tree needs to be modified
  5779. //instead of using an inline tests. We could switch to using this all the time for indexes once I trust it!
  5780. OwnedHqlExpr simplified = removeMonitors(expr);
  5781. lastTransformer.set(queryExpression(simplified->queryDataset()->queryTable()));
  5782. useFilterMappings=false;
  5783. buildTransformBody(transformCtx, simplified, true, false, false);
  5784. }
  5785. //---------------------------------------------------------------------------
  5786. ABoundActivity * HqlCppTranslator::doBuildActivityIndexNormalize(BuildCtx & ctx, IHqlExpression * expr)
  5787. {
  5788. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  5789. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, HOOfold);
  5790. traceExpression("after optimize", optimized);
  5791. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  5792. if (!tableExpr)
  5793. return buildNullIndexActivity(*this, ctx, optimized);
  5794. ensureDiskAccessAllowed(tableExpr);
  5795. assertex(tableExpr->getOperator() == no_newkeyindex);
  5796. IndexNormalizeBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  5797. info.gatherVirtualFields(true, true);
  5798. return info.buildActivity(ctx, optimized, TAKindexnormalize, "IndexNormalize", NULL);
  5799. }
  5800. //---------------------------------------------------------------------------
  5801. class IndexAggregateBuilder : public IndexReadBuilderBase
  5802. {
  5803. public:
  5804. IndexAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  5805. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  5806. {
  5807. failedFilterValue.clear();
  5808. }
  5809. virtual void buildTransform(IHqlExpression * expr);
  5810. virtual void buildMembers(IHqlExpression * expr);
  5811. protected:
  5812. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  5813. {
  5814. doBuildAggregateSelectIterator(ctx, expr);
  5815. }
  5816. virtual void analyseGraph(IHqlExpression * expr)
  5817. {
  5818. IndexReadBuilderBase::analyseGraph(expr);
  5819. returnIfFilterFails = !isNormalize;
  5820. }
  5821. };
  5822. void IndexAggregateBuilder::buildMembers(IHqlExpression * expr)
  5823. {
  5824. StringBuffer s;
  5825. buildFilenameMember();
  5826. IndexReadBuilderBase::buildMembers(expr);
  5827. buildAggregateHelpers(expr);
  5828. //virtual void processRow(void * self, const void * src) = 0;
  5829. BuildCtx rowctx(instance->startctx);
  5830. rowctx.addQuotedCompoundLiteral("virtual void processRow(ARowBuilder & crSelf, const void * src)");
  5831. rowctx.addQuotedLiteral("doProcessRow(crSelf, (byte *)src);");
  5832. //virtual void processRows(void * self, size32_t srcLen, const void * src) = 0;
  5833. BuildCtx rowsctx(instance->startctx);
  5834. rowsctx.addQuotedCompoundLiteral("virtual void processRows(ARowBuilder & crSelf, size32_t srcLen, const void * _left)");
  5835. rowsctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  5836. OwnedHqlExpr ds = createVariable("left", makeReferenceModifier(tableExpr->getType()));
  5837. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  5838. OwnedHqlExpr fullDs = createTranslated(ds, len);
  5839. Owned<IHqlCppDatasetCursor> iter = translator.createDatasetSelector(rowsctx, fullDs);
  5840. BoundRow * curRow = iter->buildIterateLoop(rowsctx, false);
  5841. s.clear().append("doProcessRow(crSelf, ");
  5842. translator.generateExprCpp(s, curRow->queryBound());
  5843. s.append(");");
  5844. rowsctx.addQuoted(s);
  5845. }
  5846. void IndexAggregateBuilder::buildTransform(IHqlExpression * expr)
  5847. {
  5848. BuildCtx transformCtx(instance->startctx);
  5849. transformCtx.addQuotedCompoundLiteral("void doProcessRow(ARowBuilder & crSelf, byte * left)");
  5850. translator.ensureRowAllocated(transformCtx, "crSelf");
  5851. translator.associateBlobHelper(transformCtx, tableExpr, "fpp");
  5852. buildTransformBody(transformCtx, expr, false, false, true);
  5853. }
  5854. //---------------------------------------------------------------------------
  5855. class IndexCountBuilder : public IndexReadBuilderBase
  5856. {
  5857. public:
  5858. IndexCountBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, node_operator _aggOp)
  5859. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  5860. {
  5861. aggOp = _aggOp;
  5862. isCompoundCount = true;
  5863. failedFilterValue.set(queryZero());
  5864. }
  5865. virtual void buildTransform(IHqlExpression * expr);
  5866. virtual void buildMembers(IHqlExpression * expr);
  5867. virtual bool isExplicitExists() { return (aggOp == no_existsgroup); }
  5868. protected:
  5869. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  5870. {
  5871. doBuildAggregateSelectIterator(ctx, expr);
  5872. }
  5873. virtual void analyseGraph(IHqlExpression * expr)
  5874. {
  5875. IndexReadBuilderBase::analyseGraph(expr);
  5876. returnIfFilterFails = !isNormalize;
  5877. IHqlExpression * aggregate = expr->queryChild(0);
  5878. if (isKeyedCountAggregate(aggregate))
  5879. {
  5880. if (isNormalize)
  5881. translator.throwError(HQLERR_KeyedCountCantNormalize);
  5882. if (!monitors.isKeyedExplicitly())
  5883. translator.throwError(HQLERR_KeyedCountNotKeyed);
  5884. if (transformCanFilter)
  5885. {
  5886. ForEachItemIn(i, originalFilters)
  5887. removedFilters.append(OLINK(originalFilters.item(i)));
  5888. originalFilters.kill();
  5889. mappedFilters.kill();
  5890. transformCanFilter = false;
  5891. }
  5892. }
  5893. if (aggOp == no_existsgroup)
  5894. choosenValue.setown(getSizetConstant(1));
  5895. }
  5896. protected:
  5897. node_operator aggOp;
  5898. };
  5899. void IndexCountBuilder::buildMembers(IHqlExpression * expr)
  5900. {
  5901. buildFilenameMember();
  5902. IndexReadBuilderBase::buildMembers(expr);
  5903. buildCountHelpers(expr, false);
  5904. }
  5905. void IndexCountBuilder::buildTransform(IHqlExpression * expr)
  5906. {
  5907. if (transformCanFilter||isNormalize)
  5908. {
  5909. BuildCtx transformCtx(instance->startctx);
  5910. transformCtx.addQuotedCompoundLiteral("virtual size32_t numValid(const void * _left)");
  5911. transformCtx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  5912. translator.associateBlobHelper(transformCtx, tableExpr, "fpp");
  5913. OwnedHqlExpr cnt;
  5914. if (isNormalize)
  5915. {
  5916. compoundCountVar.setown(transformCtx.getTempDeclare(sizetType, queryZero()));
  5917. cnt.set(compoundCountVar);
  5918. }
  5919. else
  5920. cnt.setown(getSizetConstant(1));
  5921. BuildCtx subctx(transformCtx);
  5922. buildTransformBody(subctx, expr, false, false, true);
  5923. transformCtx.addReturn(cnt);
  5924. }
  5925. }
  5926. //---------------------------------------------------------------------------
  5927. ABoundActivity * HqlCppTranslator::doBuildActivityIndexAggregate(BuildCtx & ctx, IHqlExpression * expr)
  5928. {
  5929. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  5930. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags());
  5931. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  5932. if (!tableExpr)
  5933. return buildNullIndexActivity(*this, ctx, optimized);
  5934. ensureDiskAccessAllowed(tableExpr);
  5935. assertex(tableExpr->getOperator() == no_newkeyindex);
  5936. node_operator aggOp = querySimpleAggregate(expr, true, false);
  5937. if (aggOp == no_countgroup || aggOp == no_existsgroup)
  5938. {
  5939. IndexCountBuilder info(*this, tableExpr, tableExpr->queryChild(3), aggOp);
  5940. info.gatherVirtualFields(true, true);
  5941. return info.buildActivity(ctx, optimized, TAKindexcount, "IndexCount", NULL);
  5942. }
  5943. else
  5944. {
  5945. IndexAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  5946. info.gatherVirtualFields(true, true);
  5947. return info.buildActivity(ctx, optimized, TAKindexaggregate, "IndexAggregate", NULL);
  5948. }
  5949. }
  5950. //---------------------------------------------------------------------------
  5951. class IndexGroupAggregateBuilder : public IndexReadBuilderBase
  5952. {
  5953. public:
  5954. IndexGroupAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  5955. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  5956. {
  5957. failedFilterValue.clear();
  5958. transformAccessesCallback = false;
  5959. }
  5960. virtual void buildTransform(IHqlExpression * expr);
  5961. virtual void buildMembers(IHqlExpression * expr);
  5962. protected:
  5963. void doBuildProcessCountMembers(BuildCtx & ctx, IHqlExpression * aggregate);
  5964. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  5965. {
  5966. doBuildAggregateSelectIterator(ctx, expr);
  5967. }
  5968. virtual void analyseGraph(IHqlExpression * expr)
  5969. {
  5970. IndexReadBuilderBase::analyseGraph(expr);
  5971. returnIfFilterFails = !isNormalize;
  5972. }
  5973. protected:
  5974. bool transformAccessesCallback;
  5975. };
  5976. void IndexGroupAggregateBuilder::buildMembers(IHqlExpression * expr)
  5977. {
  5978. transformAccessesCallback = containsOperator(expr, no_filepos) || containsOperator(expr, no_id2blob);
  5979. buildFilenameMember();
  5980. buildGroupingMonitors(expr, monitors);
  5981. IndexReadBuilderBase::buildMembers(expr);
  5982. buildGlobalGroupAggregateHelpers(expr);
  5983. if (!isNormalize && !transformCanFilter && monitorsForGrouping && !transformAccessesCallback)
  5984. {
  5985. IHqlExpression * aggregate = expr->queryChild(0);
  5986. ThorActivityKind newKind = TAKnone;
  5987. switch (querySingleAggregate(aggregate, false, true, true))
  5988. {
  5989. case no_countgroup:
  5990. newKind = TAKindexgroupcount;
  5991. break;
  5992. case no_existsgroup:
  5993. newKind = TAKindexgroupexists;
  5994. break;
  5995. }
  5996. if (newKind)
  5997. {
  5998. instance->changeActivityKind(newKind);
  5999. doBuildProcessCountMembers(instance->startctx, aggregate);
  6000. }
  6001. }
  6002. }
  6003. void IndexGroupAggregateBuilder::doBuildProcessCountMembers(BuildCtx & ctx, IHqlExpression * aggregate)
  6004. {
  6005. IHqlExpression * dataset = aggregate->queryChild(0);
  6006. IHqlExpression * tgtRecord = aggregate->queryChild(1);
  6007. IHqlExpression * transform = aggregate->queryChild(2);
  6008. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  6009. {
  6010. BuildCtx funcctx(ctx);
  6011. funcctx.addQuotedCompoundLiteral("virtual size32_t initialiseCountGrouping(ARowBuilder & crSelf, const void * _src)");
  6012. translator.ensureRowAllocated(funcctx, "crSelf");
  6013. funcctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  6014. translator.associateBlobHelper(funcctx, tableExpr, "fpp");
  6015. BoundRow * selfCursor = translator.bindSelf(funcctx, resultDataset, "crSelf");
  6016. translator.bindTableCursor(funcctx, dataset, "src");
  6017. //Replace count() with 0, exists() with true and call as a transform - which will error if the replacement fails.
  6018. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType));
  6019. OwnedHqlExpr exists = createValue(no_existsgroup, makeBoolType());
  6020. OwnedHqlExpr newCount = createNullExpr(count);
  6021. OwnedHqlExpr newTransform = replaceExpression(transform, count, newCount);
  6022. newTransform.setown(replaceExpression(newTransform, exists, queryBoolExpr(true)));
  6023. translator.doTransform(funcctx, newTransform, selfCursor);
  6024. translator.buildReturnRecordSize(funcctx, selfCursor);
  6025. }
  6026. {
  6027. BuildCtx funcctx(ctx);
  6028. funcctx.addQuotedCompoundLiteral("virtual size32_t processCountGrouping(ARowBuilder & crSelf, unsigned __int64 count)");
  6029. translator.ensureRowAllocated(funcctx, "crSelf");
  6030. BoundRow * selfCursor = translator.bindSelf(funcctx, resultDataset, "crSelf");
  6031. OwnedHqlExpr newCount = createTranslatedOwned(createVariable("count", LINK(defaultIntegralType)));
  6032. OwnedHqlExpr self = getSelf(aggregate);
  6033. ForEachChild(idx, transform)
  6034. {
  6035. IHqlExpression * cur = transform->queryChild(idx);
  6036. if (cur->isAttribute())
  6037. continue;
  6038. OwnedHqlExpr target = selfCursor->bindToRow(cur->queryChild(0), self);
  6039. IHqlExpression * src = cur->queryChild(1);
  6040. IHqlExpression * arg = queryRealChild(src, 0);
  6041. BuildCtx condctx(funcctx);
  6042. node_operator srcOp = src->getOperator();
  6043. switch (srcOp)
  6044. {
  6045. case no_countgroup:
  6046. {
  6047. if (arg)
  6048. translator.buildFilter(condctx, arg);
  6049. OwnedHqlExpr newValue = createValue(no_add, target->getType(), LINK(target), ensureExprType(newCount, target->queryType()));
  6050. translator.buildAssign(condctx, target, newValue);
  6051. }
  6052. break;
  6053. }
  6054. }
  6055. translator.buildReturnRecordSize(funcctx, selfCursor);
  6056. }
  6057. }
  6058. void IndexGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
  6059. {
  6060. BuildCtx transformCtx(instance->startctx);
  6061. transformCtx.addQuotedCompoundLiteral("void doProcessRow(byte * left, IHThorGroupAggregateCallback * callback)");
  6062. translator.associateBlobHelper(transformCtx, tableExpr, "fpp");
  6063. buildGroupAggregateTransformBody(transformCtx, expr, isNormalize || transformAccessesCallback, true);
  6064. }
  6065. //---------------------------------------------------------------------------
  6066. ABoundActivity * HqlCppTranslator::doBuildActivityIndexGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
  6067. {
  6068. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  6069. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags());
  6070. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  6071. if (!tableExpr)
  6072. return buildNullIndexActivity(*this, ctx, optimized);
  6073. ensureDiskAccessAllowed(tableExpr);
  6074. IHqlExpression * aggregate = expr->queryChild(0);
  6075. assertex(aggregate->getOperator() == no_newaggregate || aggregate->getOperator() == no_aggregate);
  6076. ThorActivityKind tak = TAKindexgroupaggregate;
  6077. assertex(tableExpr->getOperator() == no_newkeyindex);
  6078. IndexGroupAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  6079. info.gatherVirtualFields(true, true);
  6080. return info.buildActivity(ctx, optimized, tak, "IndexGroupAggregate", NULL);
  6081. }
  6082. //---------------------------------------------------------------------------
  6083. void associateVirtualCallbacks(HqlCppTranslator & translator, BuildCtx & ctx, IHqlExpression * dataset)
  6084. {
  6085. OwnedHqlExpr fpos = getFilepos(dataset, false);
  6086. OwnedHqlExpr lfpos = getFilepos(dataset, true);
  6087. Owned<IHqlExpression> fposExpr = createFileposCall(translator, getFilePositionId, "fpp", "crSelf.row()");
  6088. Owned<IHqlExpression> lfposExpr = createFileposCall(translator, getLocalFilePositionId, "fpp", "crSelf.row()");
  6089. ctx.associateExpr(fpos, fposExpr);
  6090. ctx.associateExpr(lfpos, lfposExpr);
  6091. }
  6092. void HqlCppTranslator::buildXmlReadTransform(IHqlExpression * dataset, StringBuffer & factoryName, bool & usesContents)
  6093. {
  6094. OwnedHqlExpr xmlMarker = createAttribute(xmlReadMarkerAtom, LINK(dataset->queryRecord()));
  6095. BuildCtx declarectx(*code, declareAtom);
  6096. HqlExprAssociation * match = declarectx.queryMatchExpr(xmlMarker);
  6097. if (match)
  6098. {
  6099. IHqlExpression * matchExpr = match->queryExpr();
  6100. matchExpr->queryChild(0)->queryValue()->getStringValue(factoryName);
  6101. usesContents = matchExpr->queryChild(1)->queryValue()->getBoolValue();
  6102. return;
  6103. }
  6104. StringBuffer s, id, className;
  6105. getUniqueId(id);
  6106. className.append("cx2r").append(id);
  6107. const char * interfaceName = "IXmlToRowTransformer";
  6108. StringBuffer prolog, epilog;
  6109. prolog.append("struct ").append(className).append(" : public RtlCInterface, implements ").append(interfaceName);
  6110. epilog.append(";");
  6111. GlobalClassBuilder builder(*this, declarectx, className, "CXmlToRowTransformer", interfaceName);
  6112. builder.buildClass(XmlTransformerPrio);
  6113. builder.setIncomplete(true);
  6114. BuildCtx & classctx = builder.classctx;
  6115. s.clear().append("inline ").append(className).append("(unsigned _activityId) : CXmlToRowTransformer(_activityId) {}");
  6116. classctx.addQuoted(s);
  6117. BuildCtx funcctx(classctx);
  6118. funcctx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, IColumnProvider * row, IThorDiskCallback * fpp)");
  6119. ensureRowAllocated(funcctx, "crSelf");
  6120. xmlUsesContents = false;
  6121. //MORE: If this becomes a compound activity
  6122. BoundRow * rootSelfRow = bindSelf(funcctx, dataset, "crSelf");
  6123. bindXmlTableCursor(funcctx, dataset, "row", no_none, NULL, true);
  6124. OwnedHqlExpr activityId = createVariable("activityId", LINK(sizetType));
  6125. funcctx.associateExpr(queryActivityIdMarker(), activityId);
  6126. associateVirtualCallbacks(*this, funcctx, dataset);
  6127. OwnedHqlExpr active = ensureActiveRow(dataset);
  6128. buildAssign(funcctx, rootSelfRow->querySelector(), active);
  6129. buildReturnRecordSize(funcctx, rootSelfRow);
  6130. usesContents = xmlUsesContents;
  6131. rootSelfRow = NULL;
  6132. buildMetaMember(classctx, dataset, false, "queryRecordSize");
  6133. builder.setIncomplete(false);
  6134. builder.completeClass(XmlTransformerPrio);
  6135. factoryName.append(builder.accessorName);
  6136. OwnedHqlExpr matchedValue = createAttribute(internalAtom, createConstant(factoryName.str()), createConstant(usesContents));
  6137. declarectx.associateExpr(xmlMarker, matchedValue);
  6138. }
  6139. //---------------------------------------------------------------------------
  6140. unsigned HqlCppTranslator::buildCsvReadTransform(BuildCtx & subctx, IHqlExpression * dataset, bool newInterface, IHqlExpression * csvAttr)
  6141. {
  6142. BuildCtx funcctx(subctx);
  6143. if (newInterface)
  6144. funcctx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenSrc, const char * * dataSrc)");
  6145. else
  6146. funcctx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenSrc, const char * * dataSrc, unsigned __int64 _fpos)");
  6147. //MORE: If this becomes a compound activity
  6148. BoundRow * rootSelfRow = bindSelf(funcctx, dataset, "crSelf");
  6149. bindCsvTableCursor(funcctx, dataset, "Src", no_none, NULL, true, queryCsvEncoding(csvAttr));
  6150. ensureRowAllocated(funcctx, rootSelfRow);
  6151. if (newInterface)
  6152. {
  6153. associateVirtualCallbacks(*this, funcctx, dataset);
  6154. }
  6155. else
  6156. {
  6157. OwnedHqlExpr fpos = getFilepos(dataset, false);
  6158. OwnedHqlExpr fposVar = createVariable("_fpos", fpos->getType());
  6159. funcctx.associateExpr(fpos, fposVar);
  6160. }
  6161. OwnedHqlExpr active = ensureActiveRow(dataset);
  6162. buildAssign(funcctx, rootSelfRow->querySelector(), active);
  6163. buildReturnRecordSize(funcctx, rootSelfRow);
  6164. rootSelfRow = NULL;
  6165. return countTotalFields(dataset->queryRecord(), false);
  6166. }
  6167. void HqlCppTranslator::buildCsvReadTransformer(IHqlExpression * dataset, StringBuffer & instanceName, IHqlExpression * optCsvAttr)
  6168. {
  6169. OwnedHqlExpr csvMarker = createAttribute(csvReadMarkerAtom, LINK(dataset->queryRecord()), LINK(optCsvAttr));
  6170. BuildCtx declarectx(*code, declareAtom);
  6171. HqlExprAssociation * match = declarectx.queryMatchExpr(csvMarker);
  6172. if (match)
  6173. {
  6174. IHqlExpression * matchExpr = match->queryExpr();
  6175. matchExpr->queryChild(0)->queryValue()->getStringValue(instanceName);
  6176. return;
  6177. }
  6178. StringBuffer id, className;
  6179. getUniqueId(id);
  6180. instanceName.append("c2r").append(id);
  6181. className.append("cc2r").append(id);
  6182. StringBuffer prolog, epilog;
  6183. prolog.append("struct ").append(className).append(" : public RtlCInterface, implements ICsvToRowTransformer");
  6184. epilog.append(" ").append(instanceName).append(";");
  6185. BuildCtx classctx(declarectx);
  6186. classctx.setNextPriority(XmlTransformerPrio);
  6187. IHqlStmt * transformClass = classctx.addQuotedCompound(prolog, epilog);
  6188. transformClass->setIncomplete(true);
  6189. transformClass->setIncluded(false); // if can't generate csv for this record, then don't generate an invalid class.
  6190. classctx.addQuotedLiteral("virtual void Link() const { RtlCInterface::Link(); }");
  6191. classctx.addQuotedLiteral("virtual bool Release() const { return RtlCInterface::Release(); }");
  6192. unsigned maxColumns = buildCsvReadTransform(classctx, dataset, false, optCsvAttr);
  6193. doBuildUnsignedFunction(classctx, "getMaxColumns", maxColumns);
  6194. buildMetaMember(classctx, dataset, false, "queryRecordSize");
  6195. buildCsvParameters(classctx, optCsvAttr, NULL, true);
  6196. transformClass->setIncomplete(false);
  6197. transformClass->setIncluded(true);
  6198. if (options.spanMultipleCpp)
  6199. {
  6200. StringBuffer helperFunc;
  6201. createAccessFunctions(helperFunc, declarectx, XmlTransformerPrio, "ICsvToRowTransformer", instanceName.str());
  6202. instanceName.clear().append(helperFunc).append("()");
  6203. }
  6204. OwnedHqlExpr matchedValue = createAttribute(internalAtom, createConstant(instanceName.str()));
  6205. declarectx.associateExpr(csvMarker, matchedValue);
  6206. }
  6207. ABoundActivity * HqlCppTranslator::doBuildActivityXmlRead(BuildCtx & ctx, IHqlExpression * expr)
  6208. {
  6209. IHqlExpression * tableExpr = expr;
  6210. ensureDiskAccessAllowed(tableExpr);
  6211. IHqlExpression * filename = tableExpr->queryChild(0);
  6212. IHqlExpression * mode = tableExpr->queryChild(2);
  6213. node_operator modeType = mode->getOperator();
  6214. StringBuffer s;
  6215. ThorActivityKind kind = (modeType == no_json) ? TAKjsonread : TAKxmlread;
  6216. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "XmlRead");
  6217. buildActivityFramework(instance);
  6218. buildInstancePrefix(instance);
  6219. //MORE: Improve when we support projecting xml instead of reading all
  6220. SourceFieldUsage * fieldUsage = querySourceFieldUsage(tableExpr);
  6221. if (fieldUsage && !fieldUsage->seenAll())
  6222. fieldUsage->noteAll();
  6223. //---- virtual const char * getFileName() { return "x.d00"; } ----
  6224. buildFilenameFunction(*instance, instance->startctx, "getFileName", filename, hasDynamicFilename(tableExpr));
  6225. buildEncryptHelper(instance->startctx, tableExpr->queryAttribute(encryptAtom));
  6226. bool usesContents = false;
  6227. doBuildXmlReadMember(*instance, tableExpr, "queryTransformer", usesContents);
  6228. doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryRealChild(mode, 0));
  6229. buildMetaMember(instance->classctx, tableExpr, false, "queryDiskRecordSize"); // A lie, but I don't care....
  6230. //virtual unsigned getFlags() = 0;
  6231. StringBuffer flags;
  6232. if (expr->hasAttribute(_spill_Atom)) flags.append("|TDXtemporary");
  6233. if (expr->hasAttribute(unsortedAtom)) flags.append("|TDRunsorted");
  6234. if (expr->hasAttribute(optAtom)) flags.append("|TDRoptional");
  6235. if (usesContents) flags.append("|TDRusexmlcontents");
  6236. if (mode->hasAttribute(noRootAtom)) flags.append("|TDRxmlnoroot");
  6237. if (!filename->isConstant()) flags.append("|TDXvarfilename");
  6238. if (hasDynamicFilename(expr)) flags.append("|TDXdynamicfilename");
  6239. if (flags.length())
  6240. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  6241. //Note the helper base class contains code like the following
  6242. //IThorDiskCallback * fpp;");
  6243. //virtual void setCallback(IThorDiskCallback * _tc) { fpp = _tc; }");
  6244. buildInstanceSuffix(instance);
  6245. addFileDependency(filename, instance->queryBoundActivity());
  6246. return instance->getBoundActivity();
  6247. }
  6248. //---------------------------------------------------------------------------
  6249. ABoundActivity * HqlCppTranslator::doBuildActivityTable(BuildCtx & ctx, IHqlExpression * expr)
  6250. {
  6251. node_operator mode = expr->queryChild(2)->getOperator();
  6252. switch (mode)
  6253. {
  6254. case no_thor:
  6255. case no_flat:
  6256. case no_pipe:
  6257. case no_csv:
  6258. return doBuildActivityDiskRead(ctx, expr);
  6259. case no_xml:
  6260. case no_json:
  6261. return doBuildActivityXmlRead(ctx, expr);
  6262. default:
  6263. UNIMPLEMENTED;
  6264. }
  6265. }
  6266. //---------------------------------------------------------------------------
  6267. class FetchBuilder : public SourceBuilder
  6268. {
  6269. public:
  6270. FetchBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, IHqlExpression * _fetchExpr)
  6271. : SourceBuilder(_translator, _tableExpr, _nameExpr)
  6272. {
  6273. compoundExpr.set(_fetchExpr);
  6274. fetchExpr.set(queryFetch(_fetchExpr));
  6275. selSeq.set(querySelSeq(fetchExpr));
  6276. fetchRhs = fetchExpr->queryChild(1);
  6277. memoryRhsRecord = fetchRhs->queryRecord();
  6278. serializedRhsRecord.setown(getSerializedForm(memoryRhsRecord, diskAtom));
  6279. }
  6280. virtual void buildMembers(IHqlExpression * expr);
  6281. virtual void buildTransform(IHqlExpression * expr);
  6282. virtual void buildTransformFpos(BuildCtx & transformCtx);
  6283. protected:
  6284. HqlExprAttr compoundExpr;
  6285. HqlExprAttr fetchExpr;
  6286. HqlExprAttr selSeq;
  6287. HqlExprAttr serializedRhsRecord;
  6288. IHqlExpression * fetchRhs;
  6289. IHqlExpression * memoryRhsRecord;
  6290. };
  6291. void FetchBuilder::buildMembers(IHqlExpression * expr)
  6292. {
  6293. buildReadMembers(expr);
  6294. IHqlExpression * fetch = queryFetch(expr);
  6295. BuildCtx getposctx(instance->startctx);
  6296. getposctx.addQuotedCompoundLiteral("virtual unsigned __int64 extractPosition(const void * _right)");
  6297. getposctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  6298. translator.bindTableCursor(getposctx, fetch->queryChild(1), "right", no_right, selSeq);
  6299. translator.buildReturn(getposctx, fetch->queryChild(2));
  6300. translator.buildEncryptHelper(instance->startctx, tableExpr->queryAttribute(encryptAtom), "getFileEncryptKey");
  6301. //Fetch flags
  6302. StringBuffer flags;
  6303. if (tableExpr->hasAttribute(optAtom))
  6304. flags.append("|FFdatafileoptional");
  6305. if (!nameExpr->isConstant())
  6306. flags.append("|FFvarfilename");
  6307. if (translator.hasDynamicFilename(tableExpr))
  6308. flags.append("|FFdynamicfilename");
  6309. if (flags.length())
  6310. translator.doBuildUnsignedFunction(instance->classctx, "getFetchFlags", flags.str()+1);
  6311. if (tableExpr->hasAttribute(optAtom) && translator.targetRoxie())
  6312. instance->addAttributeBool("_isOpt", true);
  6313. buildLimits(instance->startctx, expr, instance->activityId);
  6314. switch (getDatasetKind(tableExpr))
  6315. {
  6316. case no_csv:
  6317. {
  6318. translator.buildCsvParameters(instance->nestedctx, tableExpr->queryChild(2), NULL, true);
  6319. unsigned maxColumns = getFieldCount(tableExpr->queryRecord());
  6320. StringBuffer s;
  6321. s.clear().append("virtual unsigned getMaxColumns() { return ").append(maxColumns).append("; }");
  6322. instance->classctx.addQuoted(s);
  6323. break;
  6324. }
  6325. case no_xml:
  6326. case no_json:
  6327. {
  6328. // virtual const char * getXmlIteratorPath()
  6329. translator.doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryRealChild(tableExpr->queryChild(2), 0));
  6330. break;
  6331. }
  6332. default:
  6333. translator.buildFormatCrcFunction(instance->classctx, "getDiskFormatCrc", physicalRecord, NULL, 0);
  6334. break;
  6335. }
  6336. if (!containsOnlyLeft(fetch->queryChild(3), true))
  6337. {
  6338. //MORE: Need to change following if we optimize it to only extract the relevant fields.
  6339. instance->classctx.addQuotedLiteral("virtual bool extractAllJoinFields() { return true; }");
  6340. BuildCtx funcctx(instance->startctx);
  6341. funcctx.addQuotedCompoundLiteral("virtual size32_t extractJoinFields(ARowBuilder & crSelf, const void * _left)");
  6342. translator.ensureRowAllocated(funcctx, "crSelf");
  6343. translator.buildRecordSerializeExtract(funcctx, memoryRhsRecord);
  6344. StringBuffer s;
  6345. MetaInstance meta(translator, serializedRhsRecord, false);
  6346. translator.buildMetaInfo(meta);
  6347. instance->classctx.addQuoted(s.clear().append("virtual IOutputMetaData * queryExtractedSize() { return &").append(meta.queryInstanceObject()).append("; }"));
  6348. }
  6349. }
  6350. void FetchBuilder::buildTransform(IHqlExpression * expr)
  6351. {
  6352. translator.xmlUsesContents = false;
  6353. BuildCtx transformCtx(instance->startctx);
  6354. switch (getDatasetKind(tableExpr))
  6355. {
  6356. case no_csv:
  6357. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenLeft, const char * * dataLeft, const void * _right, unsigned __int64 _fpos)");
  6358. transformCtx.addQuotedLiteral("unsigned char * right = (unsigned char *)_right;");
  6359. break;
  6360. case no_xml:
  6361. case no_json:
  6362. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, IColumnProvider * xmlLeft, const void * _right, unsigned __int64 _fpos)");
  6363. transformCtx.addQuotedLiteral("unsigned char * right = (unsigned char *)_right;");
  6364. break;
  6365. default:
  6366. transformCtx.addQuotedCompoundLiteral("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned __int64 _fpos)");
  6367. transformCtx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  6368. transformCtx.addQuotedLiteral("unsigned char * right = (unsigned char *)_right;");
  6369. break;
  6370. }
  6371. translator.ensureRowAllocated(transformCtx, "crSelf");
  6372. buildTransformBody(transformCtx, expr, true, false, true);
  6373. if (translator.xmlUsesContents)
  6374. instance->classctx.addQuotedLiteral("virtual bool requiresContents() { return true; }");
  6375. }
  6376. void FetchBuilder::buildTransformFpos(BuildCtx & transformCtx)
  6377. {
  6378. fpos.setown(createVariable("_fpos", LINK(fposType)));
  6379. //NB: Because the fetch gets merged with the usertable used to project the dataset, the
  6380. //transform contains filepos(LEFT) not filepos(tableExpr)
  6381. OwnedHqlExpr leftSelect = createSelector(no_left, fetchExpr->queryChild(0), selSeq);
  6382. OwnedHqlExpr fposField = getFilepos(leftSelect, false);
  6383. transformCtx.associateExpr(fposField, fpos);
  6384. //MORE: Could possibly support virtual(filename) here
  6385. }
  6386. static HqlTransformerInfo fetchInputReplacerInfo("FetchInputReplacer");
  6387. class FetchInputReplacer : public NewHqlTransformer
  6388. {
  6389. public:
  6390. FetchInputReplacer(IHqlExpression * _newDataset, node_operator side)
  6391. : NewHqlTransformer(fetchInputReplacerInfo)
  6392. {
  6393. newDataset = _newDataset;
  6394. child = (side == no_left) ? 0 : 1;
  6395. }
  6396. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  6397. {
  6398. if (expr->getOperator() == no_fetch)
  6399. return replaceChild(expr, child, newDataset);
  6400. return NewHqlTransformer::createTransformed(expr);
  6401. }
  6402. protected:
  6403. IHqlExpression * newDataset;
  6404. unsigned child;
  6405. };
  6406. IHqlExpression * replaceFetchInput(IHqlExpression * expr, IHqlExpression * newDataset, node_operator side)
  6407. {
  6408. FetchInputReplacer replacer(newDataset, side);
  6409. return replacer.transformRoot(expr);
  6410. }
  6411. ABoundActivity * HqlCppTranslator::doBuildActivityFetch(BuildCtx & ctx, IHqlExpression * expr)
  6412. {
  6413. IHqlExpression *fetch = queryFetch(expr);
  6414. IHqlExpression *tableExpr = queryPhysicalRootTable(fetch->queryChild(0));
  6415. if (!tableExpr)
  6416. throwError(HQLERR_FetchNonDiskfile);
  6417. FetchBuilder info(*this, tableExpr, tableExpr->queryChild(0), expr);
  6418. info.gatherVirtualFields(false, true);//?needToSerializeRecord(mode)
  6419. unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
  6420. if (info.recordHasVirtualsOrDeserialize())
  6421. {
  6422. OwnedHqlExpr projected = createTableWithoutVirtuals(info.fieldInfo, tableExpr);
  6423. //Nasty: We don't want to optimize the rhs, otherwise references get changed!
  6424. //so optimize everything except the rhs, and then add the rhs back in again.
  6425. IHqlExpression * fetchRhs = fetch->queryChild(1);
  6426. OwnedHqlExpr null = createDataset(no_anon, LINK(fetchRhs->queryRecord()));
  6427. OwnedHqlExpr simple = replaceFetchInput(expr, null, no_right);
  6428. OwnedHqlExpr transformed = replaceExpression(simple, tableExpr, projected);
  6429. OwnedHqlExpr optSimple = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  6430. OwnedHqlExpr optimized = replaceFetchInput(optSimple, fetchRhs, no_right);
  6431. return doBuildActivityFetch(ctx, optimized);
  6432. }
  6433. if (getProjectCount(expr) > 1)
  6434. {
  6435. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, optFlags);
  6436. return doBuildActivityFetch(ctx, optimized);
  6437. }
  6438. Owned<ABoundActivity> childActivity = buildCachedActivity(ctx, fetch->queryChild(1));
  6439. node_operator kind = getDatasetKind(tableExpr);
  6440. switch (kind)
  6441. {
  6442. case no_csv:
  6443. return info.buildActivity(ctx, expr, TAKcsvfetch, "CsvFetch", childActivity);
  6444. case no_xml:
  6445. return info.buildActivity(ctx, expr, TAKxmlfetch, "XmlFetch", childActivity);
  6446. case no_json:
  6447. //Note use of "XmlFetch" because we want the code generator to leverage existing xml classes
  6448. return info.buildActivity(ctx, expr, TAKjsonfetch, "XmlFetch", childActivity);
  6449. case no_flat:
  6450. case no_thor:
  6451. return info.buildActivity(ctx, expr, TAKfetch, "Fetch", childActivity);
  6452. }
  6453. throwError1(HQLERR_FetchNotSupportMode, getOpString(kind));
  6454. return NULL;
  6455. }