hqlsource.cpp 190 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jliball.hpp"
  14. #include "hql.hpp"
  15. #include "platform.h"
  16. #include "jlib.hpp"
  17. #include "jmisc.hpp"
  18. #include "jstream.ipp"
  19. #include "jdebug.hpp"
  20. #include "eclrtl_imp.hpp"
  21. #include "rtlkey.hpp"
  22. #include "hql.hpp"
  23. #include "hqlattr.hpp"
  24. #include "hqlmeta.hpp"
  25. #include "hqlthql.hpp"
  26. #include "hqlhtcpp.ipp"
  27. #include "hqlttcpp.ipp"
  28. #include "hqlutil.hpp"
  29. #include "hqlthql.hpp"
  30. #include "hqlwcpp.hpp"
  31. #include "hqlcpputil.hpp"
  32. #include "hqltcppc.ipp"
  33. #include "hqlopt.hpp"
  34. #include "hqlfold.hpp"
  35. #include "hqlcerrors.hpp"
  36. #include "hqlcatom.hpp"
  37. #include "hqlccommon.hpp"
  38. #include "hqltrans.ipp"
  39. #include "hqlpmap.hpp"
  40. #include "hqlttcpp.ipp"
  41. #include "hqlsource.ipp"
  42. #include "hqlcse.ipp"
  43. #include "hqliter.ipp"
  44. #include "thorcommon.hpp"
  45. #include "hqlinline.hpp"
  46. #include "hqliproj.hpp"
  47. //#define FLATTEN_DATASETS
  48. //#define HACK_TO_IGNORE_TABLE
  49. //#define TraceExprPrintLog(x, expr) DBGLOG(x ": %s", expr->toString(StringBuffer()).str());
  50. #define TraceExprPrintLog(x, expr)
  51. //#define TraceTableFields
  52. inline bool needToSerializeRecord(node_operator mode)
  53. {
  54. return (mode == no_thor || mode == no_flat);
  55. }
  56. inline bool needToSerializeRecord(IHqlExpression * mode)
  57. {
  58. return needToSerializeRecord(mode->getOperator());
  59. }
  60. //---------------------------------------------------------------------------
  61. void HqlCppTranslator::addGlobalOnWarning(IHqlExpression * setMetaExpr)
  62. {
  63. globalOnWarnings->addOnWarning(setMetaExpr);
  64. }
  65. unsigned HqlCppTranslator::getSourceAggregateOptimizeFlags() const
  66. {
  67. const bool insideChildQuery = false; // value does not currently matter
  68. return getOptimizeFlags(insideChildQuery)|HOOfold|HOOinsidecompound;
  69. }
  70. void HqlCppTranslator::doBuildExprFilepos(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  71. {
  72. if (buildExprInCorrectContext(ctx, expr, tgt, false))
  73. return;
  74. throwError(HQLERR_CouldNotResolveFileposition); // internal error: fileposition should have been available.
  75. }
  76. void HqlCppTranslator::doBuildExprFileLogicalName(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  77. {
  78. if (buildExprInCorrectContext(ctx, expr, tgt, false))
  79. return;
  80. throwError(HQLERR_CouldNotResolveFileposition); // internal error: fileposition should have been available.
  81. }
  82. //---------------------------------------------------------------------------
  83. node_operator getDatasetKind(IHqlExpression * dataset)
  84. {
  85. dataset = queryPhysicalRootTable(dataset);
  86. if (dataset)
  87. {
  88. IHqlExpression * mode = dataset->queryChild(2);
  89. if (mode)
  90. return mode->getOperator();
  91. }
  92. return no_none;
  93. }
  94. unsigned getProjectCount(IHqlExpression * expr)
  95. {
  96. unsigned projectCount = 0;
  97. while (expr->getOperator() != no_table)
  98. {
  99. switch (expr->getOperator())
  100. {
  101. case no_hqlproject:
  102. case no_usertable:
  103. case no_newusertable:
  104. case no_selectfields:
  105. projectCount++;
  106. break;
  107. }
  108. expr = expr->queryChild(0);
  109. }
  110. return projectCount;
  111. }
  112. IHqlExpression * queryFetch(IHqlExpression * expr)
  113. {
  114. for (;;)
  115. {
  116. switch (expr->getOperator())
  117. {
  118. case no_fetch:
  119. return expr;
  120. case no_filter:
  121. case no_compound_fetch:
  122. case no_limit:
  123. case no_keyedlimit:
  124. case no_choosen:
  125. break;
  126. default:
  127. UNIMPLEMENTED;
  128. }
  129. expr = expr->queryChild(0);
  130. }
  131. }
  132. bool isSimpleSource(IHqlExpression * expr)
  133. {
  134. for (;;)
  135. {
  136. switch (expr->getOperator())
  137. {
  138. case no_keyindex:
  139. case no_newkeyindex:
  140. case no_table:
  141. case no_temptable:
  142. case no_inlinetable:
  143. case no_workunit_dataset:
  144. case no_xmlproject:
  145. case no_null:
  146. case no_datasetfromrow:
  147. case no_datasetfromdictionary:
  148. case no_getgraphresult:
  149. case no_getgraphloopresult:
  150. case no_rows:
  151. return true;
  152. case no_choosen:
  153. case no_limit:
  154. case no_keyedlimit:
  155. case no_sorted:
  156. case no_stepped:
  157. case no_distributed:
  158. case no_preservemeta:
  159. case no_unordered:
  160. case no_grouped:
  161. case no_compound_diskread:
  162. case no_compound_disknormalize:
  163. case no_compound_diskaggregate:
  164. case no_compound_diskcount:
  165. case no_compound_diskgroupaggregate:
  166. case no_compound_indexread:
  167. case no_compound_indexnormalize:
  168. case no_compound_indexaggregate:
  169. case no_compound_indexcount:
  170. case no_compound_indexgroupaggregate:
  171. case no_compound_childread:
  172. case no_compound_childnormalize:
  173. case no_compound_childaggregate:
  174. case no_compound_childcount:
  175. case no_compound_childgroupaggregate:
  176. case no_compound_selectnew:
  177. case no_compound_inline:
  178. case no_section:
  179. case no_sectioninput:
  180. case no_nofold:
  181. case no_nohoist:
  182. case no_nocombine:
  183. case no_dataset_alias:
  184. break;
  185. default:
  186. return false;
  187. }
  188. expr = expr->queryChild(0);
  189. }
  190. }
  191. static bool isSimpleProjectingDiskRead(IHqlExpression * expr)
  192. {
  193. bool projected = false;
  194. for (;;)
  195. {
  196. switch (expr->getOperator())
  197. {
  198. case no_table:
  199. return true;
  200. case no_hqlproject:
  201. case no_newusertable:
  202. if (projected)
  203. return false;
  204. //MORE: HPCC-18469 Check if the transform only assigns fields with the same name from source to the target
  205. if (!isSimpleProject(expr))
  206. return false;
  207. projected = true;
  208. break;
  209. default:
  210. return false;
  211. }
  212. expr = expr->queryChild(0);
  213. }
  214. }
  215. IHqlExpression * getVirtualSelector(IHqlExpression * dataset)
  216. {
  217. IHqlExpression * table = queryPhysicalRootTable(dataset);
  218. if (!table)
  219. table = dataset;
  220. return LINK(table->queryNormalizedSelector());
  221. }
  222. IHqlExpression * getFilepos(IHqlExpression * dataset, bool isLocal)
  223. {
  224. IHqlExpression * attr = isLocal ? createLocalAttribute() : NULL;
  225. return createValue(no_filepos, LINK(fposType), getVirtualSelector(dataset), attr);
  226. }
  227. IHqlExpression * getFileLogicalName(IHqlExpression * dataset)
  228. {
  229. return createValue(no_file_logicalname, makeVarStringType(UNKNOWN_LENGTH, NULL, NULL), getVirtualSelector(dataset));
  230. }
  231. IHqlExpression * getVirtualReplacement(IHqlExpression * field, IHqlExpression * virtualDef, IHqlExpression * dataset)
  232. {
  233. IAtom * virtualKind = virtualDef->queryName();
  234. if (virtualKind == filepositionAtom)
  235. return getFilepos(dataset, false);
  236. else if (virtualKind == localFilePositionAtom)
  237. return getFilepos(dataset, true);
  238. else if (virtualKind == sizeofAtom)
  239. return createValue(no_sizeof, LINK(sizetType), getVirtualSelector(dataset));
  240. else if (virtualKind == logicalFilenameAtom)
  241. return createValue(no_implicitcast, field->getType(), getFileLogicalName(dataset));
  242. throwError1(HQLERR_UnknownVirtualAttr, str(virtualKind));
  243. return NULL;
  244. }
  245. static IHqlExpression * createFileposCall(HqlCppTranslator & translator, IIdAtom * name, const char * provider, const char * rowname)
  246. {
  247. HqlExprArray args;
  248. args.append(*createVariable(provider, makeBoolType()));
  249. args.append(*createVariable(rowname, makeBoolType())); // really a row
  250. return translator.bindFunctionCall(name, args);
  251. }
  252. //---------------------------------------------------------------------------
  253. void VirtualFieldsInfo::gatherVirtualFields(IHqlExpression * _record, bool ignoreVirtuals, bool ensureSerialized)
  254. {
  255. OwnedHqlExpr record = ensureSerialized ? getSerializedForm(_record, diskAtom) : LINK(_record);
  256. if (record != _record)
  257. requiresDeserialize = true;
  258. //MORE: This should really recurse through records to check for nested virtual fields.
  259. // e.g., inside ifblocks, or even records....
  260. ForEachChild(idx, record)
  261. {
  262. IHqlExpression * cur = record->queryChild(idx);
  263. IHqlExpression * virtualAttr = NULL;
  264. if (!ignoreVirtuals)
  265. virtualAttr = cur->queryAttribute(virtualAtom);
  266. if (virtualAttr)
  267. {
  268. selects.append(*LINK(cur));
  269. if (isUnknownSize(cur->queryType()))
  270. simpleVirtualsAtEnd = false;
  271. if (virtuals.find(*virtualAttr) == NotFound)
  272. virtuals.append(*LINK(virtualAttr));
  273. }
  274. else
  275. {
  276. //Also adds attributes...
  277. physicalFields.append(*LINK(cur));
  278. if (virtuals.ordinality())
  279. simpleVirtualsAtEnd = false;
  280. }
  281. }
  282. }
  283. IHqlExpression * VirtualFieldsInfo::createPhysicalRecord()
  284. {
  285. if (physicalFields.ordinality() == 1)
  286. if (physicalFields.item(0).getOperator() == no_record)
  287. return LINK(&physicalFields.item(0));
  288. return createRecord(physicalFields);
  289. }
  290. //---------------------------------------------------------------------------
  291. class VirtualRecordTransformCreator : public RecordTransformCreator
  292. {
  293. public:
  294. VirtualRecordTransformCreator(IHqlExpression * _dataset) { dataset = _dataset; }
  295. virtual IHqlExpression * getMissingAssignValue(IHqlExpression * expr)
  296. {
  297. IHqlExpression * virtualAttr = expr->queryAttribute(virtualAtom);
  298. assertex(virtualAttr);
  299. return getVirtualReplacement(expr, virtualAttr->queryChild(0), dataset);
  300. }
  301. protected:
  302. IHqlExpression * dataset;
  303. };
  304. IHqlExpression * createTableWithoutVirtuals(VirtualFieldsInfo & info, IHqlExpression * tableExpr)
  305. {
  306. IHqlExpression * record = tableExpr->queryChild(1);
  307. OwnedHqlExpr diskRecord = info.createPhysicalRecord();
  308. //Clone the annotations to improve the regenerated text in the graph
  309. OwnedHqlExpr diskRecordWithMeta = record->cloneAllAnnotations(diskRecord);
  310. HqlExprArray args;
  311. unwindChildren(args, tableExpr);
  312. args.replace(*LINK(diskRecordWithMeta), 1);
  313. IHqlExpression * newDataset = tableExpr->queryBody()->clone(args);
  314. VirtualRecordTransformCreator mapper(newDataset);
  315. IHqlExpression * newTransform = mapper.createMappingTransform(no_newtransform, record, newDataset);
  316. OwnedHqlExpr projected = createDatasetF(no_newusertable, newDataset, LINK(record), newTransform, createAttribute(_internal_Atom), NULL);
  317. return tableExpr->cloneAllAnnotations(projected);
  318. }
  319. IHqlExpression * buildTableWithoutVirtuals(VirtualFieldsInfo & info, IHqlExpression * expr)
  320. {
  321. IHqlExpression * tableExpr = queryPhysicalRootTable(expr);
  322. OwnedHqlExpr projected = createTableWithoutVirtuals(info, tableExpr);
  323. return replaceExpression(expr, tableExpr, projected);
  324. }
  325. static IHqlExpression * createTableFromSerialized(IHqlExpression * tableExpr)
  326. {
  327. IHqlExpression * record = tableExpr->queryChild(1);
  328. OwnedHqlExpr diskRecord = getSerializedForm(record, diskAtom);
  329. OwnedHqlExpr diskRecordWithMeta = record->cloneAllAnnotations(diskRecord);
  330. OwnedHqlExpr newTable = replaceChild(tableExpr->queryBody(), 1, diskRecordWithMeta);
  331. OwnedHqlExpr transform = createRecordMappingTransform(no_newtransform, record, newTable->queryNormalizedSelector());
  332. OwnedHqlExpr projected = createDatasetF(no_newusertable, LINK(newTable), LINK(record), LINK(transform), createAttribute(_internal_Atom), NULL);
  333. return tableExpr->cloneAllAnnotations(projected);
  334. }
  335. static IHqlExpression * buildTableFromSerialized(IHqlExpression * expr)
  336. {
  337. IHqlExpression * tableExpr = queryPhysicalRootTable(expr);
  338. OwnedHqlExpr projected = createTableFromSerialized(tableExpr);
  339. return replaceExpression(expr, tableExpr, projected);
  340. }
  341. static IHqlExpression * nextDiskField(IHqlExpression * diskRecord, unsigned & diskIndex)
  342. {
  343. for (;;)
  344. {
  345. IHqlExpression * cur = diskRecord->queryChild(diskIndex++);
  346. if (!cur || !cur->isAttribute())
  347. return cur;
  348. }
  349. }
  350. static IHqlExpression * queryOriginalKey(IHqlExpression * expr)
  351. {
  352. IHqlExpression * original = queryAttributeChild(expr, _original_Atom, 0);
  353. if (original)
  354. return original;
  355. else
  356. return expr;
  357. }
  358. static void createPhysicalLogicalAssigns(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * diskRecord, IHqlExpression * record, IHqlExpression * diskDataset, bool allowTranslate, unsigned fileposIndex)
  359. {
  360. unsigned numFields = record->numChildren();
  361. unsigned diskIndex = 0;
  362. for (unsigned idx2=0; idx2 < numFields; idx2++)
  363. {
  364. IHqlExpression * cur = record->queryChild(idx2);
  365. switch (cur->getOperator())
  366. {
  367. case no_ifblock:
  368. {
  369. IHqlExpression * ifblock = nextDiskField(diskRecord, diskIndex);
  370. assertex(ifblock && ifblock->getOperator() == no_ifblock);
  371. createPhysicalLogicalAssigns(assigns, self, ifblock->queryChild(1), cur->queryChild(1), diskDataset, false, NotFound);
  372. break;
  373. }
  374. case no_record:
  375. {
  376. IHqlExpression * srcRecord = nextDiskField(diskRecord, diskIndex);
  377. assertex(srcRecord && srcRecord->getOperator() == no_record);
  378. createPhysicalLogicalAssigns(assigns, self, srcRecord, cur, diskDataset, allowTranslate, NotFound);
  379. break;
  380. }
  381. case no_field:
  382. {
  383. OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(cur));
  384. OwnedHqlExpr newValue;
  385. IHqlExpression * curPhysical = nextDiskField(diskRecord, diskIndex);
  386. OwnedHqlExpr physicalSelect = createSelectExpr(LINK(diskDataset), LINK(curPhysical));
  387. if (cur->isDatarow() && !cur->hasAttribute(blobAtom) && (!isInPayload() || (physicalSelect->queryType() != target->queryType())))
  388. {
  389. HqlExprArray subassigns;
  390. OwnedHqlExpr childSelf = createSelector(no_self, cur, NULL);
  391. createPhysicalLogicalAssigns(subassigns, childSelf, curPhysical->queryRecord(), cur->queryRecord(), physicalSelect, false, NotFound);
  392. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(cur->queryRecord()->getType()), subassigns);
  393. newValue.setown(createRow(no_createrow, transform.getClear()));
  394. }
  395. else
  396. newValue.setown(convertIndexPhysical2LogicalValue(cur, physicalSelect, allowTranslate && (idx2 != fileposIndex)));
  397. if (newValue)
  398. assigns.append(*createAssign(target.getClear(), newValue.getClear()));
  399. break;
  400. }
  401. }
  402. }
  403. }
  404. static void createPhysicalLogicalAssigns(HqlExprArray & assigns, IHqlExpression * diskDataset, IHqlExpression * tableExpr, bool hasFilePosition)
  405. {
  406. IHqlExpression * record = tableExpr->queryRecord();
  407. unsigned fileposIndex = (hasFilePosition ? record->numChildren() - 1 : NotFound);
  408. OwnedHqlExpr self = getSelf(record);
  409. createPhysicalLogicalAssigns(assigns, self, diskDataset->queryRecord(), record, diskDataset, true, fileposIndex);
  410. }
  411. IHqlExpression * HqlCppTranslator::convertToPhysicalIndex(IHqlExpression * tableExpr)
  412. {
  413. LinkedHqlExpr * match = physicalIndexCache.getValue(tableExpr);
  414. if (match)
  415. return LINK(*match);
  416. if (tableExpr->hasAttribute(_original_Atom))
  417. return LINK(tableExpr);
  418. assertex(tableExpr->getOperator() == no_newkeyindex);
  419. IHqlExpression * record = tableExpr->queryRecord();
  420. HqlMapTransformer mapper;
  421. bool hasFilePosition = getBoolAttribute(tableExpr, filepositionAtom, true);
  422. IHqlExpression * diskRecord = createPhysicalIndexRecord(mapper, record, hasFilePosition, false);
  423. unsigned payload = numPayloadFields(tableExpr);
  424. assertex(payload || !hasFilePosition);
  425. HqlExprArray args;
  426. unwindChildren(args, tableExpr);
  427. args.replace(*diskRecord, 1);
  428. removeAttribute(args, _payload_Atom);
  429. args.append(*createAttribute(_payload_Atom, getSizetConstant(payload)));
  430. args.append(*createAttribute(_original_Atom, LINK(tableExpr)));
  431. //remove the preload attribute and replace with correct value
  432. IHqlExpression * newDataset = createDataset(tableExpr->getOperator(), args);
  433. HqlExprArray assigns;
  434. createPhysicalLogicalAssigns(assigns, newDataset, tableExpr, hasFilePosition);
  435. OwnedHqlExpr projectedTable = createDataset(no_newusertable, newDataset, createComma(LINK(record), createValue(no_newtransform, makeTransformType(record->getType()), assigns)));
  436. physicalIndexCache.setValue(tableExpr, projectedTable);
  437. return projectedTable.getClear();
  438. }
  439. IHqlExpression * convertToPhysicalTable(IHqlExpression * tableExpr, bool ensureSerialized)
  440. {
  441. VirtualFieldsInfo fieldInfo;
  442. fieldInfo.gatherVirtualFields(tableExpr->queryRecord(), tableExpr->hasAttribute(_noVirtual_Atom), ensureSerialized);
  443. if (fieldInfo.hasVirtualsOrDeserialize())
  444. return createTableWithoutVirtuals(fieldInfo, tableExpr);
  445. return LINK(tableExpr);
  446. }
  447. IHqlExpression * HqlCppTranslator::buildIndexFromPhysical(IHqlExpression * expr)
  448. {
  449. IHqlExpression * tableExpr = queryPhysicalRootTable(expr);
  450. OwnedHqlExpr newProject;
  451. if (queryOptions().newIndexReadMapping && !recordContainsBlobs(tableExpr->queryRecord()))
  452. {
  453. //once it is legal for the input to a transform to be non-serialized then following should be enabled
  454. //return LINK(expr);
  455. IHqlExpression * record = tableExpr->queryChild(1);
  456. OwnedHqlExpr diskRecord = getSerializedForm(record, diskAtom);
  457. if (record == diskRecord)
  458. return LINK(expr);
  459. OwnedHqlExpr newDataset = replaceChild(tableExpr, 1, diskRecord);
  460. VirtualRecordTransformCreator mapper(newDataset);
  461. IHqlExpression * newTransform = mapper.createMappingTransform(no_newtransform, record, newDataset);
  462. newProject.setown(createDatasetF(no_newusertable, LINK(newDataset), LINK(record), newTransform, createAttribute(_internal_Atom), NULL));
  463. newProject.setown(tableExpr->cloneAllAnnotations(newProject));
  464. }
  465. else
  466. newProject.setown(convertToPhysicalIndex(tableExpr));
  467. return replaceExpression(expr, tableExpr, newProject);
  468. }
  469. //---------------------------------------------------------------------------
  470. class SourceSteppingInfo
  471. {
  472. public:
  473. inline bool exists() { return rawStepping.exists(); }
  474. IHqlExpression * firstStepped()
  475. {
  476. if (rawStepping.exists())
  477. return rawStepping.fields->queryChild(0);
  478. return NULL;
  479. }
  480. void extractRaw()
  481. {
  482. rawSteppingProject.extractFields(rawStepping);
  483. }
  484. void checkKeyable(CppFilterExtractor & monitors)
  485. {
  486. if (!rawStepping.exists())
  487. return;
  488. unsigned prev = NotFound;
  489. ForEachChild(i, rawStepping.fields)
  490. {
  491. IHqlExpression * cur = rawStepping.fields->queryChild(i);
  492. unsigned thisMatch = monitors.queryKeySelectIndex(cur);
  493. if (thisMatch == NotFound)
  494. throwError1(HQLERR_StepFieldNotKeyed, str(cur->queryChild(1)->queryName()));
  495. if ((prev != NotFound) && (thisMatch != prev+1))
  496. throwError1(HQLERR_StepFieldNotContiguous, str(cur->queryChild(1)->queryName()));
  497. prev = thisMatch;
  498. }
  499. }
  500. void generateMembers(HqlCppTranslator & translator, BuildCtx & ctx)
  501. {
  502. rawStepping.generateSteppingMetaMember(translator, ctx, "RawSteppingMeta");
  503. if (outputStepping.exists())
  504. {
  505. if (outputStepping.exists() && outputStepping.ds != rawStepping.ds)
  506. {
  507. outputStepping.generateSteppingMetaMember(translator, ctx, "ProjectedSteppingMeta");
  508. MemberFunction func(translator, ctx, "virtual void mapOutputToInput(ARowBuilder & crSelf, const void * _projected, unsigned numFields) override");
  509. translator.ensureRowAllocated(func.ctx, "crSelf");
  510. func.ctx.addQuotedLiteral("const byte * pr = (const byte *)_projected;");
  511. translator.bindTableCursor(func.ctx, rawStepping.ds, "crSelf.row()");
  512. translator.bindTableCursor(func.ctx, outputStepping.ds, "pr");
  513. StringBuffer s;
  514. ForEachChild(i, outputStepping.fields)
  515. {
  516. IHqlExpression * curOutput = outputStepping.fields->queryChild(i);
  517. IHqlExpression * curRawExpr = rawSteppingProject.fields->queryChild(i);
  518. IHqlExpression * curRawSelect = rawStepping.fields->queryChild(i);
  519. OwnedHqlExpr original = outputStepping.invertTransform(curRawExpr, curOutput);
  520. func.ctx.addQuoted(s.clear().append("if (numFields < ").append(i+1).append(") return;"));
  521. translator.buildAssign(func.ctx, curRawSelect, original);
  522. }
  523. }
  524. }
  525. else
  526. {
  527. OwnedHqlExpr fail = createValue(no_fail, makeVoidType(), createConstant("Cannot step output of index read"));
  528. MemberFunction func(translator, ctx, "virtual void mapOutputToInput(ARowBuilder & crSelf, const void * _projected, unsigned numFields) override");
  529. translator.buildStmt(func.ctx, fail);
  530. }
  531. }
  532. public:
  533. SteppingFieldSelection outputStepping;
  534. SteppingFieldSelection rawSteppingProject;
  535. SteppingFieldSelection rawStepping;
  536. };
  537. //---------------------------------------------------------------------------
  538. static bool forceLegacyMapping(IHqlExpression * expr)
  539. {
  540. //Use __OPTION__(LEGACY(TRUE)) to force legacy mapping code
  541. IHqlExpression * options = expr->queryAttribute(__option__Atom);
  542. return getBoolAttribute(options, legacyAtom, false);
  543. }
  544. class SourceBuilder
  545. {
  546. public:
  547. SourceBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  548. : tableExpr(_tableExpr), translator(_translator), newInputMapping(false)
  549. {
  550. nameExpr.setown(foldHqlExpression(_nameExpr));
  551. needDefaultTransform = true;
  552. needToCallTransform = false;
  553. isPreloaded = false;
  554. isCompoundCount = false;
  555. transformCanFilter = false;
  556. IHqlExpression * preload = tableExpr ? tableExpr->queryAttribute(preloadAtom) : NULL;
  557. if (preload)
  558. {
  559. isPreloaded = true;
  560. preloadSize.set(preload->queryChild(0));
  561. }
  562. failedFilterValue.set(queryZero());
  563. isNormalize = false;
  564. aggregation = false;
  565. instance = NULL;
  566. returnIfFilterFails = true;
  567. useFilterMappings = true;
  568. generateUnfilteredTransform = false;
  569. allowDynamicFormatChange = tableExpr && !tableExpr->hasAttribute(fixedAtom);
  570. onlyExistsAggreate = false;
  571. monitorsForGrouping = false;
  572. useImplementationClass = false;
  573. isUnfilteredCount = false;
  574. requiresOrderedMerge = false;
  575. genericDiskReads = translator.queryOptions().genericDiskReads;
  576. rootSelfRow = NULL;
  577. activityKind = TAKnone;
  578. if (tableExpr)
  579. {
  580. if (isKey(tableExpr))
  581. newInputMapping = translator.queryOptions().newIndexReadMapping;
  582. else
  583. newInputMapping = translator.queryOptions().newDiskReadMapping;
  584. if (forceLegacyMapping(tableExpr))
  585. newInputMapping = false;
  586. //If this index has been translated using the legacy method then ensure we continue to use that method
  587. if (isKey(tableExpr) && queryAttributeChild(tableExpr, _original_Atom, 0))
  588. newInputMapping = false;
  589. switch (tableExpr->getOperator())
  590. {
  591. case no_fetch:
  592. case no_compound_fetch:
  593. newInputMapping = false;
  594. break;
  595. }
  596. }
  597. else
  598. newInputMapping = false;
  599. }
  600. virtual ~SourceBuilder() {}
  601. virtual void buildMembers(IHqlExpression * expr) = 0;
  602. virtual void buildTransformFpos(BuildCtx & transformCtx) = 0;
  603. virtual void extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds);
  604. virtual void buildTransformElements(BuildCtx & ctx, IHqlExpression * expr, bool ignoreFilters);
  605. virtual void buildTransform(IHqlExpression * expr) = 0;
  606. virtual void analyse(IHqlExpression * expr);
  607. void buildCanMatch(IHqlExpression * expr);
  608. void buildMatchFilter(BuildCtx & ctx, IHqlExpression * expr);
  609. void buildFilenameMember();
  610. void appendFilter(SharedHqlExpr & unkeyedFilter, IHqlExpression * expr);
  611. void buildKeyedLimitHelper(IHqlExpression * expr);
  612. void buildLimits(BuildCtx & classctx, IHqlExpression * expr, unique_id_t id);
  613. void buildReadMembers( IHqlExpression * expr);
  614. void buildSteppingMeta(IHqlExpression * expr, CppFilterExtractor * monitors);
  615. void buildTransformBody(BuildCtx & transformCtx, IHqlExpression * expr, bool returnSize, bool ignoreFilters, bool bindInputRow);
  616. void checkDependencies(BuildCtx & ctx, IHqlExpression * expr);
  617. bool containsStepping(IHqlExpression * expr);
  618. ABoundActivity * buildActivity(BuildCtx & ctx, IHqlExpression * expr, ThorActivityKind activityKind, const char *kind, ABoundActivity *input);
  619. void gatherVirtualFields(bool ignoreVirtuals, bool ensureSerialized);
  620. void deduceDiskRecords();
  621. void deduceIndexRecords();
  622. bool recordHasVirtuals() { return fieldInfo.hasVirtuals(); }
  623. bool recordHasVirtualsOrDeserialize() { return fieldInfo.hasVirtualsOrDeserialize(); }
  624. bool isSourceInvariant(IHqlExpression * dataset, IHqlExpression * expr);
  625. bool hasExistChoosenLimit() { return (choosenValue && getIntValue(choosenValue) == 1); }
  626. bool isRootSelector(IHqlExpression * expr) const;
  627. protected:
  628. void assignLocalExtract(BuildCtx & ctx, ParentExtract * extractBuilder, IHqlExpression * dataset, const char * argName);
  629. void associateFilePositions(BuildCtx & ctx, const char * provider, const char * rowname);
  630. void buildSteppedHelpers();
  631. void doBuildAggregateSelectIterator(BuildCtx & ctx, IHqlExpression * expr);
  632. void doBuildNormalizeIterators(BuildCtx & ctx, IHqlExpression * expr, bool isChildIterator);
  633. void buildAggregateHelpers(IHqlExpression * expr);
  634. void buildCountHelpers(IHqlExpression * expr, bool allowMultiple);
  635. virtual void buildFlagsMember(IHqlExpression * expr) {}
  636. void buildGlobalGroupAggregateHelpers(IHqlExpression * expr);
  637. void buildGroupAggregateHelpers(ParentExtract * extractBuilder, IHqlExpression * aggregate);
  638. void buildGroupAggregateCompareHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, HqlExprArray & recordFields, HqlExprArray & agrgegateFields);
  639. void buildGroupAggregateHashHelper(ParentExtract * extractBuilder, IHqlExpression * dataset, IHqlExpression * fields);
  640. void buildGroupAggregateProcessHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, const char * name, bool doneAny);
  641. void buildGroupingMonitors(IHqlExpression * expr, CppFilterExtractor & monitors);
  642. void buildGroupAggregateTransformBody(BuildCtx & transformctx, IHqlExpression * expr, bool useExtract, bool bindInputRow);
  643. void buildNormalizeHelpers(IHqlExpression * expr);
  644. void buildTargetCursor(Shared<BoundRow> & tempRow, Shared<BoundRow> & rowBuilder, BuildCtx & ctx, IHqlExpression * expr);
  645. void associateTargetCursor(BuildCtx & subctx, BuildCtx & ctx, BoundRow * tempRow, BoundRow * rowBuilder, IHqlExpression * expr);
  646. IHqlExpression * ensureAggregateGroupingAliased(IHqlExpression * aggregate);
  647. void gatherSteppingMeta(IHqlExpression * expr, SourceSteppingInfo & info);
  648. void gatherSteppingMeta(IHqlExpression * expr, SteppingFieldSelection & outputStepping, SteppingFieldSelection & rawStepping);
  649. void gatherFieldUsage(SourceFieldUsage * fieldUsage, IHqlExpression * expr);
  650. void rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq, bool isLocal);
  651. void rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq);
  652. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr);
  653. virtual void analyseGraph(IHqlExpression * expr);
  654. virtual bool isExplicitExists() { return false; }
  655. public:
  656. VirtualFieldsInfo fieldInfo;
  657. ActivityInstance * instance;
  658. BoundRow * rootSelfRow;
  659. HqlExprAttr tableExpr;
  660. HqlExprAttr nameExpr;
  661. HqlExprAttr fpos;
  662. HqlExprAttr lfpos;
  663. HqlExprAttr limitExpr;
  664. HqlExprAttr keyedLimitExpr;
  665. HqlExprAttr choosenValue;
  666. HqlExprAttr preloadSize;
  667. HqlExprAttr firstTransformer;
  668. HqlExprAttr lastTransformer;
  669. HqlExprAttr alreadyDoneFlag;
  670. HqlExprArray originalFilters;
  671. HqlExprArray mappedFilters;
  672. HqlExprArray removedFilters;
  673. HqlExprAttr failedFilterValue;
  674. HqlExprAttr compoundCountVar;
  675. HqlExprAttr physicalRecord;
  676. HqlExprAttr inputRecord; // The format of the row that is passed to the transform
  677. LinkedHqlExpr expectedRecord;
  678. LinkedHqlExpr projectedRecord;
  679. LinkedHqlExpr tableSelector;
  680. LinkedHqlExpr projectedSelector;
  681. HqlExprAttr steppedExpr;
  682. Linked<BuildCtx> globaliterctx;
  683. HqlExprCopyArray parentCursors;
  684. HqlExprAttr logicalFilenameMarker;
  685. ThorActivityKind activityKind;
  686. bool useFilterMappings;
  687. bool needDefaultTransform;
  688. bool needToCallTransform;
  689. bool isPreloaded;
  690. bool transformCanFilter;
  691. bool isCompoundCount;
  692. bool isNormalize;
  693. bool aggregation;
  694. bool returnIfFilterFails;
  695. bool allowDynamicFormatChange;
  696. bool onlyExistsAggreate;
  697. bool monitorsForGrouping;
  698. bool generateUnfilteredTransform;
  699. bool useImplementationClass;
  700. bool isUnfilteredCount;
  701. bool isVirtualLogicalFilenameUsed = false;
  702. bool transformUsesVirtualLogicalFilename = false;
  703. bool transformUsesVirtualFilePosition = false;
  704. bool requiresOrderedMerge;
  705. bool newInputMapping;
  706. bool extractCanMatch = false;
  707. bool genericDiskReads;
  708. bool genericDiskRead = false;
  709. bool hasDynamicOptions = false;
  710. protected:
  711. HqlCppTranslator & translator;
  712. };
  713. struct HQLCPP_API MonitoredDefinedValue : public HqlSimpleDefinedValue
  714. {
  715. public:
  716. MonitoredDefinedValue(bool & _usedFlag, IHqlExpression * _original, IHqlExpression * _expr)
  717. : HqlSimpleDefinedValue(_original, _expr), usedFlag(_usedFlag)
  718. { }
  719. virtual IHqlExpression * queryExpr() const
  720. {
  721. usedFlag = true;
  722. return HqlSimpleDefinedValue::queryExpr();
  723. }
  724. public:
  725. bool & usedFlag;
  726. };
  727. bool SourceBuilder::isSourceInvariant(IHqlExpression * dataset, IHqlExpression * expr)
  728. {
  729. if (containsAssertKeyed(expr))
  730. return false;
  731. if (!containsActiveDataset(expr))
  732. return true;
  733. HqlExprCopyArray inScope;
  734. expr->gatherTablesUsed(inScope);
  735. if (!canEvaluateInScope(parentCursors, inScope))
  736. return false;
  737. //Carefull.... It looks ok, but it is possible that the same dataset occurs at multiple levels (sqfilt.hql)
  738. //So need to be careful that the datasets being referenced aren't newly in scope for this activity...
  739. for (;;)
  740. {
  741. if (inScope.contains(*dataset->queryNormalizedSelector()))
  742. return false;
  743. //To be strictly correct we need to walk no_select chain of root datasets!
  744. dataset = queryNextMultiLevelDataset(dataset, true);
  745. if (!dataset)
  746. return true;
  747. }
  748. }
  749. bool SourceBuilder::isRootSelector(IHqlExpression * expr) const
  750. {
  751. if (!tableExpr)
  752. return false;
  753. return (expr->queryNormalizedSelector() == tableExpr->queryNormalizedSelector());
  754. }
  755. void SourceBuilder::analyse(IHqlExpression * expr)
  756. {
  757. IHqlExpression * body = expr->queryBody(true);
  758. if (expr != body)
  759. {
  760. switch (expr->getAnnotationKind())
  761. {
  762. case annotate_meta:
  763. //the onwarning state will be restored by the scope held in HqlCppTranslator::buildActivity
  764. translator.localOnWarnings->processMetaAnnotation(expr);
  765. break;
  766. case annotate_location:
  767. instance->addLocationAttribute(expr);
  768. break;
  769. case annotate_symbol:
  770. //don't clear onWarnings when we hit a symbol because the warnings within a compound activity aren't generated at the correct point
  771. instance->addNameAttribute(expr);
  772. break;
  773. }
  774. analyse(body);
  775. return;
  776. }
  777. node_operator op = expr->getOperator();
  778. switch (op)
  779. {
  780. case no_cachealias:
  781. analyse(expr->queryChild(1));
  782. return;
  783. case no_newkeyindex:
  784. case no_table:
  785. case no_fetch:
  786. case no_select: // handled below
  787. case no_null:
  788. case no_anon:
  789. case no_pseudods:
  790. case no_workunit_dataset:
  791. case no_call:
  792. case no_externalcall:
  793. case no_rows:
  794. case no_libraryinput:
  795. break;
  796. default:
  797. analyse(expr->queryChild(0));
  798. break;
  799. }
  800. switch (op)
  801. {
  802. case no_table:
  803. case no_newkeyindex:
  804. if (!newInputMapping)
  805. {
  806. assertex(!fieldInfo.hasVirtuals());
  807. }
  808. if (newInputMapping)
  809. {
  810. if (!tableExpr->hasAttribute(_noVirtual_Atom) && (tableExpr->queryChild(2)->getOperator() != no_pipe))
  811. {
  812. if (containsVirtualField(tableExpr->queryRecord(), logicalFilenameAtom))
  813. isVirtualLogicalFilenameUsed = true;
  814. }
  815. }
  816. break;
  817. case no_null:
  818. case no_anon:
  819. case no_pseudods:
  820. case no_workunit_dataset:
  821. case no_getgraphresult:
  822. case no_call:
  823. case no_externalcall:
  824. case no_rows:
  825. case no_libraryinput:
  826. break;
  827. case no_filter:
  828. {
  829. //LIMIT(ds(filter1))(filter2) cannot be implemented as a compound activity - because it is impossible to count the rows being
  830. //filtered by filter1.
  831. if (limitExpr)
  832. throwError(HQLERR_CannotFilterLimitInsideActivity);
  833. OwnedHqlExpr unkeyedFilter;
  834. HqlExprArray conds;
  835. unwindFilterConditions(conds, expr);
  836. extractMonitors(expr, unkeyedFilter, conds);
  837. if (unkeyedFilter)
  838. {
  839. if (!extractCanMatch || !isRootSelector(expr))
  840. transformCanFilter = true;
  841. originalFilters.append(*LINK(expr));
  842. mappedFilters.append(*unkeyedFilter.getClear());
  843. }
  844. else
  845. removedFilters.append(*LINK(expr));
  846. break;
  847. }
  848. case no_select:
  849. {
  850. bool isNew;
  851. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  852. if (isNew && isMultiLevelDatasetSelector(expr, false))
  853. {
  854. if (!translator.resolveSelectorDataset(instance->startctx, ds))
  855. {
  856. analyse(ds);
  857. isNormalize = true;
  858. }
  859. }
  860. break;
  861. }
  862. case no_stepped:
  863. if (steppedExpr)
  864. throwError(HQLERR_MultipleStepped);
  865. steppedExpr.set(expr);
  866. break;
  867. case no_sorted:
  868. case no_distributed:
  869. case no_preservemeta:
  870. case no_unordered:
  871. case no_grouped:
  872. case no_alias_scope:
  873. case no_section:
  874. case no_sectioninput:
  875. case no_nofold:
  876. case no_nohoist:
  877. case no_nocombine:
  878. case no_dataset_alias:
  879. break;
  880. case no_preload:
  881. isPreloaded = true;
  882. preloadSize.set(queryRealChild(expr, 1));
  883. break;
  884. case no_limit:
  885. limitExpr.set(expr);
  886. break;
  887. case no_keyedlimit:
  888. keyedLimitExpr.set(expr);
  889. break;
  890. case no_choosen:
  891. {
  892. choosenValue.set(expr->queryChild(1));
  893. IHqlExpression * first = queryRealChild(expr, 2);
  894. if (first)
  895. {
  896. Owned<ITypeInfo> type = makeIntType(8, true);
  897. choosenValue.setown(createValue(no_sub, LINK(type), createValue(no_add, LINK(type), ensureExprType(choosenValue, type), ensureExprType(first, type)), createConstant(I64C(1))));
  898. }
  899. choosenValue.setown(foldHqlExpression(choosenValue));
  900. }
  901. break;
  902. case no_hqlproject:
  903. needToCallTransform = true;
  904. needDefaultTransform = false;
  905. if (!firstTransformer)
  906. firstTransformer.set(expr);
  907. lastTransformer.set(expr);
  908. break;
  909. case no_newusertable:
  910. needToCallTransform = true;
  911. needDefaultTransform = false;
  912. if (!firstTransformer)
  913. firstTransformer.set(expr);
  914. lastTransformer.set(expr);
  915. break;
  916. case no_aggregate:
  917. {
  918. needToCallTransform = true;
  919. needDefaultTransform = false;
  920. aggregation = true;
  921. if (!firstTransformer)
  922. firstTransformer.set(expr);
  923. lastTransformer.set(expr);
  924. break;
  925. }
  926. case no_newaggregate:
  927. {
  928. needToCallTransform = true;
  929. needDefaultTransform = false;
  930. aggregation = true;
  931. if (!firstTransformer)
  932. firstTransformer.set(expr);
  933. lastTransformer.set(expr);
  934. IHqlExpression * transform = expr->queryChild(2);
  935. node_operator aggOp = queryTransformSingleAggregate(transform);
  936. onlyExistsAggreate = ((aggOp == no_existsgroup) || (aggOp == no_none)); // The implicit project code can remove all the aggregate() operators....
  937. if (isCompoundCount)
  938. {
  939. IHqlExpression * rhs = transform->queryChild(0)->queryChild(1);
  940. IHqlExpression * filter = queryRealChild(rhs, 0);
  941. if (filter)
  942. transformCanFilter = true;
  943. }
  944. break;
  945. }
  946. case no_usertable:
  947. case no_selectfields:
  948. UNIMPLEMENTED;
  949. break;
  950. case no_fetch:
  951. needToCallTransform = true;
  952. needDefaultTransform = false;
  953. if (!firstTransformer)
  954. firstTransformer.set(expr);
  955. lastTransformer.set(expr);
  956. break;
  957. case no_compound_diskread:
  958. case no_compound_disknormalize:
  959. case no_compound_diskaggregate:
  960. case no_compound_diskcount:
  961. case no_compound_diskgroupaggregate:
  962. case no_compound_indexread:
  963. case no_compound_indexnormalize:
  964. case no_compound_indexaggregate:
  965. case no_compound_indexcount:
  966. case no_compound_indexgroupaggregate:
  967. case no_compound_childread:
  968. case no_compound_childnormalize:
  969. case no_compound_childaggregate:
  970. case no_compound_childcount:
  971. case no_compound_childgroupaggregate:
  972. case no_compound_fetch:
  973. case no_compound_selectnew:
  974. break;
  975. default:
  976. throwUnexpectedOp(op);
  977. }
  978. }
  979. void SourceBuilder::appendFilter(SharedHqlExpr & unkeyedFilter, IHqlExpression * expr)
  980. {
  981. if (expr)
  982. {
  983. if (expr->queryValue())
  984. {
  985. if (!expr->queryValue()->getBoolValue())
  986. unkeyedFilter.set(expr);
  987. }
  988. else
  989. {
  990. if (unkeyedFilter)
  991. unkeyedFilter.setown(createValue(no_and, unkeyedFilter.getClear(), LINK(expr)));
  992. else
  993. unkeyedFilter.set(expr);
  994. }
  995. }
  996. }
  997. void SourceBuilder::associateFilePositions(BuildCtx & ctx, const char * provider, const char * rowname)
  998. {
  999. if (fpos)
  1000. {
  1001. Owned<IHqlExpression> fposExpr = createFileposCall(translator, getFilePositionId, provider, rowname);
  1002. ctx.associateOwn(*new MonitoredDefinedValue(transformUsesVirtualFilePosition, fpos, fposExpr));
  1003. }
  1004. if (lfpos)
  1005. {
  1006. Owned<IHqlExpression> fposExpr = createFileposCall(translator, getLocalFilePositionId, provider, rowname);
  1007. ctx.associateOwn(*new MonitoredDefinedValue(transformUsesVirtualFilePosition, lfpos, fposExpr));
  1008. }
  1009. if (logicalFilenameMarker)
  1010. {
  1011. Owned<IHqlExpression> nameExpr = createFileposCall(translator, queryLogicalFilenameId, provider, rowname);
  1012. ctx.associateOwn(*new MonitoredDefinedValue(transformUsesVirtualLogicalFilename, logicalFilenameMarker, nameExpr));
  1013. }
  1014. }
  1015. void SourceBuilder::rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq, bool isLocal)
  1016. {
  1017. if (!tableExpr)
  1018. return;
  1019. OwnedHqlExpr searchPos = getFilepos(tableExpr, isLocal);
  1020. HqlExprAssociation * match = ctx.queryMatchExpr(searchPos);
  1021. if (match)
  1022. {
  1023. OwnedHqlExpr selector = createSelector(side, dataset, selSeq);
  1024. OwnedHqlExpr selectorFpos = getFilepos(selector, isLocal);
  1025. ctx.associateOwn(*new MonitoredDefinedValue(transformUsesVirtualFilePosition, selectorFpos, match->queryExpr()));
  1026. }
  1027. }
  1028. void SourceBuilder::rebindFilepositons(BuildCtx & ctx, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq)
  1029. {
  1030. // don't allow the rebinding to modify these flags.
  1031. bool savedVirtualLogicalFilenameUsed = transformUsesVirtualLogicalFilename;
  1032. bool savedVirtualFilePositionUsed = transformUsesVirtualFilePosition;
  1033. rebindFilepositons(ctx, dataset, side, selSeq, true);
  1034. rebindFilepositons(ctx, dataset, side, selSeq, false);
  1035. OwnedHqlExpr searchLogicalFilename = getFileLogicalName(dataset);
  1036. HqlExprAssociation * match = ctx.queryMatchExpr(searchLogicalFilename);
  1037. if (match)
  1038. {
  1039. OwnedHqlExpr selector = createSelector(side, dataset, selSeq);
  1040. OwnedHqlExpr selectorLogicalFilename = getFileLogicalName(dataset);
  1041. ctx.associateOwn(*new MonitoredDefinedValue(transformUsesVirtualLogicalFilename, selectorLogicalFilename, match->queryExpr()));
  1042. }
  1043. transformUsesVirtualLogicalFilename = savedVirtualLogicalFilenameUsed;
  1044. transformUsesVirtualFilePosition = savedVirtualFilePositionUsed;
  1045. }
  1046. void SourceBuilder::buildFilenameMember()
  1047. {
  1048. //---- virtual const char * getFileName() { return "x.d00"; } ----
  1049. translator.buildFilenameFunction(*instance, instance->startctx, WaFilename, "getFileName", nameExpr, translator.hasDynamicFilename(tableExpr));
  1050. }
  1051. void SourceBuilder::buildReadMembers(IHqlExpression * expr)
  1052. {
  1053. buildFilenameMember();
  1054. //---- virtual bool needTransform() { return <bool>; } ----
  1055. if (needToCallTransform || transformCanFilter)
  1056. translator.doBuildBoolFunction(instance->classctx, "needTransform", true);
  1057. //---- virtual bool transformMayFilter() { return <bool>; } ----
  1058. if (transformCanFilter)
  1059. translator.doBuildBoolFunction(instance->classctx, "transformMayFilter", true);
  1060. if (translator.queryOptions().generateDiskFormats)
  1061. translator.addFormatAttribute(*instance, WaDiskFormat, tableExpr->queryRecord());
  1062. }
  1063. void SourceBuilder::buildLimits(BuildCtx & classctx, IHqlExpression * expr, unique_id_t id)
  1064. {
  1065. if (limitExpr)
  1066. translator.buildLimitHelpers(classctx, limitExpr, nameExpr, id);
  1067. if (choosenValue)
  1068. {
  1069. MemberFunction func(translator, classctx, "virtual unsigned __int64 getChooseNLimit() override");
  1070. OwnedHqlExpr newLimit = ensurePositiveOrZeroInt64(choosenValue);
  1071. translator.buildReturn(func.ctx, newLimit);
  1072. }
  1073. }
  1074. void SourceBuilder::buildTransformBody(BuildCtx & transformCtx, IHqlExpression * expr, bool returnSize, bool ignoreFilters, bool bindInputRow)
  1075. {
  1076. if (tableExpr && bindInputRow)
  1077. {
  1078. IHqlExpression * mode = (tableExpr->getOperator() == no_table) ? tableExpr->queryChild(2) : NULL;
  1079. if (mode && mode->getOperator() == no_csv && !genericDiskRead)
  1080. {
  1081. translator.bindCsvTableCursor(transformCtx, tableExpr, "Src", no_none, NULL, true, queryCsvEncoding(mode));
  1082. }
  1083. else
  1084. {
  1085. translator.bindTableCursor(transformCtx, projectedSelector, "left");
  1086. }
  1087. transformCtx.addGroup();
  1088. }
  1089. rootSelfRow = translator.bindSelf(transformCtx, expr, "crSelf");
  1090. buildTransformFpos(transformCtx);
  1091. buildTransformElements(transformCtx, expr, ignoreFilters);
  1092. if (returnSize)
  1093. {
  1094. CHqlBoundExpr boundTargetSize;
  1095. if (needDefaultTransform)
  1096. {
  1097. IHqlExpression * left = expr->queryNormalizedSelector();
  1098. OwnedHqlExpr source = ensureActiveRow(left);
  1099. translator.buildAssign(transformCtx, rootSelfRow->querySelector(), source);
  1100. }
  1101. translator.getRecordSize(transformCtx, rootSelfRow->querySelector(), boundTargetSize);
  1102. transformCtx.setNextDestructor();
  1103. transformCtx.addReturn(boundTargetSize.expr);
  1104. }
  1105. rootSelfRow = NULL;
  1106. }
  1107. void SourceBuilder::buildTargetCursor(Shared<BoundRow> & tempRow, Shared<BoundRow> & rowBuilder, BuildCtx & ctx, IHqlExpression * expr)
  1108. {
  1109. assertex(lastTransformer != NULL);
  1110. if (expr == lastTransformer)
  1111. {
  1112. rowBuilder.set(rootSelfRow);
  1113. }
  1114. else
  1115. {
  1116. tempRow.setown(translator.declareTempAnonRow(ctx, ctx, expr));
  1117. ctx.addGroup();
  1118. // group is important, otherwise sizeof(self.x) gets cached incorrectly
  1119. // not so sure, but references to LEFT(x) may be misresolved
  1120. rowBuilder.setown(translator.createRowBuilder(ctx, tempRow));
  1121. }
  1122. }
  1123. void SourceBuilder::associateTargetCursor(BuildCtx & subctx, BuildCtx & ctx, BoundRow * tempRow, BoundRow * rowBuilder, IHqlExpression * expr)
  1124. {
  1125. //First remove the old active dataset
  1126. //This is not strictly necessary, but it avoids the redundant row being serialized to any child queries
  1127. BoundRow * oldCursor = translator.resolveSelectorDataset(ctx, expr->queryChild(0));
  1128. ctx.removeAssociation(oldCursor);
  1129. //And add an association for expr
  1130. if (tempRow)
  1131. {
  1132. translator.finalizeTempRow(subctx, tempRow, rowBuilder);
  1133. translator.bindTableCursor(ctx, expr, tempRow->queryBound());
  1134. }
  1135. else
  1136. translator.bindTableCursor(ctx, expr, rowBuilder->queryBound());
  1137. }
  1138. void SourceBuilder::buildTransformElements(BuildCtx & ctx, IHqlExpression * expr, bool ignoreFilters)
  1139. {
  1140. //This function can be called again for the unfiltered tranform. Don't process annotations again.
  1141. if ((expr != instance->activityExpr) && !ignoreFilters)
  1142. instance->processAnnotations(expr);
  1143. expr = expr->queryBody();
  1144. node_operator op = expr->getOperator();
  1145. switch (op)
  1146. {
  1147. case no_cachealias:
  1148. buildTransformElements(ctx, expr->queryChild(1), ignoreFilters);
  1149. return;
  1150. case no_newkeyindex:
  1151. case no_table:
  1152. case no_fetch:
  1153. case no_select: // handled below
  1154. case no_null:
  1155. case no_anon:
  1156. case no_pseudods:
  1157. case no_workunit_dataset:
  1158. case no_getgraphresult:
  1159. case no_call:
  1160. case no_externalcall:
  1161. case no_rows:
  1162. case no_libraryinput:
  1163. break;
  1164. default:
  1165. buildTransformElements(ctx, expr->queryChild(0), ignoreFilters);
  1166. break;
  1167. }
  1168. switch (op)
  1169. {
  1170. case no_newkeyindex:
  1171. case no_table:
  1172. if (newInputMapping)
  1173. {
  1174. }
  1175. else
  1176. {
  1177. assertex(!fieldInfo.hasVirtuals());
  1178. }
  1179. break;
  1180. case no_null:
  1181. case no_anon:
  1182. case no_pseudods:
  1183. break;
  1184. case no_workunit_dataset:
  1185. case no_getgraphresult:
  1186. case no_call:
  1187. case no_externalcall:
  1188. case no_rows:
  1189. case no_libraryinput:
  1190. throwUnexpectedOp(op);
  1191. break;
  1192. case no_select:
  1193. processTransformSelect(ctx, expr);
  1194. break;
  1195. case no_sorted:
  1196. case no_stepped:
  1197. case no_distributed:
  1198. case no_preservemeta:
  1199. case no_unordered:
  1200. case no_grouped:
  1201. case no_preload:
  1202. case no_limit:
  1203. case no_keyedlimit:
  1204. case no_choosen:
  1205. case no_alias_scope:
  1206. case no_section:
  1207. case no_sectioninput:
  1208. case no_nofold:
  1209. case no_nohoist:
  1210. case no_nocombine:
  1211. break;
  1212. case no_filter:
  1213. {
  1214. if (!ignoreFilters && (!extractCanMatch || !isRootSelector(expr)))
  1215. {
  1216. LinkedHqlExpr cond;
  1217. if (useFilterMappings)
  1218. {
  1219. unsigned match = originalFilters.find(*expr);
  1220. if (match != NotFound)
  1221. cond.set(&mappedFilters.item(match));
  1222. }
  1223. else
  1224. {
  1225. HqlExprArray args;
  1226. unwindRealChildren(args, expr, 1);
  1227. cond.setown(createBalanced(no_and, queryBoolType(), args));
  1228. }
  1229. if (cond)
  1230. {
  1231. IHqlExpression * ds = expr->queryChild(0);
  1232. OwnedHqlExpr test = returnIfFilterFails ? getInverse(cond) : LINK(cond);
  1233. if (translator.queryOptions().foldFilter)
  1234. test.setown(foldScopedHqlExpression(translator.queryErrorProcessor(), ds->queryNormalizedSelector(), test));
  1235. if (translator.options.spotCSE)
  1236. test.setown(spotScalarCSE(test, ds, translator.queryOptions().spotCseInIfDatasetConditions));
  1237. if (!returnIfFilterFails)
  1238. translator.buildFilter(ctx, test);
  1239. else
  1240. {
  1241. LinkedHqlExpr mismatchReturnValue = failedFilterValue;
  1242. //If the output row has already been generated, then returning at this point will leak any
  1243. //child datasets. To avoid that we explicitly call the destructor on the output row.
  1244. if (recordRequiresDestructor(expr->queryRecord()))
  1245. {
  1246. if (lastTransformer && lastTransformer->queryNormalizedSelector() == expr->queryNormalizedSelector())
  1247. {
  1248. StringBuffer s;
  1249. translator.buildMetaForRecord(s, expr->queryRecord());
  1250. s.append(".destruct(crSelf.row())");
  1251. OwnedHqlExpr cleanupAction = createQuoted(s.str(), makeVoidType());
  1252. //Create a compound expression (destroy-old, return-value)
  1253. mismatchReturnValue.setown(createCompound(LINK(cleanupAction), LINK(mismatchReturnValue)));
  1254. }
  1255. }
  1256. translator.buildFilteredReturn(ctx, test, mismatchReturnValue);
  1257. }
  1258. }
  1259. }
  1260. }
  1261. break;
  1262. case no_hqlproject:
  1263. {
  1264. IHqlExpression * dataset = expr->queryChild(0);
  1265. IHqlExpression * datasetSelector = dataset->queryNormalizedSelector();
  1266. IHqlExpression * selSeq = querySelSeq(expr);
  1267. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, querySelSeq(expr));
  1268. if ((projectedSelector != tableSelector) && (expr == firstTransformer))
  1269. datasetSelector = projectedSelector;
  1270. //Following is a bit nasty....
  1271. //Converting the no_hqlproject to a no_newusertable means that some of the expressions
  1272. //are commoned up with expressions calculated by a previous filter, reducing the code.
  1273. //However, it isn't valid if transform contains an instance of newSelect -
  1274. //e.g. project(i(x), transform(exists(i....))) - see jholt25.xhql
  1275. //And unfortunately it fails silently.
  1276. //So we use queryReplaceSelector which fails if an ambiguity is introduced by the replacement
  1277. OwnedHqlExpr newSelect = ensureActiveRow(datasetSelector);
  1278. OwnedHqlExpr transform = queryNewReplaceSelector(expr->queryChild(1), leftSelect, newSelect);
  1279. BuildCtx subctx(ctx); // buildTargetCursor adds group if necessary
  1280. Linked<BoundRow> tempRow;
  1281. Linked<BoundRow> rowBuilder;
  1282. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1283. if (!transform)
  1284. {
  1285. //The replace introduced an ambiguity => need to use the unmapped expression.
  1286. BoundRow * prevCursor = translator.resolveSelectorDataset(ctx, datasetSelector);
  1287. transform.set(expr->queryChild(1));
  1288. translator.rebindTableCursor(subctx, dataset, prevCursor, no_left, selSeq);
  1289. rebindFilepositons(subctx, dataset, no_left, selSeq);
  1290. }
  1291. if (returnIfFilterFails)
  1292. {
  1293. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL); // failedFilterValue already handles clearing the result
  1294. }
  1295. else
  1296. {
  1297. //MORE: Probably not implementable, should try and prevent this happening!
  1298. //translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL);
  1299. }
  1300. translator.doTransform(subctx, transform, rowBuilder);
  1301. ctx.addGroup();
  1302. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1303. }
  1304. break;
  1305. case no_newusertable:
  1306. {
  1307. BuildCtx subctx(ctx);
  1308. Linked<BoundRow> tempRow;
  1309. Linked<BoundRow> rowBuilder;
  1310. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1311. LinkedHqlExpr transform = expr->queryChild(2);
  1312. if (tableExpr && (expr == firstTransformer))
  1313. {
  1314. if (tableSelector != projectedSelector)
  1315. transform.setown(newReplaceSelector(transform, tableSelector, projectedSelector));
  1316. }
  1317. if (returnIfFilterFails)
  1318. {
  1319. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL); // failedFilterValue already handles clearing the result
  1320. }
  1321. else
  1322. {
  1323. //MORE: Probably not implementable
  1324. //translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL);
  1325. }
  1326. translator.doTransform(subctx, transform, rowBuilder);
  1327. ctx.addGroup();
  1328. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1329. }
  1330. break;
  1331. case no_aggregate:
  1332. {
  1333. if (alreadyDoneFlag)
  1334. {
  1335. IHqlExpression * dataset = expr->queryChild(0);
  1336. IHqlExpression * selSeq = querySelSeq(expr);
  1337. IHqlExpression * transform = expr->queryChild(2);
  1338. BuildCtx subctx(ctx);
  1339. //Similar code to no_hqlproject. Should possibly try and do a similar mapping to the transforms
  1340. //(but complicated by having merge/first)
  1341. BoundRow * prevCursor = translator.resolveSelectorDataset(ctx, dataset);
  1342. translator.rebindTableCursor(subctx, dataset, prevCursor, no_left, selSeq);
  1343. rebindFilepositons(subctx, dataset, no_left, selSeq);
  1344. Linked<BoundRow> tempRow;
  1345. Linked<BoundRow> rowBuilder;
  1346. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1347. translator.doBuildUserAggregateProcessTransform(subctx, rowBuilder, expr, transform, alreadyDoneFlag);
  1348. subctx.addAssign(alreadyDoneFlag, queryBoolExpr(true));
  1349. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1350. }
  1351. }
  1352. break;
  1353. case no_newaggregate:
  1354. {
  1355. IHqlExpression * transform = expr->queryChild(2);
  1356. if (isCompoundCount)
  1357. {
  1358. //This should really be special cased in a count() baseclass, but can't be bothered at the moment.
  1359. IHqlExpression * rhs = transform->queryChild(0)->queryChild(1);
  1360. IHqlExpression * filter = queryRealChild(rhs, 0);
  1361. if (filter)
  1362. {
  1363. if (!returnIfFilterFails)
  1364. translator.buildFilter(ctx, filter);
  1365. else
  1366. {
  1367. OwnedHqlExpr test = getInverse(filter);
  1368. translator.buildFilteredReturn(ctx, test, failedFilterValue);
  1369. }
  1370. }
  1371. if (compoundCountVar)
  1372. {
  1373. OwnedHqlExpr inc = adjustValue(compoundCountVar, 1);
  1374. ctx.addAssign(compoundCountVar, inc);
  1375. }
  1376. }
  1377. else if (alreadyDoneFlag)
  1378. {
  1379. BuildCtx subctx(ctx);
  1380. Linked<BoundRow> tempRow;
  1381. Linked<BoundRow> rowBuilder;
  1382. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1383. translator.doBuildAggregateProcessTransform(subctx, rowBuilder, expr, alreadyDoneFlag);
  1384. subctx.addAssign(alreadyDoneFlag, queryBoolExpr(true));
  1385. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1386. }
  1387. }
  1388. break;
  1389. case no_usertable:
  1390. case no_selectfields:
  1391. UNIMPLEMENTED;
  1392. break;
  1393. case no_fetch:
  1394. {
  1395. BuildCtx subctx(ctx);
  1396. Linked<BoundRow> tempRow;
  1397. Linked<BoundRow> rowBuilder;
  1398. buildTargetCursor(tempRow, rowBuilder, subctx, expr);
  1399. // MORE - don't understand why this is required here but not in hqlproject above
  1400. IHqlExpression * dataset = expr->queryChild(0);
  1401. BoundRow * leftCursor = nullptr;
  1402. switch (getDatasetKind(tableExpr))
  1403. {
  1404. case no_csv:
  1405. leftCursor = translator.bindCsvTableCursor(subctx, dataset, "Left", no_left, querySelSeq(expr), true, queryCsvTableEncoding(tableExpr));
  1406. break;
  1407. case no_xml:
  1408. case no_json:
  1409. leftCursor = translator.bindXmlTableCursor(subctx, dataset, "xmlLeft", no_left, querySelSeq(expr), true);
  1410. break;
  1411. }
  1412. if (!leftCursor)
  1413. leftCursor = translator.bindTableCursor(subctx, dataset, "left", no_left, querySelSeq(expr));
  1414. BoundRow * rightCursor = NULL;
  1415. LinkedHqlExpr transform = expr->queryChild(3);
  1416. if (!containsOnlyLeft(transform, true))
  1417. {
  1418. IHqlExpression * rhs = expr->queryChild(1);
  1419. IHqlExpression * memoryRhsRecord = rhs->queryRecord();
  1420. //RIGHT is the input data row.
  1421. //a) In hthor the remote file is read locally, so RIGHT is a deserialized unmodified row.
  1422. //b) in roxie it is serialized, and accessed in its serialized form.
  1423. //c) in thor it is serialized, but also (inefficiently) deserialized, so use the deserialized form.
  1424. //NOTE: Currently extractJoinFields either does nothing, or sends the entire row. Needless to say that could be improved -
  1425. //and would mean the roxie/thor code required changing
  1426. if (translator.targetRoxie())
  1427. {
  1428. OwnedHqlExpr serializedRhsRecord = getSerializedForm(memoryRhsRecord, diskAtom);
  1429. OwnedHqlExpr serializedRhs = createDataset(no_null, LINK(serializedRhsRecord));
  1430. rightCursor = translator.bindTableCursor(subctx, serializedRhs, "right", no_right, querySelSeq(expr));
  1431. transform.setown(replaceMemorySelectorWithSerializedSelector(transform, memoryRhsRecord, no_right, querySelSeq(expr), diskAtom));
  1432. }
  1433. else
  1434. {
  1435. rightCursor = translator.bindTableCursor(subctx, rhs, "right", no_right, querySelSeq(expr));
  1436. }
  1437. }
  1438. buildTransformFpos(subctx); // unusual, but this must occur after the row cursor is bound
  1439. translator.associateSkipReturnMarker(subctx, failedFilterValue, NULL); // failedFilterValue already handles clearing the result
  1440. translator.doTransform(subctx, transform, rowBuilder);
  1441. subctx.removeAssociation(leftCursor);
  1442. subctx.removeAssociation(rightCursor);
  1443. associateTargetCursor(subctx, ctx, tempRow, rowBuilder, expr);
  1444. }
  1445. break;
  1446. case no_compound_diskread:
  1447. case no_compound_disknormalize:
  1448. case no_compound_diskaggregate:
  1449. case no_compound_diskcount:
  1450. case no_compound_diskgroupaggregate:
  1451. case no_compound_indexread:
  1452. case no_compound_indexnormalize:
  1453. case no_compound_indexaggregate:
  1454. case no_compound_indexcount:
  1455. case no_compound_indexgroupaggregate:
  1456. case no_compound_childread:
  1457. case no_compound_childnormalize:
  1458. case no_compound_childaggregate:
  1459. case no_compound_childcount:
  1460. case no_compound_childgroupaggregate:
  1461. case no_compound_fetch:
  1462. case no_compound_selectnew:
  1463. break;
  1464. default:
  1465. throwUnexpectedOp(op);
  1466. }
  1467. }
  1468. void SourceBuilder::buildMatchFilter(BuildCtx & ctx, IHqlExpression * expr)
  1469. {
  1470. expr = expr->queryBody();
  1471. node_operator op = expr->getOperator();
  1472. switch (op)
  1473. {
  1474. case no_cachealias:
  1475. buildMatchFilter(ctx, expr->queryChild(1));
  1476. return;
  1477. case no_newkeyindex:
  1478. case no_table:
  1479. case no_fetch:
  1480. case no_select: // handled below
  1481. case no_null:
  1482. case no_anon:
  1483. case no_pseudods:
  1484. case no_workunit_dataset:
  1485. case no_getgraphresult:
  1486. case no_call:
  1487. case no_externalcall:
  1488. case no_rows:
  1489. case no_libraryinput:
  1490. return;
  1491. default:
  1492. buildMatchFilter(ctx, expr->queryChild(0));
  1493. break;
  1494. }
  1495. switch (op)
  1496. {
  1497. case no_filter:
  1498. {
  1499. LinkedHqlExpr cond;
  1500. if (useFilterMappings)
  1501. {
  1502. unsigned match = originalFilters.find(*expr);
  1503. if (match != NotFound)
  1504. cond.set(&mappedFilters.item(match));
  1505. }
  1506. else
  1507. {
  1508. HqlExprArray args;
  1509. unwindRealChildren(args, expr, 1);
  1510. cond.setown(createBalanced(no_and, queryBoolType(), args));
  1511. }
  1512. if (cond)
  1513. {
  1514. IHqlExpression * ds = expr->queryChild(0);
  1515. OwnedHqlExpr test = getInverse(cond);
  1516. if (translator.queryOptions().foldFilter)
  1517. test.setown(foldScopedHqlExpression(translator.queryErrorProcessor(), ds->queryNormalizedSelector(), test));
  1518. if (translator.options.spotCSE)
  1519. test.setown(spotScalarCSE(test, ds, translator.queryOptions().spotCseInIfDatasetConditions));
  1520. if (tableSelector != projectedSelector)
  1521. test.setown(newReplaceSelector(test, tableSelector, projectedSelector));
  1522. translator.buildFilteredReturn(ctx, test, queryBoolExpr(false));
  1523. }
  1524. }
  1525. break;
  1526. }
  1527. }
  1528. void SourceBuilder::doBuildAggregateSelectIterator(BuildCtx & ctx, IHqlExpression * expr)
  1529. {
  1530. IHqlExpression * ds = expr->queryChild(0);
  1531. if (isNewSelector(expr))
  1532. buildTransformElements(ctx, ds, false);
  1533. Owned<IHqlCppDatasetCursor> cursor = translator.createDatasetSelector(ctx, expr->queryNormalizedSelector());
  1534. cursor->buildIterateLoop(ctx, false);
  1535. }
  1536. void SourceBuilder::processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  1537. {
  1538. throwUnexpected();
  1539. }
  1540. void SourceBuilder::doBuildNormalizeIterators(BuildCtx & ctx, IHqlExpression * expr, bool isChildIterator)
  1541. {
  1542. HqlExprArray iterators;
  1543. IHqlExpression * root = gatherSelectorLevels(iterators, expr);
  1544. //MORE: transform also needs to be inside this iterctx
  1545. BuildCtx iterctx(*globaliterctx);
  1546. MemberFunction firstFunc(translator, instance->startctx);
  1547. CursorArray cursors;
  1548. if (isChildIterator)
  1549. {
  1550. assertex(!root);
  1551. firstFunc.start("virtual bool first() override");
  1552. }
  1553. else
  1554. {
  1555. assertex(root);
  1556. firstFunc.start("virtual bool first(const void * _src) override");
  1557. bool isProjected = (root->queryNormalizedSelector() != tableExpr->queryNormalizedSelector());
  1558. if (!isProjected)
  1559. {
  1560. iterctx.addQuotedLiteral("byte * src;");
  1561. associateFilePositions(iterctx, "activity->fpp", "activity->src"); // in case no projection in first()
  1562. firstFunc.ctx.addQuotedLiteral("src = (byte *)_src;");
  1563. }
  1564. else
  1565. {
  1566. firstFunc.ctx.addQuotedLiteral("byte * src = (byte *)_src;");
  1567. }
  1568. translator.associateBlobHelper(firstFunc.ctx, tableExpr, "fpp");
  1569. BoundRow * tableCursor = translator.bindTableCursor(firstFunc.ctx, tableExpr, "src");
  1570. associateFilePositions(firstFunc.ctx, "fpp", "src");
  1571. TransformSequenceBuilder builder(translator, queryBoolExpr(false));
  1572. builder.buildSequence(firstFunc.ctx, &iterctx, root);
  1573. if (!isProjected)
  1574. cursors.append(*LINK(tableCursor));
  1575. else
  1576. {
  1577. BoundRow * match = translator.resolveSelectorDataset(firstFunc.ctx, root);
  1578. assertex(match);
  1579. cursors.append(*LINK(match));
  1580. }
  1581. }
  1582. CompoundIteratorBuilder iterBuilder(translator, instance->nestedctx, iterctx);
  1583. if (iterators.ordinality() == 1)
  1584. {
  1585. StringBuffer s, iterName, cursorName;
  1586. iterBuilder.createSingleLevelIterator(iterName, cursorName, &iterators.item(0), cursors);
  1587. firstFunc.ctx.addQuoted(s.clear().append("return (").append(cursorName).append(" = (byte *)").append(iterName).append(".first()) != 0;"));
  1588. {
  1589. BuildCtx nextctx(instance->startctx);
  1590. nextctx.addQuotedFunction("virtual bool next() override");
  1591. nextctx.addQuoted(s.clear().append("return (").append(cursorName).append(" = (byte *)").append(iterName).append(".next()) != 0;"));
  1592. }
  1593. }
  1594. else
  1595. {
  1596. iterBuilder.buildCompoundIterator(instance->onlyEvalOnceContext(), iterators, cursors);
  1597. firstFunc.ctx.addQuotedLiteral("return iter.first();");
  1598. {
  1599. BuildCtx nextctx(instance->startctx);
  1600. nextctx.addQuotedFunction("virtual bool next() override");
  1601. nextctx.addQuotedLiteral("return iter.next();");
  1602. }
  1603. }
  1604. ForEachItemIn(i, cursors)
  1605. ctx.associate(cursors.item(i));
  1606. }
  1607. void SourceBuilder::checkDependencies(BuildCtx & ctx, IHqlExpression * expr)
  1608. {
  1609. //Add dependency information
  1610. Owned<ABoundActivity> bound = instance->getBoundActivity();
  1611. translator.addFileDependency(nameExpr, bound);
  1612. }
  1613. void SourceBuilder::extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds)
  1614. {
  1615. ForEachItemIn(i, conds)
  1616. {
  1617. IHqlExpression * filter = &conds.item(i);
  1618. #ifdef ALLOW_CHILD_ITERATORS_TO_CALL_CANMATCHANY
  1619. if (isSourceInvariant(ds, filter)) // more actually isSourceInvariant.
  1620. extendAndCondition(globalGuard, filter);
  1621. else
  1622. #endif
  1623. appendFilter(unkeyedFilter, filter);
  1624. }
  1625. }
  1626. void SourceBuilder::analyseGraph(IHqlExpression * expr)
  1627. {
  1628. analyse(expr);
  1629. SourceFieldUsage * fieldUsage = translator.querySourceFieldUsage(tableExpr);
  1630. if (fieldUsage && !fieldUsage->seenAll())
  1631. {
  1632. if (expr->queryNormalizedSelector() == tableExpr->queryNormalizedSelector())
  1633. fieldUsage->noteAll();
  1634. else
  1635. gatherFieldUsage(fieldUsage, expr);
  1636. }
  1637. }
  1638. void SourceBuilder::gatherFieldUsage(SourceFieldUsage * fieldUsage, IHqlExpression * expr)
  1639. {
  1640. for (;;)
  1641. {
  1642. if (expr->queryBody() == tableExpr->queryBody())
  1643. return;
  1644. if (fieldUsage->seenAll())
  1645. return;
  1646. IHqlExpression * ds = expr->queryChild(0);
  1647. switch (expr->getOperator())
  1648. {
  1649. case no_fetch:
  1650. {
  1651. assertex(ds->queryBody() == tableExpr->queryBody());
  1652. IHqlExpression * selSeq = querySelSeq(expr);
  1653. OwnedHqlExpr left = createSelector(no_left, ds, selSeq);
  1654. ::gatherFieldUsage(fieldUsage, expr, left);
  1655. return;
  1656. }
  1657. }
  1658. assertex(getNumChildTables(expr) == 1);
  1659. if (ds->queryNormalizedSelector() == tableExpr->queryNormalizedSelector())
  1660. gatherParentFieldUsage(fieldUsage, expr);
  1661. expr = ds;
  1662. }
  1663. }
  1664. inline bool useDescriptiveGraphLabel(ThorActivityKind kind)
  1665. {
  1666. switch (kind)
  1667. {
  1668. case TAKcsvfetch:
  1669. case TAKxmlfetch:
  1670. case TAKjsonfetch:
  1671. case TAKfetch:
  1672. return false;
  1673. }
  1674. return true;
  1675. }
  1676. static bool expandGraphLabel(ThorActivityKind kind)
  1677. {
  1678. switch (kind)
  1679. {
  1680. case TAKdiskread:
  1681. case TAKnewdiskread:
  1682. case TAKcsvread:
  1683. case TAKxmlread:
  1684. case TAKjsonread:
  1685. case TAKdiskcount:
  1686. case TAKdiskexists:
  1687. case TAKspillread:
  1688. return true;
  1689. default:
  1690. return false;
  1691. }
  1692. }
  1693. ABoundActivity * SourceBuilder::buildActivity(BuildCtx & ctx, IHqlExpression * expr, ThorActivityKind _activityKind, const char *kind, ABoundActivity *input)
  1694. {
  1695. activityKind = _activityKind;
  1696. translator.gatherActiveCursors(ctx, parentCursors);
  1697. bool isSpill = tableExpr && tableExpr->hasAttribute(_spill_Atom);
  1698. //If genericDiskReads are supported, this will no longer generate spill activities.
  1699. //Good for testing, but will change once all disk reads go through that interface
  1700. if (isSpill && (activityKind == TAKdiskread))
  1701. activityKind = TAKspillread;
  1702. useImplementationClass = translator.queryOptions().minimizeActivityClasses && translator.targetRoxie() && (activityKind == TAKspillread);
  1703. Owned<ActivityInstance> localInstance = new ActivityInstance(translator, ctx, activityKind, expr, kind);
  1704. if (useImplementationClass)
  1705. localInstance->setImplementationClass(newMemorySpillReadArgId);
  1706. if (((activityKind >= TAKdiskread) && (activityKind <= TAKdiskgroupaggregate)) || (activityKind == TAKspillread) || (activityKind == TAKnewdiskread))
  1707. {
  1708. IHqlExpression * seq = querySequence(tableExpr);
  1709. translator.noteResultAccessed(ctx, seq, nameExpr);
  1710. }
  1711. instance = localInstance;
  1712. StringBuffer graphLabel;
  1713. graphLabel.append(getActivityText(activityKind));
  1714. bool isFiltered = false;
  1715. double filterLikelihood = 1.0;
  1716. if (expandGraphLabel(activityKind))
  1717. {
  1718. graphLabel.clear();
  1719. if (expr != tableExpr)
  1720. {
  1721. if (isGrouped(expr))
  1722. graphLabel.append("Grouped\n");
  1723. IHqlExpression * cur = expr;
  1724. bool isProjected = false;
  1725. for (;;)
  1726. {
  1727. switch (cur->getOperator())
  1728. {
  1729. case no_filter:
  1730. if (isKnownLikelihood(filterLikelihood))
  1731. {
  1732. double likelihood = queryActivityLikelihood(cur);
  1733. if (isKnownLikelihood(likelihood))
  1734. // Combine the likelihood of the 2 filter conditions
  1735. // N.B. this only works if the filter probability are independent
  1736. filterLikelihood *= likelihood;
  1737. else
  1738. // One of the filter probability is unknown, so the overall probability is unknown
  1739. setUnknownLikelihood(filterLikelihood);
  1740. }
  1741. isFiltered = true;
  1742. break;
  1743. case no_hqlproject:
  1744. case no_newusertable:
  1745. case no_transformascii:
  1746. case no_transformebcdic:
  1747. if (!cur->hasAttribute(_internal_Atom))
  1748. isProjected = true;
  1749. break;
  1750. case no_table:
  1751. cur = NULL;
  1752. break;
  1753. }
  1754. if (!cur)
  1755. break;
  1756. cur = cur->queryChild(0);
  1757. }
  1758. if (isFiltered)
  1759. {
  1760. graphLabel.append("Filtered\n");
  1761. }
  1762. if (isProjected)
  1763. graphLabel.append("Projected\n");
  1764. }
  1765. if ((translator.getTargetClusterType() == RoxieCluster) && isSpill)
  1766. graphLabel.append("Read");
  1767. else if (isExplicitExists() && (activityKind == TAKdiskcount))
  1768. graphLabel.append("Disk Exists");
  1769. else
  1770. graphLabel.append(getActivityText(activityKind));
  1771. }
  1772. if (isExplicitExists())
  1773. {
  1774. if (activityKind == TAKindexcount)
  1775. graphLabel.clear().append("Index Exists");
  1776. }
  1777. if (useDescriptiveGraphLabel(activityKind))
  1778. {
  1779. StringBuffer eclChunk;
  1780. bool isLimited = false;
  1781. bool isStepped = false;
  1782. IHqlExpression * cur = expr;
  1783. instance->graphEclText.clear();
  1784. for (;;)
  1785. {
  1786. eclChunk.clear();
  1787. switch (cur->getOperator())
  1788. {
  1789. case no_hqlproject:
  1790. case no_newusertable:
  1791. case no_transformascii:
  1792. case no_transformebcdic:
  1793. break;
  1794. case no_filter:
  1795. toECL(cur->queryBody(), eclChunk, false, true);
  1796. break;
  1797. case no_table:
  1798. case no_newkeyindex:
  1799. case no_select:
  1800. toECL(cur->queryBody(), eclChunk, false, true);
  1801. cur = NULL;
  1802. break;
  1803. case no_stepped:
  1804. isStepped = true;
  1805. break;
  1806. case no_limit:
  1807. case no_keyedlimit:
  1808. isLimited = true;
  1809. break;
  1810. default:
  1811. if (getNumChildTables(cur) == 0)
  1812. {
  1813. toECL(cur->queryBody(), eclChunk, false, true);
  1814. cur = NULL;
  1815. }
  1816. break;
  1817. }
  1818. instance->graphEclText.insert(0, eclChunk);
  1819. if (!cur)
  1820. break;
  1821. cur = cur->queryChild(0);
  1822. }
  1823. if (isLimited)
  1824. graphLabel.insert(0, "Limited\n");
  1825. if (isStepped)
  1826. graphLabel.insert(0, "Stepped\n");
  1827. if (localInstance->isLocal && !isSpill)
  1828. graphLabel.insert(0, "Local ");
  1829. }
  1830. if (nameExpr && nameExpr->queryValue())
  1831. {
  1832. if (isSpill)
  1833. {
  1834. if (activityKind != TAKspillread)
  1835. graphLabel.append("\nSpill");
  1836. }
  1837. else
  1838. {
  1839. graphLabel.newline();
  1840. if (tableExpr->hasAttribute(_workflowPersist_Atom))
  1841. graphLabel.append("Persist ");
  1842. StringBuffer filename;
  1843. //Call getStringValue() rather than generateECL() to avoid 't quote \ etc. in the string
  1844. getStringValue(filename.append("'"), nameExpr).append("'");
  1845. const char * coloncolon = strstr(filename, "::");
  1846. if (coloncolon)
  1847. {
  1848. for (;;)
  1849. {
  1850. const char * next = strstr(coloncolon+2, "::");
  1851. if (!next)
  1852. break;
  1853. coloncolon = next;
  1854. }
  1855. graphLabel.append("'...").append(coloncolon);
  1856. }
  1857. else
  1858. graphLabel.append(filename);
  1859. }
  1860. }
  1861. instance->graphLabel.set(graphLabel.str());
  1862. translator.buildActivityFramework(localInstance);
  1863. translator.buildInstancePrefix(localInstance);
  1864. analyseGraph(expr);
  1865. if (!useImplementationClass)
  1866. {
  1867. buildMembers(expr);
  1868. buildTransform(expr);
  1869. buildCanMatch(expr);
  1870. buildFlagsMember(expr);
  1871. if (tableExpr && (activityKind < TAKchildread || activityKind > TAKchildthroughnormalize))
  1872. {
  1873. switch (activityKind)
  1874. {
  1875. case TAKindexread:
  1876. case TAKindexnormalize:
  1877. case TAKindexaggregate:
  1878. case TAKindexcount:
  1879. case TAKindexgroupaggregate:
  1880. case TAKindexexists:
  1881. {
  1882. translator.buildMetaMember(instance->classctx, expectedRecord, false, "queryDiskRecordSize");
  1883. translator.buildMetaMember(instance->classctx, projectedRecord, false, "queryProjectedDiskRecordSize");
  1884. break;
  1885. }
  1886. }
  1887. }
  1888. }
  1889. else
  1890. {
  1891. assertex(!hasDynamic(tableExpr));
  1892. bool matched = translator.registerGlobalUsage(nameExpr);
  1893. if (!matched)
  1894. {
  1895. StringBuffer spillName;
  1896. getExprECL(nameExpr, spillName);
  1897. if (translator.queryOptions().allowThroughSpill)
  1898. throwError1(HQLERR_ReadSpillBeforeWriteFix, spillName.str());
  1899. else
  1900. throwError1(HQLERR_ReadSpillBeforeWrite, spillName.str());
  1901. }
  1902. translator.addFilenameConstructorParameter(*instance, WaFilename, nameExpr);
  1903. }
  1904. if (steppedExpr)
  1905. buildSteppedHelpers();
  1906. if (translator.targetRoxie())
  1907. instance->addAttributeBool(WaIsSpill, isSpill);
  1908. else if (needToCallTransform || transformCanFilter)
  1909. instance->addAttributeBool(WaIsTransformSpill, isSpill);
  1910. else
  1911. instance->addAttributeBool(WaIsSpill, isSpill);
  1912. if (isFiltered)
  1913. {
  1914. if (isKnownLikelihood(filterLikelihood))
  1915. {
  1916. StringBuffer text;
  1917. filterLikelihood *= 100;
  1918. text.setf("%3.2f%%", filterLikelihood);
  1919. instance->addAttribute(WaMatchLikelihood, text);
  1920. }
  1921. }
  1922. IHqlExpression * spillReason = tableExpr ? queryAttributeChild(tableExpr, _spillReason_Atom, 0) : NULL;
  1923. if (spillReason && !translator.queryOptions().obfuscateOutput)
  1924. {
  1925. StringBuffer text;
  1926. getStringValue(text, spillReason);
  1927. instance->addAttribute(WaSpillReason, text.str());
  1928. }
  1929. if (tableExpr)
  1930. instance->addSignedAttribute(tableExpr->queryAttribute(_signed_Atom));
  1931. checkDependencies(ctx, expr);
  1932. translator.buildInstanceSuffix(localInstance);
  1933. if (input)
  1934. translator.buildConnectInputOutput(ctx, localInstance, input, 0, 0);
  1935. instance = NULL;
  1936. return localInstance->getBoundActivity();
  1937. }
  1938. void SourceBuilder::buildKeyedLimitHelper(IHqlExpression * self)
  1939. {
  1940. if (keyedLimitExpr)
  1941. {
  1942. IHqlExpression * limitValue = keyedLimitExpr->queryChild(1);
  1943. {
  1944. MemberFunction func(translator, instance->startctx, "virtual unsigned __int64 getKeyedLimit() override");
  1945. translator.buildReturn(func.ctx, limitValue);
  1946. if (isZero(limitValue))
  1947. translator.WARNING(CategoryUnusual, HQLWRN_KeyedLimitIsZero);
  1948. }
  1949. LinkedHqlExpr fail = keyedLimitExpr->queryChild(2);
  1950. if (!fail || fail->isAttribute())
  1951. fail.setown(translator.createFailAction("Keyed limit exceeded", limitValue, NULL, instance->activityId));
  1952. {
  1953. MemberFunction func(translator, instance->startctx, "virtual void onKeyedLimitExceeded() override");
  1954. translator.buildStmt(func.ctx, fail);
  1955. }
  1956. IHqlExpression * transform = queryAttributeChild(keyedLimitExpr, onFailAtom, 0);
  1957. if (transform)
  1958. {
  1959. MemberFunction func(translator, instance->startctx, "virtual size32_t transformOnKeyedLimitExceeded(ARowBuilder & crSelf) override");
  1960. translator.ensureRowAllocated(func.ctx, "crSelf");
  1961. translator.buildTransformBody(func.ctx, transform, NULL, NULL, self, NULL);
  1962. }
  1963. }
  1964. }
  1965. void SourceBuilder::buildSteppedHelpers()
  1966. {
  1967. StringBuffer steppedFlags;
  1968. IHqlExpression * priority = steppedExpr->queryAttribute(priorityAtom);
  1969. if (priority)
  1970. {
  1971. steppedFlags.append("|SSFhaspriority");
  1972. translator.doBuildFunction(instance->startctx, doubleType, "getPriority", priority->queryChild(0));
  1973. }
  1974. IHqlExpression * prefetch = steppedExpr->queryAttribute(prefetchAtom);
  1975. if (prefetch)
  1976. {
  1977. steppedFlags.append("|SSFhasprefetch");
  1978. translator.doBuildUnsignedFunction(instance->startctx, "getPrefetchSize", prefetch->queryChild(0));
  1979. }
  1980. IHqlExpression * filtered = steppedExpr->queryAttribute(filteredAtom);
  1981. if (filtered)
  1982. steppedFlags.append("|SSFalwaysfilter");
  1983. if (steppedFlags.length())
  1984. translator.doBuildUnsignedFunction(instance->classctx, "getSteppedFlags", steppedFlags.str()+1);
  1985. }
  1986. void SourceBuilder::assignLocalExtract(BuildCtx & ctx, ParentExtract * extractBuilder, IHqlExpression * dataset, const char * argName)
  1987. {
  1988. if (extractBuilder)
  1989. {
  1990. StringBuffer s;
  1991. s.append("byte * ");
  1992. translator.generateExprCpp(s, extractBuilder->queryExtractName());
  1993. s.append(" = (byte *) ").append(argName).append(";");
  1994. ctx.addQuoted(s);
  1995. }
  1996. else
  1997. {
  1998. StringBuffer s;
  1999. ctx.addQuoted(s.append("unsigned char * left = (unsigned char *) ").append(argName).append(";"));
  2000. translator.bindTableCursor(ctx, dataset, "left");
  2001. }
  2002. }
  2003. void SourceBuilder::buildGroupAggregateHashHelper(ParentExtract * extractBuilder, IHqlExpression * dataset, IHqlExpression * fields)
  2004. {
  2005. instance->classctx.addQuotedLiteral("virtual IHash * queryHash() override { return &hash; }");
  2006. BuildCtx classctx(instance->nestedctx);
  2007. IHqlStmt * classStmt = translator.beginNestedClass(classctx, "hash", "IHash", NULL, extractBuilder);
  2008. {
  2009. MemberFunction func(translator, classctx, "virtual unsigned hash(const void * _self) override");
  2010. assignLocalExtract(func.ctx, extractBuilder, dataset, "_self");
  2011. OwnedHqlExpr hash = createValue(no_hash32, LINK(unsignedType), LINK(fields), createAttribute(internalAtom));
  2012. translator.buildReturn(func.ctx, hash);
  2013. }
  2014. translator.endNestedClass(classStmt);
  2015. }
  2016. void SourceBuilder::buildGroupAggregateCompareHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, HqlExprArray & recordFields, HqlExprArray & aggregateFields)
  2017. {
  2018. //Special case comparison of IF(<global-bool>, value, some-constant), so that the order expression only compares if <global-bool> is true
  2019. //specifically to improve david's BIRPs code.
  2020. HqlExprArray optimizedLeft, optimizedRight;
  2021. ForEachItemIn(i, recordFields)
  2022. {
  2023. IHqlExpression & curLeft = recordFields.item(i);
  2024. IHqlExpression & curRight = aggregateFields.item(i);
  2025. IHqlExpression * newLeft = NULL;
  2026. IHqlExpression * newRight = NULL;
  2027. if (curLeft.getOperator() == no_if)
  2028. {
  2029. IHqlExpression * cond = curLeft.queryChild(0);
  2030. if (isIndependentOfScope(cond))
  2031. {
  2032. IHqlExpression * elseValue = curLeft.queryChild(2);
  2033. if (elseValue->getOperator() == no_constant)
  2034. {
  2035. newLeft = LINK(&curLeft);
  2036. newRight = createValue(no_if, curRight.getType(), LINK(cond), LINK(&curRight), LINK(elseValue));
  2037. }
  2038. }
  2039. }
  2040. if (newLeft)
  2041. {
  2042. optimizedLeft.append(*newLeft);
  2043. optimizedRight.append(*newRight);
  2044. }
  2045. else
  2046. {
  2047. optimizedLeft.append(OLINK(curLeft));
  2048. optimizedRight.append(OLINK(curRight));
  2049. }
  2050. }
  2051. OwnedHqlExpr leftList = createSortList(optimizedLeft);
  2052. DatasetReference datasetRight(aggregate, no_activetable, NULL);
  2053. OwnedHqlExpr selSeq = createDummySelectorSequence();
  2054. OwnedHqlExpr rightList = createSortList(optimizedRight);
  2055. OwnedHqlExpr rightSelect = datasetRight.getSelector(no_right, selSeq);
  2056. OwnedHqlExpr rightResolved = datasetRight.mapCompound(rightList, rightSelect);
  2057. OwnedHqlExpr order = createValue(no_order, makeIntType(sizeof(signed), true), LINK(leftList), LINK(rightResolved));
  2058. //Now generate the nested class
  2059. instance->classctx.addQuotedLiteral("virtual ICompare * queryCompareRowElement() override { return &compareRowElement; }");
  2060. BuildCtx classctx(instance->nestedctx);
  2061. IHqlStmt * classStmt = translator.beginNestedClass(classctx, "compareRowElement", "ICompare", NULL, extractBuilder);
  2062. {
  2063. MemberFunction func(translator, classctx, "virtual int docompare(const void * _left, const void * _right) const override");
  2064. assignLocalExtract(func.ctx, extractBuilder, aggregate->queryChild(0), "_left");
  2065. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  2066. func.ctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  2067. translator.bindTableCursor(func.ctx, aggregate, "right", no_right, selSeq);
  2068. translator.doBuildReturnCompare(func.ctx, order, no_eq, false, false);
  2069. }
  2070. translator.endNestedClass(classStmt);
  2071. }
  2072. void SourceBuilder::buildGroupAggregateProcessHelper(ParentExtract * extractBuilder, IHqlExpression * aggregate, const char * name, bool doneAny)
  2073. {
  2074. StringBuffer proto;
  2075. IHqlExpression * dataset = aggregate->queryChild(0);
  2076. IHqlExpression * tgtRecord = aggregate->queryChild(1);
  2077. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  2078. proto.append("virtual size32_t ").append(name).append("(ARowBuilder & crSelf, const void * _src) override");
  2079. MemberFunction validateFunc(translator, instance->nestedctx, proto, MFdynamicproto);
  2080. translator.ensureRowAllocated(validateFunc.ctx, "crSelf");
  2081. assignLocalExtract(validateFunc.ctx, extractBuilder, dataset, "_src");
  2082. BoundRow * selfRow = translator.bindSelf(validateFunc.ctx, resultDataset, "crSelf");
  2083. if (extractBuilder)
  2084. {
  2085. MemberEvalContext * evalContext = new MemberEvalContext(translator, extractBuilder, translator.queryEvalContext(validateFunc.ctx), validateFunc.ctx);
  2086. validateFunc.ctx.associateOwn(*evalContext);
  2087. evalContext->initContext();
  2088. validateFunc.ctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  2089. }
  2090. if (aggregate->getOperator() == no_aggregate)
  2091. {
  2092. //It is inefficient to call processUserAggregateTransform() twice, but this is an unusual construct, so leave as it
  2093. //is for the moment.
  2094. OwnedHqlExpr firstTransform;
  2095. OwnedHqlExpr nextTransform;
  2096. translator.processUserAggregateTransform(aggregate, aggregate->queryChild(2), firstTransform, nextTransform);
  2097. IHqlExpression * transform = doneAny ? nextTransform : firstTransform;
  2098. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(aggregate));
  2099. OwnedHqlExpr mappedTransform = replaceSelector(transform, left, dataset);
  2100. translator.doBuildUserAggregateProcessTransform(validateFunc.ctx, selfRow, aggregate, mappedTransform, queryBoolExpr(doneAny));
  2101. }
  2102. else
  2103. translator.doBuildAggregateProcessTransform(validateFunc.ctx, selfRow, aggregate, queryBoolExpr(doneAny));
  2104. translator.buildReturnRecordSize(validateFunc.ctx, selfRow);
  2105. }
  2106. void SourceBuilder::buildGroupAggregateHelpers(ParentExtract * extractBuilder, IHqlExpression * aggregate)
  2107. {
  2108. IHqlExpression * dataset = aggregate->queryChild(0);
  2109. LinkedHqlExpr transform = aggregate->queryChild(2);
  2110. LinkedHqlExpr grouping = aggregate->queryChild(3);
  2111. if (aggregate->getOperator() == no_aggregate)
  2112. {
  2113. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(aggregate));
  2114. grouping.setown(replaceSelector(grouping, left, dataset));
  2115. transform.setown(replaceSelector(transform, left, dataset));
  2116. }
  2117. HqlExprArray recordFields, aggregateFields;
  2118. grouping->unwindList(recordFields, no_sortlist);
  2119. getMappedFields(aggregateFields, transform, recordFields, queryActiveTableSelector());
  2120. OwnedHqlExpr allRecordFields = createValueSafe(no_sortlist, makeSortListType(NULL), recordFields);
  2121. OwnedHqlExpr allAggregateFields = createValueSafe(no_sortlist, makeSortListType(NULL), aggregateFields);
  2122. //virtual size32_t processFirst(void * target, const void * src)
  2123. buildGroupAggregateProcessHelper(extractBuilder, aggregate, "processFirst", false);
  2124. //virtual size32_t processNext(void * target, const void * src)
  2125. buildGroupAggregateProcessHelper(extractBuilder, aggregate, "processNext", true);
  2126. //virtual IHash * queryHash()
  2127. buildGroupAggregateHashHelper(extractBuilder, dataset, allRecordFields);
  2128. //virtual ICompare * queryCompareElements()
  2129. DatasetReference outRef(aggregate, no_activetable, NULL);
  2130. translator.buildCompareMember(instance->nestedctx, "CompareElements", allAggregateFields, outRef); // compare transformed elements
  2131. //virtual ICompare * queryCompareRowElement()
  2132. buildGroupAggregateCompareHelper(extractBuilder, aggregate, recordFields, aggregateFields);
  2133. //virtual IHash * queryHashElement()
  2134. translator.buildHashOfExprsClass(instance->nestedctx, "HashElement", allAggregateFields, outRef, true);
  2135. }
  2136. IHqlExpression * SourceBuilder::ensureAggregateGroupingAliased(IHqlExpression * aggregate)
  2137. {
  2138. IHqlExpression * dataset = aggregate->queryChild(0);
  2139. IHqlExpression * grouping = aggregate->queryChild(3);
  2140. //Force complex grouping fields into aliases to reduce processing...
  2141. HqlMapTransformer transformer;
  2142. transformer.setMapping(dataset, dataset);
  2143. ForEachChild(i, grouping)
  2144. {
  2145. IHqlExpression * cur = grouping->queryChild(i);
  2146. if (translator.requiresTemp(instance->nestedctx, cur, true) && (cur->getOperator() != no_alias))
  2147. {
  2148. OwnedHqlExpr alias = createAliasOwn(LINK(cur), createAttribute(internalAtom));
  2149. transformer.setMapping(cur, alias);
  2150. }
  2151. }
  2152. return transformer.transformRoot(aggregate);
  2153. }
  2154. void SourceBuilder::buildGlobalGroupAggregateHelpers(IHqlExpression * expr)
  2155. {
  2156. IHqlExpression * aggregate = expr->queryChild(0);
  2157. node_operator op = aggregate->getOperator();
  2158. assertex(op == no_newaggregate || op == no_aggregate);
  2159. StringBuffer s;
  2160. //virtual size32_t clearAggregate(void * self) = 0;
  2161. translator.doBuildAggregateClearFunc(instance->startctx, aggregate);
  2162. //virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) = 0; //only call if transform called at least once on src.
  2163. translator.doBuildAggregateMergeFunc(instance->startctx, aggregate, requiresOrderedMerge);
  2164. //virtual void processRow(void * self, const void * src) = 0;
  2165. {
  2166. BuildCtx rowctx(instance->startctx);
  2167. rowctx.addQuotedFunction("virtual void processRow(const void * src, IHThorGroupAggregateCallback * callback) override");
  2168. rowctx.addQuotedLiteral("doProcessRow((byte *)src, callback);");
  2169. }
  2170. //virtual void processRows(void * self, size32_t srcLen, const void * src) = 0;
  2171. //Only meaningful for a dataset, and even then I'm not sure it is ever used.
  2172. if (!isKey(tableExpr))
  2173. {
  2174. OwnedHqlExpr newTableExpr = LINK(tableExpr);
  2175. MemberFunction func(translator, instance->startctx, "virtual void processRows(size32_t srcLen, const void * _left, IHThorGroupAggregateCallback * callback) override");
  2176. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2177. OwnedHqlExpr ds = createVariable("left", makeReferenceModifier(newTableExpr->getType()));
  2178. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  2179. OwnedHqlExpr fullDs = createTranslated(ds, len);
  2180. BoundRow * curRow = translator.buildDatasetIterate(func.ctx, fullDs, false);
  2181. s.clear().append("doProcessRow(");
  2182. translator.generateExprCpp(s, curRow->queryBound());
  2183. s.append(", callback);");
  2184. func.ctx.addQuoted(s);
  2185. }
  2186. }
  2187. void SourceBuilder::buildGroupingMonitors(IHqlExpression * expr, CppFilterExtractor & monitors)
  2188. {
  2189. IHqlExpression * aggregate = expr->queryChild(0);
  2190. node_operator op = aggregate->getOperator();
  2191. assertex(op == no_newaggregate || op == no_aggregate);
  2192. IHqlExpression * dataset = aggregate->queryChild(0);
  2193. IHqlExpression * grouping = aggregate->queryChild(3);
  2194. //virtual void createGroupSegmentMonitors(IIndexReadContext *ctx) = 0;
  2195. MemberFunction func(translator, instance->startctx, "virtual bool createGroupSegmentMonitors(IIndexReadContext * irc) override");
  2196. monitorsForGrouping = true;
  2197. if (op == no_newaggregate)
  2198. translator.bindTableCursor(func.ctx, dataset, "_dummy");
  2199. else
  2200. translator.bindTableCursor(func.ctx, dataset, "_dummy", no_left, querySelSeq(aggregate));
  2201. unsigned maxField = 0;
  2202. ForEachChild(i, grouping)
  2203. {
  2204. unsigned nextField = 0;
  2205. if (!monitors.createGroupingMonitor(func.ctx, "irc", grouping->queryChild(i), nextField))
  2206. {
  2207. monitorsForGrouping = false;
  2208. func.setIncluded(false);
  2209. break;
  2210. }
  2211. if (maxField < nextField)
  2212. maxField = nextField;
  2213. }
  2214. if (monitorsForGrouping)
  2215. func.ctx.addReturn(queryBoolExpr(true));
  2216. if (monitorsForGrouping)
  2217. {
  2218. translator.doBuildUnsignedFunction(instance->classctx, "getGroupingMaxField", maxField);
  2219. }
  2220. }
  2221. void SourceBuilder::buildAggregateHelpers(IHqlExpression * expr)
  2222. {
  2223. IHqlExpression * aggregate = expr->queryChild(0);
  2224. node_operator op = aggregate->getOperator();
  2225. assertex(op == no_newaggregate || op == no_aggregate);
  2226. StringBuffer s;
  2227. alreadyDoneFlag.setown(instance->startctx.getTempDeclare(queryBoolType(), NULL));
  2228. instance->onstartctx.addAssign(alreadyDoneFlag, queryBoolExpr(false));
  2229. //virtual bool processedAnyRows() = 0;
  2230. translator.doBuildBoolFunction(instance->startctx, "processedAnyRows", alreadyDoneFlag);
  2231. //virtual size32_t clearAggregate(ARowBuilder & crSelf) = 0;
  2232. translator.doBuildAggregateClearFunc(instance->startctx, aggregate);
  2233. //virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) = 0; //only call if transform called at least once on src.
  2234. translator.doBuildAggregateMergeFunc(instance->startctx, aggregate, requiresOrderedMerge);
  2235. }
  2236. void SourceBuilder::buildCountHelpers(IHqlExpression * expr, bool allowMultiple)
  2237. {
  2238. StringBuffer s;
  2239. //---- virtual bool hasFilter() { return <bool>; } ----
  2240. if (transformCanFilter||isNormalize)
  2241. translator.doBuildBoolFunction(instance->classctx, "hasFilter", true);
  2242. if (allowMultiple)
  2243. {
  2244. bool isExists = hasExistChoosenLimit();
  2245. OwnedHqlExpr one = getSizetConstant(1);
  2246. if (transformCanFilter||isNormalize)
  2247. {
  2248. //virtual size32_t numValid(const void * src) = 0;
  2249. {
  2250. BuildCtx rowctx(instance->startctx);
  2251. rowctx.addQuotedFunction("virtual size32_t numValid(const void * src) override");
  2252. rowctx.addQuotedLiteral("return valid((byte *)src);");
  2253. }
  2254. //virtual size32_t numValid(size32_t srcLen, const void * src);
  2255. {
  2256. MemberFunction func(translator, instance->startctx, "virtual size32_t numValid(size32_t srcLen, const void * _src) override");
  2257. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *)_src;");
  2258. OwnedHqlExpr ds = createVariable("src", makeReferenceModifier(tableExpr->getType()));
  2259. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  2260. OwnedHqlExpr fullDs = createTranslated(ds, len);
  2261. if (isExists)
  2262. {
  2263. BuildCtx iterctx(func.ctx);
  2264. BoundRow * curRow = translator.buildDatasetIterate(iterctx, fullDs, false);
  2265. s.clear().append("if (valid(");
  2266. translator.generateExprCpp(s, curRow->queryBound());
  2267. s.append("))");
  2268. iterctx.addQuotedCompound(s, nullptr);
  2269. iterctx.addReturn(one);
  2270. func.ctx.addQuotedLiteral("return 0;");
  2271. }
  2272. else
  2273. {
  2274. func.ctx.addQuotedLiteral("size32_t cnt = 0;");
  2275. BuildCtx iterctx(func.ctx);
  2276. BoundRow * curRow = translator.buildDatasetIterate(iterctx, fullDs, false);
  2277. s.clear().append("cnt += valid(");
  2278. translator.generateExprCpp(s, curRow->queryBound());
  2279. s.append(");");
  2280. iterctx.addQuoted(s);
  2281. func.ctx.addQuotedLiteral("return cnt;");
  2282. }
  2283. }
  2284. }
  2285. else
  2286. {
  2287. //virtual size32_t numValid(size32_t srcLen, const void * src);
  2288. MemberFunction func(translator, instance->startctx, "virtual size32_t numValid(size32_t srcLen, const void * _src) override");
  2289. if (isExists)
  2290. func.ctx.addReturn(one);
  2291. else
  2292. {
  2293. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *)_src;");
  2294. CHqlBoundExpr bound;
  2295. bound.length.setown(createVariable("srcLen", LINK(sizetType)));
  2296. bound.expr.setown(createVariable("src", makeReferenceModifier(tableExpr->getType())));
  2297. OwnedHqlExpr count = translator.getBoundCount(bound);
  2298. func.ctx.addReturn(count);
  2299. }
  2300. }
  2301. }
  2302. }
  2303. void SourceBuilder::buildNormalizeHelpers(IHqlExpression * expr)
  2304. {
  2305. }
  2306. void SourceBuilder::buildCanMatch(IHqlExpression * expr)
  2307. {
  2308. if (extractCanMatch)
  2309. {
  2310. MemberFunction func(translator, instance->startctx);
  2311. func.start("virtual bool canMatch(const void * _left) override");
  2312. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2313. if (newInputMapping)
  2314. translator.bindTableCursor(func.ctx, projectedSelector, "left");
  2315. else
  2316. translator.bindTableCursor(func.ctx, tableExpr, "left");
  2317. //This will have no ill effect for disk read, and is used for blob lookup
  2318. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  2319. buildTransformFpos(func.ctx);
  2320. unsigned mark = func.numStmts();
  2321. buildMatchFilter(func.ctx, firstTransformer ? firstTransformer->queryChild(0) : expr);
  2322. if (func.numStmts() != mark)
  2323. {
  2324. func.ctx.addReturn(queryBoolExpr(true));
  2325. translator.doBuildBoolFunction(instance->classctx, "hasMatchFilter", true);
  2326. }
  2327. else
  2328. func.setIncluded(false);
  2329. }
  2330. }
  2331. void SourceBuilder::buildGroupAggregateTransformBody(BuildCtx & transformCtx, IHqlExpression * expr, bool useExtract, bool bindInputRow)
  2332. {
  2333. buildTransformBody(transformCtx, expr, false, false, bindInputRow);
  2334. IHqlExpression * aggregate = expr->queryChild(0);
  2335. OwnedHqlExpr mappedAggregate = ensureAggregateGroupingAliased(aggregate);
  2336. Owned<ParentExtract> extractBuilder;
  2337. if (useExtract || (aggregate != mappedAggregate))
  2338. {
  2339. extractBuilder.setown(translator.createExtractBuilder(transformCtx, PETcallback, NULL, GraphCoLocal, true));
  2340. if (!translator.queryOptions().serializeRowsetInExtract)
  2341. extractBuilder->setAllowDestructor();
  2342. translator.beginExtract(transformCtx, extractBuilder);
  2343. buildGroupAggregateHelpers(extractBuilder, mappedAggregate);
  2344. translator.endExtract(transformCtx, extractBuilder);
  2345. }
  2346. else
  2347. buildGroupAggregateHelpers(NULL, mappedAggregate);
  2348. HqlExprArray args;
  2349. args.append(*createVariable("callback", makeBoolType()));
  2350. if (extractBuilder)
  2351. {
  2352. CHqlBoundExpr boundExtract;
  2353. extractBuilder->endCreateExtract(boundExtract);
  2354. args.append(*boundExtract.getTranslatedExpr());
  2355. }
  2356. else
  2357. {
  2358. BoundRow * match = translator.resolveDatasetRequired(transformCtx, aggregate->queryChild(0));
  2359. Owned<ITypeInfo> rowType = makeReferenceModifier(makeRowType(queryNullRecord()->getType()));
  2360. OwnedHqlExpr rowAddr = getPointer(match->queryBound());
  2361. OwnedHqlExpr castBound = createValue(no_typetransfer, LINK(rowType), LINK(rowAddr));
  2362. args.append(*createTranslated(castBound));
  2363. }
  2364. OwnedHqlExpr call = translator.bindFunctionCall(addAggregateRowId, args);
  2365. translator.buildStmt(transformCtx, call);
  2366. }
  2367. void SourceBuilder::gatherVirtualFields(bool ignoreVirtuals, bool ensureSerialized)
  2368. {
  2369. IHqlExpression * record = tableExpr->queryRecord();
  2370. fieldInfo.gatherVirtualFields(record, ignoreVirtuals, ensureSerialized);
  2371. if (fieldInfo.hasVirtuals())
  2372. physicalRecord.setown(fieldInfo.createPhysicalRecord());
  2373. else
  2374. physicalRecord.set(record);
  2375. expectedRecord.set(physicalRecord);
  2376. projectedRecord.set(physicalRecord);
  2377. tableSelector.set(tableExpr->queryNormalizedSelector());
  2378. projectedSelector.set(tableSelector);
  2379. }
  2380. void SourceBuilder::deduceDiskRecords()
  2381. {
  2382. HqlExprAttr mode = tableExpr->queryChild(2);
  2383. node_operator modeOp = mode->getOperator();
  2384. bool isPiped = modeOp==no_pipe;
  2385. gatherVirtualFields(tableExpr->hasAttribute(_noVirtual_Atom) || isPiped, needToSerializeRecord(modeOp));
  2386. if (newInputMapping)
  2387. {
  2388. projectedRecord.set(tableExpr->queryRecord());
  2389. expectedRecord.setown(getSerializedForm(physicalRecord, diskAtom));
  2390. //MORE: HPCC-18469 Reduce projected to the fields that are actually required by the dataset, and will need to remap field references.
  2391. if (fieldInfo.hasVirtuals())
  2392. {
  2393. StringBuffer typeName;
  2394. unsigned recordTypeFlags = translator.buildRtlType(typeName, projectedRecord->queryType());
  2395. if (recordTypeFlags & RFTMcannotinterpret)
  2396. throwError(HQLERR_CannotInterpretRecord);
  2397. }
  2398. }
  2399. else
  2400. {
  2401. projectedRecord.set(tableExpr->queryRecord());
  2402. expectedRecord.setown(getSerializedForm(physicalRecord, diskAtom));
  2403. }
  2404. }
  2405. void SourceBuilder::deduceIndexRecords()
  2406. {
  2407. gatherVirtualFields(true, true);
  2408. //A slightly round about way to get the meta including keyed/blob information for the physical file.
  2409. IHqlExpression * indexExpr = queryOriginalKey(tableExpr);
  2410. OwnedHqlExpr serializedRecord;
  2411. unsigned numPayload = numPayloadFields(indexExpr);
  2412. if (numPayload)
  2413. serializedRecord.setown(notePayloadFields(indexExpr->queryRecord(), numPayload));
  2414. else
  2415. serializedRecord.set(indexExpr->queryRecord());
  2416. serializedRecord.setown(getSerializedForm(serializedRecord, diskAtom));
  2417. bool hasFilePosition = getBoolAttribute(indexExpr, filepositionAtom, true);
  2418. expectedRecord.setown(createMetadataIndexRecord(serializedRecord, hasFilePosition));
  2419. if (newInputMapping)
  2420. {
  2421. //We are expecting the translator to map the field values, this uses the expected ecl structure
  2422. projectedRecord.set(tableExpr->queryRecord());
  2423. //physical?
  2424. }
  2425. else
  2426. {
  2427. projectedRecord.set(expectedRecord); // This needs to match expectedRecord so that no translation occurs on keyed fields etc.
  2428. }
  2429. }
  2430. /*
  2431. interface ICompoundSourceSteppingMeta : extends ISteppingMeta
  2432. {
  2433. virtual ISteppingMeta * queryRawSteppingMeta() = 0;
  2434. virtual ISteppingMeta * queryProjectedSteppingMeta() = 0; // if null no projection takes place
  2435. virtual void mapOutputToIInput(void * originalRow, const void * projectedRow, unsigned firstField, unsigned numFields) = 0;
  2436. };
  2437. */
  2438. bool SourceBuilder::containsStepping(IHqlExpression * expr)
  2439. {
  2440. for (;;)
  2441. {
  2442. switch (expr->getOperator())
  2443. {
  2444. case no_stepped:
  2445. return true;
  2446. default:
  2447. {
  2448. if (expr->queryBody() == tableExpr)
  2449. return false;
  2450. unsigned numChildren = getNumChildTables(expr);
  2451. if (numChildren == 0)
  2452. return false;
  2453. assertex(numChildren == 1);
  2454. }
  2455. }
  2456. expr = expr->queryChild(0);
  2457. }
  2458. }
  2459. void SourceBuilder::gatherSteppingMeta(IHqlExpression * expr, SteppingFieldSelection & outputStepping, SteppingFieldSelection & rawStepping)
  2460. {
  2461. for (;;)
  2462. {
  2463. switch (expr->getOperator())
  2464. {
  2465. case no_newusertable:
  2466. case no_hqlproject:
  2467. if (rawStepping.exists())
  2468. {
  2469. rawStepping.expandTransform(expr);
  2470. }
  2471. else
  2472. {
  2473. gatherSteppingMeta(expr->queryChild(0), outputStepping, rawStepping);
  2474. outputStepping.clear();
  2475. return;
  2476. //throwError(HQLERR_CantProjectStepping);
  2477. //gatherSteppingMeta(expr->queryChild(0), outputStepping, rawStepping);
  2478. //apply projection to the output fields and inverse to the raw fields.
  2479. }
  2480. break;
  2481. case no_stepped:
  2482. {
  2483. outputStepping.setStepping(expr);
  2484. rawStepping.setStepping(expr);
  2485. break;
  2486. }
  2487. default:
  2488. {
  2489. if (expr->queryBody() == tableExpr)
  2490. return;
  2491. unsigned numChildren = getNumChildTables(expr);
  2492. if (numChildren == 0)
  2493. return;
  2494. assertex(numChildren == 1);
  2495. }
  2496. }
  2497. expr = expr->queryChild(0);
  2498. }
  2499. }
  2500. void SourceBuilder::gatherSteppingMeta(IHqlExpression * expr, SourceSteppingInfo & info)
  2501. {
  2502. if (!steppedExpr)
  2503. return;
  2504. gatherSteppingMeta(expr, info.outputStepping, info.rawSteppingProject);
  2505. if (info.rawSteppingProject.exists())
  2506. info.extractRaw();
  2507. }
  2508. //-----------------------------------------------------------------------------------------------
  2509. //-- Disk file processing
  2510. //-----------------------------------------------------------------------------------------------
  2511. class DiskReadBuilderBase : public SourceBuilder
  2512. {
  2513. public:
  2514. DiskReadBuilderBase(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, bool canReadGenerically)
  2515. : SourceBuilder(_translator, _tableExpr, _nameExpr), monitors(_tableExpr, _translator, 0, true, false)
  2516. {
  2517. fpos.setown(getFilepos(tableExpr, false));
  2518. lfpos.setown(getFilepos(tableExpr, true));
  2519. logicalFilenameMarker.setown(getFileLogicalName(tableExpr));
  2520. mode = tableExpr->queryChild(2);
  2521. modeOp = mode->getOperator();
  2522. genericDiskRead = genericDiskReads && canReadGenerically;
  2523. includeFormatCrc = ((modeOp != no_csv) || genericDiskRead) && (modeOp != no_pipe);
  2524. }
  2525. virtual void buildMembers(IHqlExpression * expr);
  2526. virtual void buildTransformFpos(BuildCtx & transformCtx);
  2527. virtual void extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds);
  2528. protected:
  2529. virtual void buildFlagsMember(IHqlExpression * expr);
  2530. protected:
  2531. CppFilterExtractor monitors;
  2532. OwnedHqlExpr globalGuard;
  2533. IHqlExpression * mode;
  2534. node_operator modeOp;
  2535. bool includeFormatCrc;
  2536. };
  2537. void DiskReadBuilderBase::buildMembers(IHqlExpression * expr)
  2538. {
  2539. StringBuffer s;
  2540. //Process any KEYED() information
  2541. if (monitors.isKeyed())
  2542. {
  2543. MemberFunction func(translator, instance->startctx, "virtual void createSegmentMonitors(IIndexReadContext *irc) override");
  2544. monitors.buildSegments(func.ctx, "irc", true);
  2545. }
  2546. instance->addAttributeBool(WaIsKeyed, monitors.isKeyed());
  2547. //---- virtual unsigned getFlags()
  2548. instance->addAttributeBool(WaIsPreload, isPreloaded);
  2549. bool matched = translator.registerGlobalUsage(tableExpr->queryChild(0));
  2550. if (translator.getTargetClusterType() == RoxieCluster)
  2551. {
  2552. instance->addAttributeBool(WaIsFileOpt, tableExpr->hasAttribute(optAtom));
  2553. instance->addAttributeBool(WaIsGlobalSpill, tableExpr->hasAttribute(jobTempAtom));
  2554. if (tableExpr->hasAttribute(jobTempAtom) && !matched)
  2555. throwUnexpected();
  2556. }
  2557. if (!matched && expr->hasAttribute(_spill_Atom))
  2558. {
  2559. StringBuffer spillName;
  2560. getExprECL(tableExpr->queryChild(0), spillName);
  2561. if (translator.queryOptions().allowThroughSpill)
  2562. throwError1(HQLERR_ReadSpillBeforeWriteFix, spillName.str());
  2563. else
  2564. throwError1(HQLERR_ReadSpillBeforeWrite, spillName.str());
  2565. }
  2566. if (genericDiskRead)
  2567. {
  2568. if ((modeOp != no_thor) && (modeOp != no_flat))
  2569. {
  2570. StringBuffer format;
  2571. format.append(getOpString(modeOp)).toLowerCase();
  2572. instance->startctx.addQuotedF("virtual const char * queryFormat() { return \"%s\"; }", format.str());
  2573. }
  2574. }
  2575. //---- virtual bool canMatchAny() { return <value>; } ----
  2576. LinkedHqlExpr guard = globalGuard.get();
  2577. extendConditionOwn(guard, no_and, LINK(monitors.queryGlobalGuard()));
  2578. if (guard)
  2579. translator.doBuildBoolFunction(instance->startctx, "canMatchAny", guard);
  2580. translator.buildEncryptHelper(instance->startctx, tableExpr->queryAttribute(encryptAtom));
  2581. //---- preloadSize is passed via the xgmml, not via a member
  2582. if (preloadSize)
  2583. {
  2584. instance->addAttributeInt(WaSizePreload, preloadSize->queryValue()->getIntValue());
  2585. }
  2586. if (includeFormatCrc)
  2587. {
  2588. //Spill files can still have virtual attributes in their physical records => remove them.
  2589. OwnedHqlExpr noVirtualRecord = removeVirtualAttributes(expectedRecord);
  2590. translator.buildFormatCrcFunction(instance->classctx, "getDiskFormatCrc", noVirtualRecord);
  2591. if (newInputMapping)
  2592. translator.buildFormatCrcFunction(instance->classctx, "getProjectedFormatCrc", projectedRecord);
  2593. else
  2594. translator.buildFormatCrcFunction(instance->classctx, "getProjectedFormatCrc", noVirtualRecord);
  2595. }
  2596. translator.buildMetaMember(instance->classctx, expectedRecord, isGrouped(tableExpr), "queryDiskRecordSize");
  2597. if (activityKind != TAKpiperead)
  2598. translator.buildMetaMember(instance->classctx, projectedRecord, isGrouped(tableExpr), "queryProjectedDiskRecordSize");
  2599. buildLimits(instance->startctx, expr, instance->activityId);
  2600. buildKeyedLimitHelper(expr);
  2601. //Note the helper base class contains code like the following
  2602. //IThorDiskCallback * fpp;");
  2603. //virtual void setCallback(IThorDiskCallback * _tc) { fpp = _tc; }");
  2604. }
  2605. void DiskReadBuilderBase::buildFlagsMember(IHqlExpression * expr)
  2606. {
  2607. StringBuffer flags;
  2608. if (tableExpr->hasAttribute(_spill_Atom)) flags.append("|TDXtemporary");
  2609. if (tableExpr->hasAttribute(jobTempAtom)) flags.append("|TDXjobtemp");
  2610. if (tableExpr->hasAttribute(groupedAtom)) flags.append("|TDXgrouped");
  2611. if (tableExpr->hasAttribute(__compressed__Atom)) flags.append("|TDXcompress");
  2612. if (tableExpr->hasAttribute(unsortedAtom)) flags.append("|TDRunsorted");
  2613. if (tableExpr->hasAttribute(optAtom)) flags.append("|TDRoptional");
  2614. if (tableExpr->hasAttribute(_workflowPersist_Atom)) flags.append("|TDXupdateaccessed");
  2615. if (isPreloaded) flags.append("|TDRpreload");
  2616. if (monitors.isKeyed()) flags.append("|TDRkeyed");
  2617. if (limitExpr)
  2618. {
  2619. if (limitExpr->hasAttribute(onFailAtom))
  2620. flags.append("|TDRlimitcreates");
  2621. else if (limitExpr->hasAttribute(skipAtom))
  2622. flags.append("|TDRlimitskips");
  2623. }
  2624. if (keyedLimitExpr)
  2625. {
  2626. if (keyedLimitExpr->hasAttribute(onFailAtom))
  2627. flags.append("|TDRkeyedlimitcreates|TDRcountkeyedlimit"); // is count correct?
  2628. else if (keyedLimitExpr->hasAttribute(skipAtom))
  2629. flags.append("|TDRkeyedlimitskips|TDRcountkeyedlimit");
  2630. else if (keyedLimitExpr->hasAttribute(countAtom))
  2631. flags.append("|TDRcountkeyedlimit");
  2632. }
  2633. if (onlyExistsAggreate) flags.append("|TDRaggregateexists");
  2634. if (monitorsForGrouping) flags.append("|TDRgroupmonitors");
  2635. if (!nameExpr->isConstant()) flags.append("|TDXvarfilename");
  2636. if (translator.hasDynamicFilename(tableExpr)) flags.append("|TDXdynamicfilename");
  2637. if (isUnfilteredCount) flags.append("|TDRunfilteredcount");
  2638. if (isVirtualLogicalFilenameUsed || transformUsesVirtualLogicalFilename)
  2639. flags.append("|TDRfilenamecallback");
  2640. if (transformUsesVirtualFilePosition || transformUsesVirtualLogicalFilename)
  2641. flags.append("|TDRtransformvirtual");
  2642. if (requiresOrderedMerge) flags.append("|TDRorderedmerge");
  2643. if (hasDynamicOptions) flags.append("|TDRdynformatoptions");
  2644. if (flags.length())
  2645. translator.doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  2646. //New activity doesn't currently support virtual callbacks from the transform.
  2647. //At a later date this error will be removed, and a new variant of the activity will be created
  2648. //that does not imposing the overhead of tracking filepositions on the general cases.
  2649. if (genericDiskRead && (transformUsesVirtualFilePosition || transformUsesVirtualLogicalFilename))
  2650. throwError(HQLERR_NoVirtualAndAlien);
  2651. }
  2652. void DiskReadBuilderBase::buildTransformFpos(BuildCtx & transformCtx)
  2653. {
  2654. if ((modeOp == no_csv) && !genericDiskRead)
  2655. associateFilePositions(transformCtx, "fpp", "dataSrc[0]");
  2656. else
  2657. associateFilePositions(transformCtx, "fpp", "left");
  2658. }
  2659. void DiskReadBuilderBase::extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds)
  2660. {
  2661. HqlExprAttr mode = tableExpr->queryChild(2);
  2662. //KEYED filters can only currently be implemented for binary files - not csv, xml or pipe....
  2663. if (queryTableMode(tableExpr) == no_flat)
  2664. {
  2665. if (translator.queryOptions().implicitKeyedDiskFilter)
  2666. {
  2667. HqlExprArray newconds;
  2668. ForEachItemIn(i, conds)
  2669. {
  2670. IHqlExpression * filter = &conds.item(i);
  2671. if (isSourceInvariant(ds, filter)) // more actually isSourceInvariant.
  2672. extendConditionOwn(globalGuard, no_and, LINK(filter));
  2673. else
  2674. newconds.append(OLINK(*filter));
  2675. }
  2676. OwnedHqlExpr extraFilter;
  2677. monitors.extractFilters(newconds, extraFilter);
  2678. appendFilter(unkeyedFilter, extraFilter);
  2679. }
  2680. else
  2681. {
  2682. OwnedHqlExpr implicitFilter;
  2683. ForEachItemIn(i, conds)
  2684. {
  2685. IHqlExpression * filter = &conds.item(i);
  2686. if (isSourceInvariant(ds, filter)) // more actually isSourceInvariant.
  2687. extendConditionOwn(globalGuard, no_and, LINK(filter));
  2688. else
  2689. {
  2690. node_operator op = filter->getOperator();
  2691. switch (op)
  2692. {
  2693. case no_assertkeyed:
  2694. case no_assertwild:
  2695. {
  2696. //MORE: This needs to test that the fields are at fixed offsets, fixed length, and collatable.
  2697. OwnedHqlExpr extraFilter;
  2698. monitors.extractFilters(filter, extraFilter);
  2699. //NB: Even if it is keyed then (part of) the test condition might be duplicated.
  2700. appendFilter(unkeyedFilter, extraFilter);
  2701. break;
  2702. }
  2703. default:
  2704. // Add this condition to the catchall filter
  2705. appendFilter(implicitFilter, filter);
  2706. break;
  2707. }
  2708. }
  2709. }
  2710. if (implicitFilter)
  2711. {
  2712. if (translator.queryOptions().implicitKeyedDiskFilter && !monitors.isKeyed())
  2713. {
  2714. OwnedHqlExpr extraFilter;
  2715. monitors.extractFilters(implicitFilter.get(), extraFilter);
  2716. appendFilter(unkeyedFilter, extraFilter);
  2717. }
  2718. else
  2719. appendFilter(unkeyedFilter, implicitFilter);
  2720. }
  2721. }
  2722. }
  2723. else
  2724. SourceBuilder::extractMonitors(ds, unkeyedFilter, conds);
  2725. }
  2726. //---------------------------------------------------------------------------
  2727. class DiskReadBuilder : public DiskReadBuilderBase
  2728. {
  2729. public:
  2730. DiskReadBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2731. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr, (_tableExpr->queryChild(2)->getOperator() != no_pipe))
  2732. {
  2733. extractCanMatch = (modeOp == no_thor) || (modeOp == no_flat) ||
  2734. ((modeOp == no_csv) && genericDiskRead);
  2735. }
  2736. protected:
  2737. virtual void buildTransform(IHqlExpression * expr) override;
  2738. virtual void buildMembers(IHqlExpression * expr) override;
  2739. virtual void analyseGraph(IHqlExpression * expr) override;
  2740. void buildFormatOption(BuildCtx & ctx, IHqlExpression * name, IHqlExpression * value);
  2741. void buildFormatOptions(BuildCtx & fixedCtx, BuildCtx & dynCtx, IHqlExpression * expr);
  2742. void buildFormatOptions(IHqlExpression * expr);
  2743. };
  2744. void DiskReadBuilder::analyseGraph(IHqlExpression * expr)
  2745. {
  2746. DiskReadBuilderBase::analyseGraph(expr);
  2747. if (newInputMapping && extractCanMatch && firstTransformer)
  2748. {
  2749. //Calculate the minimum set of fields required by any post-filters and projects.
  2750. projectedRecord.setown(getMinimumInputRecord(translator, firstTransformer));
  2751. if (projectedRecord != firstTransformer->queryChild(0)->queryRecord())
  2752. {
  2753. OwnedHqlExpr selSeq = createUniqueSelectorSequence();
  2754. projectedSelector.setown(createSelector(no_left, projectedRecord, selSeq));
  2755. //Check if projecting the input fields to the minimum now means the transform can be removed.
  2756. if ((firstTransformer == lastTransformer) && (projectedRecord == firstTransformer->queryRecord()))
  2757. {
  2758. if (isSimpleProject(firstTransformer))
  2759. needToCallTransform = false;
  2760. }
  2761. }
  2762. }
  2763. }
  2764. void DiskReadBuilder::buildMembers(IHqlExpression * expr)
  2765. {
  2766. if ((modeOp == no_csv) && !genericDiskRead)
  2767. buildFilenameMember();
  2768. else if (modeOp != no_pipe)
  2769. buildReadMembers(expr);
  2770. DiskReadBuilderBase::buildMembers(expr);
  2771. //---- virtual const char * getPipeProgram() { return "grep"; } ----
  2772. if (modeOp==no_pipe)
  2773. {
  2774. if (expr->hasAttribute(_disallowed_Atom))
  2775. throwError(HQLERR_PipeNotAllowed);
  2776. {
  2777. MemberFunction func(translator, instance->startctx, "virtual const char * getPipeProgram() override");
  2778. translator.buildReturn(func.ctx, mode->queryChild(0), unknownVarStringType);
  2779. }
  2780. IHqlExpression * csvFromPipe = tableExpr->queryAttribute(csvAtom);
  2781. IHqlExpression * xmlFromPipe = tableExpr->queryAttribute(xmlAtom);
  2782. bool usesContents = false;
  2783. if (csvFromPipe)
  2784. {
  2785. if (isValidCsvRecord(tableExpr->queryRecord()))
  2786. {
  2787. StringBuffer csvInstanceName;
  2788. translator.buildCsvReadTransformer(tableExpr, csvInstanceName, csvFromPipe);
  2789. StringBuffer s;
  2790. s.append("virtual ICsvToRowTransformer * queryCsvTransformer() override { return &").append(csvInstanceName).append("; }");
  2791. instance->classctx.addQuoted(s);
  2792. }
  2793. else
  2794. {
  2795. throwUnexpected(); // should be caught earlier
  2796. }
  2797. }
  2798. else if (xmlFromPipe)
  2799. {
  2800. translator.doBuildXmlReadMember(*instance, expr, "queryXmlTransformer", usesContents);
  2801. translator.doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryAttributeChild(xmlFromPipe, rowAtom, 0));
  2802. }
  2803. StringBuffer flags;
  2804. if (tableExpr->hasAttribute(groupAtom)) // not supported in parser?
  2805. flags.append("|TPFgroupeachrow");
  2806. if (tableExpr->hasAttribute(optAtom)) // not supported in parser?
  2807. flags.append("|TPFnofail");
  2808. if (csvFromPipe)
  2809. flags.append("|TPFreadcsvfrompipe");
  2810. if (xmlFromPipe)
  2811. flags.append("|TPFreadxmlfrompipe");
  2812. if (usesContents)
  2813. flags.append("|TPFreadusexmlcontents");
  2814. if (flags.length())
  2815. translator.doBuildUnsignedFunction(instance->classctx, "getPipeFlags", flags.str()+1);
  2816. }
  2817. }
  2818. void DiskReadBuilder::buildFormatOption(BuildCtx & ctx, IHqlExpression * name, IHqlExpression * value)
  2819. {
  2820. if (value->isAttribute())
  2821. {
  2822. }
  2823. else if (value->isList())
  2824. {
  2825. node_operator op = value->getOperator();
  2826. if ((op == no_list) && value->numChildren())
  2827. {
  2828. ForEachChild(i, value)
  2829. buildFormatOption(ctx, name, value->queryChild(i));
  2830. }
  2831. else if ((op == no_list) || (op == no_null))
  2832. {
  2833. //MORE: There should be a better way of doing this!
  2834. translator.buildXmlSerializeBeginNested(ctx, name, false);
  2835. translator.buildXmlSerializeEndNested(ctx, name);
  2836. }
  2837. }
  2838. else
  2839. {
  2840. translator.buildXmlSerializeScalar(ctx, value, name);
  2841. }
  2842. }
  2843. void DiskReadBuilder::buildFormatOptions(BuildCtx & fixedCtx, BuildCtx & dynCtx, IHqlExpression * expr)
  2844. {
  2845. ForEachChild(i, expr)
  2846. {
  2847. IHqlExpression * cur = expr->queryChild(i);
  2848. if (cur->isAttribute())
  2849. {
  2850. OwnedHqlExpr name = createConstant(str(cur->queryName()));
  2851. if (cur->numChildren())
  2852. {
  2853. BuildCtx & ctx = cur->isConstant() ? fixedCtx : dynCtx;
  2854. ForEachChild(c, cur)
  2855. buildFormatOption(ctx, name, cur->queryChild(c));
  2856. }
  2857. else
  2858. translator.buildXmlSerializeScalar(fixedCtx, queryBoolExpr(true), name);
  2859. }
  2860. }
  2861. }
  2862. void DiskReadBuilder::buildFormatOptions(IHqlExpression * expr)
  2863. {
  2864. MemberFunction fixedFunc(translator, instance->createctx, "virtual void getFormatOptions(IXmlWriter & out) override", MFopt);
  2865. MemberFunction dynFunc(translator, instance->startctx, "virtual void getFormatDynOptions(IXmlWriter & out) override", MFopt);
  2866. buildFormatOptions(fixedFunc.ctx, dynFunc.ctx, expr);
  2867. if (!dynFunc.isEmpty())
  2868. hasDynamicOptions = true;
  2869. }
  2870. void DiskReadBuilder::buildTransform(IHqlExpression * expr)
  2871. {
  2872. if (modeOp == no_pipe)
  2873. {
  2874. assertex(!(needToCallTransform || transformCanFilter));
  2875. return;
  2876. }
  2877. if (recordRequiresSerialization(tableExpr->queryRecord(), diskAtom))
  2878. {
  2879. //Sanity check to ensure that the projected row is only in the in memory format if no transform needs to be called.
  2880. if (needToCallTransform || transformCanFilter)
  2881. throwUnexpectedX("Projected dataset should have been serialized");
  2882. //Base implementation for a disk read throws an exception if it is called.
  2883. return;
  2884. }
  2885. if ((modeOp == no_csv) && !genericDiskRead)
  2886. {
  2887. translator.buildCsvParameters(instance->nestedctx, mode, NULL, true);
  2888. {
  2889. MemberFunction func(translator, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenSrc, const char * * dataSrc) override");
  2890. translator.ensureRowAllocated(func.ctx, "crSelf");
  2891. //associateVirtualCallbacks(*this, func.ctx, tableExpr);
  2892. buildTransformBody(func.ctx, expr, true, false, true);
  2893. }
  2894. rootSelfRow = NULL;
  2895. unsigned maxColumns = countTotalFields(tableExpr->queryRecord(), false);
  2896. translator.doBuildUnsignedFunction(instance->classctx, "getMaxColumns", maxColumns);
  2897. return;
  2898. }
  2899. if (genericDiskRead)
  2900. buildFormatOptions(mode);
  2901. MemberFunction func(translator, instance->startctx);
  2902. if ((instance->kind == TAKdiskread) || (instance->kind == TAKspillread) || (instance->kind == TAKnewdiskread))
  2903. func.start("virtual size32_t transform(ARowBuilder & crSelf, const void * _left) override");
  2904. else
  2905. func.start("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IFilePositionProvider * fpp) override");
  2906. translator.ensureRowAllocated(func.ctx, "crSelf");
  2907. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  2908. buildTransformBody(func.ctx, expr, true, false, true);
  2909. }
  2910. //---------------------------------------------------------------------------
  2911. ABoundActivity * HqlCppTranslator::doBuildActivityDiskRead(BuildCtx & ctx, IHqlExpression * expr)
  2912. {
  2913. // assertex(!isGroupedActivity(expr));
  2914. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  2915. if (!tableExpr)
  2916. return buildCachedActivity(ctx, expr->queryChild(0)); // Somehow a null appeared.
  2917. HqlExprAttr mode = tableExpr->queryChild(2);
  2918. node_operator modeOp = mode->getOperator();
  2919. bool isPiped = modeOp==no_pipe;
  2920. DiskReadBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  2921. info.deduceDiskRecords();
  2922. unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
  2923. if (info.newInputMapping && ((modeOp != no_csv) || options.genericDiskReads) && (modeOp != no_xml) && (modeOp != no_pipe))
  2924. {
  2925. //The projected disk information (which is passed to the transform) uses the in memory format IFF
  2926. // - The disk read is a trivial slimming transform (so no transform needs calling on the projected disk format.
  2927. // - It is used for all disk reads since directly transforming is always at least as efficient as going via
  2928. // the serialized form.
  2929. // Otherwise the table is converted to the serialized format.
  2930. const bool forceAllProjectedSerialized = options.forceAllProjectedDiskSerialized;
  2931. //Reading from a spill file uses the in-memory format to optimize on-demand spilling.
  2932. bool optimizeInMemorySpill = targetThor();
  2933. bool useInMemoryFormat = optimizeInMemorySpill && isSimpleProjectingDiskRead(expr);
  2934. if (forceAllProjectedSerialized || !useInMemoryFormat)
  2935. {
  2936. //else if the the table isn't serialized, then map to a serialized table, and then project to the real format
  2937. if (recordRequiresSerialization(tableExpr->queryRecord(), diskAtom))
  2938. {
  2939. OwnedHqlExpr transformed = buildTableFromSerialized(expr);
  2940. //Need to wrap a possible no_usertable, otherwise the localisation can go wrong.
  2941. if (expr->getOperator() == no_table)
  2942. transformed.setown(createDataset(no_compound_diskread, LINK(transformed)));
  2943. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  2944. traceExpression("after disk optimize", optimized);
  2945. return doBuildActivityDiskRead(ctx, optimized);
  2946. }
  2947. }
  2948. //Otherwise the dataset is in the correct format
  2949. }
  2950. else
  2951. {
  2952. if (info.recordHasVirtuals() || info.fieldInfo.requiresDeserialize)
  2953. {
  2954. OwnedHqlExpr transformed = buildTableWithoutVirtuals(info.fieldInfo, expr);
  2955. //Need to wrap a possible no_usertable, otherwise the localisation can go wrong.
  2956. if (expr->getOperator() == no_table)
  2957. transformed.setown(createDataset(no_compound_diskread, LINK(transformed)));
  2958. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  2959. traceExpression("after disk optimize", optimized);
  2960. return doBuildActivityDiskRead(ctx, optimized);
  2961. }
  2962. }
  2963. OwnedHqlExpr optimized;
  2964. if (expr->getOperator() == no_table)
  2965. optimized.set(expr);
  2966. else
  2967. optimized.setown(optimizeHqlExpression(queryErrorProcessor(), expr, optFlags));
  2968. if (optimized != expr)
  2969. return buildActivity(ctx, optimized, false);
  2970. if (isPiped)
  2971. return info.buildActivity(ctx, expr, TAKpiperead, "PipeRead", NULL);
  2972. ensureDiskAccessAllowed(tableExpr);
  2973. if (info.genericDiskRead)
  2974. return info.buildActivity(ctx, expr, TAKnewdiskread, "NewDiskRead", NULL);
  2975. if (modeOp == no_csv)
  2976. return info.buildActivity(ctx, expr, TAKcsvread, "CsvRead", NULL);
  2977. return info.buildActivity(ctx, expr, TAKdiskread, "DiskRead", NULL);
  2978. }
  2979. //---------------------------------------------------------------------------
  2980. class DiskNormalizeBuilder : public DiskReadBuilderBase
  2981. {
  2982. public:
  2983. DiskNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  2984. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr, false)
  2985. {
  2986. }
  2987. virtual void buildTransform(IHqlExpression * expr);
  2988. virtual void buildMembers(IHqlExpression * expr);
  2989. protected:
  2990. virtual void analyseGraph(IHqlExpression * expr);
  2991. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  2992. {
  2993. doBuildNormalizeIterators(ctx, expr, false);
  2994. }
  2995. };
  2996. void DiskNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  2997. {
  2998. DiskReadBuilderBase::analyseGraph(expr);
  2999. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  3000. }
  3001. void DiskNormalizeBuilder::buildMembers(IHqlExpression * expr)
  3002. {
  3003. buildFilenameMember();
  3004. DiskReadBuilderBase::buildMembers(expr);
  3005. buildNormalizeHelpers(expr);
  3006. }
  3007. void DiskNormalizeBuilder::buildTransform(IHqlExpression * expr)
  3008. {
  3009. globaliterctx.setown(new BuildCtx(instance->startctx));
  3010. globaliterctx->addGroup();
  3011. MemberFunction func(translator, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf) override");
  3012. translator.ensureRowAllocated(func.ctx, "crSelf");
  3013. buildTransformBody(func.ctx, expr, true, false, false);
  3014. }
  3015. //---------------------------------------------------------------------------
  3016. ABoundActivity * HqlCppTranslator::doBuildActivityDiskNormalize(BuildCtx & ctx, IHqlExpression * expr)
  3017. {
  3018. assertex(!isGroupedActivity(expr));
  3019. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  3020. ensureDiskAccessAllowed(tableExpr);
  3021. HqlExprAttr mode = tableExpr->queryChild(2);
  3022. assertex(mode->getOperator()!=no_pipe);
  3023. DiskNormalizeBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  3024. info.deduceDiskRecords();
  3025. LinkedHqlExpr transformed = expr;
  3026. if (info.recordHasVirtualsOrDeserialize())
  3027. transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
  3028. unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
  3029. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  3030. if (optimized != expr)
  3031. return buildActivity(ctx, optimized, false);
  3032. return info.buildActivity(ctx, expr, TAKdisknormalize, "DiskNormalize", NULL);
  3033. }
  3034. //---------------------------------------------------------------------------
  3035. class DiskAggregateBuilder : public DiskReadBuilderBase
  3036. {
  3037. public:
  3038. DiskAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3039. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr, false)
  3040. {
  3041. failedFilterValue.clear();
  3042. }
  3043. virtual void buildTransform(IHqlExpression * expr);
  3044. virtual void buildMembers(IHqlExpression * expr);
  3045. protected:
  3046. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3047. {
  3048. doBuildAggregateSelectIterator(ctx, expr);
  3049. }
  3050. virtual void analyseGraph(IHqlExpression * expr)
  3051. {
  3052. DiskReadBuilderBase::analyseGraph(expr);
  3053. returnIfFilterFails = !isNormalize;
  3054. }
  3055. };
  3056. void DiskAggregateBuilder::buildMembers(IHqlExpression * expr)
  3057. {
  3058. StringBuffer s;
  3059. buildFilenameMember();
  3060. DiskReadBuilderBase::buildMembers(expr);
  3061. buildAggregateHelpers(expr);
  3062. //virtual void processRow(void * self, const void * src) = 0;
  3063. {
  3064. BuildCtx rowctx(instance->startctx);
  3065. rowctx.addQuotedFunction("virtual void processRow(ARowBuilder & crSelf, const void * src) override");
  3066. rowctx.addQuotedLiteral("doProcessRow(crSelf, (const byte *)src);");
  3067. }
  3068. //virtual void processRows(void * self, size32_t srcLen, const void * src) = 0;
  3069. {
  3070. MemberFunction func(translator, instance->startctx, "virtual void processRows(ARowBuilder & crSelf, size32_t srcLen, const void * _left) override");
  3071. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  3072. OwnedHqlExpr ds = createVariable("left", makeReferenceModifier(tableExpr->getType()));
  3073. OwnedHqlExpr len = createVariable("srcLen", LINK(sizetType));
  3074. OwnedHqlExpr fullDs = createTranslated(ds, len);
  3075. Owned<IHqlCppDatasetCursor> iter = translator.createDatasetSelector(func.ctx, fullDs);
  3076. BoundRow * curRow = iter->buildIterateLoop(func.ctx, false);
  3077. s.clear().append("doProcessRow(crSelf, ");
  3078. translator.generateExprCpp(s, curRow->queryBound());
  3079. s.append(");");
  3080. func.ctx.addQuoted(s);
  3081. }
  3082. }
  3083. void DiskAggregateBuilder::buildTransform(IHqlExpression * expr)
  3084. {
  3085. MemberFunction func(translator, instance->startctx, "void doProcessRow(ARowBuilder & crSelf, const byte * left)");
  3086. translator.ensureRowAllocated(func.ctx, "crSelf");
  3087. buildTransformBody(func.ctx, expr, false, false, true);
  3088. }
  3089. //---------------------------------------------------------------------------
  3090. class DiskCountBuilder : public DiskReadBuilderBase
  3091. {
  3092. public:
  3093. DiskCountBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, node_operator _aggOp)
  3094. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr, false)
  3095. {
  3096. aggOp = _aggOp;
  3097. isCompoundCount = true;
  3098. failedFilterValue.set(queryZero());
  3099. }
  3100. virtual void buildTransform(IHqlExpression * expr);
  3101. virtual void buildMembers(IHqlExpression * expr);
  3102. virtual bool isExplicitExists() { return (aggOp == no_existsgroup); }
  3103. protected:
  3104. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3105. {
  3106. doBuildAggregateSelectIterator(ctx, expr);
  3107. }
  3108. virtual void analyseGraph(IHqlExpression * expr)
  3109. {
  3110. DiskReadBuilderBase::analyseGraph(expr);
  3111. returnIfFilterFails = !isNormalize;
  3112. if (aggOp == no_existsgroup)
  3113. choosenValue.setown(getSizetConstant(1));
  3114. }
  3115. protected:
  3116. node_operator aggOp;
  3117. };
  3118. void DiskCountBuilder::buildMembers(IHqlExpression * expr)
  3119. {
  3120. isUnfilteredCount = !(transformCanFilter||isNormalize);
  3121. buildFilenameMember();
  3122. DiskReadBuilderBase::buildMembers(expr);
  3123. buildCountHelpers(expr, true);
  3124. }
  3125. void DiskCountBuilder::buildTransform(IHqlExpression * expr)
  3126. {
  3127. if (transformCanFilter||isNormalize)
  3128. {
  3129. MemberFunction func(translator, instance->startctx, "size32_t valid(const byte * left)");
  3130. OwnedHqlExpr cnt;
  3131. if (isNormalize)
  3132. {
  3133. compoundCountVar.setown(func.ctx.getTempDeclare(sizetType, queryZero()));
  3134. cnt.set(compoundCountVar);
  3135. }
  3136. else
  3137. cnt.setown(getSizetConstant(1));
  3138. BuildCtx subctx(func.ctx);
  3139. buildTransformBody(subctx, expr, false, false, true);
  3140. func.ctx.addReturn(cnt);
  3141. }
  3142. }
  3143. //---------------------------------------------------------------------------
  3144. ABoundActivity * HqlCppTranslator::doBuildActivityDiskAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3145. {
  3146. assertex(!isGroupedActivity(expr));
  3147. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  3148. ensureDiskAccessAllowed(tableExpr);
  3149. HqlExprAttr mode = tableExpr->queryChild(2);
  3150. assertex(mode->getOperator()!=no_pipe);
  3151. DiskAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  3152. info.deduceDiskRecords();
  3153. LinkedHqlExpr transformed = expr;
  3154. if (info.recordHasVirtualsOrDeserialize())
  3155. transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
  3156. transformed.setown(optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags()));
  3157. if (transformed != expr)
  3158. return buildActivity(ctx, transformed, false);
  3159. node_operator aggOp = querySimpleAggregate(expr, true, false);
  3160. if (aggOp == no_countgroup || aggOp == no_existsgroup)
  3161. {
  3162. DiskCountBuilder info(*this, tableExpr, tableExpr->queryChild(0), aggOp);
  3163. info.deduceDiskRecords();
  3164. return info.buildActivity(ctx, expr, TAKdiskcount, "DiskCount", NULL);
  3165. }
  3166. else
  3167. return info.buildActivity(ctx, expr, TAKdiskaggregate, "DiskAggregate", NULL);
  3168. }
  3169. //---------------------------------------------------------------------------
  3170. class DiskGroupAggregateBuilder : public DiskReadBuilderBase
  3171. {
  3172. public:
  3173. DiskGroupAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3174. : DiskReadBuilderBase(_translator, _tableExpr, _nameExpr, false)
  3175. {
  3176. failedFilterValue.clear();
  3177. }
  3178. virtual void buildTransform(IHqlExpression * expr);
  3179. virtual void buildMembers(IHqlExpression * expr);
  3180. protected:
  3181. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3182. {
  3183. doBuildAggregateSelectIterator(ctx, expr);
  3184. }
  3185. virtual void analyseGraph(IHqlExpression * expr)
  3186. {
  3187. DiskReadBuilderBase::analyseGraph(expr);
  3188. returnIfFilterFails = !isNormalize;
  3189. }
  3190. };
  3191. void DiskGroupAggregateBuilder::buildMembers(IHqlExpression * expr)
  3192. {
  3193. buildFilenameMember();
  3194. buildGroupingMonitors(expr, monitors);
  3195. DiskReadBuilderBase::buildMembers(expr);
  3196. buildGlobalGroupAggregateHelpers(expr);
  3197. }
  3198. void DiskGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
  3199. {
  3200. MemberFunction func(translator, instance->startctx, "void doProcessRow(const byte * left, IHThorGroupAggregateCallback * callback)");
  3201. bool accessesCallback = containsOperator(expr, no_filepos) || containsOperator(expr, no_file_logicalname);
  3202. buildGroupAggregateTransformBody(func.ctx, expr, isNormalize || accessesCallback, true);
  3203. }
  3204. //---------------------------------------------------------------------------
  3205. ABoundActivity * HqlCppTranslator::doBuildActivityDiskGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3206. {
  3207. IHqlExpression *tableExpr = queryPhysicalRootTable(expr);
  3208. ensureDiskAccessAllowed(tableExpr);
  3209. HqlExprAttr mode = tableExpr->queryChild(2);
  3210. assertex(mode->getOperator()!=no_pipe);
  3211. DiskGroupAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(0));
  3212. info.deduceDiskRecords();
  3213. LinkedHqlExpr transformed = expr;
  3214. if (info.recordHasVirtualsOrDeserialize())
  3215. transformed.setown(buildTableWithoutVirtuals(info.fieldInfo, expr));
  3216. transformed.setown(optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags()));
  3217. if (transformed != expr)
  3218. return buildActivity(ctx, transformed, false);
  3219. return info.buildActivity(ctx, expr, TAKdiskgroupaggregate, "DiskGroupAggregate", NULL);
  3220. }
  3221. //-----------------------------------------------------------------------------------------------
  3222. //-- Child dataset processing
  3223. //-----------------------------------------------------------------------------------------------
  3224. class ChildBuilderBase : public SourceBuilder
  3225. {
  3226. public:
  3227. ChildBuilderBase(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3228. : SourceBuilder(_translator, _tableExpr, _nameExpr)
  3229. {
  3230. }
  3231. virtual void buildMembers(IHqlExpression * expr) {}
  3232. virtual void buildTransformFpos(BuildCtx & transformCtx) {}
  3233. };
  3234. class ChildNormalizeBuilder : public ChildBuilderBase
  3235. {
  3236. public:
  3237. ChildNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3238. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  3239. {
  3240. }
  3241. virtual void buildTransform(IHqlExpression * expr);
  3242. virtual void buildMembers(IHqlExpression * expr);
  3243. protected:
  3244. virtual void analyseGraph(IHqlExpression * expr);
  3245. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3246. {
  3247. doBuildNormalizeIterators(ctx, expr, true);
  3248. }
  3249. };
  3250. void ChildNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  3251. {
  3252. ChildBuilderBase::analyseGraph(expr);
  3253. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  3254. }
  3255. void ChildNormalizeBuilder::buildMembers(IHqlExpression * expr)
  3256. {
  3257. ChildBuilderBase::buildMembers(expr);
  3258. buildNormalizeHelpers(expr);
  3259. }
  3260. void ChildNormalizeBuilder::buildTransform(IHqlExpression * expr)
  3261. {
  3262. globaliterctx.setown(new BuildCtx(instance->startctx));
  3263. globaliterctx->addGroup();
  3264. MemberFunction func(translator, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf) override");
  3265. translator.ensureRowAllocated(func.ctx, "crSelf");
  3266. buildTransformBody(func.ctx, expr, true, false, false);
  3267. }
  3268. //---------------------------------------------------------------------------
  3269. ABoundActivity * HqlCppTranslator::doBuildActivityChildNormalize(BuildCtx & ctx, IHqlExpression * expr)
  3270. {
  3271. ChildNormalizeBuilder info(*this, NULL, NULL);
  3272. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, HOOfold);
  3273. if (optimized != expr)
  3274. return buildActivity(ctx, optimized, false);
  3275. return info.buildActivity(ctx, expr, TAKchildnormalize, "ChildNormalize", NULL);
  3276. }
  3277. //---------------------------------------------------------------------------
  3278. class ChildAggregateBuilder : public ChildBuilderBase
  3279. {
  3280. public:
  3281. ChildAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3282. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  3283. {
  3284. failedFilterValue.clear();
  3285. }
  3286. virtual void buildTransform(IHqlExpression * expr);
  3287. virtual void buildMembers(IHqlExpression * expr);
  3288. protected:
  3289. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3290. {
  3291. doBuildAggregateSelectIterator(ctx, expr);
  3292. }
  3293. virtual void analyseGraph(IHqlExpression * expr)
  3294. {
  3295. ChildBuilderBase::analyseGraph(expr);
  3296. returnIfFilterFails = false;
  3297. }
  3298. };
  3299. void ChildAggregateBuilder::buildMembers(IHqlExpression * expr)
  3300. {
  3301. ChildBuilderBase::buildMembers(expr);
  3302. buildAggregateHelpers(expr);
  3303. }
  3304. void ChildAggregateBuilder::buildTransform(IHqlExpression * expr)
  3305. {
  3306. MemberFunction func(translator, instance->startctx, "virtual void processRows(ARowBuilder & crSelf) override");
  3307. translator.ensureRowAllocated(func.ctx, "crSelf");
  3308. buildTransformBody(func.ctx, expr, false, false, false);
  3309. }
  3310. //---------------------------------------------------------------------------
  3311. ABoundActivity * HqlCppTranslator::doBuildActivityChildAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3312. {
  3313. ChildAggregateBuilder info(*this, NULL, NULL);
  3314. OwnedHqlExpr transformed = optimizeHqlExpression(queryErrorProcessor(), expr, getSourceAggregateOptimizeFlags());
  3315. if (transformed != expr)
  3316. return buildActivity(ctx, transformed, false);
  3317. return info.buildActivity(ctx, expr, TAKchildaggregate, "ChildAggregate", NULL);
  3318. }
  3319. //---------------------------------------------------------------------------
  3320. class ChildGroupAggregateBuilder : public ChildBuilderBase
  3321. {
  3322. public:
  3323. ChildGroupAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3324. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  3325. {
  3326. failedFilterValue.clear();
  3327. }
  3328. virtual void buildTransform(IHqlExpression * expr);
  3329. virtual void buildMembers(IHqlExpression * expr);
  3330. protected:
  3331. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3332. {
  3333. doBuildAggregateSelectIterator(ctx, expr);
  3334. }
  3335. virtual void analyseGraph(IHqlExpression * expr)
  3336. {
  3337. ChildBuilderBase::analyseGraph(expr);
  3338. returnIfFilterFails = false;
  3339. }
  3340. };
  3341. void ChildGroupAggregateBuilder::buildMembers(IHqlExpression * expr)
  3342. {
  3343. ChildBuilderBase::buildMembers(expr);
  3344. IHqlExpression * aggregate = expr->queryChild(0);
  3345. assertex(aggregate->getOperator() == no_newaggregate);
  3346. StringBuffer s;
  3347. //virtual size32_t clearAggregate(void * self) = 0;
  3348. translator.doBuildAggregateClearFunc(instance->startctx, aggregate);
  3349. //virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) - never actually called.
  3350. instance->startctx.addQuotedLiteral("virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * src) override { return 0; }");
  3351. }
  3352. void ChildGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
  3353. {
  3354. MemberFunction func(translator, instance->startctx, "void processRows(IHThorGroupAggregateCallback * callback)");
  3355. buildGroupAggregateTransformBody(func.ctx, expr, true, false);
  3356. }
  3357. //---------------------------------------------------------------------------
  3358. ABoundActivity * HqlCppTranslator::doBuildActivityChildGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3359. {
  3360. ChildGroupAggregateBuilder info(*this, NULL, NULL);
  3361. OwnedHqlExpr transformed = optimizeHqlExpression(queryErrorProcessor(), expr, getSourceAggregateOptimizeFlags());
  3362. if (transformed != expr)
  3363. return buildActivity(ctx, transformed, false);
  3364. return info.buildActivity(ctx, expr, TAKchildgroupaggregate, "ChildGroupAggregate", NULL);
  3365. }
  3366. //---------------------------------------------------------------------------
  3367. class ChildThroughNormalizeBuilder : public ChildBuilderBase
  3368. {
  3369. public:
  3370. ChildThroughNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3371. : ChildBuilderBase(_translator, _tableExpr, _nameExpr)
  3372. {
  3373. }
  3374. virtual void buildTransform(IHqlExpression * expr);
  3375. virtual void buildMembers(IHqlExpression * expr);
  3376. protected:
  3377. virtual void analyseGraph(IHqlExpression * expr);
  3378. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3379. {
  3380. translator.bindTableCursor(ctx, expr, "left");
  3381. doBuildNormalizeIterators(ctx, expr, false);
  3382. }
  3383. };
  3384. void ChildThroughNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  3385. {
  3386. ChildBuilderBase::analyseGraph(expr);
  3387. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  3388. }
  3389. void ChildThroughNormalizeBuilder::buildMembers(IHqlExpression * expr)
  3390. {
  3391. ChildBuilderBase::buildMembers(expr);
  3392. buildNormalizeHelpers(expr);
  3393. }
  3394. void ChildThroughNormalizeBuilder::buildTransform(IHqlExpression * expr)
  3395. {
  3396. globaliterctx.setown(new BuildCtx(instance->startctx));
  3397. globaliterctx->addGroup();
  3398. MemberFunction func(translator, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf) override");
  3399. translator.ensureRowAllocated(func.ctx, "crSelf");
  3400. buildTransformBody(func.ctx, expr, true, false, false);
  3401. }
  3402. ABoundActivity * HqlCppTranslator::doBuildActivityCompoundSelectNew(BuildCtx & ctx, IHqlExpression * expr)
  3403. {
  3404. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, HOOfold);
  3405. if (optimized->getOperator() == no_null)
  3406. return buildCachedActivity(ctx, optimized);
  3407. IHqlExpression * select = queryRoot(optimized);
  3408. if (!(select && select->getOperator() == no_select && select->hasAttribute(newAtom)))
  3409. {
  3410. if (optimized->getOperator() == no_compound_selectnew)
  3411. return buildCachedActivity(ctx, optimized->queryChild(0));
  3412. return buildCachedActivity(ctx, optimized);
  3413. }
  3414. IHqlExpression * ds = select->queryChild(0);
  3415. Owned<ABoundActivity> childActivity = buildCachedActivity(ctx, ds);
  3416. OwnedHqlExpr fakeDataset = createDataset(no_anon, LINK(ds->queryRecord()));
  3417. OwnedHqlExpr fakeSelect = createNewSelectExpr(LINK(fakeDataset), LINK(select->queryChild(1)));
  3418. OwnedHqlExpr activityExpr = replaceExpression(optimized, select, fakeSelect);
  3419. ChildThroughNormalizeBuilder info(*this, fakeDataset, NULL);
  3420. info.gatherVirtualFields(true, true); // ,false?
  3421. return info.buildActivity(ctx, activityExpr, TAKchildthroughnormalize, "ChildThroughNormalize", childActivity);
  3422. }
  3423. //---------------------------------------------------------------------------
  3424. static ABoundActivity * buildNullIndexActivity(HqlCppTranslator & translator, BuildCtx & ctx, IHqlExpression * expr)
  3425. {
  3426. while (isCompoundSource(expr))
  3427. expr = expr->queryChild(0);
  3428. return translator.buildCachedActivity(ctx, expr);
  3429. }
  3430. class IndexReadBuilderBase : public SourceBuilder
  3431. {
  3432. friend class MonitorRemovalTransformer;
  3433. public:
  3434. IndexReadBuilderBase(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3435. : SourceBuilder(_translator, _tableExpr, _nameExpr), monitors(_tableExpr, _translator, -(int)numPayloadFields(_tableExpr), false, false)
  3436. {
  3437. }
  3438. virtual void buildMembers(IHqlExpression * expr);
  3439. virtual void extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds);
  3440. protected:
  3441. virtual void buildFlagsMember(IHqlExpression * expr);
  3442. virtual void buildTransformFpos(BuildCtx & transformCtx)
  3443. {
  3444. associateFilePositions(transformCtx, "fpp", "left");
  3445. }
  3446. IHqlExpression * removeMonitors(IHqlExpression * expr);
  3447. protected:
  3448. CppFilterExtractor monitors;
  3449. SourceSteppingInfo steppingInfo;
  3450. };
  3451. void IndexReadBuilderBase::buildMembers(IHqlExpression * expr)
  3452. {
  3453. //---- virtual void createSegmentMonitors(struct IIndexReadContext *) { ... } ----
  3454. {
  3455. MemberFunction func(translator, instance->startctx, "virtual void createSegmentMonitors(IIndexReadContext *irc) override");
  3456. monitors.buildSegments(func.ctx, "irc", false);
  3457. }
  3458. buildLimits(instance->startctx, expr, instance->activityId);
  3459. if (!limitExpr && !keyedLimitExpr && !choosenValue && (instance->kind == TAKindexread || instance->kind == TAKindexnormalize) && !steppedExpr)
  3460. {
  3461. unsigned implicitLimit = translator.getDefaultImplicitIndexReadLimit();
  3462. if (translator.checkIndexReadLimit())
  3463. {
  3464. StringBuffer keyname;
  3465. if (implicitLimit)
  3466. translator.WARNINGAT2(CategoryLimit, queryLocation(expr), HQLWRN_ImplicitReadAddLimit, implicitLimit, monitors.queryKeyName(keyname));
  3467. else
  3468. translator.WARNINGAT1(CategoryLimit, queryLocation(expr), HQLWRN_ImplicitReadLimit, monitors.queryKeyName(keyname));
  3469. }
  3470. if (implicitLimit)
  3471. {
  3472. OwnedHqlExpr limit = getSizetConstant(implicitLimit);
  3473. translator.buildLimitHelpers(instance->startctx, limit, NULL, false, nameExpr, instance->activityId);
  3474. }
  3475. }
  3476. instance->addAttributeBool(WaIsPreload, isPreloaded);
  3477. if (translator.getTargetClusterType() == RoxieCluster)
  3478. instance->addAttributeBool(WaIsIndexOpt, tableExpr->hasAttribute(optAtom));
  3479. if (monitors.queryGlobalGuard())
  3480. translator.doBuildBoolFunction(instance->startctx, "canMatchAny", monitors.queryGlobalGuard());
  3481. buildKeyedLimitHelper(expr);
  3482. LinkedHqlExpr diskRecord = tableExpr->queryRecord();
  3483. if (newInputMapping)
  3484. {
  3485. HqlMapTransformer mapper;
  3486. bool hasFilePosition = getBoolAttribute(tableExpr, filepositionAtom, true);
  3487. diskRecord.setown(createPhysicalIndexRecord(mapper, diskRecord, hasFilePosition, false));
  3488. }
  3489. translator.buildFormatCrcFunction(instance->classctx, "getDiskFormatCrc", true, diskRecord, tableExpr, 1);
  3490. if (newInputMapping || (!tableExpr || !isKey(tableExpr)))
  3491. translator.buildFormatCrcFunction(instance->classctx, "getProjectedFormatCrc", projectedRecord);
  3492. else
  3493. translator.buildFormatCrcFunction(instance->classctx, "getProjectedFormatCrc", true, diskRecord, tableExpr, 1); // backward compatibility for indexes
  3494. IHqlExpression * originalKey = queryOriginalKey(tableExpr);
  3495. translator.buildSerializedLayoutMember(instance->classctx, originalKey->queryRecord(), "getIndexLayout", numKeyedFields(originalKey));
  3496. //Note the helper base class contains code like the following
  3497. //IThorIndexCallback * fpp;");
  3498. //virtual void setCallback(IThorIndexCallback * _tc) { fpp = _tc; }");
  3499. }
  3500. void IndexReadBuilderBase::buildFlagsMember(IHqlExpression * expr)
  3501. {
  3502. StringBuffer flags;
  3503. if (tableExpr->hasAttribute(sortedAtom))
  3504. flags.append("|TIRsorted");
  3505. else if (!isOrdered(tableExpr))
  3506. flags.append("|TIRunordered");
  3507. if (!monitors.isFiltered())
  3508. flags.append("|TIRnofilter");
  3509. if (isPreloaded)
  3510. flags.append("|TIRpreload");
  3511. if (tableExpr->hasAttribute(optAtom))
  3512. flags.append("|TIRoptional");
  3513. if (limitExpr && limitExpr->hasAttribute(skipAtom))
  3514. flags.append("|TIRlimitskips");
  3515. if (limitExpr && limitExpr->hasAttribute(onFailAtom))
  3516. flags.append("|TIRlimitcreates");
  3517. if (generateUnfilteredTransform)
  3518. flags.append("|TIRunfilteredtransform");
  3519. if (keyedLimitExpr)
  3520. {
  3521. if (keyedLimitExpr->hasAttribute(onFailAtom))
  3522. flags.append("|TIRkeyedlimitcreates|TIRcountkeyedlimit");
  3523. else if (keyedLimitExpr->hasAttribute(skipAtom))
  3524. flags.append("|TIRkeyedlimitskips|TIRcountkeyedlimit");
  3525. else if (keyedLimitExpr->hasAttribute(countAtom))
  3526. flags.append("|TIRcountkeyedlimit");
  3527. }
  3528. IHqlExpression * firstStepped = steppingInfo.firstStepped();
  3529. if (firstStepped && monitors.isEqualityFilterBefore(firstStepped))
  3530. flags.append("|TIRstepleadequality");
  3531. if (onlyExistsAggreate) flags.append("|TIRaggregateexists");
  3532. if (monitorsForGrouping) flags.append("|TIRgroupmonitors");
  3533. if (!nameExpr->isConstant()) flags.append("|TIRvarfilename");
  3534. if (translator.hasDynamicFilename(tableExpr)) flags.append("|TIRdynamicfilename");
  3535. if (requiresOrderedMerge) flags.append("|TIRorderedmerge");
  3536. if (translator.queryOptions().createValueSets)
  3537. flags.append("|TIRnewfilters");
  3538. if (containsOperator(expr, no_id2blob))
  3539. flags.append("|TIRusesblob");
  3540. if (flags.length())
  3541. translator.doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  3542. }
  3543. void IndexReadBuilderBase::extractMonitors(IHqlExpression * ds, SharedHqlExpr & unkeyedFilter, HqlExprArray & conds)
  3544. {
  3545. OwnedHqlExpr extraFilter;
  3546. monitors.extractFilters(conds, extraFilter);
  3547. appendFilter(unkeyedFilter, extraFilter);
  3548. }
  3549. class MonitorRemovalTransformer : public HqlMapTransformer
  3550. {
  3551. public:
  3552. MonitorRemovalTransformer(IndexReadBuilderBase & _builder) : builder(_builder) {}
  3553. virtual IHqlExpression * createTransformed(IHqlExpression * expr);
  3554. protected:
  3555. IndexReadBuilderBase & builder;
  3556. };
  3557. IHqlExpression * MonitorRemovalTransformer::createTransformed(IHqlExpression * expr)
  3558. {
  3559. switch (expr->getOperator())
  3560. {
  3561. case no_filter:
  3562. {
  3563. IHqlExpression * ds = expr->queryChild(0);
  3564. IHqlExpression * body = expr->queryBody();
  3565. unsigned match = builder.originalFilters.find(*body);
  3566. if (match == NotFound)
  3567. {
  3568. if (builder.removedFilters.contains(*body))
  3569. return transform(ds);
  3570. return NewHqlTransformer::createTransformed(expr);
  3571. }
  3572. IHqlExpression & newFilter = builder.mappedFilters.item(match);
  3573. HqlExprArray args;
  3574. args.append(*transform(ds));
  3575. args.append(*transform(&newFilter));
  3576. return expr->clone(args);
  3577. }
  3578. }
  3579. return NewHqlTransformer::createTransformed(expr);
  3580. }
  3581. IHqlExpression * IndexReadBuilderBase::removeMonitors(IHqlExpression * expr)
  3582. {
  3583. MonitorRemovalTransformer mapper(*this);
  3584. mapper.setMapping(tableExpr, tableExpr);
  3585. return mapper.transformRoot(expr);
  3586. }
  3587. //---------------------------------------------------------------------------
  3588. class NewIndexReadBuilder : public IndexReadBuilderBase
  3589. {
  3590. public:
  3591. NewIndexReadBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3592. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  3593. {
  3594. extractCanMatch = true;
  3595. }
  3596. virtual void analyseGraph(IHqlExpression * expr)
  3597. {
  3598. IndexReadBuilderBase::analyseGraph(expr);
  3599. gatherSteppingMeta(expr, steppingInfo);
  3600. if (steppedExpr && transformCanFilter && translator.queryOptions().optimizeSteppingPostfilter)
  3601. {
  3602. //If sorted, but can't step output no point in duplicating the transform
  3603. if (steppingInfo.outputStepping.exists())
  3604. generateUnfilteredTransform = true;
  3605. }
  3606. returnIfFilterFails = !isNormalize;
  3607. }
  3608. virtual void buildTransform(IHqlExpression * expr);
  3609. virtual void buildMembers(IHqlExpression * expr);
  3610. };
  3611. void NewIndexReadBuilder::buildMembers(IHqlExpression * expr)
  3612. {
  3613. if (steppingInfo.exists())
  3614. {
  3615. steppingInfo.checkKeyable(monitors);
  3616. monitors.preventMerge(steppingInfo.firstStepped());
  3617. }
  3618. buildReadMembers(expr);
  3619. if (steppingInfo.exists())
  3620. steppingInfo.generateMembers(translator, instance->classctx);
  3621. IndexReadBuilderBase::buildMembers(expr);
  3622. }
  3623. void NewIndexReadBuilder::buildTransform(IHqlExpression * expr)
  3624. {
  3625. if (true)
  3626. {
  3627. MemberFunction func(translator, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left) override");
  3628. translator.ensureRowAllocated(func.ctx, "crSelf");
  3629. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  3630. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  3631. buildTransformBody(func.ctx, expr, true, false, true);
  3632. }
  3633. if (generateUnfilteredTransform)
  3634. {
  3635. MemberFunction func(translator, instance->startctx, "virtual size32_t unfilteredTransform(ARowBuilder & crSelf, const void * _left) override");
  3636. translator.ensureRowAllocated(func.ctx, "crSelf");
  3637. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  3638. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  3639. buildTransformBody(func.ctx, expr, true, true, true);
  3640. }
  3641. }
  3642. //---------------------------------------------------------------------------
  3643. ABoundActivity * HqlCppTranslator::doBuildActivityIndexRead(BuildCtx & ctx, IHqlExpression * expr)
  3644. {
  3645. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  3646. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, HOOfold);
  3647. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  3648. //If the filter is false, then it may get reduced to a NULL operation!
  3649. if (!tableExpr)
  3650. return buildNullIndexActivity(*this, ctx, optimized);
  3651. ensureDiskAccessAllowed(tableExpr);
  3652. if (optimized->getOperator() != no_compound_indexread)
  3653. optimized.setown(createDataset(no_compound_indexread, LINK(optimized)));
  3654. traceExpression("before index read", optimized);
  3655. assertex(tableExpr->getOperator() == no_newkeyindex);
  3656. NewIndexReadBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  3657. info.deduceIndexRecords();
  3658. if (info.containsStepping(optimized))
  3659. return info.buildActivity(ctx, optimized, TAKindexread, "SteppedIndexRead", NULL);
  3660. return info.buildActivity(ctx, optimized, TAKindexread, "IndexRead", NULL);
  3661. }
  3662. //---------------------------------------------------------------------------
  3663. class IndexNormalizeBuilder : public IndexReadBuilderBase
  3664. {
  3665. public:
  3666. IndexNormalizeBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3667. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  3668. {
  3669. }
  3670. virtual void buildTransform(IHqlExpression * expr);
  3671. virtual void buildMembers(IHqlExpression * expr);
  3672. protected:
  3673. virtual void analyseGraph(IHqlExpression * expr);
  3674. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3675. {
  3676. doBuildNormalizeIterators(ctx, expr, false);
  3677. }
  3678. };
  3679. void IndexNormalizeBuilder::analyseGraph(IHqlExpression * expr)
  3680. {
  3681. IndexReadBuilderBase::analyseGraph(expr);
  3682. needDefaultTransform = (expr->queryNormalizedSelector()->getOperator() == no_select);
  3683. }
  3684. void IndexNormalizeBuilder::buildMembers(IHqlExpression * expr)
  3685. {
  3686. buildFilenameMember();
  3687. IndexReadBuilderBase::buildMembers(expr);
  3688. buildNormalizeHelpers(expr);
  3689. }
  3690. void IndexNormalizeBuilder::buildTransform(IHqlExpression * expr)
  3691. {
  3692. globaliterctx.setown(new BuildCtx(instance->startctx));
  3693. globaliterctx->addGroup();
  3694. MemberFunction func(translator, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf) override");
  3695. translator.ensureRowAllocated(func.ctx, "crSelf");
  3696. //Because this transform creates iterator classes for the child iterators the expression tree needs to be modified
  3697. //instead of using an inline tests. We could switch to using this all the time for indexes once I trust it!
  3698. OwnedHqlExpr simplified = removeMonitors(expr);
  3699. lastTransformer.set(queryExpression(simplified->queryDataset()->queryTable()));
  3700. useFilterMappings=false;
  3701. buildTransformBody(func.ctx, simplified, true, false, false);
  3702. }
  3703. //---------------------------------------------------------------------------
  3704. ABoundActivity * HqlCppTranslator::doBuildActivityIndexNormalize(BuildCtx & ctx, IHqlExpression * expr)
  3705. {
  3706. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  3707. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, HOOfold);
  3708. traceExpression("after optimize", optimized);
  3709. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  3710. if (!tableExpr)
  3711. return buildNullIndexActivity(*this, ctx, optimized);
  3712. ensureDiskAccessAllowed(tableExpr);
  3713. assertex(tableExpr->getOperator() == no_newkeyindex);
  3714. IndexNormalizeBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  3715. info.deduceIndexRecords();
  3716. return info.buildActivity(ctx, optimized, TAKindexnormalize, "IndexNormalize", NULL);
  3717. }
  3718. //---------------------------------------------------------------------------
  3719. class IndexAggregateBuilder : public IndexReadBuilderBase
  3720. {
  3721. public:
  3722. IndexAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3723. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  3724. {
  3725. failedFilterValue.clear();
  3726. }
  3727. virtual void buildTransform(IHqlExpression * expr);
  3728. virtual void buildMembers(IHqlExpression * expr);
  3729. protected:
  3730. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3731. {
  3732. doBuildAggregateSelectIterator(ctx, expr);
  3733. }
  3734. virtual void analyseGraph(IHqlExpression * expr)
  3735. {
  3736. IndexReadBuilderBase::analyseGraph(expr);
  3737. returnIfFilterFails = !isNormalize;
  3738. }
  3739. };
  3740. void IndexAggregateBuilder::buildMembers(IHqlExpression * expr)
  3741. {
  3742. StringBuffer s;
  3743. buildFilenameMember();
  3744. IndexReadBuilderBase::buildMembers(expr);
  3745. buildAggregateHelpers(expr);
  3746. //virtual void processRow(void * self, const void * src) = 0;
  3747. {
  3748. BuildCtx rowctx(instance->startctx);
  3749. rowctx.addQuotedFunction("virtual void processRow(ARowBuilder & crSelf, const void * src) override");
  3750. rowctx.addQuotedLiteral("doProcessRow(crSelf, (const byte *)src);");
  3751. }
  3752. //virtual void processRows(ARowBuilder & crSelf, size32_t srcLen, const void * _left)
  3753. //is meaningless for an index - uses the default error implementation in the base class
  3754. }
  3755. void IndexAggregateBuilder::buildTransform(IHqlExpression * expr)
  3756. {
  3757. MemberFunction func(translator, instance->startctx, "void doProcessRow(ARowBuilder & crSelf, const byte * left)");
  3758. translator.ensureRowAllocated(func.ctx, "crSelf");
  3759. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  3760. buildTransformBody(func.ctx, expr, false, false, true);
  3761. }
  3762. //---------------------------------------------------------------------------
  3763. class IndexCountBuilder : public IndexReadBuilderBase
  3764. {
  3765. public:
  3766. IndexCountBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, node_operator _aggOp)
  3767. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  3768. {
  3769. aggOp = _aggOp;
  3770. isCompoundCount = true;
  3771. failedFilterValue.set(queryZero());
  3772. }
  3773. virtual void buildTransform(IHqlExpression * expr);
  3774. virtual void buildMembers(IHqlExpression * expr);
  3775. virtual bool isExplicitExists() { return (aggOp == no_existsgroup); }
  3776. protected:
  3777. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3778. {
  3779. doBuildAggregateSelectIterator(ctx, expr);
  3780. }
  3781. virtual void analyseGraph(IHqlExpression * expr)
  3782. {
  3783. IndexReadBuilderBase::analyseGraph(expr);
  3784. returnIfFilterFails = !isNormalize;
  3785. IHqlExpression * aggregate = expr->queryChild(0);
  3786. if (isKeyedCountAggregate(aggregate))
  3787. {
  3788. if (isNormalize)
  3789. translator.throwError(HQLERR_KeyedCountCantNormalize);
  3790. if (!monitors.isKeyedExplicitly())
  3791. translator.throwError(HQLERR_KeyedCountNotKeyed);
  3792. if (transformCanFilter)
  3793. {
  3794. ForEachItemIn(i, originalFilters)
  3795. removedFilters.append(OLINK(originalFilters.item(i)));
  3796. originalFilters.kill();
  3797. mappedFilters.kill();
  3798. transformCanFilter = false;
  3799. }
  3800. }
  3801. if (aggOp == no_existsgroup)
  3802. choosenValue.setown(getSizetConstant(1));
  3803. }
  3804. protected:
  3805. node_operator aggOp;
  3806. };
  3807. void IndexCountBuilder::buildMembers(IHqlExpression * expr)
  3808. {
  3809. buildFilenameMember();
  3810. IndexReadBuilderBase::buildMembers(expr);
  3811. buildCountHelpers(expr, false);
  3812. }
  3813. void IndexCountBuilder::buildTransform(IHqlExpression * expr)
  3814. {
  3815. if (transformCanFilter||isNormalize)
  3816. {
  3817. MemberFunction func(translator, instance->startctx, "virtual size32_t numValid(const void * _left) override");
  3818. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  3819. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  3820. OwnedHqlExpr cnt;
  3821. if (isNormalize)
  3822. {
  3823. compoundCountVar.setown(func.ctx.getTempDeclare(sizetType, queryZero()));
  3824. cnt.set(compoundCountVar);
  3825. }
  3826. else
  3827. cnt.setown(getSizetConstant(1));
  3828. BuildCtx subctx(func.ctx);
  3829. buildTransformBody(subctx, expr, false, false, true);
  3830. func.ctx.addReturn(cnt);
  3831. }
  3832. }
  3833. //---------------------------------------------------------------------------
  3834. ABoundActivity * HqlCppTranslator::doBuildActivityIndexAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3835. {
  3836. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  3837. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags());
  3838. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  3839. if (!tableExpr)
  3840. return buildNullIndexActivity(*this, ctx, optimized);
  3841. ensureDiskAccessAllowed(tableExpr);
  3842. assertex(tableExpr->getOperator() == no_newkeyindex);
  3843. node_operator aggOp = querySimpleAggregate(expr, true, false);
  3844. if (aggOp == no_countgroup || aggOp == no_existsgroup)
  3845. {
  3846. IndexCountBuilder info(*this, tableExpr, tableExpr->queryChild(3), aggOp);
  3847. info.deduceIndexRecords();
  3848. return info.buildActivity(ctx, optimized, TAKindexcount, "IndexCount", NULL);
  3849. }
  3850. else
  3851. {
  3852. IndexAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  3853. info.deduceIndexRecords();
  3854. return info.buildActivity(ctx, optimized, TAKindexaggregate, "IndexAggregate", NULL);
  3855. }
  3856. }
  3857. //---------------------------------------------------------------------------
  3858. class IndexGroupAggregateBuilder : public IndexReadBuilderBase
  3859. {
  3860. public:
  3861. IndexGroupAggregateBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr)
  3862. : IndexReadBuilderBase(_translator, _tableExpr, _nameExpr)
  3863. {
  3864. failedFilterValue.clear();
  3865. transformAccessesCallback = false;
  3866. }
  3867. virtual void buildTransform(IHqlExpression * expr);
  3868. virtual void buildMembers(IHqlExpression * expr);
  3869. protected:
  3870. void doBuildProcessCountMembers(BuildCtx & ctx, IHqlExpression * aggregate);
  3871. virtual void processTransformSelect(BuildCtx & ctx, IHqlExpression * expr)
  3872. {
  3873. doBuildAggregateSelectIterator(ctx, expr);
  3874. }
  3875. virtual void analyseGraph(IHqlExpression * expr)
  3876. {
  3877. IndexReadBuilderBase::analyseGraph(expr);
  3878. returnIfFilterFails = !isNormalize;
  3879. }
  3880. protected:
  3881. bool transformAccessesCallback;
  3882. };
  3883. void IndexGroupAggregateBuilder::buildMembers(IHqlExpression * expr)
  3884. {
  3885. transformAccessesCallback = containsOperator(expr, no_filepos) || containsOperator(expr, no_id2blob);
  3886. buildFilenameMember();
  3887. buildGroupingMonitors(expr, monitors);
  3888. IndexReadBuilderBase::buildMembers(expr);
  3889. buildGlobalGroupAggregateHelpers(expr);
  3890. if (!isNormalize && !transformCanFilter && monitorsForGrouping && !transformAccessesCallback)
  3891. {
  3892. IHqlExpression * aggregate = expr->queryChild(0);
  3893. ThorActivityKind newKind = TAKnone;
  3894. switch (querySingleAggregate(aggregate, false, true, true))
  3895. {
  3896. case no_countgroup:
  3897. newKind = TAKindexgroupcount;
  3898. break;
  3899. case no_existsgroup:
  3900. newKind = TAKindexgroupexists;
  3901. break;
  3902. }
  3903. if (newKind)
  3904. {
  3905. instance->changeActivityKind(newKind);
  3906. doBuildProcessCountMembers(instance->startctx, aggregate);
  3907. }
  3908. }
  3909. }
  3910. void IndexGroupAggregateBuilder::doBuildProcessCountMembers(BuildCtx & ctx, IHqlExpression * aggregate)
  3911. {
  3912. IHqlExpression * dataset = aggregate->queryChild(0);
  3913. IHqlExpression * tgtRecord = aggregate->queryChild(1);
  3914. IHqlExpression * transform = aggregate->queryChild(2);
  3915. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  3916. {
  3917. MemberFunction func(translator, ctx, "virtual size32_t initialiseCountGrouping(ARowBuilder & crSelf, const void * _src) override");
  3918. translator.ensureRowAllocated(func.ctx, "crSelf");
  3919. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  3920. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  3921. BoundRow * selfCursor = translator.bindSelf(func.ctx, resultDataset, "crSelf");
  3922. translator.bindTableCursor(func.ctx, dataset, "src");
  3923. //Replace count() with 0, exists() with true and call as a transform - which will error if the replacement fails.
  3924. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType));
  3925. OwnedHqlExpr exists = createValue(no_existsgroup, makeBoolType());
  3926. OwnedHqlExpr newCount = createNullExpr(count);
  3927. OwnedHqlExpr newTransform = replaceExpression(transform, count, newCount);
  3928. newTransform.setown(replaceExpression(newTransform, exists, queryBoolExpr(true)));
  3929. translator.doTransform(func.ctx, newTransform, selfCursor);
  3930. translator.buildReturnRecordSize(func.ctx, selfCursor);
  3931. }
  3932. {
  3933. MemberFunction func(translator, ctx, "virtual size32_t processCountGrouping(ARowBuilder & crSelf, unsigned __int64 count) override");
  3934. translator.ensureRowAllocated(func.ctx, "crSelf");
  3935. BoundRow * selfCursor = translator.bindSelf(func.ctx, resultDataset, "crSelf");
  3936. OwnedHqlExpr newCount = createTranslatedOwned(createVariable("count", LINK(defaultIntegralType)));
  3937. OwnedHqlExpr self = getSelf(aggregate);
  3938. ForEachChild(idx, transform)
  3939. {
  3940. IHqlExpression * cur = transform->queryChild(idx);
  3941. if (cur->isAttribute())
  3942. continue;
  3943. OwnedHqlExpr target = selfCursor->bindToRow(cur->queryChild(0), self);
  3944. IHqlExpression * src = cur->queryChild(1);
  3945. IHqlExpression * arg = queryRealChild(src, 0);
  3946. BuildCtx condctx(func.ctx);
  3947. node_operator srcOp = src->getOperator();
  3948. switch (srcOp)
  3949. {
  3950. case no_countgroup:
  3951. {
  3952. if (arg)
  3953. translator.buildFilter(condctx, arg);
  3954. OwnedHqlExpr newValue = createValue(no_add, target->getType(), LINK(target), ensureExprType(newCount, target->queryType()));
  3955. translator.buildAssign(condctx, target, newValue);
  3956. }
  3957. break;
  3958. }
  3959. }
  3960. translator.buildReturnRecordSize(func.ctx, selfCursor);
  3961. }
  3962. }
  3963. void IndexGroupAggregateBuilder::buildTransform(IHqlExpression * expr)
  3964. {
  3965. MemberFunction func(translator, instance->startctx, "void doProcessRow(const byte * left, IHThorGroupAggregateCallback * callback)");
  3966. translator.associateBlobHelper(func.ctx, tableExpr, "fpp");
  3967. buildGroupAggregateTransformBody(func.ctx, expr, isNormalize || transformAccessesCallback, true);
  3968. }
  3969. //---------------------------------------------------------------------------
  3970. ABoundActivity * HqlCppTranslator::doBuildActivityIndexGroupAggregate(BuildCtx & ctx, IHqlExpression * expr)
  3971. {
  3972. OwnedHqlExpr transformed = buildIndexFromPhysical(expr);
  3973. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), transformed, getSourceAggregateOptimizeFlags());
  3974. IHqlExpression *tableExpr = queryPhysicalRootTable(optimized);
  3975. if (!tableExpr)
  3976. return buildNullIndexActivity(*this, ctx, optimized);
  3977. ensureDiskAccessAllowed(tableExpr);
  3978. IHqlExpression * aggregate = expr->queryChild(0);
  3979. assertex(aggregate->getOperator() == no_newaggregate || aggregate->getOperator() == no_aggregate);
  3980. ThorActivityKind tak = TAKindexgroupaggregate;
  3981. assertex(tableExpr->getOperator() == no_newkeyindex);
  3982. IndexGroupAggregateBuilder info(*this, tableExpr, tableExpr->queryChild(3));
  3983. info.deduceIndexRecords();
  3984. return info.buildActivity(ctx, optimized, tak, "IndexGroupAggregate", NULL);
  3985. }
  3986. //---------------------------------------------------------------------------
  3987. void associateVirtualCallbacks(HqlCppTranslator & translator, BuildCtx & ctx, IHqlExpression * dataset)
  3988. {
  3989. OwnedHqlExpr fpos = getFilepos(dataset, false);
  3990. OwnedHqlExpr lfpos = getFilepos(dataset, true);
  3991. Owned<IHqlExpression> fposExpr = createFileposCall(translator, getFilePositionId, "fpp", "crSelf.row()");
  3992. Owned<IHqlExpression> lfposExpr = createFileposCall(translator, getLocalFilePositionId, "fpp", "crSelf.row()");
  3993. ctx.associateExpr(fpos, fposExpr);
  3994. ctx.associateExpr(lfpos, lfposExpr);
  3995. }
  3996. void HqlCppTranslator::buildXmlReadTransform(IHqlExpression * dataset, StringBuffer & factoryName, bool & usesContents)
  3997. {
  3998. OwnedHqlExpr xmlMarker = createAttribute(xmlReadMarkerAtom, LINK(dataset->queryRecord()));
  3999. BuildCtx declarectx(*code, declareAtom);
  4000. HqlExprAssociation * match = declarectx.queryMatchExpr(xmlMarker);
  4001. if (match)
  4002. {
  4003. IHqlExpression * matchExpr = match->queryExpr();
  4004. matchExpr->queryChild(0)->queryValue()->getStringValue(factoryName);
  4005. usesContents = matchExpr->queryChild(1)->queryValue()->getBoolValue();
  4006. return;
  4007. }
  4008. StringBuffer s, id, className;
  4009. getUniqueId(id);
  4010. className.append("cx2r").append(id);
  4011. const char * interfaceName = "IXmlToRowTransformer";
  4012. StringBuffer prolog, epilog;
  4013. prolog.append("struct ").append(className).append(" : public RtlCInterface, implements ").append(interfaceName);
  4014. epilog.append(";");
  4015. GlobalClassBuilder builder(*this, declarectx, className, "CXmlToRowTransformer", interfaceName, true, false);
  4016. builder.buildClass(XmlTransformerPrio);
  4017. builder.setIncomplete(true);
  4018. BuildCtx & classctx = builder.classctx;
  4019. s.clear().append("inline ").append(className).append("(unsigned _activityId) : CXmlToRowTransformer(_activityId) {}");
  4020. classctx.addQuoted(s);
  4021. {
  4022. MemberFunction func(*this, classctx, "virtual size32_t transform(ARowBuilder & crSelf, IColumnProvider * row, IThorDiskCallback * fpp) override");
  4023. ensureRowAllocated(func.ctx, "crSelf");
  4024. xmlUsesContents = false;
  4025. //MORE: If this becomes a compound activity
  4026. BoundRow * rootSelfRow = bindSelf(func.ctx, dataset, "crSelf");
  4027. bindXmlTableCursor(func.ctx, dataset, "row", no_none, NULL, true);
  4028. OwnedHqlExpr activityId = createVariable("activityId", LINK(sizetType));
  4029. func.ctx.associateExpr(queryActivityIdMarker(), activityId);
  4030. associateVirtualCallbacks(*this, func.ctx, dataset);
  4031. OwnedHqlExpr active = ensureActiveRow(dataset);
  4032. buildAssign(func.ctx, rootSelfRow->querySelector(), active);
  4033. buildReturnRecordSize(func.ctx, rootSelfRow);
  4034. usesContents = xmlUsesContents;
  4035. rootSelfRow = NULL;
  4036. }
  4037. buildMetaMember(classctx, dataset, false, "queryRecordSize");
  4038. builder.setIncomplete(false);
  4039. builder.completeClass(XmlTransformerPrio);
  4040. factoryName.append(builder.accessorName);
  4041. OwnedHqlExpr matchedValue = createAttribute(internalAtom, createConstant(factoryName.str()), createConstant(usesContents));
  4042. declarectx.associateExpr(xmlMarker, matchedValue);
  4043. }
  4044. //---------------------------------------------------------------------------
  4045. unsigned HqlCppTranslator::buildCsvReadTransform(BuildCtx & subctx, IHqlExpression * dataset, bool newInterface, IHqlExpression * csvAttr)
  4046. {
  4047. MemberFunction func(*this, subctx);
  4048. if (newInterface)
  4049. func.start("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenSrc, const char * * dataSrc) override");
  4050. else
  4051. func.start("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenSrc, const char * * dataSrc, unsigned __int64 _fpos) override");
  4052. //MORE: If this becomes a compound activity
  4053. BoundRow * rootSelfRow = bindSelf(func.ctx, dataset, "crSelf");
  4054. bindCsvTableCursor(func.ctx, dataset, "Src", no_none, NULL, true, queryCsvEncoding(csvAttr));
  4055. ensureRowAllocated(func.ctx, rootSelfRow);
  4056. if (newInterface)
  4057. {
  4058. associateVirtualCallbacks(*this, func.ctx, dataset);
  4059. }
  4060. else
  4061. {
  4062. OwnedHqlExpr fpos = getFilepos(dataset, false);
  4063. OwnedHqlExpr fposVar = createVariable("_fpos", fpos->getType());
  4064. func.ctx.associateExpr(fpos, fposVar);
  4065. }
  4066. OwnedHqlExpr active = ensureActiveRow(dataset);
  4067. buildAssign(func.ctx, rootSelfRow->querySelector(), active);
  4068. buildReturnRecordSize(func.ctx, rootSelfRow);
  4069. rootSelfRow = NULL;
  4070. return countTotalFields(dataset->queryRecord(), false);
  4071. }
  4072. void HqlCppTranslator::buildCsvReadTransformer(IHqlExpression * dataset, StringBuffer & instanceName, IHqlExpression * optCsvAttr)
  4073. {
  4074. OwnedHqlExpr csvMarker = createAttribute(csvReadMarkerAtom, LINK(dataset->queryRecord()), LINK(optCsvAttr));
  4075. BuildCtx declarectx(*code, declareAtom);
  4076. HqlExprAssociation * match = declarectx.queryMatchExpr(csvMarker);
  4077. if (match)
  4078. {
  4079. IHqlExpression * matchExpr = match->queryExpr();
  4080. matchExpr->queryChild(0)->queryValue()->getStringValue(instanceName);
  4081. return;
  4082. }
  4083. StringBuffer id, className;
  4084. getUniqueId(id);
  4085. instanceName.append("c2r").append(id);
  4086. className.append("cc2r").append(id);
  4087. StringBuffer prolog, epilog;
  4088. prolog.append("struct ").append(className).append(" : public RtlCInterface, implements ICsvToRowTransformer");
  4089. epilog.append(" ").append(instanceName).append(";");
  4090. BuildCtx classctx(declarectx);
  4091. classctx.setNextPriority(XmlTransformerPrio);
  4092. IHqlStmt * transformClass = classctx.addQuotedCompound(prolog, epilog);
  4093. transformClass->setIncomplete(true);
  4094. transformClass->setIncluded(false); // if can't generate csv for this record, then don't generate an invalid class.
  4095. classctx.addQuotedLiteral("virtual void Link() const override { RtlCInterface::Link(); }");
  4096. classctx.addQuotedLiteral("virtual bool Release() const override { return RtlCInterface::Release(); }");
  4097. unsigned maxColumns = buildCsvReadTransform(classctx, dataset, false, optCsvAttr);
  4098. doBuildUnsignedFunction(classctx, "getMaxColumns", maxColumns);
  4099. buildMetaMember(classctx, dataset, false, "queryRecordSize");
  4100. buildCsvParameters(classctx, optCsvAttr, NULL, true);
  4101. transformClass->setIncomplete(false);
  4102. transformClass->setIncluded(true);
  4103. if (options.spanMultipleCpp)
  4104. {
  4105. StringBuffer helperFunc;
  4106. createAccessFunctions(helperFunc, declarectx, XmlTransformerPrio, "ICsvToRowTransformer", instanceName.str());
  4107. instanceName.clear().append(helperFunc).append("()");
  4108. }
  4109. OwnedHqlExpr matchedValue = createAttribute(internalAtom, createConstant(instanceName.str()));
  4110. declarectx.associateExpr(csvMarker, matchedValue);
  4111. }
  4112. ABoundActivity * HqlCppTranslator::doBuildActivityXmlRead(BuildCtx & ctx, IHqlExpression * expr)
  4113. {
  4114. IHqlExpression * tableExpr = expr;
  4115. ensureDiskAccessAllowed(tableExpr);
  4116. IHqlExpression * filename = tableExpr->queryChild(0);
  4117. IHqlExpression * mode = tableExpr->queryChild(2);
  4118. node_operator modeType = mode->getOperator();
  4119. StringBuffer s;
  4120. ThorActivityKind kind = (modeType == no_json) ? TAKjsonread : TAKxmlread;
  4121. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "XmlRead");
  4122. buildActivityFramework(instance);
  4123. buildInstancePrefix(instance);
  4124. //MORE: Improve when we support projecting xml instead of reading all
  4125. SourceFieldUsage * fieldUsage = querySourceFieldUsage(tableExpr);
  4126. if (fieldUsage && !fieldUsage->seenAll())
  4127. fieldUsage->noteAll();
  4128. //---- virtual const char * getFileName() { return "x.d00"; } ----
  4129. buildFilenameFunction(*instance, instance->startctx, WaFilename, "getFileName", filename, hasDynamicFilename(tableExpr));
  4130. buildEncryptHelper(instance->startctx, tableExpr->queryAttribute(encryptAtom));
  4131. bool usesContents = false;
  4132. doBuildXmlReadMember(*instance, tableExpr, "queryTransformer", usesContents);
  4133. doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryRealChild(mode, 0));
  4134. buildMetaMember(instance->classctx, tableExpr, false, "queryDiskRecordSize"); // A lie, but I don't care....
  4135. buildMetaMember(instance->classctx, tableExpr, false, "queryProjectedDiskRecordSize"); // A lie, but I don't care....
  4136. //virtual unsigned getFlags() = 0;
  4137. StringBuffer flags;
  4138. if (expr->hasAttribute(_spill_Atom)) flags.append("|TDXtemporary");
  4139. if (expr->hasAttribute(unsortedAtom)) flags.append("|TDRunsorted");
  4140. if (expr->hasAttribute(optAtom)) flags.append("|TDRoptional");
  4141. if (usesContents) flags.append("|TDRusexmlcontents");
  4142. if (mode->hasAttribute(noRootAtom)) flags.append("|TDRxmlnoroot");
  4143. if (!filename->isConstant()) flags.append("|TDXvarfilename");
  4144. if (hasDynamicFilename(expr)) flags.append("|TDXdynamicfilename");
  4145. if (flags.length())
  4146. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  4147. //Note the helper base class contains code like the following
  4148. //IThorDiskCallback * fpp;");
  4149. //virtual void setCallback(IThorDiskCallback * _tc) { fpp = _tc; }");
  4150. buildInstanceSuffix(instance);
  4151. addFileDependency(filename, instance->queryBoundActivity());
  4152. return instance->getBoundActivity();
  4153. }
  4154. //---------------------------------------------------------------------------
  4155. ABoundActivity * HqlCppTranslator::doBuildActivityTable(BuildCtx & ctx, IHqlExpression * expr)
  4156. {
  4157. node_operator mode = expr->queryChild(2)->getOperator();
  4158. switch (mode)
  4159. {
  4160. case no_thor:
  4161. case no_flat:
  4162. case no_pipe:
  4163. case no_csv:
  4164. return doBuildActivityDiskRead(ctx, expr);
  4165. case no_xml:
  4166. case no_json:
  4167. return doBuildActivityXmlRead(ctx, expr);
  4168. default:
  4169. UNIMPLEMENTED;
  4170. }
  4171. }
  4172. //---------------------------------------------------------------------------
  4173. class FetchBuilder : public SourceBuilder
  4174. {
  4175. public:
  4176. FetchBuilder(HqlCppTranslator & _translator, IHqlExpression *_tableExpr, IHqlExpression *_nameExpr, IHqlExpression * _fetchExpr)
  4177. : SourceBuilder(_translator, _tableExpr, _nameExpr)
  4178. {
  4179. compoundExpr.set(_fetchExpr);
  4180. fetchExpr.set(queryFetch(_fetchExpr));
  4181. selSeq.set(querySelSeq(fetchExpr));
  4182. fetchRhs = fetchExpr->queryChild(1);
  4183. memoryRhsRecord = fetchRhs->queryRecord();
  4184. serializedRhsRecord.setown(getSerializedForm(memoryRhsRecord, diskAtom));
  4185. }
  4186. virtual void buildMembers(IHqlExpression * expr);
  4187. virtual void buildTransform(IHqlExpression * expr);
  4188. virtual void buildTransformFpos(BuildCtx & transformCtx);
  4189. protected:
  4190. HqlExprAttr compoundExpr;
  4191. HqlExprAttr fetchExpr;
  4192. HqlExprAttr selSeq;
  4193. HqlExprAttr serializedRhsRecord;
  4194. IHqlExpression * fetchRhs;
  4195. IHqlExpression * memoryRhsRecord;
  4196. };
  4197. void FetchBuilder::buildMembers(IHqlExpression * expr)
  4198. {
  4199. buildFilenameMember();
  4200. IHqlExpression * fetch = queryFetch(expr);
  4201. {
  4202. MemberFunction func(translator, instance->startctx, "virtual unsigned __int64 extractPosition(const void * _right) override");
  4203. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  4204. translator.bindTableCursor(func.ctx, fetch->queryChild(1), "right", no_right, selSeq);
  4205. translator.buildReturn(func.ctx, fetch->queryChild(2));
  4206. }
  4207. translator.buildEncryptHelper(instance->startctx, tableExpr->queryAttribute(encryptAtom), "getFileEncryptKey");
  4208. //Fetch flags
  4209. StringBuffer flags;
  4210. if (tableExpr->hasAttribute(optAtom))
  4211. flags.append("|FFdatafileoptional");
  4212. if (!nameExpr->isConstant())
  4213. flags.append("|FFvarfilename");
  4214. if (translator.hasDynamicFilename(tableExpr))
  4215. flags.append("|FFdynamicfilename");
  4216. if (flags.length())
  4217. translator.doBuildUnsignedFunction(instance->classctx, "getFetchFlags", flags.str()+1);
  4218. if (tableExpr->hasAttribute(optAtom) && translator.targetRoxie())
  4219. instance->addAttributeBool(WaIsFileOpt, true);
  4220. buildLimits(instance->startctx, expr, instance->activityId);
  4221. switch (getDatasetKind(tableExpr))
  4222. {
  4223. case no_csv:
  4224. {
  4225. translator.buildCsvParameters(instance->nestedctx, tableExpr->queryChild(2), NULL, true);
  4226. unsigned maxColumns = getFieldCount(tableExpr->queryRecord());
  4227. StringBuffer s;
  4228. s.clear().append("virtual unsigned getMaxColumns() override { return ").append(maxColumns).append("; }");
  4229. instance->classctx.addQuoted(s);
  4230. break;
  4231. }
  4232. case no_xml:
  4233. case no_json:
  4234. break;
  4235. default:
  4236. translator.buildFormatCrcFunction(instance->classctx, "getDiskFormatCrc", physicalRecord);
  4237. break;
  4238. }
  4239. if (!containsOnlyLeft(fetch->queryChild(3), true))
  4240. {
  4241. //MORE: Need to change following if we optimize it to only extract the relevant fields.
  4242. instance->classctx.addQuotedLiteral("virtual bool extractAllJoinFields() override { return true; }");
  4243. {
  4244. MemberFunction func(translator, instance->startctx, "virtual size32_t extractJoinFields(ARowBuilder & crSelf, const void * _left) override");
  4245. translator.ensureRowAllocated(func.ctx, "crSelf");
  4246. translator.buildRecordSerializeExtract(func.ctx, memoryRhsRecord);
  4247. }
  4248. StringBuffer s;
  4249. MetaInstance meta(translator, serializedRhsRecord, false);
  4250. translator.buildMetaInfo(meta);
  4251. instance->classctx.addQuoted(s.clear().append("virtual IOutputMetaData * queryExtractedSize() override { return &").append(meta.queryInstanceObject()).append("; }"));
  4252. }
  4253. translator.buildMetaMember(instance->classctx, expectedRecord, isGrouped(tableExpr), "queryDiskRecordSize");
  4254. translator.buildMetaMember(instance->classctx, projectedRecord, isGrouped(tableExpr), "queryProjectedDiskRecordSize");
  4255. }
  4256. void FetchBuilder::buildTransform(IHqlExpression * expr)
  4257. {
  4258. translator.xmlUsesContents = false;
  4259. MemberFunction func(translator, instance->startctx);
  4260. switch (getDatasetKind(tableExpr))
  4261. {
  4262. case no_csv:
  4263. func.start("virtual size32_t transform(ARowBuilder & crSelf, unsigned * lenLeft, const char * * dataLeft, const void * _right, unsigned __int64 _fpos) override");
  4264. func.ctx.addQuotedLiteral("unsigned char * right = (unsigned char *)_right;");
  4265. break;
  4266. case no_xml:
  4267. case no_json:
  4268. func.start("virtual size32_t transform(ARowBuilder & crSelf, IColumnProvider * xmlLeft, const void * _right, unsigned __int64 _fpos) override");
  4269. func.ctx.addQuotedLiteral("unsigned char * right = (unsigned char *)_right;");
  4270. break;
  4271. default:
  4272. func.start("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned __int64 _fpos) override");
  4273. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *)_left;");
  4274. func.ctx.addQuotedLiteral("unsigned char * right = (unsigned char *)_right;");
  4275. break;
  4276. }
  4277. translator.ensureRowAllocated(func.ctx, "crSelf");
  4278. buildTransformBody(func.ctx, expr, true, false, true);
  4279. if (translator.xmlUsesContents)
  4280. instance->classctx.addQuotedLiteral("virtual bool requiresContents() override { return true; }");
  4281. }
  4282. void FetchBuilder::buildTransformFpos(BuildCtx & transformCtx)
  4283. {
  4284. fpos.setown(createVariable("_fpos", LINK(fposType)));
  4285. //NB: Because the fetch gets merged with the usertable used to project the dataset, the
  4286. //transform contains filepos(LEFT) not filepos(tableExpr)
  4287. OwnedHqlExpr leftSelect = createSelector(no_left, fetchExpr->queryChild(0), selSeq);
  4288. OwnedHqlExpr fposField = getFilepos(leftSelect, false);
  4289. transformCtx.associateExpr(fposField, fpos);
  4290. //MORE: Could possibly support virtual(filename) here
  4291. }
  4292. static HqlTransformerInfo fetchInputReplacerInfo("FetchInputReplacer");
  4293. class FetchInputReplacer : public NewHqlTransformer
  4294. {
  4295. public:
  4296. FetchInputReplacer(IHqlExpression * _newDataset, node_operator side)
  4297. : NewHqlTransformer(fetchInputReplacerInfo)
  4298. {
  4299. newDataset = _newDataset;
  4300. child = (side == no_left) ? 0 : 1;
  4301. }
  4302. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  4303. {
  4304. if (expr->getOperator() == no_fetch)
  4305. return replaceChild(expr, child, newDataset);
  4306. return NewHqlTransformer::createTransformed(expr);
  4307. }
  4308. protected:
  4309. IHqlExpression * newDataset;
  4310. unsigned child;
  4311. };
  4312. IHqlExpression * replaceFetchInput(IHqlExpression * expr, IHqlExpression * newDataset, node_operator side)
  4313. {
  4314. FetchInputReplacer replacer(newDataset, side);
  4315. return replacer.transformRoot(expr);
  4316. }
  4317. ABoundActivity * HqlCppTranslator::doBuildActivityFetch(BuildCtx & ctx, IHqlExpression * expr)
  4318. {
  4319. IHqlExpression *fetch = queryFetch(expr);
  4320. IHqlExpression *tableExpr = queryPhysicalRootTable(fetch->queryChild(0));
  4321. if (!tableExpr)
  4322. throwError(HQLERR_FetchNonDiskfile);
  4323. FetchBuilder info(*this, tableExpr, tableExpr->queryChild(0), expr);
  4324. info.deduceDiskRecords();//?needToSerializeRecord(mode)
  4325. unsigned optFlags = (options.foldOptimized ? HOOfold : 0);
  4326. if (info.recordHasVirtualsOrDeserialize())
  4327. {
  4328. OwnedHqlExpr projected = createTableWithoutVirtuals(info.fieldInfo, tableExpr);
  4329. //Nasty: We don't want to optimize the rhs, otherwise references get changed!
  4330. //so optimize everything except the rhs, and then add the rhs back in again.
  4331. IHqlExpression * fetchRhs = fetch->queryChild(1);
  4332. OwnedHqlExpr null = createDataset(no_anon, LINK(fetchRhs->queryRecord()));
  4333. OwnedHqlExpr simple = replaceFetchInput(expr, null, no_right);
  4334. OwnedHqlExpr transformed = replaceExpression(simple, tableExpr, projected);
  4335. OwnedHqlExpr optSimple = optimizeHqlExpression(queryErrorProcessor(), transformed, optFlags);
  4336. IHqlExpression * newFetch = queryFetch(optSimple);
  4337. assertex(newFetch);
  4338. IHqlExpression * lhs = newFetch->queryChild(0);
  4339. if (lhs->getOperator() != no_table)
  4340. throwError1(HQLERR_ExpectedFileLhsFetch, getOpString(lhs->getOperator()));
  4341. OwnedHqlExpr optimized = replaceFetchInput(optSimple, fetchRhs, no_right);
  4342. return doBuildActivityFetch(ctx, optimized);
  4343. }
  4344. if (getProjectCount(expr) > 1)
  4345. {
  4346. OwnedHqlExpr optimized = optimizeHqlExpression(queryErrorProcessor(), expr, optFlags);
  4347. return doBuildActivityFetch(ctx, optimized);
  4348. }
  4349. Owned<ABoundActivity> childActivity = buildCachedActivity(ctx, fetch->queryChild(1));
  4350. node_operator kind = getDatasetKind(tableExpr);
  4351. switch (kind)
  4352. {
  4353. case no_csv:
  4354. return info.buildActivity(ctx, expr, TAKcsvfetch, "CsvFetch", childActivity);
  4355. case no_xml:
  4356. return info.buildActivity(ctx, expr, TAKxmlfetch, "XmlFetch", childActivity);
  4357. case no_json:
  4358. //Note use of "XmlFetch" because we want the code generator to leverage existing xml classes
  4359. return info.buildActivity(ctx, expr, TAKjsonfetch, "XmlFetch", childActivity);
  4360. case no_flat:
  4361. case no_thor:
  4362. return info.buildActivity(ctx, expr, TAKfetch, "Fetch", childActivity);
  4363. }
  4364. throwError1(HQLERR_FetchNotSupportMode, getOpString(kind));
  4365. return NULL;
  4366. }