hqlcppds.cpp 201 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634
  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 "hql.hpp"
  21. #include "hqlthql.hpp"
  22. #include "hqlhtcpp.ipp"
  23. #include "hqlttcpp.ipp"
  24. #include "hqlutil.hpp"
  25. #include "hqlthql.hpp"
  26. #include "hqlpmap.hpp"
  27. #include "hqlattr.hpp"
  28. #include "hqlwcpp.hpp"
  29. #include "hqlcpputil.hpp"
  30. #include "hqltcppc.ipp"
  31. #include "hqlopt.hpp"
  32. #include "hqlfold.hpp"
  33. #include "hqlcerrors.hpp"
  34. #include "hqlcatom.hpp"
  35. #include "hqlresource.hpp"
  36. #include "hqlregex.ipp"
  37. #include "hqlsource.ipp"
  38. #include "hqlcse.ipp"
  39. #include "hqlgraph.ipp"
  40. #include "hqlccommon.hpp"
  41. #include "hqliter.ipp"
  42. #include "hqlinline.hpp"
  43. #include "hqlusage.hpp"
  44. #include "hqlcppds.hpp"
  45. #include "hqlattr.hpp"
  46. #define MAX_FIXED_SIZE_RAW 1024
  47. #define INLINE_TABLE_EXPAND_LIMIT 4
  48. void addGraphIdAttribute(ActivityInstance * instance, BuildCtx & ctx, IHqlExpression * graphId)
  49. {
  50. SubGraphInfo * match = matchActiveGraph(ctx, graphId);
  51. if (!match)
  52. {
  53. StringBuffer graphname;
  54. graphname.append(graphId->queryChild(0)->querySequenceExtra());
  55. throwError1(HQLERR_AccessUnavailableGraph, graphname.str());
  56. }
  57. instance->addAttributeInt("_graphId", match->graphId);
  58. }
  59. //===========================================================================
  60. void HqlCppTranslator::doBuildRowIfBranch(BuildCtx & initctx, BuildCtx & ctx, BoundRow * targetRow, IHqlExpression * branchExpr)
  61. {
  62. IHqlExpression * targetRowExpr = targetRow->queryBound();
  63. Owned<IReferenceSelector> rowSelector = buildNewRow(ctx, branchExpr);
  64. Owned<BoundRow> boundRow = rowSelector->getRow(ctx);
  65. OwnedHqlExpr rowExpr = getPointer(boundRow->queryBound());
  66. OwnedHqlExpr castRow = createValue(no_implicitcast, targetRowExpr->getType(), LINK(rowExpr));
  67. ctx.addAssign(targetRowExpr, castRow);
  68. if (rowSelector->isConditional())
  69. targetRow->setConditional(true);
  70. }
  71. IReferenceSelector * HqlCppTranslator::doBuildRowIf(BuildCtx & ctx, IHqlExpression * expr)
  72. {
  73. OwnedHqlExpr foldedCond = foldHqlExpression(expr->queryChild(0));
  74. if (foldedCond->queryValue())
  75. {
  76. unsigned branch = (foldedCond->queryValue()->getBoolValue()) ? 1 : 2;
  77. return buildNewRow(ctx, expr->queryChild(branch));
  78. }
  79. IHqlExpression * trueBranch = expr->queryChild(1);
  80. IHqlExpression * falseBranch = expr->queryChild(2);
  81. //Ideally should have a constant modifier on the following row...
  82. Owned<ITypeInfo> rowType = makeReferenceModifier(expr->getType());
  83. OwnedHqlExpr rowExpr = ctx.getTempDeclare(rowType, NULL);
  84. Owned<BoundRow> row = createBoundRow(expr->queryBody(), rowExpr);
  85. //MORE: Need casts because cursor may be (probably are) constant, but temporary isn't
  86. //should find out by looking at the a const modifier on the cursor.
  87. BuildCtx condctx(ctx);
  88. IHqlStmt * cond = buildFilterViaExpr(condctx, foldedCond);
  89. //Mark the context as conditional after the filter test, so any temporaries from the filter aren't affected.
  90. condctx.associateExpr(queryConditionalRowMarker(), rowExpr);
  91. doBuildRowIfBranch(ctx, condctx, row, trueBranch);
  92. condctx.selectElse(cond);
  93. condctx.associateExpr(queryConditionalRowMarker(), rowExpr);
  94. doBuildRowIfBranch(ctx, condctx, row, falseBranch);
  95. ctx.associate(*row);
  96. return createReferenceSelector(row);
  97. }
  98. IReferenceSelector * HqlCppTranslator::doBuildRowDeserializeRow(BuildCtx & ctx, IHqlExpression * expr)
  99. {
  100. IHqlExpression * srcRow = expr->queryChild(0);
  101. IHqlExpression * record = expr->queryRecord();
  102. IAtom * serializeForm = expr->queryChild(2)->queryName();
  103. Owned<BoundRow> tempRow = declareLinkedRow(ctx, expr, false);
  104. CHqlBoundTarget target;
  105. target.expr.set(tempRow->queryBound());
  106. HqlExprArray args;
  107. args.append(*createSerializer(ctx, record, serializeForm, deserializerAtom));
  108. args.append(*LINK(srcRow));
  109. Owned<ITypeInfo> resultType = makeReferenceModifier(makeAttributeModifier(makeRowType(record->getType()), getLinkCountedAttr()));
  110. OwnedHqlExpr call = bindFunctionCall(rtlDeserializeRowId, args, resultType);
  111. buildExprAssign(ctx, target, call);
  112. ctx.associate(*tempRow);
  113. return createReferenceSelector(tempRow);
  114. }
  115. void HqlCppTranslator::buildConstRow(IHqlExpression * record, IHqlExpression * rowData, CHqlBoundExpr & bound)
  116. {
  117. OwnedHqlExpr marker = createAttribute(rowAtom, LINK(record), LINK(rowData));
  118. BuildCtx declareCtx(*code, literalAtom);
  119. if (declareCtx.getMatchExpr(marker, bound))
  120. return;
  121. //MORE: This probably needs to go in the header as well...
  122. Owned<ITypeInfo> rowType = makeConstantModifier(makeRowType(record->getType()));
  123. if (options.canLinkConstantRows)
  124. rowType.setown(setLinkCountedAttr(rowType, true));
  125. StringBuffer rowName;
  126. getUniqueId(rowName.append("r"));
  127. //Generate two variables to cope with the different ways the data is interpreted.
  128. //Would prefer it to be cleaner... row value would need an associated size
  129. unsigned dataSize = rowData->queryType()->getSize();
  130. OwnedITypeInfo declareType;
  131. OwnedHqlExpr initializer;
  132. if (options.staticRowsUseStringInitializer)
  133. {
  134. //Generates smaller code (and probably more efficient representation in the c++ compiler
  135. //const byte[5+1] = "Hello"; need an extra byte for the implicit \0
  136. declareType.setown(makeDataType(dataSize+1));
  137. initializer.set(rowData);
  138. }
  139. else
  140. {
  141. //Following is strictly correct, but much larger.
  142. //const byte[5] = { 'H','e','l','l','o' };
  143. declareType.set(rowData->queryType());
  144. initializer.setown(createValue(no_create_initializer, rowData->getType(), LINK(rowData)));
  145. }
  146. //MORE: Currently these are marked as const rows, but not generated as such
  147. OwnedHqlExpr boundDeclare = createVariable(rowName, makeConstantModifier(LINK(declareType)));
  148. OwnedHqlExpr boundRow = createVariable(rowName, LINK(rowType));
  149. declareCtx.addDeclare(boundDeclare, initializer);
  150. if (options.spanMultipleCpp)
  151. {
  152. BuildCtx protoctx(*code, mainprototypesAtom);
  153. protoctx.addDeclareExternal(boundDeclare);
  154. }
  155. bound.length.setown(getSizetConstant(dataSize));
  156. bound.expr.set(boundRow);
  157. declareCtx.associateExpr(marker, bound);
  158. }
  159. bool HqlCppTranslator::doBuildRowConstantTransform(IHqlExpression * transform, CHqlBoundExpr & bound)
  160. {
  161. if (!transform->isConstant() || !options.generateStaticInlineTables)
  162. return false;
  163. OwnedHqlExpr constRow = createConstantRowExpr(transform);
  164. if (!constRow || !canGenerateStringInline(constRow->queryType()->getSize()))
  165. return false;
  166. buildConstRow(transform->queryRecord(), constRow, bound);
  167. return true;
  168. }
  169. IReferenceSelector * HqlCppTranslator::doBuildRowCreateRow(BuildCtx & ctx, IHqlExpression * expr)
  170. {
  171. CHqlBoundExpr bound;
  172. if (!doBuildRowConstantTransform(expr->queryChild(0), bound))
  173. return doBuildRowViaTemp(ctx, expr);
  174. BoundRow * row = bindConstantRow(ctx, expr, bound);
  175. return createReferenceSelector(row);
  176. }
  177. BoundRow * HqlCppTranslator::bindConstantRow(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & bound)
  178. {
  179. BoundRow * row = bindRow(ctx, expr, bound.expr);
  180. //MORE: This should be done more cleanly
  181. OwnedHqlExpr sizeOfRow = createSizeof(row->querySelector());
  182. ctx.associateExpr(sizeOfRow, bound.length);
  183. return row;
  184. }
  185. bool HqlCppTranslator::doBuildRowConstantNull(IHqlExpression * expr, CHqlBoundExpr & bound)
  186. {
  187. if (!options.generateStaticInlineTables)
  188. return false;
  189. IHqlExpression * record = expr->queryRecord();
  190. OwnedHqlExpr constRow = createConstantNullRowExpr(record);
  191. if (!constRow)
  192. return false;
  193. buildConstRow(record, constRow, bound);
  194. return true;
  195. }
  196. IReferenceSelector * HqlCppTranslator::doBuildRowNull(BuildCtx & ctx, IHqlExpression * expr)
  197. {
  198. CHqlBoundExpr bound;
  199. if (!doBuildRowConstantNull(expr, bound))
  200. return doBuildRowViaTemp(ctx, expr);
  201. BoundRow * row = bindRow(ctx, expr, bound.expr);
  202. return createReferenceSelector(row);
  203. }
  204. IReferenceSelector * HqlCppTranslator::doBuildRowViaTemp(BuildCtx & ctx, IHqlExpression * expr)
  205. {
  206. HqlExprAssociation * match;
  207. if (expr->isDataset())
  208. match = ctx.queryAssociation(expr->queryNormalizedSelector(), AssocCursor, NULL);
  209. else
  210. match = ctx.queryAssociation(expr, AssocRow, NULL);
  211. if (match)
  212. {
  213. BoundRow * row = (BoundRow *)match;
  214. return createReferenceSelector(row, expr);
  215. }
  216. Owned<BoundRow> tempRow = declareTempRow(ctx, ctx, expr);
  217. buildRowAssign(ctx, tempRow, expr);
  218. ctx.associate(*tempRow);
  219. return createReferenceSelector(tempRow);
  220. }
  221. void HqlCppTranslator::buildDefaultRow(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & bound)
  222. {
  223. OwnedHqlExpr clearExpr = createRow(no_null, LINK(expr->queryRecord()), createAttribute(clearAtom));
  224. BoundRow * matchedRow = (BoundRow *)ctx.queryAssociation(clearExpr, AssocRow, NULL);
  225. if (!matchedRow)
  226. {
  227. if (doBuildRowConstantNull(expr, bound))
  228. {
  229. bindRow(ctx, clearExpr, bound.expr);
  230. }
  231. else
  232. {
  233. BuildCtx * declarectx = &ctx;
  234. BuildCtx * callCtx = &ctx;
  235. getInvariantMemberContext(ctx, &declarectx, &callCtx, true, false);
  236. Owned<BoundRow> tempRow = declareTempRow(*declarectx, *callCtx, clearExpr);
  237. Owned<BoundRow> rowBuilder = createRowBuilder(*callCtx, tempRow);
  238. OwnedHqlExpr size = createVariable(LINK(sizetType));
  239. OwnedHqlExpr clearCall = createClearRowCall(*callCtx, rowBuilder);
  240. callCtx->addDeclare(size, clearCall);
  241. OwnedHqlExpr sizeOfRow = createSizeof(rowBuilder->querySelector());
  242. callCtx->associateExpr(sizeOfRow, size);
  243. finalizeTempRow(*callCtx, tempRow, rowBuilder);
  244. declarectx->associate(*tempRow);
  245. bound.expr.set(tempRow->queryBound());
  246. }
  247. }
  248. else
  249. bound.expr.set(matchedRow->queryBound());
  250. //yuk yuk, hack. If called from a const context then need to make the reference unconst.
  251. //The real fix is to implement real const tracking throughout the code generator, but that is far from trivial.
  252. //rkc39.hql is an example...
  253. if (ctx.queryMatchExpr(constantMemberMarkerExpr))
  254. bound.expr.setown(createValue(no_cast, makeReferenceModifier(bound.expr->getType()), getPointer(bound.expr)));
  255. }
  256. void HqlCppTranslator::buildNullRow(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & bound)
  257. {
  258. bound.expr.setown(createValue(no_nullptr, makeRowReferenceType(expr)));
  259. }
  260. IReferenceSelector * HqlCppTranslator::doBuildRowFromXMLorJSON(BuildCtx & ctx, IHqlExpression * expr)
  261. {
  262. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  263. // assertex(supportsLinkCountedRows);
  264. Owned<ITypeInfo> overrideType = setLinkCountedAttr(expr->queryType(), true);
  265. Owned<ITypeInfo> utf8Type = makeUtf8Type(UNKNOWN_LENGTH, NULL);
  266. IHqlExpression * record = expr->queryRecord();
  267. OwnedHqlExpr ds = createDataset(no_anon, LINK(record));
  268. StringBuffer instanceName, factoryName, s;
  269. bool usesContents = false;
  270. node_operator op = expr->getOperator();
  271. getUniqueId(instanceName.append(op==no_fromjson ? "json" : "xml"));
  272. buildXmlReadTransform(ds, factoryName, usesContents);
  273. OwnedHqlExpr curActivityId = getCurrentActivityId(ctx);
  274. //MORE: This should be generalised so that any invariant class creation can be handled by the same code.
  275. BuildCtx * declareCtx = &ctx;
  276. BuildCtx * initCtx = &ctx;
  277. if (!insideOnCreate(ctx) && getInvariantMemberContext(ctx, &declareCtx, &initCtx, false, false))
  278. {
  279. declareCtx->addQuoted(s.clear().append("Owned<IXmlToRowTransformer> ").append(instanceName).append(";"));
  280. s.clear().append(instanceName).append(".setown(").append(factoryName).append("(ctx,");
  281. generateExprCpp(s, curActivityId).append("));");
  282. initCtx->addQuoted(s);
  283. }
  284. else
  285. {
  286. s.append("Owned<IXmlToRowTransformer> ").append(instanceName).append(" = ").append(factoryName).append("(ctx,");
  287. generateExprCpp(s, curActivityId).append(");");
  288. ctx.addQuoted(s);
  289. }
  290. HqlExprArray args;
  291. args.append(*ensureExprType(expr->queryChild(1), utf8Type));
  292. args.append(*createQuoted(instanceName, makeBoolType()));
  293. args.append(*createConstant(expr->hasAttribute(trimAtom)));
  294. OwnedHqlExpr function;
  295. if (op==no_fromjson)
  296. function.setown(bindFunctionCall(createRowFromJsonId, args, overrideType));
  297. else
  298. function.setown(bindFunctionCall(createRowFromXmlId, args, overrideType));
  299. Owned<BoundRow> result;
  300. if (onFail)
  301. {
  302. result.setown(declareTempRow(ctx, ctx, expr));
  303. BuildCtx tryctx(ctx);
  304. tryctx.addTry();
  305. buildRowAssign(tryctx, result, function);
  306. HqlExprArray dummyArgs;
  307. OwnedHqlExpr exception = createParameter(createIdAtom("e"), 0, makePointerType(makeClassType("IException")), dummyArgs);
  308. BuildCtx catchctx(ctx);
  309. catchctx.addCatch(exception);
  310. catchctx.addQuoted("Owned<IException> _e = e;"); // ensure that the exception is released
  311. associateLocalFailure(catchctx, "e");
  312. OwnedHqlExpr row = createRow(no_createrow, LINK(onFail->queryChild(0)));
  313. buildRowAssign(catchctx, result, row);
  314. }
  315. else
  316. {
  317. CHqlBoundExpr bound;
  318. buildExpr(ctx, function, bound);
  319. Owned<ITypeInfo> rowType = makeReferenceModifier(LINK(overrideType));
  320. OwnedHqlExpr rowExpr = ctx.getTempDeclare(rowType, NULL);
  321. result.setown(createBoundRow(expr, rowExpr));
  322. OwnedHqlExpr defaultRowPtr = getPointer(bound.expr);
  323. ctx.addAssign(rowExpr, defaultRowPtr);
  324. }
  325. ctx.associate(*result);
  326. return createReferenceSelector(result);
  327. }
  328. //NB: If this is a dataset operation, this function assumes that any parent datasets are already in scope
  329. // i.e. processed in buildDatasetAssign()
  330. // the one exception is aggregate because it needs to treat its input differently.
  331. IReferenceSelector * HqlCppTranslator::buildNewOrActiveRow(BuildCtx & ctx, IHqlExpression * expr, bool isNew)
  332. {
  333. if (isNew)
  334. return buildNewRow(ctx, expr);
  335. else
  336. return buildActiveRow(ctx, expr);
  337. }
  338. IReferenceSelector * HqlCppTranslator::buildNewRow(BuildCtx & ctx, IHqlExpression * expr)
  339. {
  340. assertex(!expr->isDataset());
  341. BoundRow * match = static_cast<BoundRow *>(ctx.queryAssociation(expr, AssocRow, NULL));
  342. if (match)
  343. return createReferenceSelector(match, expr);
  344. BoundRow * row = NULL;
  345. node_operator op = expr->getOperator();
  346. switch (op)
  347. {
  348. case no_activerow:
  349. return buildActiveRow(ctx, expr->queryChild(0));
  350. case no_if:
  351. return doBuildRowIf(ctx, expr);
  352. case no_id2blob:
  353. return doBuildRowIdToBlob(ctx, expr, true);
  354. case no_index:
  355. case no_selectnth:
  356. return buildDatasetIndex(ctx, expr);
  357. case no_selectmap:
  358. return buildDatasetSelectMap(ctx, expr);
  359. case no_left:
  360. case no_right:
  361. case no_self:
  362. case no_top:
  363. case no_activetable:
  364. return buildActiveRow(ctx, expr);
  365. case no_fromxml:
  366. case no_fromjson:
  367. return doBuildRowFromXMLorJSON(ctx, expr);
  368. case no_serialize:
  369. {
  370. IHqlExpression * deserialized = expr->queryChild(0);
  371. IAtom * serializeForm = expr->queryChild(1)->queryName();
  372. if (isDummySerializeDeserialize(expr))
  373. return buildNewRow(ctx, deserialized->queryChild(0));
  374. else if (!typeRequiresDeserialization(deserialized->queryType(), serializeForm))
  375. return buildNewRow(ctx, deserialized);
  376. else
  377. return doBuildRowViaTemp(ctx, expr);
  378. }
  379. case no_deserialize:
  380. {
  381. IHqlExpression * serialized = expr->queryChild(0);
  382. IAtom * serializeForm = expr->queryChild(2)->queryName();
  383. if (isDummySerializeDeserialize(expr))
  384. return buildNewRow(ctx, serialized->queryChild(0));
  385. else if (!typeRequiresDeserialization(expr->queryType(), serializeForm))
  386. return buildNewRow(ctx, serialized);
  387. else
  388. return doBuildRowDeserializeRow(ctx, expr);
  389. }
  390. case no_deref:
  391. {
  392. //Untested
  393. CHqlBoundExpr bound;
  394. buildExpr(ctx, expr, bound);
  395. row = bindRow(ctx, expr, bound.expr);
  396. break;
  397. }
  398. case no_createrow:
  399. return doBuildRowCreateRow(ctx, expr);
  400. case no_newusertable:
  401. case no_hqlproject:
  402. case no_temprow:
  403. case no_projectrow:
  404. return doBuildRowViaTemp(ctx, expr);
  405. case no_null:
  406. return doBuildRowNull(ctx, expr);
  407. case no_typetransfer:
  408. {
  409. CHqlBoundExpr bound;
  410. IHqlExpression * value = expr->queryChild(1);
  411. if (value->isDatarow())
  412. buildAddress(ctx, value, bound);
  413. else
  414. buildExpr(ctx, value, bound);
  415. OwnedHqlExpr cursorExpr = createValue(no_implicitcast, makeReferenceModifier(expr->getType()), LINK(bound.expr));
  416. row = bindRow(ctx, expr, cursorExpr);
  417. break;
  418. }
  419. case no_getresult:
  420. {
  421. IAtom * serializeForm = diskAtom; // What if we start using internal in the engines?
  422. IHqlExpression * seqAttr = expr->queryAttribute(sequenceAtom);
  423. IHqlExpression * nameAttr = expr->queryAttribute(namedAtom);
  424. IHqlExpression * record = expr->queryRecord();
  425. OwnedHqlExpr serializedRecord = getSerializedForm(record, serializeForm);
  426. OwnedHqlExpr temp = createDatasetF(no_getresult, LINK(serializedRecord), LINK(seqAttr), LINK(nameAttr), NULL);
  427. OwnedHqlExpr row = createRow(no_selectnth, LINK(temp), createComma(getSizetConstant(1), createAttribute(noBoundCheckAtom)));
  428. row.setown(ensureDeserialized(row, expr->queryType(), serializeForm));
  429. return buildNewRow(ctx, row);
  430. }
  431. case no_matchattr:
  432. return doBuildRowMatchAttr(ctx, expr);
  433. case no_matchrow:
  434. return doBuildRowMatchRow(ctx, expr, true);
  435. case no_getgraphresult:
  436. {
  437. if (expr->hasAttribute(externalAtom))
  438. {
  439. OwnedHqlExpr translated = translateGetGraphResult(ctx, expr);
  440. Owned<IReferenceSelector> selector = buildNewRow(ctx, translated);
  441. //Ensure the no_getresult is also associated in the context, so requiresTemp() works correctly
  442. Owned<BoundRow> boundRow = selector->getRow(ctx);
  443. bindRow(ctx, expr, boundRow->queryBound());
  444. return selector.getClear();
  445. }
  446. //fall through
  447. }
  448. case no_call:
  449. case no_externalcall:
  450. case no_alias:
  451. case no_translated:
  452. case no_libraryinput:
  453. {
  454. CHqlBoundExpr bound;
  455. buildExpr(ctx, expr, bound);
  456. Owned<ITypeInfo> rawType = removeModifier(expr->queryType(), typemod_ref);
  457. OwnedHqlExpr cursorExpr = createValue(no_implicitcast, makeReferenceModifier(LINK(rawType)), LINK(bound.expr));
  458. row = bindRow(ctx, expr, cursorExpr);
  459. if (bound.length)
  460. {
  461. OwnedHqlExpr sizeOfRow = createSizeof(row->querySelector());
  462. ctx.associateExpr(sizeOfRow, bound.length);
  463. }
  464. //We could associate the original expression to allow better cse for child datasets in transforms, but it doesn't actually improve any examples
  465. //IHqlExpression * original = queryAttributeChild(expr, _original_Atom, 0);
  466. //if (original)
  467. // bindRow(ctx, original, cursorExpr)->setResultAlias();
  468. break;//return createReferenceSelector(cursor);
  469. }
  470. case no_comma:
  471. case no_compound:
  472. buildStmt(ctx, expr->queryChild(0));
  473. return buildNewRow(ctx, expr->queryChild(1));
  474. case no_select:
  475. {
  476. #ifdef _DEBUG
  477. IHqlExpression * field = expr->queryChild(1);
  478. #endif
  479. Owned<IReferenceSelector> selector;
  480. if (isNewSelector(expr))
  481. selector.setown(buildNewRow(ctx, expr->queryChild(0)));
  482. else
  483. selector.setown(buildActiveRow(ctx, expr->queryChild(0)));
  484. return selector->select(ctx, expr);
  485. }
  486. //If called because known to be a single row.
  487. case no_datasetfromrow:
  488. case no_nofold:
  489. case no_nohoist:
  490. case no_forcegraph:
  491. case no_nocombine:
  492. case no_section:
  493. case no_sectioninput:
  494. return buildNewRow(ctx, expr->queryChild(0));
  495. case no_skip:
  496. {
  497. buildStmt(ctx, expr);
  498. OwnedHqlExpr null = createNullExpr(expr);
  499. return buildNewRow(ctx, null);
  500. }
  501. case no_alias_scope:
  502. {
  503. expandAliasScope(ctx, expr);
  504. return buildNewRow(ctx, expr->queryChild(0));
  505. }
  506. case no_split:
  507. throwUnexpected();
  508. //not at all sure about this.....
  509. return buildNewRow(ctx, expr->queryChild(0));
  510. default:
  511. {
  512. HqlExprAssociation * match;
  513. if (expr->isDataset())
  514. match = ctx.queryAssociation(expr->queryNormalizedSelector(), AssocCursor, NULL);
  515. else
  516. match = ctx.queryAssociation(expr, AssocRow, NULL);
  517. if (match)
  518. {
  519. BoundRow * row = (BoundRow *)match;
  520. IReferenceSelector * alias = row->queryAlias();
  521. if (alias)
  522. return LINK(alias);
  523. return createReferenceSelector(row, expr);
  524. }
  525. UNIMPLEMENTED_XY("row", getOpString(expr->getOperator()));
  526. }
  527. }
  528. assertex(row);
  529. return createReferenceSelector(row);
  530. }
  531. IReferenceSelector * HqlCppTranslator::buildActiveRow(BuildCtx & ctx, IHqlExpression * expr)
  532. {
  533. node_operator op = expr->getOperator();
  534. switch (op)
  535. {
  536. case no_left:
  537. case no_right:
  538. case no_self:
  539. case no_top:
  540. case no_activetable:
  541. case no_selfref: // shouldn't ever occur...
  542. //All selectors should be listed here...
  543. break;
  544. case no_activerow:
  545. return buildActiveRow(ctx, expr->queryChild(0));
  546. default:
  547. if (!expr->isDataset() && !expr->isDictionary())
  548. return buildNewRow(ctx, expr);
  549. break;
  550. }
  551. HqlExprAssociation * match = ctx.queryAssociation(expr->queryNormalizedSelector(), AssocCursor, NULL);
  552. if (match)
  553. {
  554. BoundRow * row = (BoundRow *)match;
  555. IReferenceSelector * alias = row->queryAlias();
  556. if (alias)
  557. return LINK(alias);
  558. return createReferenceSelector(row, expr);
  559. }
  560. switch (op)
  561. {
  562. case no_select:
  563. {
  564. #ifdef _DEBUG
  565. IHqlExpression * field = expr->queryChild(1);
  566. #endif
  567. Owned<IReferenceSelector> selector = buildNewOrActiveRow(ctx, expr->queryChild(0), isNewSelector(expr));
  568. return selector->select(ctx, expr);
  569. }
  570. case no_id2blob:
  571. return doBuildRowIdToBlob(ctx, expr, false);
  572. }
  573. StringBuffer tablename;
  574. getExprIdentifier(tablename, expr);
  575. traceExpression("Dataset not found", expr);
  576. RowAssociationIterator iter(ctx);
  577. ForEach(iter)
  578. {
  579. BoundRow & cur = iter.get();
  580. traceExpression("BoundCursor:", cur.querySelector());
  581. }
  582. throwError1(HQLERR_DatasetNotActive, tablename.str());
  583. return NULL; //remove warning about control paths
  584. }
  585. BoundRow * HqlCppTranslator::ensureLinkCountedRow(BuildCtx & ctx, BoundRow * row)
  586. {
  587. if (row->isLinkCounted())
  588. return row;
  589. OwnedHqlExpr srcRow = createTranslated(row->queryBound());
  590. OwnedHqlExpr tempRowExpr = declareLinkedRowExpr(ctx, row->queryRecord(), false);
  591. Owned<BoundRow> tempRow = row->clone(tempRowExpr);
  592. OwnedHqlExpr source = getPointer(row->queryBound());
  593. BuildCtx subctx(ctx);
  594. if (row->isConditional())
  595. subctx.addFilter(source);
  596. IHqlExpression * sourceExpr = row->querySelector();
  597. OwnedHqlExpr rowExpr = sourceExpr->isDataset() ? ensureActiveRow(sourceExpr) : LINK(sourceExpr);
  598. OwnedHqlExpr size = createSizeof(rowExpr);
  599. CHqlBoundExpr boundSize;
  600. buildExpr(subctx, size, boundSize);
  601. StringBuffer allocatorName;
  602. ensureRowAllocator(allocatorName, ctx, row->queryRecord(), getCurrentActivityId(subctx));
  603. StringBuffer s;
  604. s.append("rtlCloneRow(").append(allocatorName).append(",");
  605. generateExprCpp(s, boundSize.expr).append(",");
  606. generateExprCpp(s, source);
  607. s.append(")");
  608. OwnedHqlExpr call = createQuoted(s, tempRow->queryBound()->getType());
  609. subctx.addAssign(tempRow->queryBound(), call);
  610. ctx.associate(*tempRow);
  611. return tempRow;
  612. }
  613. IReferenceSelector * HqlCppTranslator::ensureLinkCountedRow(BuildCtx & ctx, IReferenceSelector * source)
  614. {
  615. if (!source->isRoot() || !source->queryRootRow()->isLinkCounted())
  616. {
  617. Owned<BoundRow> row = source->getRow(ctx);
  618. BoundRow * lcrRow = ensureLinkCountedRow(ctx, row);
  619. assertex(row != lcrRow);
  620. return createReferenceSelector(lcrRow, source->queryExpr());
  621. }
  622. return LINK(source);
  623. }
  624. //---------------------------------------------------------------------------
  625. void HqlCppTranslator::doBuildExprAggregate(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  626. {
  627. OwnedHqlExpr normalized = normalizeAnyDatasetAliases(expr);
  628. if (expr != normalized)
  629. {
  630. buildExpr(ctx, normalized, tgt);
  631. return;
  632. }
  633. node_operator op = expr->getOperator();
  634. ITypeInfo * type = expr->queryType();
  635. ITypeInfo * tempType = op == no_count ? unsignedType : type;
  636. LoopInvariantHelper helper;
  637. BuildCtx aggctx(ctx);
  638. if (options.optimizeLoopInvariant)
  639. helper.getBestContext(aggctx, expr);
  640. CHqlBoundTarget result;
  641. createTempFor(aggctx, tempType, result, typemod_none, FormatNatural);
  642. doBuildAssignAggregate(aggctx, result, expr);
  643. tgt.setFromTarget(result);
  644. if (!isSameBasicType(type, tempType))
  645. tgt.expr.setown(createValue(no_implicitcast, LINK(type), tgt.expr.getClear()));
  646. if (expr->isPure())
  647. aggctx.associateExpr(expr, tgt);
  648. }
  649. void HqlCppTranslator::doBuildAssignAggregateLoop(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, IHqlExpression * dataset, IHqlExpression * doneFirstVar, bool multiPath)
  650. {
  651. node_operator op = expr->getOperator();
  652. switch (op)
  653. {
  654. case no_exists:
  655. {
  656. OwnedHqlExpr optimized = queryOptimizedExists(ctx, expr, dataset);
  657. if (optimized)
  658. {
  659. if (matchesBoolean(optimized, false))
  660. return;
  661. if (multiPath)
  662. {
  663. BuildCtx condctx(ctx);
  664. condctx.addFilter(optimized);
  665. assignBound(condctx, target, queryBoolExpr(true));
  666. }
  667. else
  668. assignBound(ctx, target, optimized);
  669. return;
  670. }
  671. break;
  672. }
  673. case no_count:
  674. {
  675. CHqlBoundExpr temp;
  676. if (canBuildOptimizedCount(ctx, dataset, temp, op))
  677. {
  678. OwnedHqlExpr thisCount = temp.getTranslatedExpr();
  679. buildIncrementAssign(ctx, target, thisCount);
  680. return;
  681. }
  682. break;
  683. }
  684. }
  685. switch (dataset->getOperator())
  686. {
  687. case no_if:
  688. {
  689. BuildCtx subctx(ctx);
  690. IHqlStmt * stmt = buildFilterViaExpr(subctx, dataset->queryChild(0));
  691. doBuildAssignAggregateLoop(subctx, target, expr, dataset->queryChild(1), doneFirstVar, multiPath);
  692. subctx.selectElse(stmt);
  693. doBuildAssignAggregateLoop(subctx, target, expr, dataset->queryChild(2), doneFirstVar, multiPath);
  694. return;
  695. }
  696. case no_addfiles:
  697. {
  698. doBuildAssignAggregateLoop(ctx, target, expr, dataset->queryChild(0), doneFirstVar, true);
  699. doBuildAssignAggregateLoop(ctx, target, expr, dataset->queryChild(1), doneFirstVar, true);
  700. return;
  701. }
  702. case no_chooseds:
  703. {
  704. CHqlBoundExpr cond;
  705. buildExpr(ctx, dataset->queryChild(0), cond);
  706. IHqlExpression * last = queryLastNonAttribute(dataset);
  707. BuildCtx subctx(ctx);
  708. IHqlStmt * switchstmt = subctx.addSwitch(cond.expr);
  709. ForEachChildFrom(i, dataset, 1)
  710. {
  711. IHqlExpression * cur = dataset->queryChild(i);
  712. if (cur != last)
  713. {
  714. OwnedHqlExpr label = getSizetConstant(i);
  715. subctx.addCase(switchstmt, label);
  716. }
  717. else
  718. subctx.addDefault(switchstmt);
  719. doBuildAssignAggregateLoop(subctx, target, expr, cur, doneFirstVar, multiPath);
  720. }
  721. return;
  722. }
  723. case no_null:
  724. return;
  725. }
  726. LinkedHqlExpr arg = expr->queryChild(1);
  727. IHqlExpression * oldDataset = expr->queryChild(0);
  728. //If no_if or no_addfiles has been optimized above then the selector for the argument will have changed => map it.
  729. if (arg && (dataset != oldDataset))
  730. arg.setown(replaceSelector(arg, oldDataset, dataset));
  731. bool needToBreak = (op == no_exists);
  732. if (needToBreak)
  733. {
  734. //if it can have at most one row (fairly strange code!) then don't add a break
  735. //unless it was deliberately a choosen to restrict the number of iterations.
  736. if (hasNoMoreRowsThan(dataset, 1) && (dataset->getOperator() != no_choosen))
  737. needToBreak = false;
  738. }
  739. BuildCtx loopctx(ctx);
  740. buildDatasetIterate(loopctx, dataset, needToBreak);
  741. switch (op)
  742. {
  743. case no_exists:
  744. buildExprAssign(loopctx, target, queryBoolExpr(true));
  745. if (needToBreak)
  746. loopctx.addBreak();
  747. break;
  748. case no_count:
  749. {
  750. OwnedHqlExpr inc = createValue(no_postinc, makeVoidType(), LINK(target.expr));
  751. loopctx.addExpr(inc);
  752. break;
  753. }
  754. case no_sum:
  755. {
  756. OwnedHqlExpr cseArg = options.spotCSE ? spotScalarCSE(arg, NULL, queryOptions().spotCseInIfDatasetConditions) : LINK(arg);
  757. buildIncrementAssign(loopctx, target, cseArg);
  758. break;
  759. }
  760. case no_min:
  761. case no_max:
  762. {
  763. BuildCtx maxctx(loopctx);
  764. OwnedHqlExpr resultExpr = target.getTranslatedExpr();
  765. OwnedHqlExpr cseArg = options.spotCSE ? spotScalarCSE(arg, NULL, queryOptions().spotCseInIfDatasetConditions) : LINK(arg);
  766. OwnedHqlExpr simpleArg = buildSimplifyExpr(loopctx, cseArg);
  767. OwnedHqlExpr test = createBoolExpr((op == no_min) ? no_lt : no_gt, LINK(simpleArg), LINK(resultExpr));
  768. if (doneFirstVar)
  769. {
  770. IHqlExpression * firstTest = createValue(no_not, makeBoolType(), LINK(doneFirstVar));
  771. test.setown(createBoolExpr(no_or, firstTest, test.getClear()));
  772. }
  773. buildFilter(maxctx, test);
  774. buildExprAssign(maxctx, target, simpleArg);
  775. if (doneFirstVar)
  776. buildAssignToTemp(maxctx, doneFirstVar, queryBoolExpr(true));
  777. break;
  778. }
  779. default:
  780. assertex(!"unknown aggregate on child datasets");
  781. break;
  782. }
  783. }
  784. bool assignAggregateDirect(const CHqlBoundTarget & target, IHqlExpression * expr)
  785. {
  786. node_operator op = expr->getOperator();
  787. ITypeInfo * type = expr->queryType();
  788. ITypeInfo * tempType = op == no_count ? unsignedType : type;
  789. if (!isSameUnqualifiedType(target.queryType(), tempType))
  790. return false;
  791. //For exists/count/sum use a temporary variable, and then assign rather than accumulating directly in the target
  792. switch (op)
  793. {
  794. case no_sum:
  795. if (type->getTypeCode() != type_int)
  796. break;
  797. //fall through
  798. case no_exists:
  799. case no_count:
  800. if (target.expr->getOperator() != no_variable)
  801. return false;
  802. break;
  803. }
  804. return true;
  805. }
  806. static bool isNullValueMinimumValue(ITypeInfo * type)
  807. {
  808. switch (type->getTypeCode())
  809. {
  810. case type_int:
  811. case type_swapint:
  812. case type_decimal:
  813. return !type->isSigned();
  814. case type_data:
  815. case type_qstring:
  816. return true;
  817. }
  818. return false;
  819. }
  820. void HqlCppTranslator::doBuildAssignAggregate(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * _expr)
  821. {
  822. OwnedHqlExpr expr = normalizeAnyDatasetAliases(_expr);
  823. if (assignAggregateDirect(target, expr))
  824. {
  825. IHqlExpression * dataset = expr->queryChild(0);
  826. OwnedHqlExpr resultExpr = target.getTranslatedExpr();
  827. node_operator op = expr->getOperator();
  828. switch (op)
  829. {
  830. case no_exists:
  831. buildExprAssign(ctx, target, queryBoolExpr(false));
  832. break;
  833. default:
  834. {
  835. OwnedHqlExpr null = createNullExpr(target.queryType());
  836. buildExprAssign(ctx, target, null);
  837. break;
  838. }
  839. }
  840. OwnedHqlExpr doneFirstVar;
  841. if ((op == no_min) || ((op == no_max) && !isNullValueMinimumValue(target.queryType())))
  842. {
  843. doneFirstVar.setown(ctx.getTempDeclare(queryBoolType(), queryBoolExpr(false)));
  844. }
  845. doBuildAssignAggregateLoop(ctx, target, expr, dataset, doneFirstVar, false);
  846. }
  847. else
  848. {
  849. doBuildExprAssign(ctx, target, expr);
  850. }
  851. }
  852. //---------------------------------------------------------------------------
  853. void HqlCppTranslator::setBoundCount(CHqlBoundExpr & tgt, const CHqlBoundExpr & src, node_operator aggOp)
  854. {
  855. //If checking for existence, lie and return the length as the count instead since more efficient
  856. if ((aggOp == no_exists) && src.length)
  857. tgt.expr.set(src.length);
  858. else
  859. tgt.expr.setown(getBoundCount(src));
  860. }
  861. bool HqlCppTranslator::canBuildOptimizedCount(BuildCtx & ctx, IHqlExpression * dataset, CHqlBoundExpr & tgt, node_operator aggOp)
  862. {
  863. CHqlBoundExpr bound;
  864. if (ctx.getMatchExpr(dataset, bound))
  865. {
  866. setBoundCount(tgt, bound, aggOp);
  867. return true;
  868. }
  869. switch (dataset->getOperator())
  870. {
  871. case no_select:
  872. {
  873. if (isMultiLevelDatasetSelector(dataset, false))
  874. return false;
  875. Owned<IReferenceSelector> selector = buildReference(ctx, dataset);
  876. CHqlBoundExpr temp;
  877. selector->get(ctx, temp);
  878. setBoundCount(tgt, temp, aggOp);
  879. return true;
  880. }
  881. break;
  882. case no_newusertable:
  883. case no_hqlproject:
  884. case no_iterate:
  885. {
  886. IHqlExpression * transform = queryNewColumnProvider(dataset);
  887. if (containsSkip(transform) || containsThrow(transform))
  888. return false;
  889. return canBuildOptimizedCount(ctx, dataset->queryChild(0), tgt, aggOp);
  890. }
  891. case no_group:
  892. case no_owned_ds:
  893. case no_translated:
  894. case no_alias:
  895. case no_getresult:
  896. case no_getgraphresult:
  897. case no_workunit_dataset:
  898. case no_activetable:
  899. case no_externalcall:
  900. case no_call:
  901. if (hasStreamedModifier(dataset->queryType()))
  902. return false;
  903. break;
  904. case no_distributed:
  905. case no_unordered:
  906. case no_preservemeta:
  907. case no_sorted:
  908. case no_nofold:
  909. case no_nohoist:
  910. case no_forcegraph:
  911. case no_nocombine:
  912. case no_section:
  913. case no_sectioninput:
  914. case no_sort:
  915. case no_distribute:
  916. return canBuildOptimizedCount(ctx, dataset->queryChild(0), tgt, aggOp);
  917. case no_datasetfromrow:
  918. tgt.expr.setown(getSizetConstant(1));
  919. return true;
  920. case no_if:
  921. {
  922. if (!queryRealChild(dataset, 2))
  923. return false;
  924. CHqlBoundExpr countLeft, countRight;
  925. if (!canBuildOptimizedCount(ctx, dataset->queryChild(1), countLeft, aggOp))
  926. return false;
  927. if (!canBuildOptimizedCount(ctx, dataset->queryChild(2), countRight, aggOp))
  928. return false;
  929. if (countLeft.expr != countRight.expr)
  930. {
  931. //MORE: Could create a no_if...
  932. return false;
  933. }
  934. tgt.expr.set(countLeft.expr);
  935. return true;
  936. }
  937. case no_addfiles:
  938. case no_merge:
  939. {
  940. ForEachChild(i, dataset)
  941. {
  942. IHqlExpression * cur = dataset->queryChild(i);
  943. if (!cur->isAttribute())
  944. {
  945. CHqlBoundExpr temp;
  946. if (!canBuildOptimizedCount(ctx, cur, temp, aggOp))
  947. return false;
  948. tgt.expr.setown(adjustBoundIntegerValues(tgt.expr, temp.expr, false));
  949. }
  950. }
  951. return true;
  952. }
  953. case no_compound:
  954. return canBuildOptimizedCount(ctx, dataset->queryChild(1), tgt, aggOp);
  955. case no_null:
  956. case no_rows:
  957. case no_id2blob:
  958. break;
  959. case no_inlinetable:
  960. {
  961. OwnedHqlExpr count = queryFixedRowCount(dataset);
  962. if (!count)
  963. return false;
  964. tgt.expr.set(count);
  965. return true;
  966. }
  967. default:
  968. return false;
  969. }
  970. CHqlBoundExpr temp;
  971. buildDataset(ctx, dataset, temp, FormatNatural);
  972. setBoundCount(tgt, temp, aggOp);
  973. return true;
  974. }
  975. void HqlCppTranslator::doBuildExprCount(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  976. {
  977. if (expr->hasAttribute(keyedAtom))
  978. throwError(HQLERR_KeyedCountNonKeyable);
  979. IHqlExpression * dataset = expr->queryChild(0);
  980. CHqlBoundExpr temp;
  981. if (canBuildOptimizedCount(ctx, dataset, temp, no_count))
  982. {
  983. OwnedHqlExpr translated = temp.getTranslatedExpr();
  984. OwnedHqlExpr cast = ensureExprType(translated, expr->queryType());
  985. buildExpr(ctx, cast, tgt);
  986. }
  987. else
  988. doBuildExprAggregate(ctx, expr, tgt);
  989. }
  990. //---------------------------------------------------------------------------
  991. IHqlExpression * HqlCppTranslator::queryOptimizedExists(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * dataset)
  992. {
  993. node_operator dsOp = dataset->getOperator();
  994. //really this is isSimple()
  995. CHqlBoundExpr optimized;
  996. bool canOptimizeCount = canBuildOptimizedCount(ctx, dataset, optimized, no_exists);
  997. node_operator op = (expr->getOperator() == no_exists) ? no_ne : no_eq;
  998. bool specialCase = false;
  999. switch (dsOp)
  1000. {
  1001. case no_select:
  1002. specialCase = canOptimizeCount;
  1003. break;
  1004. default:
  1005. specialCase = !canOptimizeCount && alwaysEvaluatesToBound(dataset);
  1006. break;
  1007. }
  1008. OwnedHqlExpr test;
  1009. if (specialCase)
  1010. {
  1011. CHqlBoundExpr temp;
  1012. buildDataset(ctx, dataset, temp, FormatNatural);
  1013. if (temp.count)
  1014. test.set(temp.count);
  1015. else
  1016. test.setown(getBoundSize(temp));
  1017. }
  1018. else if (canOptimizeCount)
  1019. {
  1020. test.set(optimized.expr);
  1021. }
  1022. if (test)
  1023. {
  1024. OwnedHqlExpr cond = createBoolExpr(op, LINK(test), createConstant(test->queryType()->castFrom(false, 0)));
  1025. if (cond->isConstant())
  1026. return foldHqlExpression(cond);
  1027. return cond.getClear();
  1028. }
  1029. return NULL;
  1030. }
  1031. void HqlCppTranslator::doBuildExprExists(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  1032. {
  1033. OwnedHqlExpr optimized = queryOptimizedExists(ctx, expr, expr->queryChild(0));
  1034. if (optimized)
  1035. tgt.expr.setown(optimized.getClear());
  1036. else
  1037. doBuildExprAggregate(ctx, expr, tgt);
  1038. }
  1039. //---------------------------------------------------------------------------
  1040. static IHqlExpression * createMinMax(node_operator compareOp, ITypeInfo * type, IHqlExpression * left, IHqlExpression * right)
  1041. {
  1042. return createValue(no_if, LINK(type),
  1043. createBoolExpr(compareOp, LINK(left), LINK(right)),
  1044. LINK(left), LINK(right));
  1045. }
  1046. bool HqlCppTranslator::doBuildAggregateMinMaxList(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, IHqlExpression * list, CHqlBoundExpr * tgt, node_operator compareOp)
  1047. {
  1048. OwnedHqlExpr value;
  1049. unsigned max = list->numChildren();
  1050. switch(max)
  1051. {
  1052. case 0:
  1053. value.setown(createNullExpr(expr));
  1054. break;
  1055. case 1:
  1056. value.set(list->queryChild(0));
  1057. break;
  1058. case 2:
  1059. case 3:
  1060. {
  1061. OwnedHqlExpr simple[3];
  1062. for (unsigned i=0; i < max; i++)
  1063. {
  1064. CHqlBoundExpr bound;
  1065. buildSimpleExpr(ctx, list->queryChild(i), bound);
  1066. simple[i].setown(bound.getTranslatedExpr());
  1067. }
  1068. ITypeInfo * type = expr->queryType();
  1069. if (max == 2)
  1070. value.setown(createMinMax(compareOp, type, simple[0], simple[1]));
  1071. else
  1072. {
  1073. OwnedHqlExpr cmp02 = createMinMax(compareOp, type, simple[0], simple[2]);
  1074. OwnedHqlExpr cmp12 = createMinMax(compareOp, type, simple[1], simple[2]);
  1075. value.setown(createValue(no_if, expr->getType(),
  1076. createBoolExpr(compareOp, LINK(simple[0]), LINK(simple[1])),
  1077. LINK(cmp02), LINK(cmp12)));
  1078. }
  1079. }
  1080. }
  1081. if (value)
  1082. {
  1083. buildExprOrAssign(ctx, target, value, tgt);
  1084. return true;
  1085. }
  1086. {
  1087. CHqlBoundTarget temp;
  1088. createTempFor(ctx, expr, temp);
  1089. buildExprAssign(ctx, temp, list->queryChild(0));
  1090. OwnedHqlExpr best = temp.getTranslatedExpr();
  1091. for (unsigned i=1; i < list->numChildren(); i++)
  1092. {
  1093. CHqlBoundExpr bound;
  1094. buildSimpleExpr(ctx, list->queryChild(i), bound);
  1095. OwnedHqlExpr simple = bound.getTranslatedExpr();
  1096. BuildCtx subctx(ctx);
  1097. OwnedHqlExpr cond = createBoolExpr(compareOp, LINK(simple), LINK(best));
  1098. buildFilter(subctx, cond);
  1099. buildExprAssign(subctx, temp, simple);
  1100. }
  1101. buildExprOrAssign(ctx, target, best, tgt);
  1102. return true;
  1103. }
  1104. }
  1105. void HqlCppTranslator::doBuildAggregateList(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * tgt)
  1106. {
  1107. OwnedHqlExpr list = normalizeListCasts(expr->queryChild(0));
  1108. if (list->getOperator() == no_alias_scope)
  1109. {
  1110. expandAliasScope(ctx, list);
  1111. list.set(list->queryChild(0));
  1112. }
  1113. node_operator aggOp;
  1114. switch (expr->getOperator())
  1115. {
  1116. case no_existslist:
  1117. {
  1118. //Fixed length lists should have been optimized away
  1119. CHqlBoundExpr bound;
  1120. buildExpr(ctx, list, bound);
  1121. OwnedHqlExpr test;
  1122. if (bound.count)
  1123. test.set(bound.count);
  1124. else
  1125. test.setown(getBoundLength(bound));
  1126. OwnedHqlExpr value = createValue(no_ne, makeBoolType(), LINK(test), ensureExprType(queryZero(), test->queryType()));
  1127. OwnedHqlExpr translated = createTranslated(value);
  1128. buildExprOrAssign(ctx, target, translated, tgt);
  1129. return;
  1130. }
  1131. case no_countlist:
  1132. {
  1133. //Fixed length lists should have been optimized away
  1134. CHqlBoundExpr bound;
  1135. buildExpr(ctx, list, bound);
  1136. OwnedHqlExpr test = getBoundCount(bound);
  1137. OwnedHqlExpr value = ensureExprType(test, expr->queryType());
  1138. OwnedHqlExpr translated = createTranslated(value);
  1139. buildExprOrAssign(ctx, target, translated, tgt);
  1140. return;
  1141. }
  1142. case no_sumlist:
  1143. aggOp = no_sumgroup;
  1144. if (list->getOperator() == no_list)
  1145. {
  1146. HqlExprArray args;
  1147. ITypeInfo * exprType = expr->queryType();
  1148. ForEachChild(i, list)
  1149. args.append(*ensureExprType(list->queryChild(i), exprType));
  1150. OwnedHqlExpr balanced = createBalanced(no_add, exprType, args);
  1151. if (!balanced)
  1152. balanced.setown(ensureExprType(queryZero(), exprType));
  1153. buildExprOrAssign(ctx, target, balanced, tgt);
  1154. return;
  1155. }
  1156. //special case fixed length lists
  1157. break;
  1158. case no_minlist:
  1159. aggOp = no_mingroup;
  1160. if (list->getOperator() == no_list)
  1161. {
  1162. if (doBuildAggregateMinMaxList(ctx, target, expr, list, tgt, no_lt))
  1163. return;
  1164. }
  1165. break;
  1166. case no_maxlist:
  1167. aggOp = no_maxgroup;
  1168. if (list->getOperator() == no_list)
  1169. {
  1170. if (doBuildAggregateMinMaxList(ctx, target, expr, list, tgt, no_gt))
  1171. return;
  1172. }
  1173. break;
  1174. default:
  1175. throwUnexpectedOp(expr->getOperator());
  1176. }
  1177. ITypeInfo * elemType = list->queryType()->queryChildType();
  1178. if (!elemType)
  1179. elemType = defaultIntegralType;
  1180. //Default implementation in terms of a dataset
  1181. OwnedHqlExpr field = createField(valueId, LINK(elemType), NULL);
  1182. OwnedHqlExpr record = createRecord(field);
  1183. OwnedHqlExpr ds = createDataset(no_temptable, LINK(list), LINK(record));
  1184. OwnedHqlExpr aggField = createField(valueId, expr->getType(), NULL);
  1185. OwnedHqlExpr aggRecord = createRecord(aggField);
  1186. OwnedHqlExpr self = createSelector(no_self, aggRecord, NULL);
  1187. OwnedHqlExpr aggExpr = createValue(aggOp, expr->getType(), createSelectExpr(LINK(ds), LINK(field)));
  1188. OwnedHqlExpr aggAssign = createAssign(createSelectExpr(LINK(self), LINK(aggField)), LINK(aggExpr));
  1189. OwnedHqlExpr aggTransform = createValue(no_newtransform, makeTransformType(aggRecord->getType()), LINK(aggAssign));
  1190. OwnedHqlExpr agg = createDataset(no_newaggregate, LINK(ds), createComma(LINK(aggRecord), LINK(aggTransform)));
  1191. OwnedHqlExpr result = createNewSelectExpr(createRow(no_selectnth, LINK(agg), createConstantOne()), LINK(aggField));
  1192. buildExprOrAssign(ctx, target, result, tgt);
  1193. }
  1194. //---------------------------------------------------------------------------
  1195. static HqlTransformerInfo graphIndependanceCheckerInfo("GraphIndependanceChecker");
  1196. class GraphIndependanceChecker : public NewHqlTransformer
  1197. {
  1198. public:
  1199. GraphIndependanceChecker(IHqlExpression * _graph) : NewHqlTransformer(graphIndependanceCheckerInfo), graph(_graph) { independent = true; }
  1200. void analyseExpr(IHqlExpression * expr)
  1201. {
  1202. if (!independent || alreadyVisited(expr))
  1203. return;
  1204. switch (expr->getOperator())
  1205. {
  1206. case no_getgraphresult:
  1207. case no_getgraphloopresultset:
  1208. case no_getgraphloopresult:
  1209. if (expr->queryChild(1) == graph)
  1210. {
  1211. independent = false;
  1212. return;
  1213. }
  1214. break;
  1215. }
  1216. NewHqlTransformer::analyseExpr(expr);
  1217. }
  1218. inline bool isIndependent() const { return independent; }
  1219. protected:
  1220. LinkedHqlExpr graph;
  1221. bool independent;
  1222. };
  1223. bool isGraphIndependent(IHqlExpression * expr, IHqlExpression * graph)
  1224. {
  1225. switch (expr->getOperator())
  1226. {
  1227. case no_constant:
  1228. return true;
  1229. }
  1230. GraphIndependanceChecker checker(graph);
  1231. checker.analyse(expr, 0);
  1232. return checker.isIndependent();
  1233. }
  1234. ///--------------------------------------------------------------------------------------------------------------------
  1235. IHqlExpression * createCounterAsGraphResult(IHqlExpression * counter, IHqlExpression * represents, unsigned seq)
  1236. {
  1237. OwnedHqlExpr value = createScalarFromGraphResult(counter->queryType(), unsignedType, represents, seq);
  1238. OwnedHqlExpr internalAttr = createAttribute(internalAtom);
  1239. return createAlias(value, internalAttr);
  1240. }
  1241. ChildGraphExprBuilder::ChildGraphExprBuilder(unsigned _numInputs)
  1242. : numInputs(_numInputs)
  1243. {
  1244. numOutputs=0;
  1245. represents.setown(createAttribute(graphAtom, createUniqueId()));
  1246. resultsExpr.setown(createAttribute(resultsAtom, LINK(represents)));
  1247. }
  1248. IHqlExpression * ChildGraphExprBuilder::addDataset(IHqlExpression * expr)
  1249. {
  1250. OwnedHqlExpr resultNumExpr;
  1251. ForEachItemIn(i, results)
  1252. {
  1253. IHqlExpression & curSetResult = results.item(i);
  1254. if (expr->queryBody() == curSetResult.queryChild(0)->queryBody())
  1255. {
  1256. resultNumExpr.set(curSetResult.queryChild(2));
  1257. break;
  1258. }
  1259. }
  1260. if (!resultNumExpr)
  1261. {
  1262. resultNumExpr.setown(getSizetConstant(numResults()));
  1263. results.append(*createValue(no_setgraphresult, makeVoidType(), LINK(expr), LINK(represents), LINK(resultNumExpr)));
  1264. numOutputs++;
  1265. }
  1266. HqlExprArray args;
  1267. args.append(*LINK(expr->queryRecord()));
  1268. args.append(*LINK(represents));
  1269. args.append(*LINK(resultNumExpr));
  1270. if (isGrouped(expr))
  1271. args.append(*createAttribute(groupedAtom));
  1272. if (!expr->isDataset())
  1273. args.append(*createAttribute(rowAtom));
  1274. args.append(*createAttribute(externalAtom, LINK(resultsExpr)));
  1275. args.append(*createAttribute(_original_Atom, LINK(expr)));
  1276. IHqlExpression * recordCountAttr = queryRecordCountInfo(expr);
  1277. if (recordCountAttr)
  1278. args.append(*LINK(recordCountAttr));
  1279. if (expr->isDictionary())
  1280. return createDictionary(no_getgraphresult, args);
  1281. if (expr->isDatarow())
  1282. return createRow(no_getgraphresult, args);
  1283. return createDataset(no_getgraphresult, args);
  1284. }
  1285. void ChildGraphExprBuilder::addAction(IHqlExpression * expr)
  1286. {
  1287. results.append(*LINK(expr));
  1288. }
  1289. unsigned ChildGraphExprBuilder::addInput()
  1290. {
  1291. unsigned id = numResults();
  1292. numInputs++;
  1293. return id;
  1294. }
  1295. IHqlExpression * ChildGraphExprBuilder::getGraph(node_operator listOp)
  1296. {
  1297. HqlExprArray args;
  1298. args.append(*LINK(represents));
  1299. args.append(*getSizetConstant(numResults()));
  1300. args.append(*createActionList(listOp, results));
  1301. return createValue(no_childquery, makeVoidType(), args);
  1302. }
  1303. //---------------------------------------------------------------------------
  1304. // Child dataset processing
  1305. ChildGraphBuilder::ChildGraphBuilder(HqlCppTranslator & _translator, IHqlExpression * subgraph)
  1306. : translator(_translator), childQuery(subgraph)
  1307. {
  1308. represents.set(subgraph->queryChild(0));
  1309. id = translator.nextActivityId();
  1310. appendUniqueId(instanceName.append("child"), id);
  1311. instanceExpr.setown(createQuoted(instanceName, makeBoolType()));
  1312. resultsExpr.setown(createAttribute(resultsAtom, LINK(represents)));
  1313. StringBuffer s;
  1314. resultInstanceExpr.setown(createQuoted(appendUniqueId(s.append("res"), id), makeBoolType()));
  1315. numResults = (unsigned)getIntValue(subgraph->queryChild(1));
  1316. }
  1317. void ChildGraphBuilder::generateGraph(BuildCtx & ctx)
  1318. {
  1319. if (translator.queryOptions().showChildCountInGraph)
  1320. {
  1321. ActivityInstance * activeActivity = translator.queryCurrentActivity(ctx);
  1322. if (activeActivity)
  1323. activeActivity->noteChildQuery();
  1324. }
  1325. BuildCtx graphctx(ctx);
  1326. //Make sure at least one results - because currently that's how we determine if new resourcing is being used
  1327. //Remove this line once all engines use the new child queries exclusively
  1328. if (numResults == 0) numResults++;
  1329. OwnedHqlExpr resourced = translator.getResourcedChildGraph(graphctx, childQuery, numResults, no_none);
  1330. Owned<ParentExtract> extractBuilder = translator.createExtractBuilder(graphctx, PETchild, represents, resourced, true);
  1331. if (!translator.queryOptions().serializeRowsetInExtract)
  1332. extractBuilder->setAllowDestructor();
  1333. translator.beginExtract(graphctx, extractBuilder);
  1334. translator.doBuildThorSubGraph(graphctx, resourced, SubGraphChild, id, represents);
  1335. EvalContext * instance = translator.queryEvalContext(graphctx);
  1336. OwnedHqlExpr retInstanceExpr;
  1337. if (instance && !translator.insideOnCreate(graphctx))
  1338. retInstanceExpr.setown(instance->createGraphLookup(id, true));
  1339. else
  1340. retInstanceExpr.setown(translator.doCreateGraphLookup(graphctx, graphctx, id, "this", true));
  1341. assertex(retInstanceExpr == instanceExpr);
  1342. CHqlBoundExpr boundExtract;
  1343. extractBuilder->endCreateExtract(boundExtract);
  1344. HqlExprArray args;
  1345. args.append(*LINK(instanceExpr));
  1346. args.append(*createTranslated(boundExtract.length));
  1347. args.append(*boundExtract.getTranslatedExpr());
  1348. OwnedHqlExpr call = translator.bindFunctionCall(evaluateChildQueryInstanceId, args);
  1349. CHqlBoundExpr bound;
  1350. translator.buildExpr(graphctx, call, bound);
  1351. StringBuffer s;
  1352. s.append("Owned<IEclGraphResults> ");
  1353. translator.generateExprCpp(s, resultInstanceExpr);
  1354. s.append(" = ");
  1355. translator.generateExprCpp(s, bound.expr);
  1356. s.append(";");
  1357. graphctx.addQuoted(s);
  1358. translator.endExtract(graphctx, extractBuilder);
  1359. ctx.associateExpr(resultsExpr, resultInstanceExpr);
  1360. }
  1361. void ChildGraphBuilder::generatePrefetchGraph(BuildCtx & _ctx, OwnedHqlExpr * retGraphExpr)
  1362. {
  1363. BuildCtx ctx(_ctx);
  1364. ctx.addGroup();
  1365. BuildCtx aliasctx(ctx);
  1366. aliasctx.addGroup();
  1367. OwnedHqlExpr resourced = translator.getResourcedChildGraph(ctx, childQuery, numResults, no_none);
  1368. Owned<ParentExtract> extractBuilder = translator.createExtractBuilder(ctx, PETchild, represents, resourced, false);
  1369. createBuilderAlias(aliasctx, extractBuilder);
  1370. translator.beginExtract(ctx, extractBuilder);
  1371. translator.doBuildThorSubGraph(ctx, resourced, SubGraphChild, id, represents);
  1372. EvalContext * instance = translator.queryEvalContext(ctx);
  1373. OwnedHqlExpr retInstanceExpr;
  1374. assertex(instance && !translator.insideOnCreate(ctx));
  1375. retInstanceExpr.setown(instance->createGraphLookup(id, true));
  1376. assertex(retInstanceExpr == instanceExpr);
  1377. retGraphExpr->setown(retInstanceExpr.getClear());
  1378. }
  1379. void ChildGraphBuilder::createBuilderAlias(BuildCtx & ctx, ParentExtract * extractBuilder)
  1380. {
  1381. StringBuffer s;
  1382. s.append("rtlRowBuilder & ");
  1383. translator.generateExprCpp(s, extractBuilder->queryExtractName());
  1384. s.append(" = builder;");
  1385. ctx.addQuoted(s);
  1386. }
  1387. unique_id_t ChildGraphBuilder::buildLoopBody(BuildCtx & ctx, bool multiInstance)
  1388. {
  1389. BuildCtx subctx(ctx);
  1390. subctx.addGroup();
  1391. OwnedHqlExpr resourced = translator.getResourcedChildGraph(ctx, childQuery, numResults, no_loop);
  1392. //Add a flag to indicate multi instance
  1393. if (multiInstance)
  1394. resourced.setown(appendOwnedOperand(resourced, createAttribute(multiInstanceAtom)));
  1395. bool isGlobalThorLoop = translator.targetThor() && !translator.insideChildQuery(ctx);
  1396. Owned<ParentExtract> extractBuilder = isGlobalThorLoop ? translator.createExtractBuilder(ctx, PETloop, represents, GraphRemote, false)
  1397. : translator.createExtractBuilder(ctx, PETloop, represents, resourced, false);
  1398. createBuilderAlias(subctx, extractBuilder);
  1399. translator.beginExtract(ctx, extractBuilder);
  1400. translator.doBuildThorSubGraph(ctx, resourced, SubGraphLoop, id, represents);
  1401. translator.endExtract(ctx, extractBuilder);
  1402. return id;
  1403. }
  1404. static HqlTransformerInfo graphLoopReplacerInfo("GraphLoopReplacer");
  1405. class GraphLoopReplacer : public NewHqlTransformer
  1406. {
  1407. public:
  1408. GraphLoopReplacer(IHqlExpression * _rowsid, IHqlExpression * _represents, IHqlExpression * _counter, bool _isParallel) :
  1409. NewHqlTransformer(graphLoopReplacerInfo), rowsid(_rowsid), represents(_represents), counter(_counter), isParallel(_isParallel)
  1410. {
  1411. }
  1412. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  1413. {
  1414. switch (expr->getOperator())
  1415. {
  1416. case no_counter:
  1417. if (expr->queryBody() == counter)
  1418. {
  1419. if (isParallel)
  1420. {
  1421. HqlExprArray args;
  1422. args.append(*LINK(represents));
  1423. // unwindChildren(args, expr);
  1424. OwnedHqlExpr ret = createValue(no_loopcounter, expr->getType(), args);
  1425. //Yuk: Wrap this in an alias to ensure it is evaluated at the correct place.
  1426. //there has to be a better way..... We could...
  1427. //a) strictly defined when it can be evaluated - e.g., ctx->defines(graph) && (!parentctx || !parentctx->definesGraph)
  1428. //b) set a flag in the expression to indicate forced evaluation (even worse than the alias)
  1429. //c) add the code to evaluate no_loopcounter inside evaluateInContext
  1430. return createAlias(ret, internalAttrExpr);
  1431. }
  1432. else
  1433. {
  1434. counterResult.setown(createCounterAsGraphResult(counter, represents, 0));
  1435. return LINK(counterResult);
  1436. }
  1437. }
  1438. break;
  1439. case no_rowsetindex:
  1440. {
  1441. IHqlExpression * rowset = expr->queryChild(0);
  1442. if (rowset->getOperator() != no_rowset)
  1443. break;
  1444. IHqlExpression * rows = rowset->queryChild(0);
  1445. if (rows->queryChild(1) != rowsid)
  1446. break;
  1447. HqlExprArray args;
  1448. args.append(*LINK(rows->queryChild(0)->queryRecord()));
  1449. args.append(*LINK(represents));
  1450. args.append(*transform(expr->queryChild(1)));
  1451. return createDataset(no_getgraphloopresult, args);
  1452. }
  1453. case no_rowset:
  1454. {
  1455. IHqlExpression * rows = expr->queryChild(0);
  1456. if (rows->queryChild(1) != rowsid)
  1457. break;
  1458. HqlExprArray args;
  1459. args.append(*LINK(rows->queryChild(0)->queryRecord()));
  1460. args.append(*LINK(represents));
  1461. return createValue(no_getgraphloopresultset, expr->getType(), args);
  1462. }
  1463. }
  1464. return NewHqlTransformer::createTransformed(expr);
  1465. }
  1466. inline IHqlExpression * queryCounterResult() { return counterResult; }
  1467. protected:
  1468. IHqlExpression * rowsid;
  1469. IHqlExpression * represents;
  1470. IHqlExpression * counter;
  1471. OwnedHqlExpr counterResult;
  1472. bool isParallel;
  1473. };
  1474. unique_id_t ChildGraphBuilder::buildGraphLoopBody(BuildCtx & ctx, bool isParallel)
  1475. {
  1476. BuildCtx subctx(ctx);
  1477. subctx.addGroup();
  1478. IHqlExpression * query = childQuery->queryChild(2);
  1479. translator.traceExpression("Before Loop resource", query);
  1480. OwnedHqlExpr resourced = translator.getResourcedChildGraph(ctx, childQuery, numResults, no_loop);
  1481. translator.traceExpression("After Loop resource", resourced);
  1482. //Add a flag to indicate multi instance
  1483. if (isParallel)
  1484. {
  1485. HqlExprArray args;
  1486. unwindChildren(args, resourced);
  1487. args.append(*createAttribute(multiInstanceAtom));
  1488. args.append(*createAttribute(delayedAtom));
  1489. resourced.setown(resourced->clone(args));
  1490. }
  1491. bool isGlobalThorLoop = translator.targetThor() && !translator.insideChildQuery(ctx);
  1492. Owned<ParentExtract> extractBuilder = isGlobalThorLoop ? translator.createExtractBuilder(ctx, PETloop, represents, GraphRemote, false)
  1493. : translator.createExtractBuilder(ctx, PETloop, represents, resourced, false);
  1494. createBuilderAlias(subctx, extractBuilder);
  1495. translator.beginExtract(ctx, extractBuilder);
  1496. translator.doBuildThorSubGraph(ctx, resourced, SubGraphLoop, id, represents);
  1497. translator.endExtract(ctx, extractBuilder);
  1498. return id;
  1499. }
  1500. unique_id_t ChildGraphBuilder::buildRemoteGraph(BuildCtx & ctx)
  1501. {
  1502. BuildCtx subctx(ctx);
  1503. subctx.addGroup();
  1504. OwnedHqlExpr resourced = translator.getResourcedChildGraph(ctx, childQuery, numResults, no_allnodes);
  1505. Owned<ParentExtract> extractBuilder = translator.createExtractBuilder(ctx, PETremote, represents, GraphRemote, false);
  1506. createBuilderAlias(subctx, extractBuilder);
  1507. translator.beginExtract(ctx, extractBuilder);
  1508. translator.doBuildThorSubGraph(ctx, resourced, SubGraphChild, id, represents);
  1509. translator.endExtract(ctx, extractBuilder);
  1510. return id;
  1511. }
  1512. void HqlCppTranslator::buildChildGraph(BuildCtx & ctx, IHqlExpression * expr)
  1513. {
  1514. IHqlExpression * represents= expr->queryChild(0);
  1515. OwnedHqlExpr resultsExpr = createAttribute(resultsAtom, LINK(represents));
  1516. //Shouldn't really happen, but if this graph has already benn called just use the results
  1517. if (ctx.queryMatchExpr(resultsExpr))
  1518. return;
  1519. ChildGraphBuilder graphBuilder(*this, expr);
  1520. graphBuilder.generateGraph(ctx);
  1521. }
  1522. void HqlCppTranslator::beginExtract(BuildCtx & ctx, ParentExtract * extractBuilder)
  1523. {
  1524. ctx.associate(*extractBuilder);
  1525. }
  1526. void HqlCppTranslator::endExtract(BuildCtx & ctx, ParentExtract * extractBuilder)
  1527. {
  1528. extractBuilder->endUseExtract(ctx);
  1529. ctx.removeAssociation(extractBuilder);
  1530. }
  1531. void HqlCppTranslator::buildAssignChildDataset(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  1532. {
  1533. switch (expr->getOperator())
  1534. {
  1535. case no_call:
  1536. case no_externalcall:
  1537. case no_libraryinput:
  1538. buildDatasetAssign(ctx, target, expr);
  1539. return;
  1540. }
  1541. OwnedHqlExpr call;
  1542. {
  1543. ChildGraphExprBuilder builder(0);
  1544. call.setown(builder.addDataset(expr));
  1545. OwnedHqlExpr subquery = builder.getGraph();
  1546. buildStmt(ctx, subquery);
  1547. }
  1548. buildExprAssign(ctx, target, call);
  1549. }
  1550. IHqlExpression * HqlCppTranslator::getResourcedChildGraph(BuildCtx & ctx, IHqlExpression * childQuery, unsigned numResults, node_operator graphKind)
  1551. {
  1552. if (options.paranoidCheckNormalized || options.paranoidCheckDependencies)
  1553. DBGLOG("Before resourcing a child graph");
  1554. IHqlExpression * graphIdExpr = childQuery->queryChild(0);
  1555. IHqlExpression * originalQuery = childQuery->queryChild(2);
  1556. LinkedHqlExpr resourced = originalQuery;
  1557. checkNormalized(ctx, resourced);
  1558. unsigned csfFlags = CSFindex|options.optimizeDiskFlag;
  1559. switch (targetClusterType)
  1560. {
  1561. case HThorCluster:
  1562. csfFlags |= CSFcompoundSpill;
  1563. break;
  1564. case ThorLCRCluster:
  1565. //Don't compound spills inside a child query because it can cause non remote projects to become remote
  1566. //And we'll also probably be using the roxie code to implement
  1567. break;
  1568. case RoxieCluster:
  1569. break;
  1570. }
  1571. {
  1572. cycle_t startCycles = get_cycles_now();
  1573. CompoundSourceTransformer transformer(*this, CSFpreload|csfFlags);
  1574. resourced.setown(transformer.process(resourced));
  1575. checkNormalized(ctx, resourced);
  1576. noteFinishedTiming("workunit;tree transform: optimize disk read", startCycles);
  1577. }
  1578. if (options.optimizeGraph)
  1579. {
  1580. cycle_t startCycles = get_cycles_now();
  1581. traceExpression("BeforeOptimizeSub", resourced);
  1582. resourced.setown(optimizeHqlExpression(queryErrorProcessor(), resourced, getOptimizeFlags()|HOOcompoundproject));
  1583. traceExpression("AfterOptimizeSub", resourced);
  1584. noteFinishedTiming("workunit;optimize graph", startCycles);
  1585. }
  1586. traceExpression("BeforeResourcing Child", resourced);
  1587. cycle_t startCycles = get_cycles_now();
  1588. HqlExprCopyArray activeRows;
  1589. gatherActiveCursors(ctx, activeRows);
  1590. if (graphKind == no_loop)
  1591. {
  1592. bool insideChild = insideChildQuery(ctx);
  1593. resourced.setown(resourceLoopGraph(*this, activeRows, resourced, targetClusterType, graphIdExpr, numResults, insideChild));
  1594. }
  1595. else
  1596. resourced.setown(resourceNewChildGraph(*this, activeRows, resourced, targetClusterType, graphIdExpr, numResults));
  1597. noteFinishedTiming("workunit;resource graph", startCycles);
  1598. checkNormalized(ctx, resourced);
  1599. traceExpression("AfterResourcing Child", resourced);
  1600. resourced.setown(optimizeGraphPostResource(resourced, csfFlags, false));
  1601. if (options.optimizeSpillProject)
  1602. {
  1603. resourced.setown(convertSpillsToActivities(resourced, true));
  1604. resourced.setown(optimizeGraphPostResource(resourced, csfFlags, false));
  1605. }
  1606. if (options.paranoidCheckNormalized || options.paranoidCheckDependencies)
  1607. DBGLOG("After resourcing a child graph");
  1608. return resourced.getClear();
  1609. }
  1610. void HqlCppTranslator::buildChildDataset(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  1611. {
  1612. if (expr->isPure() && ctx.getMatchExpr(expr, tgt))
  1613. return;
  1614. LoopInvariantHelper helper;
  1615. BuildCtx bestctx(ctx);
  1616. if (options.optimizeLoopInvariant)
  1617. helper.getBestContext(bestctx, expr);
  1618. CHqlBoundTarget temp;
  1619. //MORE: Should have similar code to buildTempExpr()
  1620. createTempFor(bestctx, expr, temp);
  1621. buildAssignChildDataset(bestctx, temp, expr);
  1622. tgt.setFromTarget(temp);
  1623. if (expr->isPure())
  1624. bestctx.associateExpr(expr, tgt);
  1625. }
  1626. unique_id_t HqlCppTranslator::buildGraphLoopSubgraph(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * selSeq, IHqlExpression * rowsid, IHqlExpression * body, IHqlExpression * counter, bool multiInstance)
  1627. {
  1628. ChildGraphExprBuilder graphBuilder(0);
  1629. OwnedHqlExpr transformedBody;
  1630. OwnedHqlExpr counterResult;
  1631. IHqlExpression * graphid = graphBuilder.queryRepresents();
  1632. {
  1633. const bool isParallel = multiInstance;
  1634. GraphLoopReplacer replacer(rowsid, graphid, counter, isParallel);
  1635. transformedBody.setown(replacer.transformRoot(body));
  1636. counterResult.set(replacer.queryCounterResult());
  1637. }
  1638. if (counterResult)
  1639. graphBuilder.addInput();
  1640. OwnedHqlExpr result = createValue(no_setgraphloopresult, makeVoidType(), LINK(transformedBody), LINK(graphid));
  1641. graphBuilder.addAction(result);
  1642. OwnedHqlExpr subquery = graphBuilder.getGraph();
  1643. ChildGraphBuilder builder(*this, subquery);
  1644. return builder.buildGraphLoopBody(ctx, multiInstance);
  1645. }
  1646. unique_id_t HqlCppTranslator::buildRemoteSubgraph(BuildCtx & ctx, IHqlExpression * dataset)
  1647. {
  1648. ChildGraphExprBuilder graphBuilder(0);
  1649. if (dataset->isAction())
  1650. {
  1651. graphBuilder.addAction(dataset);
  1652. }
  1653. else
  1654. {
  1655. OwnedHqlExpr ignoredResult = graphBuilder.addDataset(dataset);
  1656. }
  1657. OwnedHqlExpr subquery = graphBuilder.getGraph();
  1658. ChildGraphBuilder builder(*this, subquery);
  1659. return builder.buildRemoteGraph(ctx);
  1660. }
  1661. //---------------------------------------------------------------------------
  1662. // Functions to check whether a dataset can be evaluated inline or not.
  1663. //MORE: These should probably be split out into an hqlinline.cpp
  1664. bool HqlCppTranslator::canIterateInline(BuildCtx * ctx, IHqlExpression * expr)
  1665. {
  1666. return (isInlineOk() && ::canIterateInline(ctx, expr));
  1667. }
  1668. bool HqlCppTranslator::canAssignInline(BuildCtx * ctx, IHqlExpression * expr)
  1669. {
  1670. if (!isInlineOk())
  1671. return false;
  1672. return options.allowInlineSpill ? ::canProcessInline(ctx, expr) : ::canAssignInline(ctx, expr);
  1673. }
  1674. bool HqlCppTranslator::canEvaluateInline(BuildCtx * ctx, IHqlExpression * expr)
  1675. {
  1676. if (!isInlineOk())
  1677. return false;
  1678. return options.allowInlineSpill ? ::canProcessInline(ctx, expr) : ::canEvaluateInline(ctx, expr);
  1679. }
  1680. bool HqlCppTranslator::canProcessInline(BuildCtx * ctx, IHqlExpression * expr)
  1681. {
  1682. if (!isInlineOk())
  1683. return false;
  1684. return ::canProcessInline(ctx, expr);
  1685. }
  1686. bool HqlCppTranslator::isInlineOk()
  1687. {
  1688. if (!activeGraphCtx)
  1689. return true;
  1690. return true;
  1691. }
  1692. IHqlExpression * HqlCppTranslator::buildSpillChildDataset(BuildCtx & ctx, IHqlExpression * expr)
  1693. {
  1694. CHqlBoundExpr bound;
  1695. buildChildDataset(ctx, expr, bound);
  1696. return bound.getTranslatedExpr();
  1697. }
  1698. IHqlExpression * HqlCppTranslator::forceInlineAssignDataset(BuildCtx & ctx, IHqlExpression * expr)
  1699. {
  1700. loop
  1701. {
  1702. CHqlBoundExpr bound;
  1703. if (expr->isPure() && ctx.getMatchExpr(expr, bound))
  1704. return bound.getTranslatedExpr();
  1705. if (canProcessInline(&ctx, expr) || (expr->getOperator() == no_translated))
  1706. return LINK(expr);
  1707. switch (expr->getOperator())
  1708. {
  1709. case no_compound:
  1710. buildStmt(ctx, expr->queryChild(0));
  1711. expr = expr->queryChild(1);
  1712. break;
  1713. default:
  1714. return buildSpillChildDataset(ctx, expr);
  1715. }
  1716. }
  1717. }
  1718. //---------------------------------------------------------------------------
  1719. // Dataset temp creation
  1720. IHqlExpression * createGetResultFromWorkunitDataset(IHqlExpression * expr)
  1721. {
  1722. IHqlExpression * name = queryAttributeChild(expr, nameAtom, 0);
  1723. if (name)
  1724. name = createExprAttribute(namedAtom, LINK(name));
  1725. assertex(expr->isDataset());
  1726. return createDataset(no_getresult, LINK(expr->queryRecord()), createComma(LINK(expr->queryAttribute(sequenceAtom)), name));
  1727. }
  1728. void HqlCppTranslator::buildAssignSerializedDataset(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, IAtom * serializeForm)
  1729. {
  1730. OwnedITypeInfo serializedType = getSerializedForm(expr->queryType(), serializeForm);
  1731. assertex(recordTypesMatch(target.queryType(), serializedType));
  1732. HqlExprArray args;
  1733. args.append(*createSerializer(ctx, expr->queryRecord(), serializeForm, serializerAtom));
  1734. args.append(*LINK(expr));
  1735. IIdAtom * func;
  1736. if (target.expr->isDictionary())
  1737. {
  1738. assertex(serializeForm == internalAtom);
  1739. func = rtlSerializeDictionaryId;
  1740. }
  1741. else if (expr->isDictionary())
  1742. {
  1743. assertex(serializeForm == diskAtom);
  1744. func = rtlSerializeDictionaryToDatasetId;
  1745. }
  1746. else
  1747. {
  1748. if (isGrouped(expr))
  1749. func = groupedRowset2DatasetXId;
  1750. else
  1751. func = rowset2DatasetXId;
  1752. }
  1753. OwnedHqlExpr call = bindFunctionCall(func, args, serializedType);
  1754. buildExprAssign(ctx, target, call);
  1755. }
  1756. void HqlCppTranslator::buildSerializedDataset(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, IAtom * serializeForm)
  1757. {
  1758. CHqlBoundTarget target;
  1759. OwnedITypeInfo serializedType = getSerializedForm(expr->queryType(), serializeForm);
  1760. createTempFor(ctx, serializedType, target, typemod_none, FormatBlockedDataset);
  1761. buildAssignSerializedDataset(ctx, target, expr, serializeForm);
  1762. tgt.setFromTarget(target);
  1763. }
  1764. void HqlCppTranslator::buildAssignDeserializedDataset(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, IAtom * serializeForm)
  1765. {
  1766. OwnedITypeInfo serializedType = getSerializedForm(target.queryType(), serializeForm);
  1767. assertex(recordTypesMatch(serializedType, expr->queryType()));
  1768. IIdAtom * func;
  1769. IHqlExpression * record = ::queryRecord(target.queryType());
  1770. HqlExprArray args;
  1771. args.append(*createSerializer(ctx, record, serializeForm, deserializerAtom));
  1772. if (target.expr->isDictionary())
  1773. {
  1774. if (serializeForm == internalAtom)
  1775. {
  1776. assertex(expr->isDictionary());
  1777. func = rtlDeserializeDictionaryId;
  1778. }
  1779. else if (serializeForm == diskAtom)
  1780. {
  1781. assertex(expr->isDataset());
  1782. func = rtlDeserializeDictionaryFromDatasetId;
  1783. StringBuffer lookupHelperName;
  1784. buildDictionaryHashClass(record, lookupHelperName);
  1785. args.append(*createQuoted(lookupHelperName.str(), makeBoolType()));
  1786. }
  1787. else
  1788. throwUnexpected();
  1789. }
  1790. else
  1791. {
  1792. if (isGrouped(expr))
  1793. func = groupedDataset2RowsetXId;
  1794. else
  1795. func = dataset2RowsetXId;
  1796. }
  1797. args.append(*LINK(expr));
  1798. OwnedHqlExpr call = bindFunctionCall(func, args, target.queryType());
  1799. buildExprAssign(ctx, target, call);
  1800. }
  1801. void HqlCppTranslator::buildDeserializedDataset(BuildCtx & ctx, ITypeInfo * type, IHqlExpression * expr, CHqlBoundExpr & tgt, IAtom * serializeForm)
  1802. {
  1803. #ifdef _DEBUG
  1804. OwnedITypeInfo serializedType = getSerializedForm(type, serializeForm);
  1805. assertex(recordTypesMatch(expr->queryType(), serializedType));
  1806. #endif
  1807. ITypeInfo * const exprType = expr->queryType();
  1808. assertex(!hasLinkedRow(exprType));
  1809. CHqlBoundTarget target;
  1810. createTempFor(ctx, type, target, typemod_none, FormatLinkedDataset);
  1811. buildAssignDeserializedDataset(ctx, target, expr, serializeForm);
  1812. tgt.setFromTarget(target);
  1813. }
  1814. void HqlCppTranslator::ensureDatasetFormat(BuildCtx & ctx, ITypeInfo * type, CHqlBoundExpr & tgt, ExpressionFormat format)
  1815. {
  1816. IAtom * serializeForm = internalAtom; // The format of serialized expressions in memory must match the internal serialization format
  1817. ITypeInfo * tgtType = tgt.queryType();
  1818. switch (format)
  1819. {
  1820. case FormatStreamedDataset:
  1821. if (!hasStreamedModifier(tgtType))
  1822. {
  1823. ensureDatasetFormat(ctx, type, tgt, FormatLinkedDataset);
  1824. HqlExprArray args;
  1825. args.append(*tgt.getTranslatedExpr());
  1826. OwnedITypeInfo streamedType = setStreamedAttr(type, true);
  1827. OwnedHqlExpr call = bindFunctionCall(createRowStreamId, args, streamedType);
  1828. buildTempExpr(ctx, call, tgt);
  1829. return;
  1830. }
  1831. break;
  1832. case FormatBlockedDataset:
  1833. if (isArrayRowset(tgtType))
  1834. {
  1835. OwnedHqlExpr deserializedExpr = tgt.getTranslatedExpr();
  1836. LinkedHqlExpr savedCount = tgt.count;
  1837. assertex(!deserializedExpr->isDictionary());
  1838. buildSerializedDataset(ctx, deserializedExpr, tgt, serializeForm);
  1839. if (savedCount && !isFixedWidthDataset(deserializedExpr))
  1840. tgt.count.set(savedCount);
  1841. return;
  1842. }
  1843. break;
  1844. case FormatLinkedDataset:
  1845. if (!hasLinkCountedModifier(tgtType))
  1846. {
  1847. OwnedHqlExpr serializedExpr = tgt.getTranslatedExpr();
  1848. if (recordTypesMatch(type, tgtType))
  1849. {
  1850. //source is an array of rows, or a simple dataset that doesn't need any transformation
  1851. buildTempExpr(ctx, serializedExpr, tgt, FormatLinkedDataset);
  1852. }
  1853. else
  1854. buildDeserializedDataset(ctx, type, serializedExpr, tgt, serializeForm);
  1855. return;
  1856. }
  1857. break;
  1858. case FormatArrayDataset:
  1859. if (!isArrayRowset(tgtType))
  1860. {
  1861. OwnedHqlExpr serializedExpr = tgt.getTranslatedExpr();
  1862. buildDeserializedDataset(ctx, type, serializedExpr, tgt, serializeForm);
  1863. return;
  1864. }
  1865. break;
  1866. }
  1867. }
  1868. void HqlCppTranslator::buildDataset(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  1869. {
  1870. doBuildDataset(ctx, expr, tgt, format);
  1871. ensureDatasetFormat(ctx, expr->queryType(), tgt, format);
  1872. }
  1873. void HqlCppTranslator::doBuildDataset(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  1874. {
  1875. if (expr->isPure() && ctx.getMatchExpr(expr, tgt))
  1876. return;
  1877. /*
  1878. OwnedHqlExpr transformed = normalizeAnyDatasetAliases(expr);
  1879. if (transformed && (transformed != expr))
  1880. {
  1881. doBuildDataset(ctx, transformed, tgt, format);
  1882. ctx.associateExpr(expr, tgt);
  1883. return;
  1884. }
  1885. */
  1886. node_operator op = expr->getOperator();
  1887. switch (op)
  1888. {
  1889. case no_dataset_alias:
  1890. if (!expr->hasAttribute(_normalized_Atom))
  1891. {
  1892. OwnedHqlExpr uniqueChild = normalizeDatasetAlias(expr);
  1893. doBuildDataset(ctx, uniqueChild, tgt, format);
  1894. }
  1895. else
  1896. doBuildDataset(ctx, expr->queryChild(0), tgt, format);
  1897. return;
  1898. case no_alias:
  1899. doBuildExprAlias(ctx, expr, &tgt, NULL);
  1900. return;
  1901. case no_owned_ds:
  1902. buildTempExpr(ctx, expr, tgt);
  1903. return;
  1904. case no_fail:
  1905. doBuildStmtFail(ctx, expr->queryChild(1));
  1906. //fallthrough
  1907. case no_null:
  1908. doBuildDatasetNull(expr, tgt, format);
  1909. return;
  1910. case no_translated:
  1911. expandTranslated(expr, tgt);
  1912. return;
  1913. case no_select:
  1914. {
  1915. if (isMultiLevelDatasetSelector(expr, false))
  1916. break;
  1917. Owned<IReferenceSelector> selected = buildReference(ctx, expr);
  1918. selected->get(ctx, tgt);
  1919. return;
  1920. }
  1921. case no_libraryinput:
  1922. if (!buildExprInCorrectContext(ctx, expr, tgt, false))
  1923. throwUnexpected();
  1924. return;
  1925. case no_call:
  1926. case no_externalcall:
  1927. buildTempExpr(ctx, expr, tgt);
  1928. return;
  1929. case no_newaggregate:
  1930. if (canAssignInline(&ctx, expr))
  1931. {
  1932. Owned<BoundRow> tempRow = declareTempAnonRow(ctx, ctx, expr);
  1933. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, tempRow);
  1934. Owned<IReferenceSelector> createdRef = createReferenceSelector(rowBuilder);
  1935. doBuildRowAssignAggregate(ctx, createdRef, expr);
  1936. finalizeTempRow(ctx, tempRow, rowBuilder);
  1937. convertBoundRowToDataset(ctx, tgt, tempRow, format);
  1938. return;
  1939. }
  1940. break;
  1941. case no_id2blob:
  1942. doBuildExprIdToBlob(ctx, expr, tgt);
  1943. return;
  1944. case no_rows:
  1945. {
  1946. if (!buildExprInCorrectContext(ctx, expr, tgt, false))
  1947. throwError(HQLERR_RowsUsedOutsideContext);
  1948. return;
  1949. }
  1950. case no_limit:
  1951. if (expr->hasAttribute(skipAtom) || expr->hasAttribute(onFailAtom))
  1952. break;
  1953. doBuildDatasetLimit(ctx, expr, tgt, format);
  1954. return;
  1955. case no_compound_childread:
  1956. case no_compound_childnormalize:
  1957. case no_compound_childaggregate:
  1958. case no_compound_selectnew:
  1959. case no_compound_inline:
  1960. case no_distributed:
  1961. case no_unordered:
  1962. case no_preservemeta:
  1963. case no_sorted:
  1964. case no_nofold:
  1965. case no_nohoist:
  1966. case no_nocombine:
  1967. case no_section:
  1968. case no_sectioninput:
  1969. buildDataset(ctx, expr->queryChild(0), tgt, format);
  1970. return;
  1971. case no_forcegraph:
  1972. #ifdef _DEBUG
  1973. throwUnexpected();
  1974. #endif
  1975. buildDataset(ctx, expr->queryChild(0), tgt, format);
  1976. return;
  1977. case no_getgraphresult:
  1978. doBuildExprGetGraphResult(ctx, expr, tgt, format);
  1979. return;
  1980. case no_getresult:
  1981. case no_workunit_dataset:
  1982. doBuildExprGetResult(ctx, expr, tgt);
  1983. return;
  1984. case no_skip:
  1985. {
  1986. buildStmt(ctx, expr);
  1987. OwnedHqlExpr null = createNullExpr(expr);
  1988. buildDataset(ctx, null, tgt, format);
  1989. return;
  1990. }
  1991. case no_serialize:
  1992. {
  1993. IHqlExpression * deserialized = expr->queryChild(0);
  1994. IAtom * serializeForm = expr->queryChild(1)->queryName();
  1995. if (isDummySerializeDeserialize(expr))
  1996. doBuildDataset(ctx, deserialized->queryChild(0), tgt, format);
  1997. else if (!typeRequiresDeserialization(deserialized->queryType(), serializeForm))
  1998. //Optimize creating a serialized version of a dataset if the record is the same serialized and unserialized
  1999. buildDataset(ctx, deserialized, tgt, FormatNatural);
  2000. else
  2001. buildSerializedDataset(ctx, deserialized, tgt, serializeForm);
  2002. return;
  2003. }
  2004. case no_deserialize:
  2005. {
  2006. IHqlExpression * serialized = expr->queryChild(0);
  2007. IAtom * serializeForm = expr->queryChild(2)->queryName();
  2008. if (isDummySerializeDeserialize(expr))
  2009. doBuildDataset(ctx, serialized->queryChild(0), tgt, format);
  2010. else if (!typeRequiresDeserialization(expr->queryType(), serializeForm))
  2011. //Optimize creating a deserialized version of a dataset if the record is the same serialized and unserialized
  2012. buildDataset(ctx, serialized, tgt, FormatNatural);
  2013. else
  2014. buildDeserializedDataset(ctx, expr->queryType(), serialized, tgt, serializeForm);
  2015. return;
  2016. }
  2017. case no_datasetfromrow:
  2018. {
  2019. IHqlExpression * row = expr->queryChild(0);
  2020. if (isAlwaysActiveRow(row) && (format == FormatNatural))
  2021. {
  2022. Owned<IReferenceSelector> selector = buildActiveRow(ctx, row);
  2023. BuildCtx groupctx(ctx);
  2024. groupctx.addGroup();
  2025. BoundRow * bound = bindSelectorAsRootRow(groupctx, selector, row);
  2026. convertBoundRowToDataset(groupctx, tgt, bound, format);
  2027. tgt.count.setown(getSizetConstant(1));
  2028. ctx.associateExpr(expr, tgt);
  2029. return;
  2030. }
  2031. break;
  2032. }
  2033. case no_inlinetable:
  2034. if (doBuildConstantDatasetInlineTable(expr, tgt, format))
  2035. return;
  2036. break;
  2037. case no_compound:
  2038. {
  2039. buildStmt(ctx, expr->queryChild(0));
  2040. buildDataset(ctx, expr->queryChild(1), tgt, format);
  2041. return;
  2042. }
  2043. case no_createdictionary:
  2044. {
  2045. if (isConstantDictionary(expr))
  2046. {
  2047. if (doBuildDictionaryInlineTable(ctx, expr, tgt, format))
  2048. return;
  2049. }
  2050. IHqlExpression * record = expr->queryRecord();
  2051. IHqlExpression * dataset = expr->queryChild(0);
  2052. Owned<IHqlCppDatasetBuilder> builder = createLinkedDictionaryBuilder(record);
  2053. builder->buildDeclare(ctx);
  2054. buildDatasetAssign(ctx, builder, dataset);
  2055. builder->buildFinish(ctx, tgt);
  2056. ctx.associateExpr(expr, tgt);
  2057. return;
  2058. }
  2059. case no_if:
  2060. if (::canEvaluateInline(&ctx, expr->queryChild(1)) && ::canEvaluateInline(&ctx, expr->queryChild(2)))
  2061. {
  2062. buildTempExpr(ctx, expr, tgt, format);
  2063. return;
  2064. }
  2065. }
  2066. if (expr->isDictionary())
  2067. {
  2068. buildTempExpr(ctx, expr, tgt, format);
  2069. return;
  2070. }
  2071. bool singleRow = hasSingleRow(expr);
  2072. bool useTempRow = singleRow && canAssignInline(&ctx, expr) && (format != FormatLinkedDataset) && (format != FormatArrayDataset);
  2073. //Conditional row assignment if variable length causes offset to be recalculated outside of the if()
  2074. //if (useTempRow && (op == no_if) && isVariableSizeRecord(expr->queryRecord()))
  2075. // useTempRow = false;
  2076. if (useTempRow)
  2077. {
  2078. Owned<BoundRow> tempRow = declareTempAnonRow(ctx, ctx, expr);
  2079. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, tempRow);
  2080. Owned<IHqlCppDatasetBuilder> builder = createSingleRowTempDatasetBuilder(expr->queryRecord(), rowBuilder);
  2081. builder->buildDeclare(ctx);
  2082. buildDatasetAssign(ctx, builder, expr);
  2083. //builder->buildFinish(ctx, tempTarget);
  2084. finalizeTempRow(ctx, tempRow, rowBuilder);
  2085. convertBoundRowToDataset(ctx, tgt, tempRow, format);
  2086. }
  2087. else
  2088. {
  2089. if (!canAssignInline(&ctx, expr))
  2090. {
  2091. CHqlBoundTarget tempTarget;
  2092. createTempFor(ctx, expr->queryType(), tempTarget, typemod_none, format);
  2093. buildDatasetAssign(ctx, tempTarget, expr);
  2094. tgt.setFromTarget(tempTarget);
  2095. //buildTempExpr(ctx, expr, tgt); // can't use this because it causes recursion on no_selectnth
  2096. }
  2097. else
  2098. {
  2099. Owned<IHqlCppDatasetBuilder> builder;
  2100. IHqlExpression * record = expr->queryRecord();
  2101. IAtom * serializeForm = internalAtom; // The format of serialized expressions in memory must match the internal serialization format
  2102. OwnedHqlExpr serializedRecord = getSerializedForm(record, serializeForm);
  2103. if (format == FormatNatural)
  2104. {
  2105. if (record != serializedRecord)
  2106. ensureContextAvailable(ctx);
  2107. if (!ctx.queryMatchExpr(codeContextMarkerExpr))
  2108. {
  2109. if (record != serializedRecord)
  2110. throwError(HQLERR_LinkedDatasetNoContext);
  2111. format = FormatBlockedDataset;
  2112. }
  2113. else
  2114. {
  2115. format = FormatLinkedDataset;
  2116. }
  2117. }
  2118. else if (record != serializedRecord)
  2119. format = FormatLinkedDataset; // Have to serialize it later - otherwise it won't be compatible
  2120. if (format == FormatLinkedDataset || format == FormatArrayDataset)
  2121. {
  2122. IHqlExpression * choosenLimit = NULL;
  2123. if ((op == no_choosen) && !isChooseNAllLimit(expr->queryChild(1)) && !queryRealChild(expr, 2))
  2124. {
  2125. choosenLimit = expr->queryChild(1);
  2126. expr = expr->queryChild(0);
  2127. }
  2128. //MORE: Extract limit and choosen and pass as parameters
  2129. builder.setown(createLinkedDatasetBuilder(record, choosenLimit));
  2130. }
  2131. else if ((op == no_choosen) && !isChooseNAllLimit(expr->queryChild(1)) && !queryRealChild(expr, 2))
  2132. {
  2133. //Build a limited builder - it is likely to be just as efficient, and often much more e.g., choosen(a+b, n)
  2134. builder.setown(createChoosenDatasetBuilder(serializedRecord, expr->queryChild(1)));
  2135. expr = expr->queryChild(0);
  2136. }
  2137. else
  2138. builder.setown(createBlockedDatasetBuilder(serializedRecord));
  2139. builder->buildDeclare(ctx);
  2140. buildDatasetAssign(ctx, builder, expr);
  2141. builder->buildFinish(ctx, tgt);
  2142. }
  2143. }
  2144. if (singleRow)
  2145. tgt.count.setown(getSizetConstant(1));
  2146. else if (op == no_inlinetable)
  2147. {
  2148. IHqlExpression * transforms = expr->queryChild(0);
  2149. if (!transformListContainsSkip(transforms))
  2150. tgt.count.setown(getSizetConstant(transforms->numChildren()));
  2151. }
  2152. ctx.associateExpr(expr, tgt);
  2153. }
  2154. //---------------------------------------------------------------------------
  2155. // Dataset assignment - to temp
  2156. static bool isWorthAssigningDirectly(BuildCtx & ctx, const CHqlBoundTarget & /*target*/, IHqlExpression * expr)
  2157. {
  2158. //target parameter is currently unused - it should be used to check that linkcounted attributes match etc.
  2159. if (expr->getOperator() == no_null)
  2160. return false;
  2161. //A poor approximation. Could also include function calls if the is-link-counted matches.
  2162. return ::canEvaluateInline(&ctx, expr);
  2163. }
  2164. void HqlCppTranslator::buildDatasetAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  2165. {
  2166. node_operator op = expr->getOperator();
  2167. switch (op)
  2168. {
  2169. case no_fail:
  2170. doBuildStmtFail(ctx, expr->queryChild(1));
  2171. return;
  2172. case no_call:
  2173. case no_externalcall:
  2174. doBuildCall(ctx, &target, expr, NULL);
  2175. return;
  2176. case no_getgraphresult:
  2177. doBuildAssignGetGraphResult(ctx, target, expr);
  2178. return;
  2179. case no_workunit_dataset:
  2180. case no_getresult:
  2181. buildExprAssign(ctx, target, expr);
  2182. return;
  2183. case no_null:
  2184. {
  2185. CHqlBoundExpr bound;
  2186. buildDataset(ctx, expr, bound, isArrayRowset(target.queryType()) ? FormatLinkedDataset : FormatBlockedDataset);
  2187. if (hasWrapperModifier(target.queryType()) && hasLinkCountedModifier(target.queryType()))
  2188. {
  2189. OwnedHqlExpr complex = bound.getComplexExpr();
  2190. ctx.addAssign(target.expr, complex);
  2191. }
  2192. else
  2193. {
  2194. if (target.count) ctx.addAssign(target.count, bound.count);
  2195. if (target.length) ctx.addAssign(target.length, bound.length);
  2196. ctx.addAssign(target.expr, bound.expr);
  2197. }
  2198. return;
  2199. }
  2200. case no_inlinetable:
  2201. {
  2202. //This will typically generate a loop. If few items then it is more efficient to expand the assigns/clones out.
  2203. if (options.canLinkConstantRows || (expr->queryChild(0)->numChildren() > INLINE_TABLE_EXPAND_LIMIT))
  2204. {
  2205. CHqlBoundExpr bound;
  2206. if (doBuildConstantDatasetInlineTable(expr, bound, FormatNatural))
  2207. {
  2208. OwnedHqlExpr translated = bound.getTranslatedExpr();
  2209. buildDatasetAssign(ctx, target, translated);
  2210. return;
  2211. }
  2212. }
  2213. break;
  2214. }
  2215. case no_alias:
  2216. {
  2217. CHqlBoundExpr bound;
  2218. buildDataset(ctx, expr, bound, FormatNatural);
  2219. OwnedHqlExpr translated = bound.getTranslatedExpr();
  2220. buildDatasetAssign(ctx, target, translated);
  2221. return;
  2222. }
  2223. case no_owned_ds:
  2224. {
  2225. ITypeInfo * targetType = target.queryType();
  2226. if (hasLinkCountedModifier(targetType) && hasWrapperModifier(targetType))
  2227. {
  2228. CHqlBoundExpr bound;
  2229. buildDataset(ctx, expr->queryChild(0), bound, FormatLinkedDataset);
  2230. OwnedHqlExpr compound = createValue(no_complex, bound.expr->getType(), LINK(bound.count), LINK(bound.expr));
  2231. ctx.addAssign(target.expr, compound);
  2232. return;
  2233. }
  2234. break;
  2235. }
  2236. case no_compound:
  2237. {
  2238. buildStmt(ctx, expr->queryChild(0));
  2239. buildDatasetAssign(ctx, target, expr->queryChild(1));
  2240. return;
  2241. }
  2242. case no_compound_childread:
  2243. case no_compound_childnormalize:
  2244. case no_compound_childaggregate:
  2245. case no_compound_selectnew:
  2246. case no_compound_inline:
  2247. case no_distributed:
  2248. case no_unordered:
  2249. case no_preservemeta:
  2250. case no_sorted:
  2251. case no_nofold:
  2252. case no_nohoist:
  2253. case no_forcegraph:
  2254. case no_nocombine:
  2255. case no_section:
  2256. case no_sectioninput:
  2257. buildDatasetAssign(ctx, target, expr->queryChild(0));
  2258. return;
  2259. case no_if:
  2260. //Only generate conditional assignments to a target if both source and target require no temporary.
  2261. if (expr->isDictionary() || (::canEvaluateInline(&ctx, expr->queryChild(1)) && ::canEvaluateInline(&ctx, expr->queryChild(2))))
  2262. //The following line would be better, but it needs improvements to the cse generation first, otherwise some examples get worse.
  2263. //if (expr->isDictionary() || (isWorthAssigningDirectly(ctx, target, expr->queryChild(1)) || isWorthAssigningDirectly(ctx, target, expr->queryChild(2))))
  2264. {
  2265. buildDatasetAssignIf(ctx, target, expr);
  2266. return;
  2267. }
  2268. break;
  2269. case no_chooseds:
  2270. if (expr->isDictionary())
  2271. {
  2272. buildDatasetAssignChoose(ctx, target, expr);
  2273. return;
  2274. }
  2275. break;
  2276. case no_serialize:
  2277. {
  2278. IHqlExpression * deserialized = expr->queryChild(0);
  2279. IAtom * serializeForm = expr->queryChild(1)->queryName();
  2280. if (isDummySerializeDeserialize(expr))
  2281. buildDatasetAssign(ctx, target, deserialized->queryChild(0));
  2282. else if (!typeRequiresDeserialization(deserialized->queryType(), serializeForm))
  2283. buildDatasetAssign(ctx, target, deserialized);
  2284. else
  2285. buildAssignSerializedDataset(ctx, target, deserialized, serializeForm);
  2286. return;
  2287. }
  2288. case no_deserialize:
  2289. {
  2290. IHqlExpression * serialized = expr->queryChild(0);
  2291. IAtom * serializeForm = expr->queryChild(2)->queryName();
  2292. if (isDummySerializeDeserialize(expr))
  2293. buildDatasetAssign(ctx, target, serialized->queryChild(0));
  2294. else if (!typeRequiresDeserialization(expr->queryType(), serializeForm))
  2295. buildDatasetAssign(ctx, target, serialized);
  2296. else
  2297. buildAssignDeserializedDataset(ctx, target, serialized, serializeForm);
  2298. return;
  2299. }
  2300. case no_select:
  2301. {
  2302. bool isNew;
  2303. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  2304. if (!isNew || ds->isDatarow())
  2305. {
  2306. Owned<IReferenceSelector> selected = buildReference(ctx, expr);
  2307. selected->assignTo(ctx, target);
  2308. return;
  2309. }
  2310. break;
  2311. }
  2312. case no_typetransfer:
  2313. {
  2314. IHqlExpression * child = expr->queryChild(0);
  2315. if (expr->isDataset() && child->isDataset())
  2316. {
  2317. //Special case no-op type transfers and assignment from a call returning unknown-type dataset
  2318. if (!recordTypesMatch(expr, child) &&
  2319. !(child->getOperator() == no_externalcall && recordTypesMatch(child, queryNullRecord())))
  2320. {
  2321. CHqlBoundExpr bound;
  2322. buildDataset(ctx, child, bound, FormatNatural);
  2323. ITypeInfo * newType = cloneModifiers(bound.expr->queryType(), expr->queryType());
  2324. bound.expr.setown(createValue(no_typetransfer, newType, LINK(bound.expr)));
  2325. OwnedHqlExpr translated = bound.getTranslatedExpr();
  2326. buildDatasetAssign(ctx, target, translated);
  2327. }
  2328. else
  2329. buildDatasetAssign(ctx, target, child);
  2330. return;
  2331. }
  2332. break;
  2333. }
  2334. case no_createdictionary:
  2335. {
  2336. if (isConstantDictionary(expr))
  2337. {
  2338. CHqlBoundExpr temp;
  2339. if (doBuildDictionaryInlineTable(ctx, expr, temp, FormatNatural))
  2340. {
  2341. OwnedHqlExpr translated = temp.getTranslatedExpr();
  2342. buildDatasetAssign(ctx, target, translated);
  2343. return;
  2344. }
  2345. }
  2346. IHqlExpression * record = expr->queryRecord();
  2347. Owned<IHqlCppDatasetBuilder> builder = createLinkedDictionaryBuilder(record);
  2348. builder->buildDeclare(ctx);
  2349. buildDatasetAssign(ctx, builder, expr->queryChild(0));
  2350. builder->buildFinish(ctx, target);
  2351. return;
  2352. }
  2353. }
  2354. if (!canAssignInline(&ctx, expr) && (op != no_translated))
  2355. {
  2356. buildAssignChildDataset(ctx, target, expr);
  2357. return;
  2358. }
  2359. ITypeInfo * to = target.queryType();
  2360. ITypeInfo * exprType = expr->queryType();
  2361. bool targetOutOfLine = isArrayRowset(to);
  2362. switch (op)
  2363. {
  2364. case no_limit:
  2365. assertex(!expr->hasAttribute(skipAtom) && !expr->hasAttribute(onFailAtom));
  2366. //Do the limit check as a post test.
  2367. //It means we may read more records than we need to, but the code is inline, and the code is generally much better.
  2368. if (target.count)
  2369. {
  2370. buildDatasetAssign(ctx, target, expr->queryChild(0));
  2371. CHqlBoundExpr bound;
  2372. bound.setFromTarget(target);
  2373. doBuildCheckDatasetLimit(ctx, expr, bound);
  2374. return;
  2375. }
  2376. break;
  2377. case no_translated:
  2378. {
  2379. bool sourceOutOfLine = isArrayRowset(exprType);
  2380. if (sourceOutOfLine != targetOutOfLine && !hasStreamedModifier(exprType))
  2381. {
  2382. IAtom * serializeFormat = internalAtom; // The format of serialized expressions in memory must match the internal serialization format
  2383. OwnedITypeInfo serializedSourceType = getSerializedForm(exprType, serializeFormat);
  2384. OwnedITypeInfo serializedTargetType = getSerializedForm(to, serializeFormat);
  2385. if (queryUnqualifiedType(serializedSourceType) == queryUnqualifiedType(serializedTargetType))
  2386. {
  2387. if (targetOutOfLine)
  2388. {
  2389. buildAssignDeserializedDataset(ctx, target, expr, serializeFormat);
  2390. }
  2391. else
  2392. {
  2393. buildAssignSerializedDataset(ctx, target, expr, serializeFormat);
  2394. }
  2395. return;
  2396. }
  2397. }
  2398. break;
  2399. }
  2400. }
  2401. if (recordTypesMatch(to, exprType))
  2402. {
  2403. switch (op)
  2404. {
  2405. case no_rows:
  2406. {
  2407. CHqlBoundExpr bound;
  2408. buildDataset(ctx, expr, bound, FormatLinkedDataset);
  2409. OwnedHqlExpr translated = bound.getTranslatedExpr();
  2410. buildDatasetAssign(ctx, target, translated);
  2411. return;
  2412. }
  2413. case no_select:
  2414. {
  2415. bool isNew;
  2416. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  2417. if (isNew && !ds->isDatarow())
  2418. break;
  2419. }
  2420. //fall through
  2421. case no_translated:
  2422. case no_null:
  2423. case no_id2blob:
  2424. {
  2425. IIdAtom * func = NULL;
  2426. if (!isArrayRowset(to))
  2427. {
  2428. if (!isArrayRowset(exprType))
  2429. func = dataset2DatasetXId;
  2430. }
  2431. else if (hasLinkCountedModifier(to))
  2432. {
  2433. if (hasLinkCountedModifier(exprType))
  2434. {
  2435. CHqlBoundExpr bound;
  2436. buildDataset(ctx, expr, bound, FormatLinkedDataset);
  2437. assertex(bound.count && bound.expr);
  2438. if (hasWrapperModifier(to))
  2439. {
  2440. //assigns to count and rows members
  2441. StringBuffer s;
  2442. generateExprCpp(s, target.expr);
  2443. s.append(".set(");
  2444. generateExprCpp(s, bound.count);
  2445. s.append(",");
  2446. generateExprCpp(s, bound.expr);
  2447. s.append(");");
  2448. ctx.addQuoted(s);
  2449. }
  2450. else
  2451. {
  2452. ctx.addAssign(target.count, bound.count);
  2453. HqlExprArray args;
  2454. args.append(*LINK(bound.expr));
  2455. OwnedHqlExpr call = bindTranslatedFunctionCall(linkRowsetId, args);
  2456. ctx.addAssign(target.expr, call);
  2457. }
  2458. return;
  2459. }
  2460. }
  2461. if (func)
  2462. {
  2463. HqlExprArray args;
  2464. args.append(*LINK(expr));
  2465. OwnedHqlExpr call = bindFunctionCall(func, args);
  2466. buildExprAssign(ctx, target, call);
  2467. return;
  2468. }
  2469. }
  2470. }
  2471. }
  2472. IHqlExpression * record = ::queryRecord(to);
  2473. Owned<IHqlCppDatasetBuilder> builder;
  2474. if (targetOutOfLine)
  2475. {
  2476. if (isDictionaryType(target.queryType()))
  2477. {
  2478. builder.setown(createLinkedDictionaryBuilder(record));
  2479. }
  2480. else
  2481. {
  2482. IHqlExpression * choosenLimit = NULL;
  2483. if ((op == no_choosen) && !isChooseNAllLimit(expr->queryChild(1)) && !queryRealChild(expr, 2))
  2484. {
  2485. choosenLimit = expr->queryChild(1);
  2486. expr = expr->queryChild(0);
  2487. }
  2488. builder.setown(createLinkedDatasetBuilder(record, choosenLimit));
  2489. }
  2490. }
  2491. else
  2492. builder.setown(createBlockedDatasetBuilder(record));
  2493. builder->buildDeclare(ctx);
  2494. buildDatasetAssign(ctx, builder, expr);
  2495. builder->buildFinish(ctx, target);
  2496. }
  2497. //---------------------------------------------------------------------------
  2498. void HqlCppTranslator::doBuildCheckDatasetLimit(BuildCtx & ctx, IHqlExpression * expr, const CHqlBoundExpr & bound)
  2499. {
  2500. IHqlExpression * record = expr->queryRecord();
  2501. IHqlExpression * limit = expr->queryChild(1);
  2502. OwnedHqlExpr test;
  2503. if (!bound.count && bound.length && isFixedRecordSize(record))
  2504. {
  2505. OwnedHqlExpr size = bound.length->queryValue() ? LINK(bound.length) : createTranslated(bound.length);
  2506. OwnedHqlExpr maxSize = createValue(no_mul, LINK(sizetType), ensureExprType(limit, sizetType), getSizetConstant(getFixedRecordSize(record)));
  2507. test.setown(createBoolExpr(no_gt, ensureExprType(size, sizetType), LINK(maxSize)));
  2508. }
  2509. else
  2510. {
  2511. OwnedHqlExpr count = getBoundCount(bound);
  2512. OwnedHqlExpr translatedCount = count->queryValue() ? LINK(count) : createTranslated(count);
  2513. test.setown(createBoolExpr(no_gt, ensureExprType(translatedCount, sizetType), ensureExprType(limit, sizetType)));
  2514. }
  2515. OwnedHqlExpr folded = foldHqlExpression(test);
  2516. LinkedHqlExpr fail = queryRealChild(expr, 2);
  2517. if (folded->queryValue())
  2518. {
  2519. if (!folded->queryValue()->getBoolValue())
  2520. return;
  2521. StringBuffer failMessageText;
  2522. if (fail)
  2523. {
  2524. OwnedHqlExpr failMessage = getFailMessage(fail, true);
  2525. if (failMessage && failMessage->queryValue())
  2526. failMessage->queryValue()->getStringValue(failMessageText);
  2527. }
  2528. if (failMessageText.length())
  2529. WARNING1(CategoryUnexpected, HQLWRN_LimitAlwaysExceededX, failMessageText.str());
  2530. else
  2531. WARNING(CategoryUnexpected, HQLWRN_LimitAlwaysExceeded);
  2532. }
  2533. if (!fail)
  2534. fail.setown(createFailAction("Limit exceeded", limit, NULL, queryCurrentActivityId(ctx)));
  2535. BuildCtx subctx(ctx);
  2536. buildFilter(subctx, folded);
  2537. buildStmt(subctx, fail);
  2538. }
  2539. void HqlCppTranslator::doBuildDatasetLimit(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  2540. {
  2541. buildDataset(ctx, expr->queryChild(0), tgt, format);
  2542. doBuildCheckDatasetLimit(ctx, expr, tgt);
  2543. }
  2544. void HqlCppTranslator::doBuildDatasetNull(IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  2545. {
  2546. tgt.count.setown(getSizetConstant(0));
  2547. tgt.length.setown(getSizetConstant(0));
  2548. IHqlExpression * record = expr->queryRecord();
  2549. Owned<ITypeInfo> type;
  2550. if (expr->isDictionary())
  2551. type.setown(makeDictionaryType(makeRowType(record->getType())));
  2552. else
  2553. type.setown(makeTableType(makeRowType(record->getType())));
  2554. if ((format == FormatLinkedDataset) || (format == FormatArrayDataset) || expr->isDictionary())
  2555. type.setown(setLinkCountedAttr(type, true));
  2556. tgt.expr.setown(createValue(no_nullptr, makeReferenceModifier(type.getClear())));
  2557. }
  2558. class ConstantRow : public CInterface
  2559. {
  2560. public:
  2561. ConstantRow(IHqlExpression * _transform, IHqlExpression * _boundRow) : transform(_transform), boundRow(_boundRow)
  2562. {
  2563. }
  2564. public:
  2565. IHqlExpression * transform;
  2566. LinkedHqlExpr boundRow;
  2567. };
  2568. class ConstantRowArray : public CIArrayOf<ConstantRow> {};
  2569. bool HqlCppTranslator::buildConstantRows(ConstantRowArray & boundRows, IHqlExpression * transforms)
  2570. {
  2571. HqlExprArray rows;
  2572. ForEachChild(row, transforms)
  2573. {
  2574. OwnedHqlExpr constRow = createConstantRowExpr(transforms->queryChild(row));
  2575. if (!constRow || !canGenerateStringInline(constRow->queryType()->getSize()))
  2576. return false;
  2577. rows.append(*constRow.getClear());
  2578. }
  2579. ForEachItemIn(i, rows)
  2580. {
  2581. IHqlExpression * transform = transforms->queryChild(i);
  2582. CHqlBoundExpr bound;
  2583. buildConstRow(transform->queryRecord(), &rows.item(i), bound);
  2584. boundRows.append(*new ConstantRow(transform, bound.expr));
  2585. }
  2586. return true;
  2587. }
  2588. bool HqlCppTranslator::doBuildConstantDatasetInlineTable(IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  2589. {
  2590. if (!options.generateStaticInlineTables)
  2591. return false;
  2592. BuildCtx declareCtx(*code, literalAtom);
  2593. IHqlExpression * transforms = expr->queryChild(0);
  2594. IHqlExpression * record = expr->queryRecord();
  2595. if (transforms->numChildren() == 0)
  2596. {
  2597. OwnedHqlExpr null = createDataset(no_null, LINK(record));
  2598. buildDataset(declareCtx, null, tgt, format);
  2599. return true;
  2600. }
  2601. //Remove unique id when checking for constant datasets already generated
  2602. OwnedHqlExpr exprKey = removeAttribute(expr, _uid_Atom);
  2603. if (declareCtx.getMatchExpr(exprKey, tgt))
  2604. return true;
  2605. ConstantRowArray boundRows;
  2606. if (!buildConstantRows(boundRows, transforms))
  2607. return false;
  2608. Owned<ITypeInfo> rowType = makeConstantModifier(makeReferenceModifier(makeRowType(LINK(queryRecordType(expr->queryType())))));
  2609. HqlExprArray args;
  2610. ForEachItemIn(i, boundRows)
  2611. args.append(*LINK(boundRows.item(i).boundRow));
  2612. OwnedHqlExpr values = createValue(no_list, makeSetType(LINK(rowType)), args);
  2613. unsigned maxRows = values->numChildren();
  2614. Owned<ITypeInfo> declareType = makeConstantModifier(makeArrayType(LINK(rowType), maxRows));
  2615. OwnedITypeInfo rowsType = makeOutOfLineModifier(makeTableType(LINK(rowType)));
  2616. if (options.canLinkConstantRows)
  2617. rowsType.setown(setLinkCountedAttr(rowsType, true));
  2618. OwnedHqlExpr table = declareCtx.getTempDeclare(declareType, values);
  2619. if (options.spanMultipleCpp)
  2620. {
  2621. BuildCtx protoctx(*code, mainprototypesAtom);
  2622. protoctx.addDeclareExternal(table);
  2623. }
  2624. tgt.count.setown(getSizetConstant(maxRows));
  2625. tgt.expr.setown(createValue(no_typetransfer, LINK(rowsType), LINK(table)));
  2626. declareCtx.associateExpr(exprKey, tgt);
  2627. return true;
  2628. }
  2629. //---------------------------------------------------------------------------------------------------------------------
  2630. //The code generator uses the the run time library code used to build dictionaries to try and ensure they stay compatible.
  2631. //
  2632. //The following classes allow IHqlExpressions to be used with those external classes. A ConstantRow * is used where a
  2633. //row would normally be used at runtime.
  2634. //This class provides the minimal functionality for the interface required to call the dictionary builder class
  2635. class EclccEngineRowAllocator : public CInterfaceOf<IEngineRowAllocator>
  2636. {
  2637. public:
  2638. virtual byte * * createRowset(unsigned _numItems) { return (byte * *)malloc(_numItems * sizeof(byte *)); }
  2639. virtual byte * * linkRowset(byte * * rowset) { throwUnexpected(); }
  2640. virtual void releaseRowset(unsigned count, byte * * rowset) { free(rowset); }
  2641. virtual byte * * appendRowOwn(byte * * rowset, unsigned newRowCount, void * row)
  2642. {
  2643. byte * * expanded = reallocRows(rowset, newRowCount-1, newRowCount);
  2644. expanded[newRowCount-1] = (byte *)row;
  2645. return expanded;
  2646. }
  2647. virtual byte * * reallocRows(byte * * rowset, unsigned oldRowCount, unsigned newRowCount)
  2648. {
  2649. return (byte * *)realloc(rowset, newRowCount * sizeof(byte *));
  2650. }
  2651. virtual void * createRow() { throwUnexpected(); }
  2652. virtual void releaseRow(const void * row) { } // can occur if a row is removed from a dictionary.
  2653. virtual void * linkRow(const void * row) { return const_cast<void *>(row); } // can occur if a dictionary is resized.
  2654. //Used for dynamically sizing rows.
  2655. virtual void * createRow(size32_t & allocatedSize) { throwUnexpected(); }
  2656. virtual void * resizeRow(size32_t newSize, void * row, size32_t & size) { throwUnexpected(); }
  2657. virtual void * finalizeRow(size32_t newSize, void * row, size32_t oldSize) { throwUnexpected(); }
  2658. virtual IOutputMetaData * queryOutputMeta() { return NULL; }
  2659. virtual unsigned queryActivityId() const { return 0; }
  2660. virtual StringBuffer &getId(StringBuffer & out) { return out; }
  2661. virtual IOutputRowSerializer *createDiskSerializer(ICodeContext *ctx = NULL) { throwUnexpected(); }
  2662. virtual IOutputRowDeserializer *createDiskDeserializer(ICodeContext *ctx) { throwUnexpected(); }
  2663. virtual IOutputRowSerializer *createInternalSerializer(ICodeContext *ctx = NULL) { throwUnexpected(); }
  2664. virtual IOutputRowDeserializer *createInternalDeserializer(ICodeContext *ctx) { throwUnexpected(); }
  2665. virtual IEngineRowAllocator *createChildRowAllocator(const RtlTypeInfo *type) { throwUnexpected(); }
  2666. };
  2667. //Use a (constant) transform to map selectors of the form queryActiveTableSelector().field
  2668. static IHqlExpression * mapExprViaTransform(IHqlExpression * transform, IHqlExpression * expr)
  2669. {
  2670. NewProjectMapper2 mapper;
  2671. mapper.setMapping(transform);
  2672. return mapper.expandFields(expr, queryActiveTableSelector(), queryActiveTableSelector(), queryActiveTableSelector());
  2673. }
  2674. //Implement hash - constructor parameter is the hash expression
  2675. class EclccCHash : implements IHash
  2676. {
  2677. public:
  2678. EclccCHash(IHqlExpression * _hashExpr) : hashExpr(_hashExpr) {}
  2679. virtual unsigned hash(const void *data)
  2680. {
  2681. const ConstantRow * row = reinterpret_cast<const ConstantRow *>(data);
  2682. OwnedHqlExpr expanded = mapExprViaTransform(row->transform, hashExpr);
  2683. OwnedHqlExpr folded = foldHqlExpression(expanded);
  2684. assertex(folded->queryValue());
  2685. return (unsigned)getIntValue(folded, 0);
  2686. }
  2687. protected:
  2688. LinkedHqlExpr hashExpr;
  2689. };
  2690. // implement compare -the constructor parameter is the list of fields to compare
  2691. class EclccCCompare : implements ICompare
  2692. {
  2693. public:
  2694. EclccCCompare(IHqlExpression * _sortorder) : sortorder(_sortorder) {}
  2695. virtual int docompare(const void * _left,const void * _right) const
  2696. {
  2697. const ConstantRow * left = reinterpret_cast<const ConstantRow *>(_left);
  2698. const ConstantRow * right = reinterpret_cast<const ConstantRow *>(_right);
  2699. OwnedHqlExpr expandedLeft = mapExprViaTransform(left->transform, sortorder);
  2700. OwnedHqlExpr expandedRight = mapExprViaTransform(right->transform, sortorder);
  2701. OwnedHqlExpr order = createValue(no_order, LINK(signedType), expandedLeft.getClear(), expandedRight.getClear());
  2702. OwnedHqlExpr folded = foldHqlExpression(order);
  2703. assertex(folded->queryValue());
  2704. return (int)getIntValue(folded, 0);
  2705. }
  2706. protected:
  2707. LinkedHqlExpr sortorder;
  2708. };
  2709. //The dictionary information class - the hash lookup versions are not implemented
  2710. class EclccHashLookupInfo : implements IHThorHashLookupInfo
  2711. {
  2712. public:
  2713. EclccHashLookupInfo(IHqlExpression * hashExpr, IHqlExpression * sortorder)
  2714. : hasher(hashExpr), comparer(sortorder)
  2715. {
  2716. }
  2717. virtual IHash * queryHash() { return &hasher; }
  2718. virtual ICompare * queryCompare() { return &comparer; }
  2719. virtual IHash * queryHashLookup() { throwUnexpected(); }
  2720. virtual ICompare * queryCompareLookup() { throwUnexpected(); }
  2721. protected:
  2722. EclccCHash hasher;
  2723. EclccCCompare comparer;
  2724. };
  2725. void HqlCppTranslator::createInlineDictionaryRows(HqlExprArray & args, ConstantRowArray & boundRows, IHqlExpression * keyRecord, IHqlExpression * nullRow)
  2726. {
  2727. //The code generator uses the the run time library code used to build dictionaries to try and ensure they stay compatible.
  2728. HqlExprArray keyedDictFields;
  2729. expandRecord(keyedDictFields, queryActiveTableSelector(), keyRecord);
  2730. OwnedHqlExpr keyedlist = createSortList(keyedDictFields);
  2731. OwnedHqlExpr hash = createValue(no_hash32, LINK(unsignedType), LINK(keyedlist));
  2732. //Estimate a good hash table size from the number of rows - otherwise the size can be more than double the number of rows
  2733. size32_t hashSize = (boundRows.ordinality() * 4 / 3) + 1;
  2734. EclccEngineRowAllocator rowsetAllocator;
  2735. EclccHashLookupInfo hasher(hash, keyedlist);
  2736. RtlLinkedDictionaryBuilder builder(&rowsetAllocator, &hasher, hashSize);
  2737. ForEachItemIn(i, boundRows)
  2738. builder.appendOwn(&boundRows.item(i));
  2739. unsigned size = builder.getcount();
  2740. ConstantRow * * rows = reinterpret_cast<ConstantRow * *>(builder.queryrows());
  2741. for (unsigned i=0; i < size; i++)
  2742. {
  2743. if (rows[i])
  2744. args.append(*LINK(rows[i]->boundRow));
  2745. else
  2746. args.append(*LINK(nullRow));
  2747. }
  2748. }
  2749. bool HqlCppTranslator::doBuildDictionaryInlineTable(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  2750. {
  2751. if (!options.generateStaticInlineTables || !options.canLinkConstantRows)
  2752. return false;
  2753. IHqlExpression * dataset = expr->queryChild(0);
  2754. assertex(dataset->getOperator() == no_inlinetable);
  2755. IHqlExpression * transforms = dataset->queryChild(0);
  2756. IHqlExpression * record = dataset->queryRecord();
  2757. if (transforms->numChildren() == 0)
  2758. {
  2759. OwnedHqlExpr null = createDictionary(no_null, LINK(record));
  2760. buildDataset(ctx, null, tgt, format);
  2761. return true;
  2762. }
  2763. BuildCtx declareCtx(*code, literalAtom);
  2764. //Remove unique id when checking for constant datasets already generated
  2765. OwnedHqlExpr exprNoUnique = removeAttribute(dataset, _uid_Atom);
  2766. OwnedHqlExpr exprKey = createAttribute(dictionaryAtom, exprNoUnique.getClear());
  2767. if (declareCtx.getMatchExpr(exprKey, tgt))
  2768. return true;
  2769. ConstantRowArray boundRows;
  2770. if (!buildConstantRows(boundRows, transforms))
  2771. return false;
  2772. OwnedHqlExpr keyRecord = getDictionaryKeyRecord(record);
  2773. Owned<ITypeInfo> rowType = makeConstantModifier(makeReferenceModifier(makeRowType(LINK(queryRecordType(expr->queryType())))));
  2774. OwnedHqlExpr nullExpr = createValue(no_nullptr, LINK(rowType));
  2775. HqlExprArray args;
  2776. try
  2777. {
  2778. createInlineDictionaryRows(args, boundRows, keyRecord, nullExpr);
  2779. }
  2780. catch (IException * e)
  2781. {
  2782. //If the hash or compare couldn't be done (e.g., some strange field type that isn't constant folded)
  2783. //then generate a warning and fall back to the default inline dictionary code
  2784. EXCLOG(e, "Generating an inline dictionary");
  2785. e->Release();
  2786. return false;
  2787. }
  2788. OwnedHqlExpr values = createValue(no_list, makeSetType(LINK(rowType)), args);
  2789. unsigned maxRows = values->numChildren();
  2790. Owned<ITypeInfo> declareType = makeConstantModifier(makeArrayType(LINK(rowType), maxRows));
  2791. OwnedITypeInfo rowsType = makeOutOfLineModifier(makeDictionaryType(LINK(rowType)));
  2792. rowsType.setown(setLinkCountedAttr(rowsType, true));
  2793. OwnedHqlExpr table = declareCtx.getTempDeclare(declareType, values);
  2794. if (options.spanMultipleCpp)
  2795. {
  2796. BuildCtx protoctx(*code, mainprototypesAtom);
  2797. protoctx.addDeclareExternal(table);
  2798. }
  2799. tgt.count.setown(getSizetConstant(maxRows));
  2800. tgt.expr.setown(createValue(no_typetransfer, LINK(rowsType), LINK(table)));
  2801. declareCtx.associateExpr(exprKey, tgt);
  2802. return true;
  2803. }
  2804. //---------------------------------------------------------------------------
  2805. // Dataset creation via builder
  2806. void HqlCppTranslator::buildDatasetAssignTempTable(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  2807. {
  2808. OwnedHqlExpr values = normalizeListCasts(expr->queryChild(0));
  2809. if (values->getOperator() == no_null)
  2810. return;
  2811. IHqlExpression * record = expr->queryChild(1);
  2812. OwnedHqlExpr rowsExpr;
  2813. if (values->queryType()->getTypeCode() == type_set)
  2814. {
  2815. if ((values->getOperator() == no_list) && !values->isConstant())
  2816. {
  2817. ForEachChild(i, values)
  2818. {
  2819. BuildCtx loopctx(ctx);
  2820. BoundRow * targetRow = target->buildCreateRow(loopctx);
  2821. OwnedHqlExpr targetField = createSelectExpr(LINK(targetRow->querySelector()), LINK(record->queryChild(0)));
  2822. buildAssign(loopctx, targetField, values->queryChild(i));
  2823. target->finishRow(loopctx, targetRow);
  2824. }
  2825. }
  2826. else
  2827. {
  2828. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, values);
  2829. BuildCtx loopctx(ctx);
  2830. CHqlBoundExpr boundCurElement;
  2831. cursor->buildIterateLoop(loopctx, boundCurElement, false);
  2832. BoundRow * targetRow = target->buildCreateRow(loopctx);
  2833. OwnedHqlExpr targetField = createSelectExpr(LINK(targetRow->querySelector()), LINK(record->queryChild(0)));
  2834. OwnedHqlExpr value = boundCurElement.getTranslatedExpr();
  2835. buildAssign(loopctx, targetField, value);
  2836. target->finishRow(loopctx, targetRow);
  2837. }
  2838. }
  2839. else
  2840. {
  2841. BuildCtx subctx(ctx);
  2842. BoundRow * targetRow = target->buildCreateRow(subctx);
  2843. Owned<IReferenceSelector> targetRef = buildActiveRow(subctx, targetRow->querySelector());
  2844. buildRowAssign(subctx, targetRef, values);
  2845. target->finishRow(subctx, targetRow);
  2846. }
  2847. }
  2848. void HqlCppTranslator::buildDatasetAssignInlineTable(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  2849. {
  2850. IHqlExpression * transforms = expr->queryChild(0);
  2851. if (transforms->numChildren() == 0)
  2852. return;
  2853. unsigned maxRows = transforms->numChildren();
  2854. unsigned row;
  2855. const bool copyConstantRows = true;//getFieldCount(expr->queryRecord()) > 2;
  2856. for (row = 0; row < maxRows; row++)
  2857. {
  2858. IHqlExpression * transform = transforms->queryChild(row);
  2859. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(transform));
  2860. BuildCtx subctx(ctx);
  2861. CHqlBoundExpr bound;
  2862. //Work in progress. Check if there are several fields - otherwise not worth it.s
  2863. if (doBuildRowConstantTransform(transform, bound))
  2864. {
  2865. BoundRow * row = bindConstantRow(subctx, rowValue, bound);
  2866. if (target->buildLinkRow(subctx, row))
  2867. continue;
  2868. }
  2869. BoundRow * targetRow = target->buildCreateRow(subctx);
  2870. Owned<IReferenceSelector> targetRef = buildActiveRow(subctx, targetRow->querySelector());
  2871. buildRowAssign(subctx, targetRef, rowValue);
  2872. target->finishRow(subctx, targetRow);
  2873. }
  2874. }
  2875. void HqlCppTranslator::buildDatasetAssignDatasetFromTransform(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  2876. {
  2877. assertex(expr->getOperator() == no_dataset_from_transform);
  2878. IHqlExpression * count = expr->queryChild(0);
  2879. if (isZero(count) || isNegative(count))
  2880. return;
  2881. IHqlExpression * transform = expr->queryChild(1);
  2882. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  2883. // If it is at all possible that it could be negative, we must test before producing rows
  2884. CHqlBoundExpr boundCount;
  2885. buildSimpleExpr(ctx, count, boundCount);
  2886. BuildCtx subctx(ctx);
  2887. if (couldBeNegative(count))
  2888. {
  2889. OwnedHqlExpr zero = createConstant(0, count->getType());
  2890. OwnedHqlExpr ifTest = createValue(no_gt, makeBoolType(), boundCount.getTranslatedExpr(), LINK(zero));
  2891. buildFilter(subctx, ifTest);
  2892. }
  2893. // loopVar = 1;
  2894. OwnedHqlExpr loopVar = subctx.getTempDeclare(counterType, NULL);
  2895. OwnedHqlExpr one = getSizetConstant(1);
  2896. buildAssignToTemp(subctx, loopVar, one);
  2897. // for(; loopVar <= maxRows; loopVar++)
  2898. OwnedHqlExpr loopTest = createValue(no_le, makeBoolType(), LINK(loopVar), LINK(boundCount.expr));
  2899. OwnedHqlExpr inc = createValue(no_postinc, loopVar->getType(), LINK(loopVar));
  2900. subctx.addLoop(loopTest, inc, false);
  2901. if (counter)
  2902. subctx.associateExpr(counter, loopVar);
  2903. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(transform));
  2904. BoundRow * targetRow = target->buildCreateRow(subctx);
  2905. Owned<IReferenceSelector> targetRef = buildActiveRow(subctx, targetRow->querySelector());
  2906. buildRowAssign(subctx, targetRef, rowValue);
  2907. target->finishRow(subctx, targetRow);
  2908. }
  2909. class InlineDatasetSkipCallback : public CInterface, implements IHqlCodeCallback
  2910. {
  2911. public:
  2912. IMPLEMENT_IINTERFACE
  2913. virtual void buildCode(HqlCppTranslator & translator, BuildCtx & ctx)
  2914. {
  2915. ctx.addContinue();
  2916. }
  2917. };
  2918. void HqlCppTranslator::buildDatasetAssignCombine(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  2919. {
  2920. BuildCtx iterctx(ctx);
  2921. IHqlExpression *left = expr->queryChild(0);
  2922. IHqlExpression *right = expr->queryChild(1);
  2923. iterctx.addGroup(); // stop bound cursors leaking outside the block.
  2924. // right iter1; right.first();
  2925. HqlExprAttr rightIter, rightRow;
  2926. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(iterctx, right);
  2927. cursor->buildIterateClass(iterctx, rightIter, rightRow);
  2928. buildIteratorFirst(iterctx, rightIter, rightRow);
  2929. BoundRow * sourceCursor = buildDatasetIterate(iterctx, left, false);
  2930. if (!sourceCursor)
  2931. return;
  2932. // handle right rows < left rows failure
  2933. {
  2934. OwnedHqlExpr test = createValue(no_not, makeBoolType(), LINK(rightRow));
  2935. OwnedHqlExpr failMsg = createFailMessage("Combine: right dataset smaller than left", NULL, NULL, queryCurrentActivityId(ctx));
  2936. OwnedHqlExpr fail = createValue(no_fail, makeVoidType(), LINK(failMsg));
  2937. BuildCtx failctx(iterctx);
  2938. failctx.addFilter(test);
  2939. buildStmt(failctx, fail);
  2940. }
  2941. bindTableCursor(iterctx, right, rightRow, no_right, querySelSeq(expr));
  2942. BoundRow * targetRow = target->buildCreateRow(iterctx);
  2943. Owned<IReferenceSelector> targetRef = buildActiveRow(iterctx, targetRow->querySelector());
  2944. doBuildRowAssignProject(iterctx, targetRef, expr);
  2945. target->finishRow(iterctx, targetRow);
  2946. // right.next();
  2947. buildIteratorNext(iterctx, rightIter, rightRow);
  2948. // handle right rows > left rows failure
  2949. {
  2950. OwnedHqlExpr failMsg = createFailMessage("Combine: right dataset larger than left", NULL, NULL, queryCurrentActivityId(ctx));
  2951. OwnedHqlExpr fail = createValue(no_fail, makeVoidType(), LINK(failMsg));
  2952. BuildCtx failctx(ctx);
  2953. failctx.addFilter(rightRow);
  2954. buildStmt(failctx, fail);
  2955. }
  2956. }
  2957. void HqlCppTranslator::buildDatasetAssignProject(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  2958. {
  2959. BuildCtx iterctx(ctx);
  2960. IHqlExpression * ds = expr->queryChild(0);
  2961. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  2962. OwnedHqlExpr counterVar;
  2963. if (counter)
  2964. {
  2965. counterVar.setown(iterctx.getTempDeclare(unsignedType, queryZero()));
  2966. }
  2967. bool containsSkip = transformContainsSkip(expr->queryChild(1));
  2968. BoundRow * sourceCursor = buildDatasetIterate(iterctx, ds, containsSkip);
  2969. if (counter)
  2970. {
  2971. iterctx.associateExpr(counter, counterVar);
  2972. OwnedHqlExpr inc = createValue(no_postinc, LINK(unsignedType), LINK(counterVar));
  2973. iterctx.addExpr(inc);
  2974. }
  2975. if (sourceCursor)
  2976. {
  2977. if (isNullProject(expr, true, false))
  2978. {
  2979. if (target->buildLinkRow(iterctx, sourceCursor))
  2980. return;
  2981. }
  2982. BoundRow * targetRow = target->buildCreateRow(iterctx);
  2983. HqlExprAssociation * skipAssociation = NULL;
  2984. if (containsSkip)
  2985. {
  2986. OwnedHqlExpr callback = createUnknown(no_unknown, makeVoidType(), NULL, new InlineDatasetSkipCallback);
  2987. skipAssociation = iterctx.associateExpr(skipActionMarker, callback);
  2988. }
  2989. Owned<IReferenceSelector> targetRef = buildActiveRow(iterctx, targetRow->querySelector());
  2990. switch (expr->getOperator())
  2991. {
  2992. case no_hqlproject:
  2993. doBuildRowAssignProject(iterctx, targetRef, expr);
  2994. break;
  2995. case no_newusertable:
  2996. doBuildRowAssignUserTable(iterctx, targetRef, expr);
  2997. break;
  2998. }
  2999. target->finishRow(iterctx, targetRow);
  3000. }
  3001. }
  3002. void HqlCppTranslator::buildDatasetAssignJoin(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  3003. {
  3004. IHqlExpression * left = expr->queryChild(0);
  3005. IHqlExpression * right = expr->queryChild(1);
  3006. IHqlExpression * cond = expr->queryChild(2);
  3007. IHqlExpression * selSeq = querySelSeq(expr);
  3008. bool leftOuter = expr->hasAttribute(leftonlyAtom) || expr->hasAttribute(leftouterAtom);
  3009. CHqlBoundExpr nullRhs;
  3010. if (leftOuter)
  3011. buildDefaultRow(ctx, right, nullRhs);
  3012. BuildCtx leftIterCtx(ctx);
  3013. BoundRow * leftCursor = buildDatasetIterate(leftIterCtx, left, false);
  3014. bindTableCursor(leftIterCtx, left, leftCursor->queryBound(), no_left, selSeq);
  3015. OwnedHqlExpr matchedAnyVar;
  3016. if (leftOuter)
  3017. matchedAnyVar.setown(leftIterCtx.getTempDeclare(queryBoolType(), queryBoolExpr(false)));
  3018. BuildCtx rightIterCtx(leftIterCtx);
  3019. BoundRow * rightCursor = buildDatasetIterate(rightIterCtx, right, false);
  3020. bindTableCursor(rightIterCtx, right, rightCursor->queryBound(), no_right, selSeq);
  3021. OwnedHqlExpr cseCond = options.spotCSE ? spotScalarCSE(cond, NULL, queryOptions().spotCseInIfDatasetConditions) : LINK(cond);
  3022. buildFilter(rightIterCtx, cseCond);
  3023. if (!expr->hasAttribute(leftonlyAtom))
  3024. {
  3025. BoundRow * targetRow = target->buildCreateRow(rightIterCtx);
  3026. Owned<IReferenceSelector> targetRef = buildActiveRow(rightIterCtx, targetRow->querySelector());
  3027. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(expr->queryChild(3)));
  3028. buildRowAssign(rightIterCtx, targetRef, rowValue);
  3029. target->finishRow(rightIterCtx, targetRow);
  3030. }
  3031. if (matchedAnyVar)
  3032. {
  3033. buildAssignToTemp(rightIterCtx, matchedAnyVar, queryBoolExpr(true));
  3034. OwnedHqlExpr test = getInverse(matchedAnyVar);
  3035. leftIterCtx.addFilter(test);
  3036. OwnedHqlExpr defaultRowPtr = getPointer(nullRhs.expr);
  3037. bindTableCursor(leftIterCtx, right, defaultRowPtr, no_right, selSeq);
  3038. BoundRow * targetRow = target->buildCreateRow(leftIterCtx);
  3039. Owned<IReferenceSelector> targetRef = buildActiveRow(leftIterCtx, targetRow->querySelector());
  3040. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(expr->queryChild(3)));
  3041. buildRowAssign(leftIterCtx, targetRef, rowValue);
  3042. target->finishRow(leftIterCtx, targetRow);
  3043. }
  3044. }
  3045. void HqlCppTranslator::buildDatasetAssignAggregate(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  3046. {
  3047. BoundRow * targetRow = target->buildCreateRow(ctx);
  3048. Owned<IReferenceSelector> targetRef = buildActiveRow(ctx, targetRow->querySelector());
  3049. doBuildRowAssignAggregate(ctx, targetRef, expr);
  3050. target->finishRow(ctx, targetRow);
  3051. }
  3052. void HqlCppTranslator::buildDatasetAssignChoose(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  3053. {
  3054. CHqlBoundExpr cond;
  3055. buildExpr(ctx, expr->queryChild(0), cond);
  3056. IHqlExpression * last = queryLastNonAttribute(expr);
  3057. BuildCtx subctx(ctx);
  3058. IHqlStmt * switchstmt = subctx.addSwitch(cond.expr);
  3059. ForEachChildFrom(i, expr, 1)
  3060. {
  3061. IHqlExpression * cur = expr->queryChild(i);
  3062. if (cur != last)
  3063. {
  3064. OwnedHqlExpr label = getSizetConstant(i);
  3065. subctx.addCase(switchstmt, label);
  3066. }
  3067. else
  3068. subctx.addDefault(switchstmt);
  3069. buildDatasetAssign(subctx, target, cur);
  3070. }
  3071. }
  3072. void HqlCppTranslator::buildDatasetAssignChoose(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  3073. {
  3074. CHqlBoundExpr cond;
  3075. buildExpr(ctx, expr->queryChild(0), cond);
  3076. IHqlExpression * last = queryLastNonAttribute(expr);
  3077. BuildCtx subctx(ctx);
  3078. IHqlStmt * switchstmt = subctx.addSwitch(cond.expr);
  3079. ForEachChildFrom(i, expr, 1)
  3080. {
  3081. IHqlExpression * cur = expr->queryChild(i);
  3082. if (cur != last)
  3083. {
  3084. OwnedHqlExpr label = getSizetConstant(i);
  3085. subctx.addCase(switchstmt, label);
  3086. }
  3087. else
  3088. subctx.addDefault(switchstmt);
  3089. buildDatasetAssign(subctx, target, cur);
  3090. }
  3091. }
  3092. void HqlCppTranslator::buildDatasetAssignIf(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  3093. {
  3094. BuildCtx subctx(ctx);
  3095. IHqlStmt * filter = buildFilterViaExpr(subctx, expr->queryChild(0));
  3096. buildDatasetAssign(subctx, target, expr->queryChild(1));
  3097. IHqlExpression * elseExpr = expr->queryChild(2);
  3098. assertex(elseExpr);
  3099. subctx.selectElse(filter);
  3100. buildDatasetAssign(subctx, target, elseExpr);
  3101. }
  3102. void HqlCppTranslator::buildDatasetAssign(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * _expr)
  3103. {
  3104. OwnedHqlExpr expr = forceInlineAssignDataset(ctx, _expr);
  3105. bool isRowAssign = false;
  3106. BuildCtx subctx(ctx);
  3107. switch (expr->getOperator())
  3108. {
  3109. case no_fail:
  3110. doBuildStmtFail(ctx, expr->queryChild(1));
  3111. return;
  3112. case no_addfiles:
  3113. buildDatasetAssign(subctx, target, expr->queryChild(0));
  3114. buildDatasetAssign(subctx, target, expr->queryChild(1));
  3115. return;
  3116. case no_temptable:
  3117. buildDatasetAssignTempTable(subctx, target, expr);
  3118. //MORE: Create rows and assign each one in turn. Could possibly be done with a different dataset selector
  3119. return;
  3120. case no_inlinetable:
  3121. buildDatasetAssignInlineTable(subctx, target, expr);
  3122. return;
  3123. case no_dataset_from_transform:
  3124. buildDatasetAssignDatasetFromTransform(subctx, target, expr);
  3125. return;
  3126. case no_xmlproject:
  3127. buildDatasetAssignXmlProject(subctx, target, expr);
  3128. return;
  3129. case no_datasetfromrow:
  3130. {
  3131. isRowAssign = true;
  3132. expr.set(expr->queryChild(0));
  3133. break;
  3134. }
  3135. case no_if:
  3136. {
  3137. CHqlBoundExpr bound;
  3138. buildExpr(subctx, expr->queryChild(0), bound);
  3139. IHqlStmt * filter = subctx.addFilter(bound.expr);
  3140. buildDatasetAssign(subctx, target, expr->queryChild(1));
  3141. IHqlExpression * elseExpr = expr->queryChild(2);
  3142. if (elseExpr && elseExpr->getOperator() != no_null)
  3143. {
  3144. subctx.selectElse(filter);
  3145. buildDatasetAssign(subctx, target, elseExpr);
  3146. }
  3147. }
  3148. return;
  3149. case no_chooseds:
  3150. buildDatasetAssignChoose(subctx, target, expr);
  3151. return;
  3152. case no_null:
  3153. return;
  3154. case no_activetable:
  3155. case no_temprow:
  3156. case no_createrow:
  3157. case no_projectrow:
  3158. case no_typetransfer:
  3159. isRowAssign = true;
  3160. break;
  3161. case no_newaggregate:
  3162. buildDatasetAssignAggregate(subctx, target, expr);
  3163. return;
  3164. case no_hqlproject:
  3165. case no_newusertable:
  3166. buildDatasetAssignProject(subctx, target, expr);
  3167. return;
  3168. case no_combine:
  3169. buildDatasetAssignCombine(subctx, target, expr);
  3170. return;
  3171. case no_compound_childread:
  3172. case no_compound_childnormalize:
  3173. case no_compound_childaggregate:
  3174. case no_compound_selectnew:
  3175. case no_compound_inline:
  3176. case no_distributed:
  3177. case no_unordered:
  3178. case no_preservemeta:
  3179. case no_sorted:
  3180. case no_nofold:
  3181. case no_nohoist:
  3182. case no_forcegraph:
  3183. case no_nocombine:
  3184. case no_section:
  3185. case no_sectioninput:
  3186. buildDatasetAssign(subctx, target, expr->queryChild(0));
  3187. return;
  3188. case no_alias_scope:
  3189. // expandAliasScope(subctx, expr);
  3190. buildDatasetAssign(subctx, target, expr->queryChild(0));
  3191. return;
  3192. case no_filter:
  3193. {
  3194. //We want to evaluate invariant conditions outside of the loop, rather than inside the dataset assignment
  3195. //Currently the test is whether the expression is independent of any tables. Better would be to
  3196. //see if the test was dependent on any of the datasets introduced by expr->queryChild(0).
  3197. HqlExprArray conds;
  3198. unwindFilterConditions(conds, expr);
  3199. IHqlExpression * ds = expr->queryChild(0);
  3200. #if 0
  3201. HqlExprCopyArray selectors;
  3202. loop
  3203. {
  3204. selectors.append(*ds->queryNormalizedSelector());
  3205. IHqlExpression * root = queryRoot(expr);
  3206. if (!root || root->getOperator() != no_select)
  3207. break;
  3208. bool isNew;
  3209. ds = querySelectorDataset(root, isNew);
  3210. if (!isNew)
  3211. break;
  3212. }
  3213. #endif
  3214. unsigned max = conds.ordinality();
  3215. unsigned i = 0;
  3216. bool optimized = false;
  3217. while (i < max)
  3218. {
  3219. IHqlExpression & cur = conds.item(i);
  3220. #if 0
  3221. bool overlap = false;
  3222. ForEachItemIn(j, selectors)
  3223. {
  3224. if (containsSelector(&cur, &selectors.item(j)))
  3225. {
  3226. overlap = true;
  3227. break;
  3228. }
  3229. }
  3230. #else
  3231. bool overlap = containsSelector(&cur, ds->queryNormalizedSelector());
  3232. #endif
  3233. if (!overlap)
  3234. {
  3235. buildFilter(subctx, &cur);
  3236. conds.remove(i);
  3237. optimized = true;
  3238. max--;
  3239. }
  3240. else
  3241. i++;
  3242. }
  3243. if (max == 0)
  3244. {
  3245. buildDatasetAssign(subctx, target, ds);
  3246. return;
  3247. }
  3248. if (optimized)
  3249. {
  3250. conds.add(*LINK(ds), 0);
  3251. expr.setown(expr->clone(conds));
  3252. }
  3253. break;
  3254. }
  3255. case no_join:
  3256. buildDatasetAssignJoin(subctx, target, expr);
  3257. return;
  3258. }
  3259. ITypeInfo * type = expr->queryType();
  3260. if (type)
  3261. {
  3262. switch (type->getTypeCode())
  3263. {
  3264. case type_record: // e.g. dataset.recordfield
  3265. case type_row:
  3266. isRowAssign = true;
  3267. break;
  3268. }
  3269. }
  3270. if (isRowAssign)
  3271. {
  3272. bool done = false;
  3273. //Some code primarily here to improve the generated code for productions inside parse statements for text parsing.
  3274. //see if we can replace a memcpy of the child record with a link...
  3275. if (!target->isRestricted())
  3276. {
  3277. switch (expr->getOperator())
  3278. {
  3279. case no_matchattr:
  3280. case no_left:
  3281. case no_right:
  3282. {
  3283. //Only try for really simple cases...
  3284. Owned<IReferenceSelector> sourceRef = buildNewRow(subctx, expr);
  3285. Owned<BoundRow> sourceRow = sourceRef->getRow(subctx);
  3286. if (!target->buildLinkRow(subctx, sourceRow))
  3287. {
  3288. BoundRow * targetRow = target->buildCreateRow(subctx);
  3289. Owned<IReferenceSelector> targetRef = buildActiveRow(subctx, targetRow->querySelector());
  3290. buildRowAssign(subctx, targetRef, sourceRef);
  3291. target->finishRow(subctx, targetRow);
  3292. }
  3293. done = true;
  3294. break;
  3295. }
  3296. }
  3297. }
  3298. if (!done)
  3299. {
  3300. BoundRow * match = static_cast<BoundRow *>(ctx.queryAssociation(expr, AssocRow, NULL));
  3301. if (match && target->buildLinkRow(subctx, match))
  3302. done = true;
  3303. }
  3304. if (!done)
  3305. {
  3306. BoundRow * targetRow = target->buildCreateRow(subctx);
  3307. Owned<IReferenceSelector> targetRef = buildActiveRow(subctx, targetRow->querySelector());
  3308. buildRowAssign(subctx, targetRef, expr);
  3309. target->finishRow(subctx, targetRow);
  3310. }
  3311. }
  3312. else
  3313. {
  3314. if (!target->buildAppendRows(subctx, expr))
  3315. {
  3316. BoundRow * sourceRow = buildDatasetIterate(subctx, expr, false);
  3317. if (sourceRow)
  3318. {
  3319. if (!target->buildLinkRow(subctx, sourceRow))
  3320. {
  3321. BoundRow * targetRow = target->buildCreateRow(subctx);
  3322. Owned<IReferenceSelector> targetRef = buildActiveRow(subctx, targetRow->querySelector());
  3323. Owned<IReferenceSelector> sourceRef = buildActiveRow(subctx, sourceRow->querySelector());
  3324. buildRowAssign(subctx, targetRef, sourceRef);
  3325. target->finishRow(subctx, targetRow);
  3326. }
  3327. }
  3328. }
  3329. }
  3330. }
  3331. //---------------------------------------------------------------------------
  3332. // Dataset iteration
  3333. BoundRow * HqlCppTranslator::buildDatasetIterateSelectN(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3334. {
  3335. OwnedHqlExpr counter = ctx.getTempDeclare(sizetType, NULL);
  3336. buildAssignToTemp(ctx, counter, expr->queryChild(1));
  3337. BoundRow * cursor = buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3338. if (cursor)
  3339. {
  3340. OwnedHqlExpr dec = createValue(no_predec, counter->getType(), LINK(counter));
  3341. OwnedHqlExpr test = createBoolExpr(no_eq, LINK(dec), getSizetConstant(0));
  3342. ctx.addFilter(test);
  3343. }
  3344. return cursor;
  3345. }
  3346. BoundRow * HqlCppTranslator::buildDatasetIterateChoosen(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3347. {
  3348. OwnedHqlExpr counter = ctx.getTempDeclare(sizetType, queryZero());
  3349. CHqlBoundExpr boundLow, boundHigh;
  3350. OwnedHqlExpr foldedHigh = foldHqlExpression(expr->queryChild(1));
  3351. if (!isChooseNAllLimit(foldedHigh))
  3352. buildSimpleExpr(ctx, foldedHigh, boundHigh);
  3353. if (queryRealChild(expr, 2))
  3354. {
  3355. OwnedHqlExpr foldedLow = foldHqlExpression(expr->queryChild(2));
  3356. OwnedHqlExpr low = adjustValue(foldedLow, -1);
  3357. buildSimpleExpr(ctx, low, boundLow);
  3358. if (boundHigh.expr)
  3359. boundHigh.expr.setown(createValue(no_add, LINK(boundHigh.queryType()), LINK(boundHigh.expr), LINK(boundLow.expr)));
  3360. }
  3361. BoundRow * cursor = buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3362. if (cursor)
  3363. {
  3364. OwnedHqlExpr inc = createValue(no_postinc, counter->getType(), LINK(counter));
  3365. ctx.addExpr(inc);
  3366. OwnedHqlExpr cond;
  3367. if (boundLow.expr)
  3368. extendConditionOwn(cond, no_and, createBoolExpr(no_gt, LINK(counter), LINK(boundLow.expr)));
  3369. if (boundHigh.expr)
  3370. extendConditionOwn(cond, no_and, createBoolExpr(no_le, LINK(counter), LINK(boundHigh.expr)));
  3371. if (cond)
  3372. ctx.addFilter(cond);
  3373. }
  3374. return cursor;
  3375. }
  3376. BoundRow * HqlCppTranslator::buildDatasetIterateLimit(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3377. {
  3378. OwnedHqlExpr counter = ctx.getTempDeclare(sizetType, queryZero());
  3379. CHqlBoundExpr boundHigh;
  3380. OwnedHqlExpr foldedHigh = foldHqlExpression(expr->queryChild(1));
  3381. buildSimpleExpr(ctx, foldedHigh, boundHigh);
  3382. BoundRow * cursor = buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3383. if (cursor)
  3384. {
  3385. OwnedHqlExpr inc = createValue(no_preinc, counter->getType(), LINK(counter));
  3386. OwnedHqlExpr cond = createBoolExpr(no_gt, LINK(inc), LINK(boundHigh.expr));
  3387. BuildCtx subctx(ctx);
  3388. subctx.addFilter(cond);
  3389. LinkedHqlExpr fail = expr->queryChild(2);
  3390. if (!fail || fail->isAttribute())
  3391. fail.setown(createFailAction("Limit exceeded", foldedHigh, NULL, queryCurrentActivityId(ctx)));
  3392. buildStmt(subctx, fail);
  3393. }
  3394. return cursor;
  3395. }
  3396. BoundRow * HqlCppTranslator::buildDatasetIterateProject(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3397. {
  3398. IHqlExpression * dataset = expr->queryChild(0);
  3399. OwnedHqlExpr counterVar;
  3400. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  3401. if (counter)
  3402. {
  3403. counterVar.setown(ctx.getTempDeclare(unsignedType, queryZero()));
  3404. }
  3405. bool containsSkip = transformContainsSkip(expr->queryChild(1));
  3406. if (containsSkip)
  3407. needToBreak = true;
  3408. buildDatasetIterate(ctx, dataset, needToBreak);
  3409. Owned<BoundRow> tempRow = declareTempAnonRow(ctx, ctx, expr);
  3410. if (counter)
  3411. {
  3412. ctx.associateExpr(counter, counterVar);
  3413. OwnedHqlExpr inc = createValue(no_postinc, LINK(unsignedType), LINK(counterVar));
  3414. ctx.addExpr(inc);
  3415. }
  3416. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, tempRow);
  3417. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, querySelSeq(expr));
  3418. OwnedHqlExpr transform = replaceSelector(expr->queryChild(1), leftSelect, dataset->queryNormalizedSelector());
  3419. HqlExprAssociation * skipAssociation = NULL;
  3420. if (containsSkip)
  3421. {
  3422. OwnedHqlExpr callback = createUnknown(no_unknown, makeVoidType(), NULL, new InlineDatasetSkipCallback);
  3423. skipAssociation = ctx.associateExpr(skipActionMarker, callback);
  3424. }
  3425. doTransform(ctx, transform, rowBuilder);
  3426. ctx.removeAssociation(skipAssociation); //remove it in case keeping hold of it causes issues.
  3427. finalizeTempRow(ctx, tempRow, rowBuilder);
  3428. return bindTableCursor(ctx, expr, tempRow->queryBound());
  3429. }
  3430. BoundRow * HqlCppTranslator::buildDatasetIterateUserTable(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3431. {
  3432. IHqlExpression * dataset = expr->queryChild(0);
  3433. buildDatasetIterate(ctx, dataset, needToBreak);
  3434. Owned<BoundRow> tempRow = declareTempAnonRow(ctx, ctx, expr);
  3435. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, tempRow);
  3436. doTransform(ctx, expr->queryChild(2), rowBuilder);
  3437. finalizeTempRow(ctx, tempRow, rowBuilder);
  3438. return bindTableCursor(ctx, expr, tempRow->queryBound());
  3439. }
  3440. BoundRow * HqlCppTranslator::buildDatasetIterateSpecialTempTable(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3441. {
  3442. IHqlExpression * values = expr->queryChild(0);
  3443. bool requiresTempRow = false;
  3444. ITypeInfo * setType = values->queryType();
  3445. ITypeInfo * type = setType->queryChildType();
  3446. switch (type->getTypeCode())
  3447. {
  3448. case type_int:
  3449. requiresTempRow = isComplexSet(setType, false);
  3450. break;
  3451. case type_swapint:
  3452. case type_packedint:
  3453. case type_alien:
  3454. case type_bitfield:
  3455. requiresTempRow = true;
  3456. break;
  3457. default:
  3458. if (type->getSize() == UNKNOWN_LENGTH)
  3459. requiresTempRow = true;
  3460. break;
  3461. }
  3462. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, values);
  3463. CHqlBoundExpr boundCurElement;
  3464. cursor->buildIterateLoop(ctx, boundCurElement, false);
  3465. if (requiresTempRow)
  3466. {
  3467. //MORE: This could probably be improved by having a variety of buildIterateLoop which returned the
  3468. //underlying bound row. However it occurs fairly infrequently, so not a priority.
  3469. Owned<BoundRow> tempRow = declareTempAnonRow(ctx, ctx, expr);
  3470. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, tempRow);
  3471. IHqlExpression * record = expr->queryRecord();
  3472. OwnedHqlExpr target = createSelectExpr(LINK(rowBuilder->querySelector()), LINK(record->queryChild(0)));
  3473. OwnedHqlExpr curValue = boundCurElement.getTranslatedExpr();
  3474. buildAssign(ctx, target, curValue);
  3475. finalizeTempRow(ctx, tempRow, rowBuilder);
  3476. return bindTableCursor(ctx, expr, tempRow->queryBound());
  3477. }
  3478. else
  3479. {
  3480. assertex(!boundCurElement.length && !boundCurElement.count);
  3481. OwnedHqlExpr address = getPointer(boundCurElement.expr);
  3482. address.setown(createValue(no_implicitcast, makeRowReferenceType(expr), LINK(address)));
  3483. return bindTableCursor(ctx, expr, address);
  3484. }
  3485. }
  3486. BoundRow * HqlCppTranslator::buildDatasetIterateFromDictionary(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3487. {
  3488. BoundRow * dictionaryRow = buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3489. assertex(dictionaryRow->isConditional());
  3490. ctx.addFilter(dictionaryRow->queryBound());
  3491. return rebindTableCursor(ctx, expr, dictionaryRow, no_none, NULL);
  3492. }
  3493. BoundRow * HqlCppTranslator::buildDatasetIterateStreamedCall(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3494. {
  3495. CHqlBoundExpr bound;
  3496. doBuildExprCall(ctx, expr, bound);
  3497. ITypeInfo * exprType = expr->queryType();
  3498. Owned<ITypeInfo> wrappedType = makeWrapperModifier(LINK(exprType));
  3499. ctx.addLoop(NULL, NULL, false);
  3500. Owned<ITypeInfo> wrappedRowType = makeWrapperModifier(LINK(queryRowType(exprType)));
  3501. OwnedHqlExpr tempRow = ctx.getTempDeclare(wrappedRowType, NULL);
  3502. StringBuffer s;
  3503. generateExprCpp(s, tempRow).append(".setown(");
  3504. generateExprCpp(s, bound.expr).append("->nextRow());");
  3505. ctx.addQuoted(s);
  3506. s.clear().append("if (!");generateExprCpp(s, tempRow).append(".getbytes()) break;");
  3507. ctx.addQuoted(s);
  3508. return bindTableCursor(ctx, expr, tempRow);
  3509. }
  3510. BoundRow * HqlCppTranslator::buildDatasetIterate(BuildCtx & ctx, IHqlExpression * expr, bool needToBreak)
  3511. {
  3512. if (!canProcessInline(&ctx, expr))
  3513. {
  3514. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, expr);
  3515. return cursor->buildIterateLoop(ctx, needToBreak);
  3516. }
  3517. switch (expr->getOperator())
  3518. {
  3519. case no_dataset_alias:
  3520. if (!expr->hasAttribute(_normalized_Atom))
  3521. {
  3522. OwnedHqlExpr uniqueChild = normalizeDatasetAlias(expr);
  3523. BoundRow * childCursor = buildDatasetIterate(ctx, uniqueChild, needToBreak);
  3524. return rebindTableCursor(ctx, expr, childCursor, no_none, NULL);
  3525. }
  3526. else
  3527. {
  3528. throwUnexpected();
  3529. //The following would only be triggered for a splitter (not yet generated), and that would require
  3530. //disambiguation when that was built.
  3531. BoundRow * childCursor = buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3532. return rebindTableCursor(ctx, expr, childCursor, no_none, NULL);
  3533. }
  3534. case no_null:
  3535. buildFilter(ctx, queryBoolExpr(false));
  3536. return NULL;
  3537. case no_filter:
  3538. {
  3539. IHqlExpression * dataset = expr->queryChild(0);
  3540. #ifdef _OPTIMZE_INLINE_FILTERS_
  3541. //Good code, but messes up accidental cse in some createSegmentMonitor calls.
  3542. HqlExprAttr invariant;
  3543. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, dataset);
  3544. if (invariant)
  3545. buildFilter(ctx, invariant);
  3546. //MORE: if (canAssignInline(ctx, ds) && !canIterateInline(ctx, ds)) break;
  3547. BoundRow * cursor = buildDatasetIterate(ctx, dataset, needToBreak);
  3548. if (cond)
  3549. buildFilter(ctx, cond);
  3550. #else
  3551. //MORE: if (canAssignInline(ctx, ds) && !canIterateInline(ctx, ds)) break;
  3552. BoundRow * cursor = buildDatasetIterate(ctx, dataset, needToBreak);
  3553. unsigned max = expr->numChildren();
  3554. for (unsigned i=1; i < max; i++)
  3555. buildFilter(ctx, expr->queryChild(i));
  3556. #endif
  3557. return cursor;
  3558. }
  3559. case no_id2blob:
  3560. case no_select:
  3561. case no_translated:
  3562. {
  3563. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, expr);
  3564. return cursor->buildIterateLoop(ctx, needToBreak);
  3565. }
  3566. case no_choosen:
  3567. return buildDatasetIterateChoosen(ctx, expr, needToBreak);
  3568. case no_limit:
  3569. return buildDatasetIterateLimit(ctx, expr, needToBreak);
  3570. case no_index:
  3571. case no_selectnth:
  3572. return buildDatasetIterateSelectN(ctx, expr, needToBreak);
  3573. case no_hqlproject:
  3574. return buildDatasetIterateProject(ctx, expr, needToBreak);
  3575. case no_newusertable:
  3576. return buildDatasetIterateUserTable(ctx, expr, needToBreak);
  3577. case no_compound_childread:
  3578. case no_compound_childnormalize:
  3579. case no_compound_childaggregate:
  3580. case no_compound_selectnew:
  3581. case no_compound_inline:
  3582. case no_distributed:
  3583. case no_unordered:
  3584. case no_preservemeta:
  3585. case no_sorted:
  3586. case no_nofold:
  3587. case no_nohoist:
  3588. case no_forcegraph:
  3589. case no_nocombine:
  3590. return buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3591. case no_sectioninput:
  3592. case no_section:
  3593. {
  3594. BoundRow * row = buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3595. #ifdef _DEBUG
  3596. StringBuffer s;
  3597. if (expr->getOperator() == no_section)
  3598. s.append("//---- section ");
  3599. else
  3600. s.append("//---- end section ");
  3601. getStringValue(s, expr->queryChild(1), "<?>").append(" ");
  3602. getStringValue(s, expr->queryChild(2)).append("----");
  3603. ctx.addQuoted(s);
  3604. #endif
  3605. return row;
  3606. }
  3607. case no_alias_scope:
  3608. // expandAliasScope(ctx, expr);
  3609. return buildDatasetIterate(ctx, expr->queryChild(0), needToBreak);
  3610. case no_temptable:
  3611. {
  3612. IHqlExpression * values = expr->queryChild(0);
  3613. if (values->queryType()->getTypeCode() == type_set)
  3614. {
  3615. if (values->getOperator() == no_alias)
  3616. values = values->queryChild(0);
  3617. bool special = false;
  3618. switch (values->getOperator())
  3619. {
  3620. case no_getresult:
  3621. case no_null:
  3622. special = true;
  3623. break;
  3624. }
  3625. if (special)
  3626. return buildDatasetIterateSpecialTempTable(ctx, expr, needToBreak);
  3627. }
  3628. break;
  3629. }
  3630. case no_datasetfromdictionary:
  3631. return buildDatasetIterateFromDictionary(ctx, expr, needToBreak);
  3632. case no_call:
  3633. case no_externalcall:
  3634. if (hasStreamedModifier(expr->queryType()))
  3635. return buildDatasetIterateStreamedCall(ctx, expr, needToBreak);
  3636. break;
  3637. #if 0
  3638. //Following should improve the code, but I'm not sure how to correctly convert a referenceSelector to a boundExpr (since it may be with an existing row)
  3639. case no_datasetfromrow:
  3640. if (!needToBreak)
  3641. {
  3642. BoundRow * row = buildNewRow(ctx, expr->queryChild(0));
  3643. bindTableCursor(ctx, expr, tempRow->queryBound(), no_none, NULL);
  3644. return row;
  3645. }
  3646. break;
  3647. #endif
  3648. }
  3649. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, expr);
  3650. return cursor->buildIterateLoop(ctx, needToBreak);
  3651. }
  3652. //---------------------------------------------------------------------------
  3653. // Row Assignment
  3654. void HqlCppTranslator::buildCompoundAssign(BuildCtx & ctx, IHqlExpression * left, IReferenceSelector * leftSelector, IHqlExpression * rightScope, IHqlExpression * rightSelector)
  3655. {
  3656. switch (left->getOperator())
  3657. {
  3658. case no_ifblock:
  3659. {
  3660. BuildCtx subctx(ctx);
  3661. OwnedHqlExpr test = replaceSelector(left->queryChild(0), querySelfReference(), leftSelector->queryExpr());
  3662. buildFilter(subctx, test);
  3663. buildCompoundAssign(subctx, left->queryChild(1), leftSelector, rightScope, rightSelector);
  3664. //This calculates the size of the previous block. It means that subsequent uses of the
  3665. //offsets are cached - even if they are inside another ifblock().
  3666. CHqlBoundExpr bound;
  3667. IHqlExpression * mapexpr = createSelectExpr(LINK(leftSelector->queryExpr()), LINK(left));
  3668. OwnedHqlExpr size = createValue(no_sizeof, makeIntType(4,false), mapexpr);
  3669. buildCachedExpr(ctx, size, bound);
  3670. }
  3671. break;
  3672. case no_field:
  3673. {
  3674. Owned<IReferenceSelector> selectedLeft = leftSelector->select(ctx, left);
  3675. OwnedHqlExpr selectedRight;
  3676. IHqlExpression * leftRecord = ::queryRecord(leftSelector->queryType());
  3677. if (!rightScope || (leftRecord==rightScope))
  3678. {
  3679. selectedRight.setown(createSelectExpr(LINK(rightSelector), LINK(left)));
  3680. }
  3681. else
  3682. {
  3683. IHqlSimpleScope * scope = rightScope->querySimpleScope();
  3684. IHqlExpression * resolved = scope->lookupSymbol(left->queryId());
  3685. assertex(resolved);
  3686. selectedRight.setown(createSelectExpr(LINK(rightSelector), resolved));
  3687. }
  3688. if (left->queryType()->getTypeCode() == type_row)
  3689. buildCompoundAssign(ctx, left->queryRecord(), selectedLeft, selectedRight->queryRecord(), selectedRight);
  3690. else
  3691. selectedLeft->set(ctx, selectedRight);
  3692. break;
  3693. }
  3694. break;
  3695. case no_record:
  3696. {
  3697. ForEachChild(i, left)
  3698. buildCompoundAssign(ctx, left->queryChild(i), leftSelector, rightScope, rightSelector);
  3699. break;
  3700. }
  3701. case no_attr:
  3702. case no_attr_expr:
  3703. case no_attr_link:
  3704. break;
  3705. default:
  3706. UNIMPLEMENTED;
  3707. }
  3708. }
  3709. void HqlCppTranslator::buildCompoundAssign(BuildCtx & ctx, IHqlExpression * left, IHqlExpression * right)
  3710. {
  3711. //MORE: May need to resolve lhs and rhs in scope to find out the record type.
  3712. // buildCompoundAssign(ctx, column->queryRecord(), selector->queryExpr(), value->queryRecord(), value);
  3713. UNIMPLEMENTED;
  3714. }
  3715. void HqlCppTranslator::doBuildRowAssignAggregateClear(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3716. {
  3717. IHqlExpression * transform = expr->queryChild(2);
  3718. unsigned numAggregates = transform->numChildren();
  3719. unsigned idx;
  3720. OwnedHqlExpr self = getSelf(expr);
  3721. for (idx = 0; idx < numAggregates; idx++)
  3722. {
  3723. IHqlExpression * cur = transform->queryChild(idx);
  3724. if (cur->isAttribute())
  3725. continue;
  3726. Owned<IReferenceSelector> curTarget = createSelfSelect(ctx, target, cur->queryChild(0), self);
  3727. IHqlExpression * src = cur->queryChild(1);
  3728. switch (src->getOperator())
  3729. {
  3730. case no_countgroup:
  3731. case no_maxgroup:
  3732. case no_mingroup:
  3733. case no_sumgroup:
  3734. case no_existsgroup:
  3735. curTarget->buildClear(ctx, 0);
  3736. break;
  3737. default:
  3738. if (src->isConstant())
  3739. curTarget->set(ctx, src);
  3740. else
  3741. curTarget->buildClear(ctx, 0);
  3742. break;
  3743. }
  3744. }
  3745. }
  3746. void HqlCppTranslator::doBuildRowAssignAggregateNext(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr, bool isSingleExists, IHqlExpression * alreadyDoneExpr)
  3747. {
  3748. IHqlExpression * transform = expr->queryChild(2);
  3749. unsigned numAggregates = transform->numChildren();
  3750. OwnedHqlExpr self = getSelf(expr);
  3751. OwnedHqlExpr notAlreadyDone = alreadyDoneExpr ? getInverse(alreadyDoneExpr) : NULL;
  3752. bool isVariableOffset = false;
  3753. for (unsigned idx = 0; idx < numAggregates; idx++)
  3754. {
  3755. IHqlExpression * cur = transform->queryChild(idx);
  3756. if (cur->isAttribute())
  3757. continue;
  3758. IHqlExpression * targetSelect = cur->queryChild(0);
  3759. Owned<IReferenceSelector> curTarget = createSelfSelect(ctx, target, targetSelect, self);
  3760. IHqlExpression * src = cur->queryChild(1);
  3761. IHqlExpression * arg = src->queryChild(0);
  3762. IHqlExpression * cond = src->queryChild(1);
  3763. BuildCtx condctx(ctx);
  3764. node_operator srcOp = src->getOperator();
  3765. switch (srcOp)
  3766. {
  3767. case no_countgroup:
  3768. {
  3769. assertex(!(arg && isVariableOffset));
  3770. if (arg)
  3771. buildFilter(condctx, arg);
  3772. OwnedHqlExpr one = getSizetConstant(1);
  3773. if (isVariableOffset)
  3774. {
  3775. IHqlStmt * ifStmt = condctx.addFilter(notAlreadyDone);
  3776. curTarget->set(condctx, one);
  3777. condctx.selectElse(ifStmt);
  3778. }
  3779. buildIncrementAssign(condctx, curTarget, one);
  3780. }
  3781. break;
  3782. case no_sumgroup:
  3783. {
  3784. assertex(!(cond && isVariableOffset));
  3785. if (cond)
  3786. buildFilter(condctx, cond);
  3787. if (isVariableOffset)
  3788. {
  3789. IHqlStmt * ifStmt = condctx.addFilter(notAlreadyDone);
  3790. curTarget->set(condctx, arg);
  3791. condctx.selectElse(ifStmt);
  3792. }
  3793. buildIncrementAssign(condctx, curTarget, arg);
  3794. }
  3795. break;
  3796. case no_maxgroup:
  3797. case no_mingroup:
  3798. {
  3799. node_operator op = (srcOp == no_maxgroup) ? no_gt : no_lt;
  3800. assertex(!cond);
  3801. OwnedHqlExpr castArg = ensureExprType(arg, targetSelect->queryType()); // cast to correct type, assume it can fit in the target type.
  3802. OwnedHqlExpr temp = buildSimplifyExpr(condctx, castArg);
  3803. OwnedHqlExpr compare = createBoolExpr (op, LINK(temp), LINK(curTarget->queryExpr()));
  3804. if (notAlreadyDone)
  3805. compare.setown(createBoolExpr(no_or, LINK(notAlreadyDone), compare.getClear()));
  3806. buildFilter(condctx, compare);
  3807. curTarget->set(condctx, temp);
  3808. }
  3809. break;
  3810. case no_existsgroup:
  3811. assertex(!(arg && isVariableOffset));
  3812. if (arg)
  3813. buildFilter(condctx, arg);
  3814. curTarget->set(condctx, queryBoolExpr(true));
  3815. if (isSingleExists)
  3816. condctx.addBreak();
  3817. break;
  3818. default:
  3819. if (!src->isConstant() || isVariableOffset)
  3820. {
  3821. condctx.addFilter(notAlreadyDone);
  3822. curTarget->set(condctx, src);
  3823. }
  3824. break;
  3825. }
  3826. if (targetSelect->queryType()->getSize() == UNKNOWN_LENGTH)
  3827. isVariableOffset = true;
  3828. }
  3829. if (alreadyDoneExpr)
  3830. buildAssignToTemp(ctx, alreadyDoneExpr, queryBoolExpr(true));
  3831. }
  3832. void HqlCppTranslator::doBuildRowAssignAggregate(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3833. {
  3834. IHqlExpression * dataset = expr->queryChild(0);
  3835. IHqlExpression * transform = expr->queryChild(2);
  3836. OwnedHqlExpr simpleAggregate = convertToSimpleAggregate(expr);
  3837. CHqlBoundExpr optimized;
  3838. if (simpleAggregate)
  3839. {
  3840. node_operator aggOp = simpleAggregate->getOperator();
  3841. if (aggOp == no_exists || aggOp == no_count)
  3842. {
  3843. if (canBuildOptimizedCount(ctx, dataset, optimized, aggOp))
  3844. {
  3845. IHqlExpression * assign = transform->queryChild(0);
  3846. IHqlExpression * lhs = assign->queryChild(0);
  3847. Owned<IReferenceSelector> selected = target->select(ctx, lhs);
  3848. selected->set(ctx, simpleAggregate);
  3849. return;
  3850. }
  3851. }
  3852. }
  3853. unsigned numAggregates = transform->numChildren();
  3854. if (isKeyedCountAggregate(expr))
  3855. throwError(HQLERR_KeyedCountNonKeyable);
  3856. bool needGuard = false;
  3857. bool isSingleExists = true;
  3858. unsigned idx;
  3859. for (idx = 0; idx < numAggregates; idx++)
  3860. {
  3861. IHqlExpression * cur = transform->queryChild(idx);
  3862. if (cur->isAttribute())
  3863. continue;
  3864. IHqlExpression * tgt = cur->queryChild(0);
  3865. IHqlExpression * src = cur->queryChild(1);
  3866. switch (src->getOperator())
  3867. {
  3868. case no_countgroup:
  3869. case no_sumgroup:
  3870. isSingleExists = false;
  3871. break;
  3872. case no_existsgroup:
  3873. break;
  3874. case no_mingroup:
  3875. isSingleExists = false;
  3876. needGuard = true;
  3877. break;
  3878. case no_maxgroup:
  3879. isSingleExists = false;
  3880. if (!isNullValueMinimumValue(src->queryType()))
  3881. needGuard = true;
  3882. break;
  3883. default:
  3884. isSingleExists = false;
  3885. if (!src->isConstant())
  3886. needGuard = true;
  3887. break;
  3888. }
  3889. if ((tgt->queryType()->getSize() == UNKNOWN_LENGTH) && (idx+1 != numAggregates))
  3890. needGuard = true;
  3891. }
  3892. OwnedHqlExpr guard;
  3893. if (needGuard)
  3894. {
  3895. Owned<ITypeInfo> boolType = makeBoolType();
  3896. guard.setown(ctx.getTempDeclare(boolType, queryBoolExpr(false)));
  3897. }
  3898. //NB: The clear must occur inside a group, otherwise afterwards sizeof(target) will be bound to fixed values
  3899. BuildCtx clearctx(ctx);
  3900. clearctx.addGroup();
  3901. doBuildRowAssignAggregateClear(clearctx, target, expr);
  3902. BuildCtx condctx(ctx);
  3903. buildDatasetIterate(condctx, dataset, isSingleExists);
  3904. doBuildRowAssignAggregateNext(condctx, target, expr, isSingleExists, guard);
  3905. }
  3906. void HqlCppTranslator::doBuildRowAssignProject(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3907. {
  3908. IHqlExpression * dataset = expr->queryChild(0);
  3909. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  3910. if (counter && !ctx.queryMatchExpr(counter))
  3911. throwError(HQLERR_CounterNotFound);
  3912. BuildCtx subctx(ctx);
  3913. assertex(target->isRoot());
  3914. IHqlExpression * selSeq = querySelSeq(expr);
  3915. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, selSeq);
  3916. OwnedHqlExpr activeDataset = ensureActiveRow(dataset->queryNormalizedSelector());
  3917. // queryChild(1) should be changed to queryTransformExpr()...
  3918. OwnedHqlExpr transform = queryNewReplaceSelector(queryNewColumnProvider(expr), leftSelect, activeDataset);
  3919. Owned<BoundRow> selfCursor;
  3920. if (!transform)
  3921. {
  3922. subctx.addGroup();
  3923. selfCursor.set(bindSelectorAsSelf(subctx, target, expr));
  3924. //Mapping may potentially be ambiguous, so do things correctly (see hqlsource for details)
  3925. BoundRow * prevCursor = resolveSelectorDataset(subctx, dataset->queryNormalizedSelector());
  3926. transform.set(expr->queryChild(1));
  3927. bindTableCursor(subctx, dataset, prevCursor->queryBound(), no_left, selSeq);
  3928. }
  3929. else
  3930. {
  3931. //Not introducing any new left rows => no problem assigning to target selector
  3932. selfCursor.setown(target->getRow(subctx));
  3933. }
  3934. doTransform(subctx, transform, selfCursor);
  3935. }
  3936. void HqlCppTranslator::doBuildRowAssignCreateRow(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3937. {
  3938. IHqlExpression * transform = expr->queryChild(0);
  3939. if (transform->isConstant())
  3940. {
  3941. #ifdef USE_CONSTANT_ROW_FOR_ASSIGN
  3942. //Generally not worthwhile - unless maybe it has a large number of fields....
  3943. CHqlBoundExpr bound;
  3944. if (doBuildRowConstantTransform(transform, bound))
  3945. {
  3946. OwnedHqlExpr raw = bound.getTranslatedExpr();
  3947. buildRowAssign(ctx, target, raw);
  3948. return;
  3949. }
  3950. #endif
  3951. }
  3952. Owned<BoundRow> selfCursor = target->getRow(ctx);
  3953. doTransform(ctx, transform, selfCursor);
  3954. }
  3955. void HqlCppTranslator::doBuildRowAssignNullRow(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3956. {
  3957. target->buildClear(ctx, 0);
  3958. }
  3959. void HqlCppTranslator::doBuildRowAssignProjectRow(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3960. {
  3961. IHqlExpression * srcRow = expr->queryChild(0);
  3962. IHqlExpression * transform = expr->queryChild(1);
  3963. Owned<IReferenceSelector> source = buildNewRow(ctx, srcRow);
  3964. BuildCtx subctx(ctx);
  3965. OwnedHqlExpr leftSelect = createSelector(no_left, srcRow, querySelSeq(expr));
  3966. OwnedHqlExpr newTransform = replaceSelector(transform, leftSelect, srcRow);
  3967. Owned<BoundRow> selfCursor = target->getRow(subctx);
  3968. doTransform(subctx, newTransform, selfCursor);
  3969. }
  3970. void HqlCppTranslator::doBuildRowAssignSerializeRow(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3971. {
  3972. IHqlExpression * srcRow = expr->queryChild(0);
  3973. IAtom * serializeForm = expr->queryChild(1)->queryName();
  3974. Owned<IReferenceSelector> source = buildNewRow(ctx, srcRow);
  3975. BuildCtx subctx(ctx);
  3976. Owned<BoundRow> leftCursor = source->getRow(subctx);
  3977. BoundRow * selfCursor = bindSelectorAsSelf(subctx, target, expr);
  3978. IHqlExpression * unserializedRecord = srcRow->queryRecord();
  3979. //If builder isn't provided then the target must be a fixed size record that doesn't require serialization
  3980. //Therefore this should never be called.
  3981. assertex(selfCursor->queryBuilder());
  3982. {
  3983. HqlExprArray args;
  3984. args.append(*createSerializer(ctx, unserializedRecord, serializeForm, serializerAtom));
  3985. args.append(*LINK(srcRow));
  3986. Owned<ITypeInfo> type = makeTransformType(expr->queryRecord()->getType());
  3987. OwnedHqlExpr call = bindFunctionCall(rtlSerializeToBuilderId, args, type);
  3988. doTransform(subctx, call, selfCursor);
  3989. //MORE: This doesn't associated the returned size with the target if assigned to a child field.
  3990. //very unusual code, so not too concerned.
  3991. }
  3992. }
  3993. void HqlCppTranslator::doBuildRowAssignUserTable(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  3994. {
  3995. Owned<BoundRow> selfCursor = target->getRow(ctx);
  3996. doTransform(ctx, expr->queryChild(2), selfCursor);
  3997. }
  3998. void HqlCppTranslator::buildRowAssign(BuildCtx & ctx, BoundRow * targetRow, IHqlExpression * expr)
  3999. {
  4000. //MORE: We should improve assigning a link counted row to a dataset as well.
  4001. //The problem is that currently the dataset constructor is responsible for finializing the rows.
  4002. //which is more compact if the row can't just be appended. Possibly needs an alwaysCreatesTemp()
  4003. //to help decide.
  4004. IHqlExpression * targetExpr = targetRow->queryBound();
  4005. if (targetRow->isLinkCounted() && hasWrapperModifier(targetExpr->queryType()))
  4006. {
  4007. CHqlBoundTarget target;
  4008. target.expr.set(targetRow->queryBound());
  4009. switch (expr->getOperator())
  4010. {
  4011. //MORE could support no_null, no_if, no_translated, constant no_createrow etc.
  4012. case no_call:
  4013. case no_externalcall:
  4014. case no_getgraphresult:
  4015. buildExprAssign(ctx, target, expr);
  4016. return;
  4017. case no_comma:
  4018. case no_compound:
  4019. buildStmt(ctx, expr->queryChild(0));
  4020. buildRowAssign(ctx, targetRow, expr->queryChild(1));
  4021. return;
  4022. case no_selectnth:
  4023. {
  4024. Owned<IReferenceSelector> src = buildNewRow(ctx, expr);
  4025. Owned<BoundRow> srcRow = src->getRow(ctx);
  4026. BoundRow * linkedRow = ensureLinkCountedRow(ctx, srcRow);
  4027. ctx.addAssignLink(targetRow->queryExpr(), linkedRow->queryExpr());
  4028. return;
  4029. }
  4030. }
  4031. }
  4032. BuildCtx subctx(ctx);
  4033. IHqlStmt * stmt = subctx.addGroup();
  4034. stmt->setIncomplete(true);
  4035. Owned<BoundRow> rowBuilder = createRowBuilder(subctx, targetRow);
  4036. Owned<IReferenceSelector> createdRef = createReferenceSelector(rowBuilder);
  4037. buildRowAssign(subctx, createdRef, expr);
  4038. finalizeTempRow(subctx, targetRow, rowBuilder);
  4039. stmt->setIncomplete(false);
  4040. stmt->mergeScopeWithContainer();
  4041. }
  4042. void HqlCppTranslator::buildRowAssign(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr)
  4043. {
  4044. switch (expr->getOperator())
  4045. {
  4046. case no_temprow:
  4047. throwUnexpected();
  4048. case no_projectrow:
  4049. doBuildRowAssignProjectRow(ctx, target, expr);
  4050. return;
  4051. case no_createrow:
  4052. doBuildRowAssignCreateRow(ctx, target, expr);
  4053. return;
  4054. case no_null:
  4055. doBuildRowAssignNullRow(ctx, target, expr);
  4056. return;
  4057. case no_nofold:
  4058. case no_forcegraph:
  4059. case no_nocombine:
  4060. buildRowAssign(ctx, target, expr->queryChild(0));
  4061. return;
  4062. case no_serialize:
  4063. {
  4064. IHqlExpression * deserialized = expr->queryChild(0);
  4065. IAtom * serializeForm = expr->queryChild(1)->queryName();
  4066. if (isDummySerializeDeserialize(expr))
  4067. buildRowAssign(ctx, target, deserialized->queryChild(0));
  4068. else if (!typeRequiresDeserialization(deserialized->queryType(), serializeForm))
  4069. buildRowAssign(ctx, target, deserialized);
  4070. else if (target->queryRootRow()->queryBuilder())
  4071. doBuildRowAssignSerializeRow(ctx, target, expr);
  4072. else
  4073. {
  4074. CHqlBoundExpr bound;
  4075. buildTempExpr(ctx, expr, bound);
  4076. OwnedHqlExpr translated = bound.getTranslatedExpr();
  4077. buildRowAssign(ctx, target, translated);
  4078. }
  4079. return;
  4080. }
  4081. case no_if:
  4082. {
  4083. //Assigning a variable size record can mean that references to self need recalculating outside of the condition,
  4084. //producing poor code.
  4085. if (!isVariableSizeRecord(expr->queryRecord()))
  4086. {
  4087. OwnedHqlExpr foldedCond = foldHqlExpression(expr->queryChild(0));
  4088. BuildCtx condctx(ctx);
  4089. IHqlStmt * cond = buildFilterViaExpr(condctx, foldedCond);
  4090. buildRowAssign(condctx, target, expr->queryChild(1));
  4091. condctx.selectElse(cond);
  4092. buildRowAssign(condctx, target, expr->queryChild(2));
  4093. return;
  4094. }
  4095. }
  4096. break;
  4097. /*
  4098. case no_externalcall:
  4099. //MORE: Should assign directly to the target, but may not be very easy....
  4100. if (target->isBinary() && queryRecord(source->queryType()) == expr->queryRecord())
  4101. {
  4102. CHqlBoundExpr address;
  4103. target->buildAddress(ctx, address);
  4104. row.setown(createValue(no_typetransfer, makeReferenceModifier(LINK(selector->queryType())), LINK(address.expr)));
  4105. doBuildCall(ctx, &target, expr, NULL);
  4106. }
  4107. break;
  4108. */
  4109. case no_comma:
  4110. case no_compound:
  4111. buildStmt(ctx, expr->queryChild(0));
  4112. buildRowAssign(ctx, target, expr->queryChild(1));
  4113. return;
  4114. }
  4115. Owned<IReferenceSelector> src = buildNewRow(ctx, expr);
  4116. buildRowAssign(ctx, target, src);
  4117. }
  4118. void HqlCppTranslator::buildRowAssign(BuildCtx & ctx, IReferenceSelector * target, IReferenceSelector * source)
  4119. {
  4120. BuildCtx subctx(ctx);
  4121. IHqlExpression * sourceRecord = ::queryRecord(source->queryType());
  4122. IHqlExpression * targetRecord = ::queryRecord(target->queryType());
  4123. //if record structures are identical, then we must just be able to block copy the information across.
  4124. bool useMemcpy = (sourceRecord == targetRecord) && source->isBinary() && !source->isConditional();
  4125. if (useMemcpy)
  4126. {
  4127. if (source->queryRootRow()->isConditional())
  4128. {
  4129. IHqlStmt * ifStmt = subctx.addFilter(source->queryRootRow()->queryBound());
  4130. target->setRow(subctx, source);
  4131. subctx.selectElse(ifStmt);
  4132. target->buildClear(subctx, 0);
  4133. }
  4134. else
  4135. target->setRow(subctx, source);
  4136. }
  4137. else
  4138. buildCompoundAssign(subctx, targetRecord, target, sourceRecord, source->queryExpr());
  4139. }
  4140. //---------------------------------------------------------------------------
  4141. // Dataset selection
  4142. IReferenceSelector * HqlCppTranslator::doBuildRowSelectTop(BuildCtx & ctx, IHqlExpression * expr)
  4143. {
  4144. //create a temporary
  4145. Owned<ITypeInfo> rowType = makeReferenceModifier(expr->getType());
  4146. OwnedHqlExpr rowExpr = ctx.getTempDeclare(rowType, NULL);
  4147. Owned<BoundRow> row = createBoundRow(expr, rowExpr);
  4148. ctx.associate(*row); // associate here because it is compared inside the loop
  4149. CHqlBoundExpr boundCleared;
  4150. #ifdef CREATE_DEAULT_ROW_IF_NULL
  4151. buildDefaultRow(ctx, expr, boundCleared);
  4152. #else
  4153. buildNullRow(ctx, expr, boundCleared);
  4154. #endif
  4155. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  4156. //Declare row for final level, iterate the appropriate number of times, and then assign and break.
  4157. BuildCtx initctx(ctx);
  4158. initctx.addGroup(); // add a group to allow a temporary to be declared later.
  4159. initctx.addAssign(rowExpr, defaultRowPtr);
  4160. HqlExprAssociation * savedMarker = ctx.associateExpr(queryConditionalRowMarker(), rowExpr);
  4161. BuildCtx iterctx(ctx);
  4162. IHqlExpression * sort = expr->queryChild(0);
  4163. IHqlExpression * dataset = sort->queryChild(0);
  4164. IHqlExpression * sortList = sort->queryChild(1);
  4165. BoundRow * chooseCursor = buildDatasetIterate(iterctx, dataset, false);
  4166. //if (!best) { best=row; } else { if (next < best) best = row; } Must short-circuit the test of best
  4167. OwnedHqlExpr testBest = createBoolExpr(no_eq, LINK(rowExpr), LINK(defaultRowPtr));
  4168. IHqlStmt * ifStmt = iterctx.addFilter(testBest);
  4169. {
  4170. OwnedHqlExpr source = ensureIteratedRowIsLive(initctx, ctx, iterctx, chooseCursor, dataset, expr);
  4171. OwnedHqlExpr castLeftRow = createValue(no_implicitcast, LINK(rowType), LINK(source));//chooseCursor->queryBound()));
  4172. iterctx.addAssign(rowExpr, castLeftRow);
  4173. }
  4174. iterctx.selectElse(ifStmt);
  4175. CHqlBoundExpr bound;
  4176. buildOrderedCompare(iterctx, dataset, sortList, bound, dataset, expr);
  4177. OwnedHqlExpr compare = createBoolExpr(no_lt, LINK(bound.expr), getZero());
  4178. iterctx.addFilter(compare);
  4179. {
  4180. OwnedHqlExpr source = ensureIteratedRowIsLive(initctx, ctx, iterctx, chooseCursor, dataset, expr);
  4181. OwnedHqlExpr castLeftRow = createValue(no_implicitcast, LINK(rowType), LINK(source));//chooseCursor->queryBound()));
  4182. iterctx.addAssign(rowExpr, castLeftRow);
  4183. }
  4184. ctx.removeAssociation(savedMarker);
  4185. //Set conditional later on, so test in main loop is explicit
  4186. #ifndef CREATE_DEAULT_ROW_IF_NULL
  4187. row->setConditional(true);
  4188. #endif
  4189. return createReferenceSelector(row);
  4190. }
  4191. BoundRow * HqlCppTranslator::buildOptimizeSelectFirstRow(BuildCtx & ctx, IHqlExpression * expr)
  4192. {
  4193. BoundRow * parentRow = NULL;
  4194. node_operator op = expr->getOperator();
  4195. switch (op)
  4196. {
  4197. case no_compound_childaggregate:
  4198. return buildOptimizeSelectFirstRow(ctx, expr->queryChild(0));
  4199. case no_hqlproject:
  4200. case no_newusertable:
  4201. {
  4202. parentRow = buildOptimizeSelectFirstRow(ctx, expr->queryChild(0));
  4203. if (!parentRow)
  4204. return NULL;
  4205. }
  4206. //fall through
  4207. case no_newaggregate:
  4208. {
  4209. OwnedHqlExpr selectRow = createRow(no_selectnth, LINK(expr), getSizetConstant(1));
  4210. BoundRow * match = static_cast<BoundRow *>(ctx.queryAssociation(selectRow, AssocRow, NULL));
  4211. if (match)
  4212. return LINK(match);
  4213. Owned<BoundRow> tempRow = declareTempRow(ctx, ctx, selectRow);
  4214. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, tempRow);
  4215. Owned<IReferenceSelector> createdRef = createReferenceSelector(rowBuilder);
  4216. BuildCtx subctx(ctx);
  4217. if (parentRow)
  4218. {
  4219. subctx.addGroup();
  4220. if (op == no_hqlproject)
  4221. bindTableCursor(ctx, expr->queryChild(0), tempRow->queryBound(), no_left, querySelSeq(expr));
  4222. else
  4223. bindTableCursor(ctx, expr->queryChild(0), tempRow->queryBound(), no_none, NULL);
  4224. }
  4225. doBuildRowAssignAggregate(subctx, createdRef, expr);
  4226. finalizeTempRow(ctx, tempRow, rowBuilder);
  4227. ctx.associate(*tempRow);
  4228. return tempRow;
  4229. }
  4230. //
  4231. default:
  4232. return NULL;
  4233. }
  4234. }
  4235. void HqlCppTranslator::convertBoundDatasetToFirstRow(IHqlExpression * expr, CHqlBoundExpr & bound)
  4236. {
  4237. Owned<ITypeInfo> type = makeReferenceModifier(expr->getType());
  4238. ITypeInfo * boundType = bound.queryType();
  4239. if (isArrayRowset(boundType))
  4240. {
  4241. Linked<ITypeInfo> rowType = queryUnqualifiedType(queryRowType(boundType));
  4242. rowType.setown(makeReferenceModifier(LINK(rowType)));
  4243. if (hasLinkedRow(boundType))
  4244. type.setown(setLinkCountedAttr(type, true));
  4245. bound.expr.setown(createValue(no_deref, LINK(rowType), LINK(bound.expr)));
  4246. }
  4247. else if (bound.queryType()->isReference())
  4248. bound.expr.setown(createValue(no_typetransfer, LINK(type), bound.expr.getClear()));
  4249. else
  4250. bound.expr.setown(createValue(no_implicitcast, LINK(type), bound.expr.getClear()));
  4251. }
  4252. void HqlCppTranslator::convertBoundRowToDataset(BuildCtx & ctx, CHqlBoundExpr & bound, const BoundRow * row, ExpressionFormat preferredFormat)
  4253. {
  4254. IHqlExpression * boundRow = row->queryBound();
  4255. IHqlExpression * record = row->queryDataset()->queryRecord();
  4256. Owned<ITypeInfo> type = makeTableType(makeRowType(LINK(record->queryType())));
  4257. Owned<ITypeInfo> refType = makeReferenceModifier(LINK(type));
  4258. if (hasLinkCountedModifier(boundRow->queryType()) && (preferredFormat != FormatBlockedDataset))
  4259. {
  4260. OwnedHqlExpr curActivityId = getCurrentActivityId(ctx);
  4261. StringBuffer allocatorName;
  4262. ensureRowAllocator(allocatorName, ctx, record, curActivityId);
  4263. OwnedHqlExpr src = getPointer(boundRow);
  4264. //We can't just take the address of the link counted row, have to create a temporary dataset
  4265. //could be fixed once the link counting is tracked on rows and datasets
  4266. CHqlBoundTarget target;
  4267. createTempFor(ctx, type, target, typemod_none, FormatLinkedDataset);
  4268. StringBuffer s;
  4269. generateExprCpp(s, target.expr).append(".setRow(").append(allocatorName).append(",");
  4270. generateExprCpp(s, src).append(");");
  4271. ctx.addQuoted(s);
  4272. bound.setFromTarget(target);
  4273. }
  4274. else if (boundRow->queryType()->isReference())
  4275. bound.expr.setown(createValue(no_typetransfer, LINK(refType), LINK(boundRow)));
  4276. else
  4277. bound.expr.setown(createValue(no_implicitcast, LINK(refType), LINK(boundRow)));
  4278. bound.count.setown(getSizetConstant(1));
  4279. }
  4280. IHqlExpression * HqlCppTranslator::ensureIteratedRowIsLive(BuildCtx & initctx, BuildCtx & searchctx, BuildCtx & iterctx, BoundRow * row, IHqlExpression * dataset, IHqlExpression * rowExpr)
  4281. {
  4282. //The problem is that we are iterating through the rows in a dataset, and we need to access the "best" row outside of the loop
  4283. //However subsequent iterations of the loop might invalidate the current row, so we need to ensure the best row is retained.
  4284. //There should really be a better way, but it isn't too bad with link counted rows.
  4285. bool needToPreserve = false;
  4286. IHqlExpression * ds = dataset;
  4287. while (ds && !needToPreserve)
  4288. {
  4289. if (ds->isDatarow())
  4290. {
  4291. if (initctx.queryAssociation(ds, AssocRow, NULL))
  4292. break;
  4293. }
  4294. else
  4295. {
  4296. if (initctx.queryMatchExpr(ds))
  4297. break;
  4298. }
  4299. switch (ds->getOperator())
  4300. {
  4301. case no_filter:
  4302. case no_grouped:
  4303. case no_stepped:
  4304. case no_sorted:
  4305. case no_distributed:
  4306. case no_unordered:
  4307. case no_preservemeta:
  4308. case no_choosen:
  4309. case no_selectnth: // can occur as the lhs of no_select
  4310. case no_compound_childnormalize:
  4311. case no_compound_selectnew:
  4312. case no_compound_childread:
  4313. case no_dataset_alias:
  4314. ds = ds->queryChild(0);
  4315. break;
  4316. case no_select:
  4317. if (ds->isDataset())
  4318. {
  4319. if (ds->hasAttribute(newAtom))
  4320. {
  4321. ds = ds->queryChild(0);
  4322. //don't walk complexds[1].childDataset<new> since the [1] will be generated as a temporary
  4323. // if (!ds->isDataset() && (ds->getOperator() != no_select))
  4324. // ds = NULL;
  4325. }
  4326. else
  4327. ds = NULL;
  4328. }
  4329. else
  4330. {
  4331. //ds.x.y, always walk to to ds.x
  4332. ds = ds->queryChild(0);
  4333. }
  4334. break;
  4335. case no_rows:
  4336. case no_call:
  4337. case no_externalcall:
  4338. case no_getresult:
  4339. case no_getgraphresult:
  4340. case no_alias:
  4341. ds = NULL;
  4342. break;
  4343. default:
  4344. needToPreserve = true;
  4345. break;
  4346. }
  4347. }
  4348. OwnedHqlExpr source = getPointer(row->queryBound());
  4349. if (!needToPreserve || initctx.hasAssociation(*row, false))
  4350. return source.getClear();
  4351. //If link counted, then declare a member that is a link counted row to ensure this row remains linked.
  4352. ITypeInfo * rowType = rowExpr->queryType();
  4353. if (hasLinkCountedModifier(row->queryBound()))
  4354. {
  4355. CHqlBoundTarget saveTarget;
  4356. createTempFor(initctx, rowType, saveTarget, typemod_wrapper, FormatLinkedDataset);
  4357. StringBuffer s;
  4358. generateExprCpp(s, saveTarget.expr);
  4359. s.append(".set(");
  4360. generateExprCpp(s, source).append(");");
  4361. iterctx.addQuoted(s);
  4362. return getPointer(saveTarget.expr);
  4363. }
  4364. BuildCtx childctx(iterctx);
  4365. Owned<BoundRow> tempRow = declareTempRow(childctx, childctx, rowExpr);
  4366. Owned<BoundRow> rowBuilder = createRowBuilder(childctx, tempRow);
  4367. OwnedHqlExpr sourceSelector = ensureActiveRow(row->querySelector());
  4368. buildAssign(childctx, rowBuilder->querySelector(), sourceSelector);
  4369. finalizeTempRow(childctx, tempRow, rowBuilder);
  4370. return getPointer(tempRow->queryBound());
  4371. }
  4372. IReferenceSelector * HqlCppTranslator::buildDatasetIndexViaIterator(BuildCtx & ctx, IHqlExpression * expr)
  4373. {
  4374. OwnedHqlExpr dataset = normalizeAnyDatasetAliases(querySkipDatasetMeta(expr->queryChild(0)));
  4375. IHqlExpression * index = expr->queryChild(1);
  4376. IHqlExpression * childDataset = dataset;
  4377. switch (dataset->getOperator())
  4378. {
  4379. case no_hqlproject:
  4380. //optimize selectnth(project(rows, t), n) to projectrow(selectnth(rows, n), t)
  4381. IHqlExpression * transform = dataset->queryChild(1);
  4382. if (!containsSkip(transform) && !expr->hasAttribute(_countProject_Atom))
  4383. childDataset = dataset->queryChild(0);
  4384. break;
  4385. }
  4386. //create a temporary
  4387. //Following works because rows are created as temporaries in the class, so still in scope outside the iterate loop.
  4388. //Not a strictly correct assumption - e.g., if ever done in the main process() code.
  4389. Owned<ITypeInfo> rowType = makeReferenceModifier(expr->getType());
  4390. OwnedHqlExpr rowExpr = ctx.getTempDeclare(rowType, NULL);
  4391. Owned<BoundRow> row = createBoundRow(expr, rowExpr);
  4392. CHqlBoundExpr boundCleared;
  4393. #ifdef CREATE_DEAULT_ROW_IF_NULL
  4394. buildDefaultRow(ctx, expr, boundCleared);
  4395. #else
  4396. buildNullRow(ctx, expr, boundCleared);
  4397. row->setConditional(true);
  4398. #endif
  4399. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  4400. //Declare row for final level, iterate the appropriate number of times, and then assign and break.
  4401. BuildCtx initctx(ctx);
  4402. initctx.addGroup(); // add a group to allow a temporary to be declared later.
  4403. initctx.addAssign(rowExpr, defaultRowPtr);
  4404. HqlExprAssociation * savedMarker = ctx.associateExpr(queryConditionalRowMarker(), rowExpr);
  4405. BuildCtx iterctx(ctx);
  4406. bool done = false;
  4407. if (childDataset->getOperator() == no_rows) //hasOutOfLineModifier(dataset->queryType()))
  4408. {
  4409. CHqlBoundExpr boundDs;
  4410. buildDataset(ctx, childDataset, boundDs, FormatNatural);
  4411. if (boundDs.count && isArrayRowset(boundDs.expr->queryType()))
  4412. {
  4413. OwnedHqlExpr castIndex = ensureExprType(index, unsignedType);
  4414. OwnedHqlExpr adjustedIndex = adjustValue(castIndex, -1);
  4415. CHqlBoundExpr boundIndex;
  4416. buildExpr(ctx, adjustedIndex, boundIndex);
  4417. OwnedHqlExpr count = getBoundCount(boundDs); // could be serialized, so can't assume bound.count is set
  4418. OwnedHqlExpr test = createValue(no_gt, makeBoolType(), LINK(count), LINK(boundIndex.expr));
  4419. iterctx.addFilter(test);
  4420. if (dataset != childDataset)
  4421. {
  4422. Owned<ITypeInfo> datasetRowType = makeRowReferenceType(boundDs);
  4423. OwnedHqlExpr selectedRow = createValue(no_index, LINK(datasetRowType), LINK(boundDs.expr), LINK(boundIndex.expr));
  4424. OwnedHqlExpr projected = createRow(no_projectrow, createTranslated(selectedRow), createComma(LINK(dataset->queryChild(1)), LINK(querySelSeq(dataset))));
  4425. Owned<IReferenceSelector> newRow = buildNewRow(iterctx, projected);
  4426. OwnedHqlExpr newPtr = getPointer(newRow->queryRootRow()->queryBound());
  4427. iterctx.addAssign(rowExpr, newPtr);
  4428. }
  4429. else
  4430. {
  4431. OwnedHqlExpr selectedRow = createValue(no_index, LINK(rowType), LINK(boundDs.expr), LINK(boundIndex.expr));
  4432. iterctx.addAssign(rowExpr, selectedRow);
  4433. }
  4434. done = true;
  4435. }
  4436. }
  4437. if (!done)
  4438. {
  4439. BoundRow * chooseCursor;
  4440. //If choosing the first element, then no need to maintain a counter...
  4441. IValue * indexValue = index->queryValue();
  4442. if (indexValue && (indexValue->getIntValue() == 1))
  4443. chooseCursor = buildDatasetIterate(iterctx, dataset, true);
  4444. else
  4445. chooseCursor = buildDatasetIterate(iterctx, expr, true);
  4446. if (chooseCursor)
  4447. {
  4448. OwnedHqlExpr source = getPointer(chooseCursor->queryBound());
  4449. //MORE: Need casts because cursor may be (probably are) constant, but temporary isn't
  4450. //should somehow fnd out by looking at the cursors.
  4451. OwnedHqlExpr castLeftRow = createValue(no_implicitcast, LINK(rowType), LINK(source));
  4452. iterctx.addAssign(rowExpr, castLeftRow);
  4453. iterctx.addBreak();
  4454. }
  4455. }
  4456. ctx.removeAssociation(savedMarker);
  4457. ctx.associate(*row);
  4458. return createReferenceSelector(row);
  4459. }
  4460. IReferenceSelector * HqlCppTranslator::buildDatasetIndex(BuildCtx & ctx, IHqlExpression * expr)
  4461. {
  4462. HqlExprAssociation * match = ctx.queryAssociation(expr, AssocRow, NULL);
  4463. if (match)
  4464. return createReferenceSelector(static_cast<BoundRow *>(match));
  4465. #if 0
  4466. //Causes some queries (ncf10) to run out of memory, so disable for the moment.
  4467. OwnedHqlExpr optimized = optimizeHqlExpression(expr, getOptimizeFlags()|HOOcompoundproject);
  4468. if (optimized != expr)
  4469. return buildNewRow(ctx, optimized);
  4470. #endif
  4471. OwnedHqlExpr dataset = normalizeAnyDatasetAliases(expr->queryChild(0));
  4472. //Special cases:
  4473. //i) selecting row [1] from something that only has a single row
  4474. //ii) selecting row [n] from something that can be iterated.
  4475. //iii) row[1] from something sorted that can be iterated.
  4476. BoundRow * row = NULL;
  4477. if (isTrivialSelectN(expr))
  4478. {
  4479. BoundRow * row = NULL;
  4480. #if 0
  4481. //This could be a good idea - but again it can mess up cse since dataset never gets bound.
  4482. //Could enable if I implement cse on datasets within transforms.
  4483. // if (canIterateInline(&ctx, dataset))
  4484. // row = buildOptimizeSelectFirstRow(ctx, dataset);
  4485. #endif
  4486. if ((dataset->getOperator() == no_newaggregate) && canProcessInline(&ctx, dataset))
  4487. row = buildOptimizeSelectFirstRow(ctx, dataset);
  4488. if (!row)
  4489. {
  4490. CHqlBoundExpr bound;
  4491. buildDataset(ctx, dataset, bound, FormatNatural);
  4492. convertBoundDatasetToFirstRow(expr, bound);
  4493. row = bindRow(ctx, expr, bound.expr);
  4494. }
  4495. return createReferenceSelector(row);
  4496. }
  4497. else if (canIterateInline(&ctx, dataset))
  4498. {
  4499. //MORE? Following doesn't work for implicit normalize which iterates multiple levels
  4500. bool specialCase = false;
  4501. dataset.set(querySkipDatasetMeta(dataset));
  4502. switch (dataset->getOperator())
  4503. {
  4504. case no_select:
  4505. specialCase = !isMultiLevelDatasetSelector(expr, false);
  4506. break;
  4507. case no_if:
  4508. case no_createdictionary:
  4509. case no_inlinetable:
  4510. case no_join:
  4511. //Always creates a temporary, so don't use an iterator
  4512. specialCase = true;
  4513. break;
  4514. default:
  4515. specialCase = alwaysEvaluatesToBound(dataset) || hasSingleRow(dataset) || !canIterateInline(&ctx, dataset);
  4516. break;
  4517. }
  4518. if (!specialCase)
  4519. return buildDatasetIndexViaIterator(ctx, expr);
  4520. }
  4521. else if (isSelectSortedTop(expr) && canIterateInline(&ctx, dataset->queryChild(0)))
  4522. {
  4523. return doBuildRowSelectTop(ctx, expr);
  4524. }
  4525. //MORE: Is this a good idea???
  4526. else if (!canProcessInline(&ctx, expr))
  4527. {
  4528. CHqlBoundExpr bound;
  4529. OwnedHqlExpr dsExpr = expr->isDatarow() ? createDatasetFromRow(LINK(expr)) : LINK(expr);
  4530. buildDataset(ctx, dsExpr, bound, FormatNatural);
  4531. convertBoundDatasetToFirstRow(expr, bound);
  4532. row = bindRow(ctx, expr, bound.expr);
  4533. }
  4534. if (!row)
  4535. {
  4536. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dataset);
  4537. row = cursor->buildSelectNth(ctx, expr);
  4538. if (!row)
  4539. {
  4540. CHqlBoundExpr boundCleared;
  4541. buildDefaultRow(ctx, dataset, boundCleared);
  4542. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  4543. row = bindRow(ctx, expr, defaultRowPtr);
  4544. }
  4545. }
  4546. return createReferenceSelector(row);
  4547. }
  4548. IReferenceSelector * HqlCppTranslator::buildDatasetSelectMap(BuildCtx & ctx, IHqlExpression * expr)
  4549. {
  4550. HqlExprAssociation * match = ctx.queryAssociation(expr, AssocRow, NULL);
  4551. if (match)
  4552. return createReferenceSelector(static_cast<BoundRow *>(match));
  4553. OwnedHqlExpr dictionary = normalizeAnyDatasetAliases(expr->queryChild(0));
  4554. //MORE: This should really be a createDictionarySelector call.
  4555. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dictionary);
  4556. Owned<BoundRow> row = cursor->buildSelectMap(ctx, expr);
  4557. if (!row)
  4558. {
  4559. CHqlBoundExpr boundCleared;
  4560. buildDefaultRow(ctx, dictionary, boundCleared);
  4561. OwnedHqlExpr defaultRowPtr = getPointer(boundCleared.expr);
  4562. row.setown(bindRow(ctx, expr, defaultRowPtr));
  4563. }
  4564. return createReferenceSelector(row);
  4565. }
  4566. //---------------------------------------------------------------------------
  4567. IHqlExpression * HqlCppTranslator::buildGetLocalResult(BuildCtx & ctx, IHqlExpression * expr)
  4568. {
  4569. IHqlExpression * graphId = expr->queryChild(1);
  4570. IHqlExpression * resultNum = expr->queryChild(2);
  4571. Linked<ITypeInfo> exprType = queryUnqualifiedType(expr->queryType());
  4572. if (!hasLinkCountedModifier(exprType))
  4573. exprType.setown(makeAttributeModifier(LINK(exprType), getLinkCountedAttr()));
  4574. if (expr->hasAttribute(externalAtom))
  4575. {
  4576. IHqlExpression * resultInstance = queryAttributeChild(expr, externalAtom, 0);
  4577. HqlExprAssociation * matchedResults = ctx.queryMatchExpr(resultInstance);
  4578. if (!matchedResults)
  4579. {
  4580. //Very unusual - a result is required from a child query, but that child query is actually in
  4581. //the parent/grandparent. We need to evaluate in the parent instead.
  4582. CHqlBoundExpr match;
  4583. if (!buildExprInCorrectContext(ctx, expr, match, false))
  4584. throwUnexpected();
  4585. return match.getTranslatedExpr();
  4586. }
  4587. HqlExprArray args;
  4588. args.append(*LINK(matchedResults->queryExpr()));
  4589. args.append(*LINK(resultNum));
  4590. if (expr->isDictionary())
  4591. return bindFunctionCall(getChildQueryDictionaryResultId, args, exprType);
  4592. if (expr->isDatarow())
  4593. return bindFunctionCall(getChildQueryLinkedRowResultId, args, exprType);
  4594. return bindFunctionCall(getChildQueryLinkedResultId, args, exprType);
  4595. }
  4596. assertex(activeActivities.ordinality());
  4597. queryAddResultDependancy(activeActivities.tos(), graphId, resultNum);
  4598. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  4599. assertex(activeSubgraph && graphId == activeSubgraph->graphTag);
  4600. unique_id_t id = activeSubgraph->graphId;
  4601. EvalContext * instance = queryEvalContext(ctx);
  4602. OwnedHqlExpr retInstanceExpr;
  4603. if (instance && !insideOnCreate(ctx))
  4604. retInstanceExpr.setown(instance->createGraphLookup(id, false));
  4605. else
  4606. retInstanceExpr.setown(doCreateGraphLookup(ctx, ctx, id, "this", true));
  4607. HqlExprArray args;
  4608. args.append(*LINK(retInstanceExpr));
  4609. args.append(*LINK(resultNum));
  4610. if (expr->isDictionary())
  4611. return bindFunctionCall(getLocalDictionaryResultId, args, exprType);
  4612. if (expr->isDatarow())
  4613. return bindFunctionCall(getLocalLinkedRowResultId, args, exprType);
  4614. return bindFunctionCall(getLocalLinkedResultId, args, exprType);
  4615. }
  4616. IHqlExpression * HqlCppTranslator::translateGetGraphResult(BuildCtx & ctx, IHqlExpression * expr)
  4617. {
  4618. if (expr->hasAttribute(_streaming_Atom))
  4619. {
  4620. if (insideLibrary())
  4621. throwError(HQLERR_StreamInputUsedDirectly);
  4622. else
  4623. throwError(HQLERR_LoopTooComplexForParallel);
  4624. }
  4625. if (expr->hasAttribute(externalAtom))
  4626. return buildGetLocalResult(ctx, expr);
  4627. if (!isCurrentActiveGraph(ctx, expr->queryChild(1)))
  4628. {
  4629. CHqlBoundExpr match;
  4630. if (!buildExprInCorrectContext(ctx, expr, match, false))
  4631. throwError(HQLERR_GraphContextNotFound);
  4632. return match.getTranslatedExpr();
  4633. }
  4634. return buildGetLocalResult(ctx, expr);
  4635. }
  4636. void HqlCppTranslator::doBuildAssignGetGraphResult(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4637. {
  4638. OwnedHqlExpr translated = translateGetGraphResult(ctx, expr);
  4639. buildExprAssign(ctx, target, translated);
  4640. }
  4641. void HqlCppTranslator::doBuildExprGetGraphResult(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  4642. {
  4643. if (!expr->hasAttribute(externalAtom) && (!isCurrentActiveGraph(ctx, expr->queryChild(1)) || !insideOnStart(ctx)))
  4644. {
  4645. doBuildAliasValue(ctx, expr, tgt, NULL);
  4646. return;
  4647. if (!isCurrentActiveGraph(ctx, expr->queryChild(1)))
  4648. {
  4649. if (!buildExprInCorrectContext(ctx, expr, tgt, false))
  4650. throwError(HQLERR_GraphContextNotFound);
  4651. return;
  4652. }
  4653. }
  4654. switch (expr->queryType()->getTypeCode())
  4655. {
  4656. case type_dictionary:
  4657. case type_table:
  4658. case type_groupedtable:
  4659. {
  4660. OwnedHqlExpr call = buildGetLocalResult(ctx, expr);
  4661. buildTempExpr(ctx, call, tgt);
  4662. break;
  4663. }
  4664. case type_row:
  4665. {
  4666. OwnedHqlExpr translated = translateGetGraphResult(ctx, expr);
  4667. buildExpr(ctx, translated, tgt);
  4668. break;
  4669. }
  4670. default:
  4671. {
  4672. OwnedHqlExpr call = buildGetLocalResult(ctx, expr);
  4673. buildExpr(ctx, call, tgt);
  4674. break;
  4675. }
  4676. }
  4677. }
  4678. ABoundActivity * HqlCppTranslator::doBuildActivityGetGraphResult(BuildCtx & ctx, IHqlExpression * expr)
  4679. {
  4680. IHqlExpression * graphId = expr->queryChild(1);
  4681. IHqlExpression * resultNum = expr->queryChild(2);
  4682. ThorActivityKind activityKind = (expr->hasAttribute(_streaming_Atom) ? TAKlocalstreamread : TAKlocalresultread);
  4683. bool useImplementationClass = options.minimizeActivityClasses && (resultNum->getOperator() == no_constant);
  4684. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, activityKind, expr, "LocalResultRead");
  4685. if (useImplementationClass)
  4686. instance->setImplementationClass(newLocalResultReadArgId);
  4687. if (expr->hasAttribute(_loop_Atom))
  4688. {
  4689. if (isCurrentActiveGraph(ctx, graphId))
  4690. instance->graphLabel.set("Begin Loop");
  4691. else
  4692. instance->graphLabel.set("Outer Loop Input");
  4693. }
  4694. buildActivityFramework(instance);
  4695. buildInstancePrefix(instance);
  4696. if (!useImplementationClass)
  4697. doBuildUnsignedFunction(instance->classctx, "querySequence", resultNum);
  4698. else
  4699. instance->addConstructorParameter(resultNum);
  4700. addGraphIdAttribute(instance, ctx, graphId);
  4701. buildInstanceSuffix(instance);
  4702. queryAddResultDependancy(*instance->queryBoundActivity(), graphId, resultNum);
  4703. return instance->getBoundActivity();
  4704. }
  4705. ABoundActivity * HqlCppTranslator::doBuildActivitySetGraphDictionaryResult(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  4706. {
  4707. IHqlExpression * dictionary = expr->queryChild(0);
  4708. IHqlExpression * dataset = dictionary->queryChild(0);
  4709. IHqlExpression * graphId = expr->queryChild(1);
  4710. IHqlExpression * resultNum = expr->queryChild(2);
  4711. bool isSpill = expr->hasAttribute(_spill_Atom);
  4712. ABoundActivity * parentActivity = activeActivities.ordinality() ? &activeActivities.tos() : NULL;
  4713. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  4714. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdictionaryresultwrite, expr, "DictionaryResultWrite");
  4715. buildActivityFramework(instance, isRoot && !isSpill);
  4716. buildInstancePrefix(instance);
  4717. doBuildUnsignedFunction(instance->classctx, "querySequence", resultNum);
  4718. doBuildBoolFunction(instance->classctx, "usedOutsideGraph", !isSpill);
  4719. if (parentActivity && !insideRemoteGraph(ctx) && !isSpill)
  4720. {
  4721. addDependency(ctx, instance->queryBoundActivity(), parentActivity, childAtom, "Child");
  4722. }
  4723. buildDictionaryHashMember(instance->createctx, dictionary, "queryHashLookupInfo");
  4724. instance->addAttributeBool("_isSpill", isSpill);
  4725. if (targetRoxie())
  4726. addGraphIdAttribute(instance, ctx, graphId);
  4727. buildInstanceSuffix(instance);
  4728. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  4729. associateRemoteResult(*instance, graphId, resultNum);
  4730. return instance->getBoundActivity();
  4731. }
  4732. ABoundActivity * HqlCppTranslator::doBuildActivitySetGraphResult(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  4733. {
  4734. IHqlExpression * dataset = expr->queryChild(0);
  4735. if (dataset->isDictionary())
  4736. return doBuildActivitySetGraphDictionaryResult(ctx, expr, isRoot);
  4737. IHqlExpression * graphId = expr->queryChild(1);
  4738. IHqlExpression * resultNum = expr->queryChild(2);
  4739. bool isSpill = expr->hasAttribute(_spill_Atom);
  4740. ABoundActivity * parentActivity = activeActivities.ordinality() ? &activeActivities.tos() : NULL;
  4741. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  4742. bool useImplementationClass = options.minimizeActivityClasses;
  4743. Owned<ActivityInstance> instance;
  4744. if (expr->getOperator() == no_spillgraphresult)
  4745. {
  4746. instance.setown(new ActivityInstance(*this, ctx, TAKlocalresultspill, expr, "LocalResultSpill"));
  4747. }
  4748. else
  4749. {
  4750. instance.setown(new ActivityInstance(*this, ctx, TAKlocalresultwrite, expr, "LocalResultWrite"));
  4751. }
  4752. if (useImplementationClass)
  4753. instance->setImplementationClass(newLocalResultSpillArgId);
  4754. if (expr->hasAttribute(_loop_Atom))
  4755. instance->graphLabel.set("End Loop");
  4756. buildActivityFramework(instance, isRoot && !isSpill);
  4757. buildInstancePrefix(instance);
  4758. if (!useImplementationClass)
  4759. {
  4760. doBuildUnsignedFunction(instance->classctx, "querySequence", resultNum);
  4761. doBuildBoolFunction(instance->classctx, "usedOutsideGraph", !isSpill);
  4762. }
  4763. else
  4764. {
  4765. instance->addConstructorParameter(resultNum);
  4766. instance->addConstructorParameter(queryBoolExpr(!isSpill));
  4767. }
  4768. if (parentActivity && !insideRemoteGraph(ctx) && !isSpill)
  4769. {
  4770. const char * relationship;
  4771. if (expr->hasAttribute(_loop_Atom))
  4772. relationship = "Body";
  4773. else if (insideRemoteGraph(ctx))
  4774. relationship = "Remote";
  4775. else
  4776. relationship = "Child";
  4777. addDependency(ctx, instance->queryBoundActivity(), parentActivity, childAtom, relationship);
  4778. }
  4779. instance->addAttributeBool("_isSpill", isSpill);
  4780. instance->addAttributeBool("_fromChild", expr->hasAttribute(_accessedFromChild_Atom));
  4781. if (targetRoxie())
  4782. addGraphIdAttribute(instance, ctx, graphId);
  4783. buildInstanceSuffix(instance);
  4784. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  4785. associateRemoteResult(*instance, graphId, resultNum);
  4786. return instance->getBoundActivity();
  4787. }
  4788. ABoundActivity * HqlCppTranslator::doBuildActivityReturnResult(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  4789. {
  4790. IHqlExpression * dataset = expr->queryChild(0);
  4791. ABoundActivity * parentActivity = activeActivities.ordinality() ? &activeActivities.tos() : NULL;
  4792. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  4793. ThorActivityKind kind;
  4794. const char * helper;
  4795. if (dataset->isDataset())
  4796. {
  4797. kind = TAKdatasetresult;
  4798. helper = "DatasetResult";
  4799. }
  4800. else
  4801. {
  4802. kind = TAKrowresult;
  4803. helper = "RowResult";
  4804. }
  4805. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  4806. buildActivityFramework(instance, isRoot);
  4807. buildInstancePrefix(instance);
  4808. if (parentActivity && !insideRemoteGraph(ctx))
  4809. addDependency(ctx, instance->queryBoundActivity(), parentActivity, childAtom, "Child");
  4810. buildInstanceSuffix(instance);
  4811. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  4812. return instance->getBoundActivity();
  4813. }
  4814. void HqlCppTranslator::doBuildAssignLoopCounter(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4815. {
  4816. if (!isCurrentActiveGraph(ctx, expr->queryChild(0)))
  4817. {
  4818. CHqlBoundExpr match;
  4819. if (!buildExprInCorrectContext(ctx, expr, match, false))
  4820. throwError(HQLERR_GraphContextNotFound);
  4821. assign(ctx, target, match);
  4822. return;
  4823. }
  4824. HqlExprArray args;
  4825. OwnedHqlExpr call = bindFunctionCall(getGraphLoopCounterId, args);
  4826. buildExprAssign(ctx, target, call);
  4827. }
  4828. //---------------------------------------------------------------------------
  4829. ABoundActivity * HqlCppTranslator::doBuildActivityGetGraphLoopResult(BuildCtx & ctx, IHqlExpression * expr)
  4830. {
  4831. IHqlExpression * graphId = expr->queryChild(1);
  4832. IHqlExpression * resultNum = expr->queryChild(2);
  4833. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKgraphloopresultread, expr, "GraphLoopResultRead");
  4834. buildActivityFramework(instance);
  4835. buildInstancePrefix(instance);
  4836. doBuildUnsignedFunction(instance->startctx, "querySequence", resultNum);
  4837. addGraphIdAttribute(instance, ctx, graphId);
  4838. buildInstanceSuffix(instance);
  4839. return instance->getBoundActivity();
  4840. }
  4841. ABoundActivity * HqlCppTranslator::doBuildActivitySetGraphLoopResult(BuildCtx & ctx, IHqlExpression * expr)
  4842. {
  4843. IHqlExpression * dataset = expr->queryChild(0);
  4844. IHqlExpression * graphId = expr->queryChild(1);
  4845. bool isSpill = expr->hasAttribute(_spill_Atom);
  4846. ABoundActivity * parentActivity = activeActivities.ordinality() ? &activeActivities.tos() : NULL;
  4847. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  4848. bool useImplementationClass = options.minimizeActivityClasses;
  4849. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKgraphloopresultwrite, expr, "GraphLoopResultWrite");
  4850. if (useImplementationClass)
  4851. instance->setImplementationClass(newGraphLoopResultWriteArgId);
  4852. buildActivityFramework(instance, true);
  4853. buildInstancePrefix(instance);
  4854. if (parentActivity && !insideRemoteGraph(ctx) && !isSpill)
  4855. addDependency(ctx, instance->queryBoundActivity(), parentActivity, childAtom, "Body");
  4856. if (targetRoxie())
  4857. addGraphIdAttribute(instance, ctx, graphId);
  4858. buildInstanceSuffix(instance);
  4859. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  4860. return instance->getBoundActivity();
  4861. }
  4862. //---------------------------------------------------------------------------
  4863. static IHqlExpression * queryResultExpr(IHqlExpression * expr)
  4864. {
  4865. loop
  4866. {
  4867. switch (expr->getOperator())
  4868. {
  4869. case no_compound:
  4870. expr = expr->queryChild(1);
  4871. break;
  4872. case no_subgraph:
  4873. expr = expr->queryChild(0);
  4874. break;
  4875. case no_returnresult:
  4876. return expr;
  4877. default:
  4878. throwUnexpectedOp(expr->getOperator());
  4879. }
  4880. }
  4881. }
  4882. ABoundActivity * HqlCppTranslator::doBuildActivityForceLocal(BuildCtx & ctx, IHqlExpression * expr)
  4883. {
  4884. IHqlExpression * child = expr->queryChild(0);
  4885. if (targetHThor() || (targetThor() && !insideChildQuery(ctx)))
  4886. {
  4887. WARNING(CategoryIgnored, HQLWRN_LocalHasNoEffect);
  4888. return buildCachedActivity(ctx, child);
  4889. }
  4890. OwnedHqlExpr result = createValue(no_returnresult, makeVoidType(), LINK(child));
  4891. OwnedHqlExpr remote = resourceThorGraph(*this, result, RoxieCluster, 1, NULL);
  4892. unique_id_t localId = doBuildThorSubGraph(ctx, remote, SubGraphRemote);
  4893. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKlocalgraph, expr, "Null");
  4894. buildActivityFramework(instance);
  4895. buildInstancePrefix(instance);
  4896. instance->addAttributeInt("_subgraph", localId);
  4897. ActivityAssociation * match = static_cast<ActivityAssociation *>(ctx.queryAssociation(queryResultExpr(remote), AssocActivity, NULL));
  4898. assertex(match);
  4899. addDependency(ctx, match->activity, instance->queryBoundActivity(), childAtom);
  4900. buildInstanceSuffix(instance);
  4901. return instance->getBoundActivity();
  4902. }
  4903. void HqlCppTranslator::doBuildStmtApply(BuildCtx & ctx, IHqlExpression * expr)
  4904. {
  4905. IHqlExpression * dataset = expr->queryChild(0);
  4906. IHqlExpression * start = expr->queryAttribute(beforeAtom);
  4907. IHqlExpression * end = expr->queryAttribute(afterAtom);
  4908. if (start)
  4909. buildStmt(ctx, start->queryChild(0));
  4910. BuildCtx condctx(ctx);
  4911. buildDatasetIterate(condctx, dataset, false);
  4912. unsigned max = expr->numChildren();
  4913. for (unsigned i=1; i < max; i++)
  4914. {
  4915. IHqlExpression * cur = expr->queryChild(i);
  4916. if (!cur->isAttribute())
  4917. buildStmt(condctx, cur);
  4918. }
  4919. if (end)
  4920. buildStmt(ctx, end->queryChild(0));
  4921. }