hqlfold.cpp 274 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431
  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 "platform.h"
  14. #include "jlib.hpp"
  15. #include "jfile.hpp"
  16. #include "jexcept.hpp"
  17. #include "jmisc.hpp"
  18. #include "jdebug.hpp"
  19. #include "defvalue.hpp"
  20. #include "hql.hpp"
  21. #include "hqlattr.hpp"
  22. #include "hqlfold.ipp"
  23. #include "eclrtl.hpp"
  24. #include "eclrtl_imp.hpp"
  25. #include "hqlerror.hpp"
  26. #include "hqlerrors.hpp"
  27. #include "hqlutil.hpp"
  28. #include "hqlpmap.hpp"
  29. #include "hqlmeta.hpp"
  30. #include "hqlfold.hpp"
  31. #include "hqlthql.hpp"
  32. #include "eclhelper.hpp"
  33. #include "math.h"
  34. #ifdef __APPLE__
  35. #include <dlfcn.h>
  36. #endif
  37. //#define LOG_ALL_FOLDING
  38. //---------------------------------------------------------------------------
  39. // The following functions do not attempt to reorder datasets, e.g., filter(project)->project(filter).
  40. // Those changes can inadvertently cause common code to be lost. Those optimizations are performed by
  41. // hqlopt which ensures it keeps track of the number of times a dataset expression is used.
  42. IHqlExpression * createNullValue(IHqlExpression * expr)
  43. {
  44. return createConstant(createNullValue(expr->queryType()));
  45. }
  46. static bool isDuplicateMapCondition(const HqlExprArray & values, IHqlExpression * cond)
  47. {
  48. ForEachItemIn(i, values)
  49. {
  50. if (values.item(i).queryChild(0) == cond)
  51. return true;
  52. }
  53. return false;
  54. }
  55. static bool areIndenticalMapResults(const HqlExprArray & values, IHqlExpression * defaultExpr)
  56. {
  57. unsigned max = values.ordinality();
  58. for (unsigned i=0; i < max; i++)
  59. {
  60. if (values.item(i).queryChild(1)->queryBody() != defaultExpr->queryBody())
  61. return false;
  62. }
  63. return true;
  64. }
  65. static bool isOrderedType(ITypeInfo * type)
  66. {
  67. switch (type->getTypeCode())
  68. {
  69. case type_boolean:
  70. return false;
  71. }
  72. return true;
  73. }
  74. static IHqlExpression * createCompareResult(node_operator op, int compare)
  75. {
  76. switch (op)
  77. {
  78. case no_eq:
  79. return createConstant(compare == 0);
  80. case no_ne:
  81. return createConstant(compare != 0);
  82. case no_lt:
  83. return createConstant(compare < 0);
  84. case no_le:
  85. return createConstant(compare <= 0);
  86. case no_gt:
  87. return createConstant(compare > 0);
  88. case no_ge:
  89. return createConstant(compare >= 0);
  90. case no_order:
  91. return createConstant(createIntValue(compare, 4, true));
  92. default:
  93. throwUnexpectedOp(op);
  94. }
  95. }
  96. /*In castExpr, constExpr: NOT linked. Out: linked */
  97. static IHqlExpression * optimizeCast(node_operator compareOp, IHqlExpression * castExpr, IHqlExpression * constExpr)
  98. {
  99. assertex(isCast(castExpr));
  100. bool createTrueConst = false;
  101. bool createFalseConst = false;
  102. node_operator newNode = no_none;
  103. //castXXX refers to types/values with the cast in place uncastXXX refer to types/values with it removed.
  104. ITypeInfo * castType = castExpr->queryType();
  105. IHqlExpression * uncastChild = castExpr->queryChild(0);
  106. ITypeInfo * uncastType = uncastChild->queryType();
  107. //If the cast loses information then we can't remove it....
  108. if (!preservesValue(castType, uncastType))
  109. return NULL;
  110. //If the comparison is non equality and the cast changes the collation sequence then you can't remove it.
  111. if ((compareOp != no_eq) && (compareOp != no_ne))
  112. {
  113. if (!preservesOrder(castType, uncastType))
  114. return NULL;
  115. //This seems an arbitrary exception, but if the comparison is ordered, and value being cast doesn't really
  116. //have a sensible ordering (i.e. boolean) then the cast shouldn't be removed.
  117. //i.e. make sure "(real)boolval < 0.5" does not become "boolval <= true".
  118. if (!isOrderedType(uncastType))
  119. return NULL;
  120. }
  121. IValue * castValue = constExpr->queryValue();
  122. OwnedIValue uncastValue(castValue->castTo(uncastType));
  123. if (uncastValue)
  124. {
  125. //Check whether casting the value to the new type can be represented. If not then
  126. int rc = castValue->rangeCompare(uncastType);
  127. if (rc != 0)
  128. {
  129. //This is effectively RHS compare min/max lhs, so invert the compare result
  130. return createCompareResult(compareOp, -rc);
  131. }
  132. else
  133. {
  134. OwnedIValue recast(uncastValue->castTo(castType));
  135. if (recast)
  136. {
  137. int test = recast->compare(castValue);
  138. //test = newValue <=> oldValue
  139. switch (compareOp)
  140. {
  141. case no_eq:
  142. if (test == 0)
  143. newNode = no_eq;
  144. else
  145. createFalseConst = true;
  146. break;
  147. case no_ne:
  148. if (test == 0)
  149. newNode = no_ne;
  150. else
  151. createTrueConst = true;
  152. break;
  153. case no_lt:
  154. //If new value less than old value, so < now becomes <=
  155. newNode = (test < 0) ? no_le : no_lt;
  156. break;
  157. case no_ge:
  158. //If new value less than old value, so >= now becomes >
  159. newNode = (test < 0) ? no_gt : no_ge;
  160. break;
  161. case no_le:
  162. //If new value is greater than old value, <= becomes <
  163. newNode = (test > 0) ? no_lt : no_le;
  164. break;
  165. case no_gt:
  166. //If new value is greater than old value, > becomes >=
  167. newNode = (test > 0) ? no_ge : no_gt;
  168. break;
  169. default:
  170. throwUnexpected();
  171. }
  172. }
  173. }
  174. }
  175. else
  176. {
  177. createTrueConst = (compareOp == no_ne);
  178. createFalseConst = (compareOp == no_eq);
  179. }
  180. if (createTrueConst)
  181. return createConstant(true);
  182. if (createFalseConst)
  183. return createConstant(false);
  184. if (newNode != no_none)
  185. return createBoolExpr(newNode, LINK(uncastChild), createConstant(uncastValue.getClear()));
  186. return NULL;
  187. }
  188. //In castExpr: not linked. Out: linked
  189. static IHqlExpression * optimizeCastList(IHqlExpression * castExpr, HqlExprArray & inList, node_operator op)
  190. {
  191. assertex(isCast(castExpr));
  192. IHqlExpression * castChild = castExpr->queryChild(0);
  193. ITypeInfo * targetType = castChild->queryType();
  194. ITypeInfo * currentType = castExpr->queryType();
  195. //If the cast loses information then we can't remove it....
  196. if (!preservesValue(currentType, targetType))
  197. return NULL;
  198. //(cast)search in <list>
  199. //Produce a new list of values which only includes values that could possibly match the search value
  200. HqlExprArray newInConstants;
  201. ForEachItemIn(i, inList)
  202. {
  203. bool skip = true;
  204. IValue * constValue = inList.item(i).queryValue();
  205. if (!constValue)
  206. return NULL;
  207. OwnedIValue cast(constValue->castTo(targetType));
  208. if (cast)
  209. {
  210. int rc = constValue->rangeCompare(targetType);
  211. if (rc == 0)
  212. {
  213. OwnedIValue recast(cast->castTo(constValue->queryType()));
  214. if (recast)
  215. {
  216. int test = recast->compare(constValue);
  217. if (test == 0)
  218. skip = false;
  219. }
  220. }
  221. }
  222. if (!skip)
  223. newInConstants.append(*createConstant(cast.getClear()));
  224. }
  225. if (newInConstants.ordinality())
  226. {
  227. IHqlExpression * newList = createValue(no_list, makeSetType(LINK(targetType)), newInConstants);
  228. return createBoolExpr(op, LINK(castChild), newList);
  229. }
  230. return createConstant(op == no_notin);
  231. }
  232. static bool isInList(IValue * v, IHqlExpression * list)
  233. {
  234. if (list->getOperator()==no_all)
  235. return true;
  236. unsigned num = list->numChildren();
  237. for (unsigned idx = 0; idx < num; idx++)
  238. {
  239. IHqlExpression * elem = list->queryChild(idx);
  240. IValue * constValue = elem->queryValue();
  241. if (constValue)
  242. {
  243. if (orderValues(v, constValue) == 0)
  244. return true;
  245. }
  246. }
  247. return false;
  248. }
  249. static IValue * compareValues(node_operator op, IValue * leftValue, IValue * rightValue)
  250. {
  251. IValue * newConst;
  252. switch (op)
  253. {
  254. case no_eq:
  255. newConst = equalValues(leftValue,rightValue);
  256. break;
  257. case no_ne:
  258. newConst = notEqualValues(leftValue,rightValue);
  259. break;
  260. case no_lt:
  261. newConst = lessValues(leftValue,rightValue);
  262. break;
  263. case no_le:
  264. newConst = lessEqualValues(leftValue,rightValue);
  265. break;
  266. case no_gt:
  267. newConst = greaterValues(leftValue,rightValue);
  268. break;
  269. case no_ge:
  270. newConst = greaterEqualValues(leftValue,rightValue);
  271. break;
  272. case no_order:
  273. newConst = createIntValue(leftValue->compare(rightValue), 4, true);
  274. break;
  275. default:
  276. throwUnexpectedOp(op);
  277. }
  278. return newConst;
  279. }
  280. static IHqlExpression * compareLists(node_operator op, IHqlExpression * leftList, IHqlExpression * rightList)
  281. {
  282. unsigned lnum = leftList->numChildren();
  283. unsigned rnum = rightList->numChildren();
  284. int order = 0;
  285. unsigned num = lnum > rnum ? rnum : lnum;
  286. for (unsigned i=0; i < num; i++)
  287. {
  288. IValue * leftValue = leftList->queryChild(i)->queryValue();
  289. IValue * rightValue = rightList->queryChild(i)->queryValue();
  290. if (!leftValue || !rightValue)
  291. return NULL;
  292. order = orderValues(leftValue, rightValue);
  293. if (order != 0)
  294. return createCompareResult(op, order);
  295. }
  296. if (lnum != rnum)
  297. order = lnum > rnum ? +1 : -1;
  298. return createCompareResult(op, order);
  299. }
  300. static IHqlExpression * optimizeListConstant(node_operator op, IHqlExpression * list, IValue * constVal)
  301. {
  302. if ((list->getOperator() != no_list) || !list->isConstant())
  303. return NULL;
  304. //I don't really know what this function is trying to do. I think it is trying to optimize the case where
  305. //comparing against any of the values in the list will give the same result.
  306. OwnedIValue nullVal = createNullValue(list->queryType()->queryChildType());
  307. OwnedIValue result = compareValues(op, nullVal, constVal);
  308. ForEachChild(i, list)
  309. {
  310. IValue * curValue = list->queryChild(i)->queryValue();
  311. if (!curValue)
  312. return NULL;
  313. Owned<IValue> curResult = compareValues(op, curValue, constVal);
  314. if (curResult->compare(result) != 0)
  315. return NULL;
  316. }
  317. return createConstant(result.getClear());
  318. }
  319. static bool flattenConstantCase(IHqlExpression * caseExpr, HqlExprArray & constants, bool out)
  320. {
  321. assertex(caseExpr->getOperator()==no_case);
  322. unsigned num = caseExpr->numChildren()-1;
  323. for (unsigned i=1; i<num; i++)
  324. {
  325. IHqlExpression * map = caseExpr->queryChild(i);
  326. IHqlExpression * val = map->queryChild(out);
  327. if (!val->queryValue())
  328. return false;
  329. constants.append(*LINK(val));
  330. }
  331. return true;
  332. }
  333. static IHqlExpression * optimizeCaseConstant(node_operator op, IHqlExpression * caseExpr, IValue * constVal, bool swap)
  334. {
  335. HqlExprArray caseResults;
  336. if (flattenConstantCase(caseExpr, caseResults, true))
  337. {
  338. IValue * defValue = caseExpr->queryChild(caseExpr->numChildren()-1)->queryValue();
  339. if (defValue)
  340. {
  341. switch (op)
  342. {
  343. case no_eq:
  344. case no_ne:
  345. {
  346. //CASE(x,a1=>v1,a2=>v2,a3=>v3,v0) [not]= y
  347. //If y ==a0 then transform to x [NOT] IN [a<n>] where v<n>!=y
  348. bool matchesDefault = (defValue->compare(constVal) == 0);
  349. HqlExprCopyArray matches;
  350. HqlExprArray exceptions;
  351. for (unsigned i=0; i<caseResults.ordinality(); i++)
  352. {
  353. IHqlExpression * key = caseExpr->queryChild(i+1)->queryChild(0);
  354. IHqlExpression * val = &caseResults.item(i);
  355. bool caseMatches = (val->queryValue()->compare(constVal) == 0);
  356. if (caseMatches == matchesDefault)
  357. matches.append(*key->queryBody());
  358. else if (!matches.contains(*key->queryBody()))
  359. exceptions.append(*LINK(key));
  360. }
  361. bool defaultsToTrue = (matchesDefault && (op == no_eq)) || (!matchesDefault && (op == no_ne));
  362. if (exceptions.ordinality() == 0)
  363. return createConstant(defaultsToTrue);
  364. node_operator inOp = defaultsToTrue ? no_notin : no_in;
  365. IHqlExpression * test = caseExpr->queryChild(0);
  366. return createBoolExpr(inOp,
  367. LINK(test),
  368. createValue(no_list, makeSetType(test->getType()), exceptions));
  369. }
  370. }
  371. }
  372. }
  373. return NULL;
  374. }
  375. static IHqlExpression * optimizeCompare(IHqlExpression * expr)
  376. {
  377. IHqlExpression * leftChild = expr->queryChild(0);
  378. IHqlExpression * rightChild = expr->queryChild(1);
  379. node_operator op = expr->getOperator();
  380. node_operator leftOp = leftChild->getOperator();
  381. node_operator rightOp = rightChild->getOperator();
  382. if ((leftChild->queryBody() == rightChild->queryBody()) ||
  383. (leftOp == no_all && rightOp == no_all))
  384. {
  385. return createCompareResult(op, 0);
  386. }
  387. if ((leftOp == no_all) && rightChild->isConstant())
  388. return createCompareResult(op, +1);
  389. if ((rightOp == no_all) && leftChild->isConstant())
  390. return createCompareResult(op, -1);
  391. if (((leftOp == no_sortlist) || (leftOp == no_list)) && ((rightOp == no_sortlist) || (rightOp == no_list)))
  392. return compareLists(op, leftChild, rightChild);
  393. IValue * leftValue = leftChild->queryValue();
  394. IValue * rightValue = rightChild->queryValue();
  395. if (leftValue && rightValue)
  396. {
  397. int order = orderValues(leftValue, rightValue);
  398. return createCompareResult(op, order);
  399. }
  400. if (op == no_order)
  401. return NULL;
  402. bool swap = false;
  403. IHqlExpression * castChild = NULL;
  404. IHqlExpression * constChild = NULL;
  405. if (leftValue)
  406. {
  407. ITypeInfo * rType = rightChild->queryType();
  408. if (rType->isUnsignedNumeric() && isZero(leftChild))
  409. {
  410. switch (op)
  411. {
  412. case no_le:
  413. return createConstant(true);
  414. case no_gt:
  415. return createConstant(false);
  416. }
  417. }
  418. if (rType->getTypeCode() == type_boolean)
  419. {
  420. bool val = leftValue->getBoolValue();
  421. switch (op)
  422. {
  423. case no_eq:
  424. if (val)
  425. return LINK(rightChild);
  426. return getInverse(rightChild);
  427. case no_ne:
  428. if (!val)
  429. return LINK(rightChild);
  430. return getInverse(rightChild);
  431. }
  432. }
  433. swap = true;
  434. switch(rightChild->getOperator())
  435. {
  436. case no_cast:
  437. case no_implicitcast:
  438. castChild = rightChild;
  439. constChild = leftChild;
  440. break;
  441. case no_index:
  442. return optimizeListConstant(getReverseOp(op), rightChild->queryChild(0), leftValue);
  443. }
  444. }
  445. else if (rightValue)
  446. {
  447. ITypeInfo * lType = leftChild->queryType();
  448. if (lType->isUnsignedNumeric() && isZero(rightChild))
  449. {
  450. switch (op)
  451. {
  452. case no_ge:
  453. return createConstant(true);
  454. case no_lt:
  455. return createConstant(false);
  456. }
  457. }
  458. if (lType->getTypeCode() == type_boolean)
  459. {
  460. bool val = rightValue->getBoolValue();
  461. switch (op)
  462. {
  463. case no_eq:
  464. if (val)
  465. return LINK(leftChild);
  466. return getInverse(leftChild);
  467. case no_ne:
  468. if (!val)
  469. return LINK(leftChild);
  470. return getInverse(leftChild);
  471. }
  472. }
  473. switch(leftChild->getOperator())
  474. {
  475. case no_cast:
  476. case no_implicitcast:
  477. castChild = leftChild;
  478. constChild = rightChild;
  479. break;
  480. case no_index:
  481. return optimizeListConstant(op, leftChild->queryChild(0), rightValue);
  482. case no_case:
  483. return optimizeCaseConstant(op, leftChild, rightValue, false);
  484. }
  485. }
  486. if (castChild)
  487. {
  488. OwnedHqlExpr value = optimizeCast(swap ? getReverseOp(op) : op, castChild, constChild);
  489. if (value)
  490. return value.getClear();
  491. }
  492. if (swap)
  493. {
  494. //Normalize simple comparisons so they are always (field op value)
  495. return createValue(getReverseOp(op), makeBoolType(), LINK(rightChild), LINK(leftChild));
  496. }
  497. return NULL;
  498. }
  499. static bool isSimpleComparisonArg(IHqlExpression * expr)
  500. {
  501. switch (expr->getOperator())
  502. {
  503. case no_constant:
  504. case no_getresult:
  505. return true;
  506. }
  507. return false;
  508. }
  509. //---------------------------------------------------------------------------
  510. /*********************************************************
  511. * Constant folding for an external function call
  512. * Supports the following external function parameter types:
  513. * - INTEGER (Tested)
  514. * - REAL
  515. * - STRINGN (Tested)
  516. * - STRING (Tested)
  517. * - VARSTRINGN
  518. * - VARSTRING
  519. * - BOOLEAN
  520. * Supports the following external function return types:
  521. * - INTEGER (TESTED)
  522. * - STRING (tested)
  523. * - STRINGN (Tested)
  524. * - VARSTRING
  525. * - VARSTRINGN
  526. * - REAL
  527. * - BOOLEAN
  528. * NOTE: Tested with the functions in default.StringLib. The
  529. * functions need to be declared with extern "C".
  530. *********************************************************/
  531. //MORE: This function never unloads the plugin dll - this may cause problems in the long run.
  532. bool checkExternFoldable(IHqlExpression* expr, unsigned foldOptions, StringBuffer &library, StringBuffer &entry)
  533. {
  534. IHqlExpression * funcdef = expr->queryExternalDefinition();
  535. if(!funcdef)
  536. return false;
  537. IHqlExpression *body = funcdef->queryChild(0);
  538. if(!body)
  539. return false;
  540. //Check all parameters are constant - saves dll load etc.
  541. unsigned numParam = expr->numChildren();
  542. for(unsigned iparam = 0; iparam < numParam; iparam++)
  543. {
  544. switch (expr->queryChild(iparam)->getOperator())
  545. {
  546. case no_constant: case no_null: case no_all: // NOTE: no_all still needs work elsewhere before it will be supported fully
  547. break;
  548. default:
  549. return false;
  550. }
  551. }
  552. IHqlExpression * formals = funcdef->queryChild(1);
  553. unsigned numArg = formals->numChildren();
  554. if(numParam > numArg)
  555. {
  556. if (foldOptions & HFOthrowerror)
  557. throw MakeStringException(ERR_PARAM_TOOMANY,"Too many parameters passed to function '%s': expected %d, given %d",
  558. str(expr->queryName()), numParam, numArg);
  559. return false;
  560. }
  561. else if(numParam < numArg)
  562. {
  563. if (foldOptions & HFOthrowerror)
  564. throw MakeStringException(ERR_PARAM_TOOFEW,"Not enough parameters passed to function '%s': expected %d, given %d",
  565. str(expr->queryName()), numParam, numArg);
  566. return false;
  567. }
  568. StringBuffer mangledEntry;
  569. getAttribute(body, entrypointAtom, entry);
  570. getAttribute(body, libraryAtom, library);
  571. if (!library.length())
  572. getAttribute(body, pluginAtom, library);
  573. if(entry.length() == 0)
  574. {
  575. if (foldOptions & HFOthrowerror)
  576. throw MakeStringException(ERR_SVC_NOENTRYPOINT,"Missing entrypoint for function folding");
  577. return false;
  578. }
  579. if (library.length() == 0)
  580. {
  581. if (foldOptions & HFOthrowerror)
  582. throw MakeStringException(ERR_SVC_NOLIBRARY,"Missing library for function folding");
  583. return false;
  584. }
  585. if (!pathExtension(library))
  586. {
  587. library.insert(0, SharedObjectPrefix);
  588. ensureFileExtension(library, SharedObjectExtension);
  589. }
  590. if (!body->hasAttribute(foldAtom) || body->hasAttribute(nofoldAtom))
  591. {
  592. if (foldOptions & HFOthrowerror)
  593. throw MakeStringException(ERR_TMPLT_NOFOLDFUNC, "%s does not have FOLD specified, can't constant fold it", str(expr->queryName()));
  594. return false;
  595. }
  596. if (body->hasAttribute(_disallowed_Atom))
  597. {
  598. if (foldOptions & HFOthrowerror)
  599. throw MakeStringException(ERR_TMPLT_NOFOLDFUNC, "You do not have permission to constant-fold %s", str(expr->queryName()));
  600. return false;
  601. }
  602. if(!body->hasAttribute(pureAtom) && !body->hasAttribute(templateAtom) && !(foldOptions & (HFOfoldimpure|HFOforcefold)))
  603. {
  604. if (foldOptions & HFOthrowerror)
  605. throw MakeStringException(ERR_TMPLT_NONPUREFUNC, "%s/%s is not a pure function, can't constant fold it", library.str(), entry.str());
  606. return false;
  607. }
  608. if(body->hasAttribute(contextAtom) || body->hasAttribute(globalContextAtom) ||
  609. body->hasAttribute(gctxmethodAtom) || body->hasAttribute(ctxmethodAtom) || body->hasAttribute(omethodAtom))
  610. {
  611. if (foldOptions & HFOthrowerror)
  612. throw MakeStringException(ERR_TMPLT_NONEXTERNCFUNC, "%s/%s requires a runtime context to be executed, can't constant fold it", library.str(), entry.str());
  613. return false;
  614. }
  615. if(!body->hasAttribute(cAtom))
  616. {
  617. if (!createMangledFunctionName(mangledEntry, funcdef))
  618. {
  619. if (foldOptions & HFOthrowerror)
  620. throw MakeStringException(ERR_TMPLT_NONEXTERNCFUNC, "%s/%s is not declared as extern C, can't constant fold it", library.str(), entry.str());
  621. return false;
  622. }
  623. entry.set(mangledEntry);
  624. }
  625. return true;
  626. }
  627. void *loadExternalEntryPoint(IHqlExpression* expr, unsigned foldOptions, ITemplateContext *templateContext, const char *library, const char *entrypoint, HINSTANCE &hDLL)
  628. {
  629. IHqlExpression * funcdef = expr->queryExternalDefinition();
  630. IHqlExpression *body = funcdef->queryChild(0);
  631. // Get the handle to the library and procedure.
  632. #ifndef _WIN32
  633. StringBuffer fullLibraryPath;
  634. if (findLoadedModule(fullLibraryPath, library))
  635. library = fullLibraryPath.str();
  636. #endif
  637. hDLL=LoadSharedObject(library, false, false);
  638. if (!LoadSucceeded(hDLL))
  639. {
  640. if (body->hasAttribute(templateAtom))
  641. throw MakeStringException(ERR_SVC_LOADLIBFAILED, "Error when trying to load library %s for template helper function", library);
  642. if (foldOptions & HFOthrowerror)
  643. throw MakeStringException(ERR_SVC_LOADLIBFAILED, "Error when trying to load library %s", library);
  644. return NULL;
  645. }
  646. void* fh = GetSharedProcedure(hDLL, entrypoint);
  647. if (!fh)
  648. {
  649. FreeSharedObject(hDLL);
  650. if (foldOptions & HFOthrowerror)
  651. throw MakeStringException(ERR_SVC_LOADFUNCFAILED, "Error when trying to load procedure %s from library %s", entrypoint, library);
  652. return NULL;
  653. }
  654. return fh;
  655. }
  656. #if defined(_WIN32) && defined(_ARCH_X86_64_)
  657. extern __int64 foldExternalCallStub(void * fh, double * doubleresult, size_t len, void * params);
  658. #endif
  659. IValue * doFoldExternalCall(IHqlExpression* expr, unsigned foldOptions, ITemplateContext *templateContext, const char *library, const char *entrypoint, void *fh)
  660. {
  661. // NOTE - on OSX there are compiler bugs that prevent exceptions thrown from within this function from properly unwinding.
  662. // Hence anything that can throw an exception should be pre-checked in one of the functions above.
  663. IHqlExpression * funcdef = expr->queryExternalDefinition();
  664. IHqlExpression *body = funcdef->queryChild(0);
  665. // create a FuncCallStack to generate a stack used to pass parameters to
  666. // the called function
  667. FuncCallStack fstack(getBoolAttribute(body, passParameterMetaAtom, false), DEFAULTSTACKSIZE);
  668. if(body->hasAttribute(templateAtom))
  669. fstack.pushPtr(templateContext);
  670. //if these were allowed to be optional - then the following code would be needed
  671. if(body->hasAttribute(contextAtom) || body->hasAttribute(globalContextAtom))
  672. fstack.pushPtr(NULL);
  673. bool retCharStar = false;
  674. bool retUCharStar = false;
  675. bool charStarInParam = false;
  676. unsigned resultsize = 4; // the number of bytes of the result.
  677. int isRealvalue = 0;
  678. unsigned tlen = 0;
  679. char* tgt = NULL;
  680. // Process return value
  681. ITypeInfo * retType = funcdef->queryType()->queryChildType();
  682. type_t typecode = retType->getTypeCode();
  683. switch (typecode)
  684. {
  685. case type_varstring:
  686. case type_varunicode:
  687. if (retType->getSize() == UNKNOWN_LENGTH)
  688. {
  689. // variable length varstring, should return as char*
  690. retCharStar = true;
  691. if(typecode==type_varunicode) retUCharStar = true;
  692. resultsize = sizeof(char *);
  693. break;
  694. }
  695. //fallthrough
  696. case type_string:
  697. case type_data:
  698. case type_qstring:
  699. case type_unicode:
  700. case type_utf8:
  701. if (retType->getSize() == UNKNOWN_LENGTH)
  702. {
  703. // string, pass in the reference of length var and char* var. After function call,
  704. // values will be stored in them.
  705. fstack.pushRef(tlen);
  706. fstack.pushRef(tgt);
  707. }
  708. else
  709. {
  710. // stringn or varstringn, create a char array and pass it. Don't pass length var(as the
  711. // length is fixed).
  712. tlen = retType->getSize();
  713. tgt = (char*) malloc(tlen + 1); // To be safe, allocate one byte more.
  714. fstack.push(tgt);
  715. }
  716. charStarInParam = true;
  717. break;
  718. case type_real:
  719. // For real, get the result size
  720. resultsize = retType->getSize();
  721. isRealvalue = 1;
  722. break;
  723. case type_boolean:
  724. case type_int:
  725. case type_decimal:
  726. case type_date:
  727. case type_char:
  728. case type_enumerated:
  729. case type_swapint:
  730. case type_packedint:
  731. resultsize = retType->getSize();
  732. break;
  733. case type_void:
  734. if (!(foldOptions & (HFOfoldimpure|HFOforcefold)))
  735. {
  736. if (foldOptions & HFOthrowerror)
  737. throw MakeStringException(ERR_TMPLT_NONPUREFUNC, "%s/%s is not an action, can't constant fold it", library, entrypoint);
  738. return NULL;
  739. }
  740. break;
  741. default:
  742. //can't fold things that return sets/datasets etc.
  743. return NULL;
  744. }
  745. // process all the parameters passed in
  746. unsigned numParam = expr->numChildren();
  747. IHqlExpression * formals = funcdef->queryChild(1);
  748. for(unsigned i = 0; i < numParam; i++)
  749. {
  750. IHqlExpression * curParam = expr->queryChild(i); //NB: Already folded...
  751. IHqlExpression * curArg = formals->queryChild(i);
  752. if(!curArg) {
  753. free(tgt);
  754. return NULL;
  755. }
  756. ITypeInfo * argType = curArg->queryType();
  757. if(!argType) {
  758. free(tgt);
  759. return NULL;
  760. }
  761. if (fstack.push(argType, curParam) == -1)
  762. {
  763. free(tgt);
  764. return NULL;
  765. }
  766. }
  767. // Get the length and address of the stack
  768. unsigned len = fstack.getSp();
  769. #ifdef REGPARAMS
  770. while (len < REGPARAMS*REGSIZE)
  771. len = fstack.pushPtr(NULL); // ensure enough to fill REGPARAMS registers
  772. #endif
  773. #ifdef ODD_STACK_ALIGNMENT
  774. // Some architectures (arm) require that the total amount pushed onto the stack for parameters is an odd number of words
  775. // (so that the stack alignment is always an even number of words once the return IP is pushed)
  776. if ((len & REGSIZE) == 0)
  777. len = fstack.pushPtr(NULL);
  778. #endif
  779. #ifdef EVEN_STACK_ALIGNMENT
  780. // Other architectures (x86) require that the total amount pushed onto the stack for parameters is an even number of words
  781. // (so that the stack alignment is always an even number of words after the callq, which pushes an even number of words)
  782. if ((len & REGSIZE) == REGSIZE)
  783. len = fstack.pushPtr(NULL);
  784. #endif
  785. char* strbuf = fstack.getMem();
  786. int intresult = 0;
  787. #ifdef __64BIT__
  788. __int64 int64result = 0;
  789. #else
  790. int intresulthigh = 0;
  791. #endif
  792. float floatresult = 0.0;
  793. double doubleresult = 0.0;
  794. #ifdef _ARCH_X86_64_
  795. // __asm__ ("\tint $0x3\n"); // for debugging
  796. #endif
  797. try{
  798. // Assembly code that does the dynamic function call. The calling convention is a combination of
  799. // Pascal and C, that is the parameters are pushed from left to right, the stack goes downward(i.e.,
  800. // the stack pointer decreases as you push), and the caller is responsible for restoring the
  801. // stack pointer.
  802. // **** Windows ****
  803. #ifdef _WIN32
  804. // Note - we assume X86/X86_64 Procedure Call Standard
  805. #if defined (_ARCH_X86_64_)
  806. int64result = foldExternalCallStub(fh, &doubleresult, len, strbuf);
  807. intresult = (int)int64result;
  808. #elif defined (_ARCH_X86_)
  809. _asm{
  810. ;save registers that will be used
  811. push ecx
  812. push esi
  813. push eax
  814. push edx
  815. push ebx
  816. ;copy parameters to the stack
  817. mov ecx, len
  818. sub esp, len
  819. mov esi, strbuf
  820. jcxz loop1tail
  821. loop1:
  822. mov al, [esi]
  823. mov [esp], al
  824. inc esp
  825. inc esi
  826. dec ecx
  827. jnz loop1
  828. loop1tail:
  829. ;call the procedure
  830. sub esp, len
  831. call fh
  832. add esp, len
  833. ;save result
  834. mov ebx, isRealvalue
  835. cmp ebx, 1
  836. je isreal
  837. mov intresult, eax
  838. mov intresulthigh, edx
  839. jmp finish
  840. isreal:
  841. mov ebx, resultsize
  842. cmp ebx, 4
  843. ja isdouble
  844. fstp DWORD PTR floatresult
  845. jmp finish
  846. isdouble:
  847. fstp QWORD PTR doubleresult
  848. finish:
  849. ;restore registers that were saved
  850. pop ebx
  851. pop edx
  852. pop eax
  853. pop esi
  854. pop ecx
  855. }
  856. #else
  857. UNIMPLEMENTED;
  858. #endif
  859. #else // WIN32
  860. // **** Linux/Mac ****
  861. #ifdef _ARCH_X86_64_
  862. assertex((len & 15) == 0); // We need to make sure we add an EVEN number of words to stack, so that it is 16-byte aligned before the callq
  863. __int64 dummy1, dummy2,dummy3,dummy4;
  864. void * floatstack = fstack.getFloatMem();
  865. if (floatstack) { // sets xmm0-7
  866. unsigned * floatSizes = fstack.getFloatSizes();
  867. __asm__ (
  868. ".doparm0: \n\t"
  869. "cmpl $4,(%%rdi) \n\t"
  870. "jl .floatdone \n\t"
  871. "je .dofloat0 \n\t"
  872. "movsd (%%rsi),%%xmm0 \n\t"
  873. "jmp .doparm1 \n\t"
  874. ".dofloat0: \n\t"
  875. "movss (%%rsi),%%xmm0 \n\t"
  876. ".doparm1: \n\t"
  877. "cmpl $4,4(%%rdi) \n\t"
  878. "jl .floatdone \n\t"
  879. "je .dofloat1 \n\t"
  880. "movsd 8(%%rsi),%%xmm1 \n\t"
  881. "jmp .doparm2 \n\t"
  882. ".dofloat1: \n\t"
  883. "movss 8(%%rsi),%%xmm1 \n\t"
  884. ".doparm2: \n\t"
  885. "cmpl $4,8(%%rdi) \n\t"
  886. "jl .floatdone \n\t"
  887. "je .dofloat2 \n\t"
  888. "movsd 16(%%rsi),%%xmm2 \n\t"
  889. "jmp .doparm3 \n\t"
  890. ".dofloat2: \n\t"
  891. "movss 16(%%rsi),%%xmm2 \n\t"
  892. ".doparm3: \n\t"
  893. "cmpl $4,12(%%rdi) \n\t"
  894. "jl .floatdone \n\t"
  895. "je .dofloat3 \n\t"
  896. "movsd 24(%%rsi),%%xmm3 \n\t"
  897. "jmp .doparm4 \n\t"
  898. ".dofloat3: \n\t"
  899. "movss 24(%%rsi),%%xmm3 \n\t"
  900. ".doparm4: \n\t"
  901. "cmpl $4,16(%%rdi) \n\t"
  902. "jl .floatdone \n\t"
  903. "je .dofloat4 \n\t"
  904. "movsd 32(%%rsi),%%xmm4 \n\t"
  905. "jmp .doparm5 \n\t"
  906. ".dofloat4: \n\t"
  907. "movss 32(%%rsi),%%xmm4 \n\t"
  908. ".doparm5: \n\t"
  909. "cmpl $4,20(%%rdi) \n\t"
  910. "jl .floatdone \n\t"
  911. "je .dofloat5 \n\t"
  912. "movsd 40(%%rsi),%%xmm5 \n\t"
  913. "jmp .doparm6 \n\t"
  914. ".dofloat5: \n\t"
  915. "movss 40(%%rsi),%%xmm5 \n\t"
  916. ".doparm6: \n\t"
  917. "cmpl $4,24(%%rdi) \n\t"
  918. "jl .floatdone \n\t"
  919. "je .dofloat6 \n\t"
  920. "movsd 48(%%rsi),%%xmm6 \n\t"
  921. "jmp .doparm7 \n\t"
  922. ".dofloat6: \n\t"
  923. "movss 48(%%rsi),%%xmm6 \n\t"
  924. ".doparm7: \n\t"
  925. "cmpl $4,28(%%rdi) \n\t"
  926. "jl .floatdone \n\t"
  927. "je .dofloat7 \n\t"
  928. "movsd 56(%%rsi),%%xmm7 \n\t"
  929. "jmp .floatdone \n\t"
  930. ".dofloat7: \n\t"
  931. "movss 56(%%rsi),%%xmm7 \n\t"
  932. ".floatdone: \n\t"
  933. :
  934. : "S"(floatstack),"D"(floatSizes)
  935. : "cc","xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"
  936. );
  937. }
  938. __asm__ (
  939. "sub %%rcx, %%rsp \n\t"
  940. "mov %%rsp, %%rdi \n\t"
  941. "cld \n\t"
  942. "rep \n\t"
  943. "movsb \n\t"
  944. "pop %%rdi \n\t"
  945. "pop %%rsi \n\t"
  946. "pop %%rdx \n\t"
  947. "pop %%rcx \n\t"
  948. "pop %%r8 \n\t"
  949. "pop %%r9 \n\t"
  950. "call *%%rax \n\t"
  951. "add %%rbx, %%rsp \n\t" // Restore stack pointer (note have popped 6 registers)
  952. : "=a"(int64result),"=d"(dummy1),"=c"(dummy1),"=S"(dummy3),"=D"(dummy4)
  953. : "c"(len),"b"(len-REGPARAMS*REGSIZE),"S"(strbuf),"a"(fh)
  954. : "cc","r8","r9","xmm0"
  955. );
  956. // Get real (float/double) return values;
  957. if(isRealvalue)
  958. {
  959. if(resultsize <= 4)
  960. {
  961. __asm__ __volatile__(
  962. "movss %%xmm0,(%%rdi) \n\t"
  963. :
  964. : "D"(&(floatresult))
  965. );
  966. }
  967. else
  968. {
  969. __asm__ __volatile__(
  970. "movsd %%xmm0, (%%rdi) \n\t"
  971. :
  972. : "D"(&(doubleresult))
  973. );
  974. }
  975. }
  976. else {
  977. intresult = (int)int64result;
  978. }
  979. #elif defined(_ARCH_X86_)
  980. int dummy1, dummy2,dummy3;
  981. __asm__ __volatile__(
  982. "push %%ebx \n\t"
  983. "movl %%ecx, %%ebx \n\t"
  984. "subl %%ecx, %%esp \n\t"
  985. "movl %%esp, %%edi \n\t"
  986. "cld \n\t"
  987. "rep \n\t"
  988. "movsb \n\t"
  989. "call *%%edx \n\t"
  990. "addl %%ebx, %%esp \n\t"
  991. "pop %%ebx \n\t"
  992. : "=a"(intresult),"=d"(intresulthigh),"=c"(dummy1),"=S"(dummy2),"=D"(dummy3)
  993. : "c"(len),"S"(strbuf),"d"(fh)
  994. : "cc"
  995. );
  996. // Get real (float/double) return values;
  997. if(isRealvalue)
  998. {
  999. if(resultsize <= 4)
  1000. {
  1001. __asm__ __volatile__(
  1002. "fstps (%%edi) \n\t"
  1003. :
  1004. : "D"(&(floatresult))
  1005. );
  1006. }
  1007. else
  1008. {
  1009. __asm__ __volatile__(
  1010. "fstpl (%%edi) \n\t"
  1011. :
  1012. : "D"(&(doubleresult))
  1013. );
  1014. }
  1015. }
  1016. #elif defined(_ARCH_ARM32_)
  1017. // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf
  1018. #ifdef MAXFPREGS
  1019. void * floatstack = fstack.getFloatMem();
  1020. if (floatstack) {
  1021. unsigned * floatSizes = fstack.getFloatSizes();
  1022. __asm__ __volatile__ (
  1023. ".doparm0: \n\t"
  1024. "ldr r0,[%[sizes],#0] \n\t"
  1025. "cmp r0, #4 \n\t"
  1026. "blt .floatdone \n\t"
  1027. "beq .dofloat0 \n\t"
  1028. "fldd d0,[%[vals], #0] \n\t"
  1029. "b .doparm1 \n\t"
  1030. ".dofloat0: \n\t"
  1031. "flds s0,[%[vals], #0] \n\t"
  1032. ".doparm1: \n\t"
  1033. "ldr r0,[%[sizes],#4] \n\t"
  1034. "cmp r0, #4 \n\t"
  1035. "blt .floatdone \n\t"
  1036. "beq .dofloat1 \n\t"
  1037. "fldd d1,[%[vals], #8] \n\t"
  1038. "b .doparm2 \n\t"
  1039. ".dofloat1: \n\t"
  1040. "flds s2,[%[vals], #8] \n\t"
  1041. ".doparm2: \n\t"
  1042. "ldr r0,[%[sizes],#8] \n\t"
  1043. "cmp r0, #4 \n\t"
  1044. "blt .floatdone \n\t"
  1045. "beq .dofloat2 \n\t"
  1046. "fldd d2,[%[vals], #16] \n\t"
  1047. "b .doparm3 \n\t"
  1048. ".dofloat2: \n\t"
  1049. "flds s4,[%[vals], #16] \n\t"
  1050. ".doparm3: \n\t"
  1051. "ldr r0,[%[sizes],#12] \n\t"
  1052. "cmp r0, #4 \n\t"
  1053. "blt .floatdone \n\t"
  1054. "beq .dofloat3 \n\t"
  1055. "fldd d3,[%[vals], #24] \n\t"
  1056. "b .doparm4 \n\t"
  1057. ".dofloat3: \n\t"
  1058. "flds s6,[%[vals], #24] \n\t"
  1059. ".doparm4: \n\t"
  1060. "ldr r0,[%[sizes],#16] \n\t"
  1061. "cmp r0, #4 \n\t"
  1062. "blt .floatdone \n\t"
  1063. "beq .dofloat4 \n\t"
  1064. "fldd d4,[%[vals], #32] \n\t"
  1065. "b .doparm5 \n\t"
  1066. ".dofloat4: \n\t"
  1067. "flds s8,[%[vals], #32] \n\t"
  1068. ".doparm5: \n\t"
  1069. "ldr r0,[%[sizes],#20] \n\t"
  1070. "cmp r0, #4 \n\t"
  1071. "blt .floatdone \n\t"
  1072. "beq .dofloat4 \n\t"
  1073. "fldd d5,[%[vals], #40] \n\t"
  1074. "b .doparm6 \n\t"
  1075. ".dofloat5: \n\t"
  1076. "flds s10,[%[vals], #40] \n\t"
  1077. ".doparm6: \n\t"
  1078. "ldr r0,[%[sizes],#24] \n\t"
  1079. "cmp r0, #4 \n\t"
  1080. "blt .floatdone \n\t"
  1081. "beq .dofloat6 \n\t"
  1082. "fldd d6,[%[vals], #48] \n\t"
  1083. "b .doparm7 \n\t"
  1084. ".dofloat6: \n\t"
  1085. "flds s12,[%[vals], #48] \n\t"
  1086. ".doparm7: \n\t"
  1087. "ldr r0,[%[sizes],#28] \n\t"
  1088. "cmp r0, #4 \n\t"
  1089. "blt .floatdone \n\t"
  1090. "beq .dofloat7 \n\t"
  1091. "fldd d7,[%[vals], #56] \n\t"
  1092. "b .floatdone \n\t"
  1093. ".dofloat7: \n\t"
  1094. "flds s14,[%[vals], #56] \n\t"
  1095. ".floatdone: \n\t"
  1096. :
  1097. : [vals] "r"(floatstack), [sizes] "r"(floatSizes)
  1098. : "r0"
  1099. );
  1100. }
  1101. #endif
  1102. assertex((len & 7) == 4); // We need to make sure we add an ODD number of words to stack, so that it gets 8-byte aligned once pc is pushed by the call
  1103. register unsigned _intresult asm("r0"); // Specific register for result
  1104. register unsigned _intresulthigh asm("r1"); // Specific register for result
  1105. register unsigned _poplen asm("r4") = len-REGPARAMS*REGSIZE; // Needs to survive the call
  1106. register void *_fh asm("r5") = fh; // Needs to survive until the call
  1107. __asm__ __volatile__ (
  1108. "subs sp, sp, %[len] \n\t" // Make space on stack
  1109. "mov r2, sp \n\t" // r2 = destination for loop
  1110. ".repLoop: \n\t"
  1111. "ldrb r3, [%[strbuf]], #1 \n\t" // copy a byte from src array to r3
  1112. "strb r3, [r2], #1 \n\t" // and then from r3 onto stack
  1113. "subs %[len], %[len], #1 \n\t" // decrement and repeat
  1114. "bne .repLoop \n\t"
  1115. "pop {r0,r1,r2,r3} \n\t" // first 4 parameters go in registers
  1116. "blx %[fh] \n\t" // make the call
  1117. "adds sp, sp, %[poplen] \n\t" // Restore stack pointer (note have popped 4 registers, so poplen is len - 16)
  1118. : "=r"(_intresult), "=r"(_intresulthigh)
  1119. : [len] "r"(len), [poplen] "r"(_poplen), [strbuf] "r"(strbuf), [fh] "r"(_fh)
  1120. : "r2","r3","lr" // function we call may corrupt lr
  1121. );
  1122. intresult = _intresult;
  1123. intresulthigh = _intresulthigh;
  1124. if (isRealvalue)
  1125. {
  1126. #ifdef MAXFPREGS
  1127. if(resultsize <= 4)
  1128. {
  1129. __asm__ __volatile__(
  1130. "fsts s0,[%[fresult]] \n\t"
  1131. :
  1132. : [fresult] "r"(&(floatresult))
  1133. );
  1134. }
  1135. else
  1136. {
  1137. __asm__ __volatile__(
  1138. "fstd d0,[%[fresult]] \n\t"
  1139. :
  1140. : [fresult] "r"(&(doubleresult))
  1141. );
  1142. }
  1143. #else
  1144. if(resultsize <= 4)
  1145. {
  1146. floatresult = *(float*)&intresult;
  1147. }
  1148. else
  1149. {
  1150. union
  1151. {
  1152. struct { int lo, int hi } i;
  1153. double d;
  1154. } u;
  1155. u.lo = intresult;
  1156. u.hi = intresulthigh;
  1157. doubleresult = u.d;
  1158. }
  1159. #endif
  1160. }
  1161. #elif defined(_ARCH_ARM64_)
  1162. // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055c/IHI0055C_beta_aapcs64.pdf
  1163. UNIMPLEMENTED;
  1164. #else
  1165. // Unknown architecture
  1166. UNIMPLEMENTED;
  1167. #endif
  1168. #endif //win32
  1169. }
  1170. catch (...) {
  1171. if(retCharStar || charStarInParam) { // Char* return type, need to free up tgt.
  1172. free(tgt);
  1173. }
  1174. if (foldOptions & HFOthrowerror)
  1175. throw MakeStringException(ERR_SVC_EXCPTIONEXEFUNC,"Exception thrown when try to execute function %s/%s, please check the function\n", library, entrypoint);
  1176. return NULL;
  1177. }
  1178. IValue* result = NULL;
  1179. if(retCharStar || charStarInParam) { // Char* return type
  1180. if(retCharStar) {
  1181. #ifdef __64BIT__
  1182. tgt = (char *)int64result;
  1183. #else
  1184. tgt = (char *)intresult;
  1185. #endif
  1186. tlen = retUCharStar ? rtlUnicodeStrlen((UChar *)tgt) : (size32_t)strlen(tgt);
  1187. }
  1188. Linked<ITypeInfo> resultType = retType;
  1189. if (resultType->getSize() == UNKNOWN_LENGTH)
  1190. resultType.setown(getStretchedType(tlen, resultType));
  1191. switch (typecode)
  1192. {
  1193. case type_varstring:
  1194. result = createVarStringValue(tlen+1, tgt, resultType.getLink());
  1195. break;
  1196. case type_data:
  1197. result = createDataValue(tgt, tlen);
  1198. break;
  1199. case type_qstring:
  1200. result = createQStringValue(tlen, tgt, resultType.getLink());
  1201. break;
  1202. case type_unicode:
  1203. result = createUnicodeValue(tlen, tgt, LINK(resultType));
  1204. break;
  1205. case type_varunicode:
  1206. result = createVarUnicodeValue(tlen, tgt, LINK(resultType));
  1207. break;
  1208. case type_utf8:
  1209. result = createUtf8Value(tlen, tgt, LINK(resultType));
  1210. break;
  1211. default:
  1212. result = createStringValue(tgt, resultType.getLink());
  1213. break;
  1214. }
  1215. rtlFree(tgt);
  1216. }
  1217. else if(isRealvalue) { // REAL return type
  1218. if(resultsize == 4) {
  1219. result = createRealValue(floatresult, resultsize);
  1220. }
  1221. else {
  1222. result = createRealValue(doubleresult, resultsize);
  1223. }
  1224. }
  1225. else if(typecode == type_boolean) { // BOOLEAN return type
  1226. intresult = intresult & 0xff;
  1227. result = createBoolValue(intresult != 0);
  1228. }
  1229. else if (typecode == type_void)
  1230. {
  1231. result = NULL;
  1232. }
  1233. else { // By default, we take the return type as INTEGER
  1234. LINK(retType);
  1235. #ifndef __64BIT__
  1236. __int64 int64result = (__int64)(((unsigned __int64) intresulthigh) << 32) + (unsigned)intresult;
  1237. #endif
  1238. unsigned shift = (sizeof(int64result)-resultsize) * 8;
  1239. if (retType->isSigned())
  1240. int64result = (int64result << shift) >> shift;
  1241. else
  1242. int64result = (((__uint64)int64result) << shift) >> shift;
  1243. result = createIntValue(int64result, retType);
  1244. }
  1245. return result;
  1246. }
  1247. IValue * foldExternalCall(IHqlExpression* expr, unsigned foldOptions, ITemplateContext *templateContext)
  1248. {
  1249. StringBuffer library;
  1250. StringBuffer entry;
  1251. if (!checkExternFoldable(expr, foldOptions, library, entry))
  1252. return NULL;
  1253. // NOTE - we do not call FreeSharedObject(hDLL) - the embedded language folding requires that the dll stay loaded, and it's also more efficient for other cases
  1254. HINSTANCE hDll;
  1255. void *funcptr = loadExternalEntryPoint(expr, foldOptions, templateContext, library.str(), entry.str(), hDll);
  1256. if (!funcptr)
  1257. return NULL;
  1258. return doFoldExternalCall(expr, foldOptions, templateContext, library.str(), entry.str(), funcptr);
  1259. }
  1260. //------------------------------------------------------------------------------------------
  1261. bool checkEmbeddedFoldable(IHqlExpression* expr, unsigned foldOptions)
  1262. {
  1263. IHqlExpression * funcdef = expr->queryBody()->queryFunctionDefinition();
  1264. IHqlExpression * outofline = funcdef->queryChild(0);
  1265. assertex(outofline->getOperator() == no_outofline);
  1266. IHqlExpression * body = outofline->queryChild(0);
  1267. assertex(body->getOperator()==no_embedbody);
  1268. IHqlExpression * formals = funcdef->queryChild(1);
  1269. ITypeInfo * returnType = funcdef->queryType()->queryChildType();
  1270. if (body->hasAttribute(_disallowed_Atom) || !body->hasAttribute(foldAtom))
  1271. return false; // Not allowed
  1272. ForEachChild(idx, body)
  1273. {
  1274. IHqlExpression *child = body->queryChild(idx);
  1275. if (child->isAttribute() && !isInternalEmbedAttr(child->queryName()) && !child->isConstant())
  1276. // Note that the language attr is a function call and thus NOT considered constant, hence we can't just
  1277. // test body->isConstant()
  1278. return false;
  1279. }
  1280. IHqlExpression *languageAttr = body->queryAttribute(languageAtom);
  1281. if (!languageAttr)
  1282. return false; // Can't fold embedded C++
  1283. switch (returnType->getTypeCode())
  1284. {
  1285. case type_row:
  1286. case type_table:
  1287. case type_groupedtable:
  1288. // Can't do as yet without the type info
  1289. return false;
  1290. }
  1291. // check all the parameters passed in
  1292. unsigned numParam = formals->numChildren();
  1293. for(unsigned i = 0; i < numParam; i++)
  1294. {
  1295. IHqlExpression * curArg = formals->queryChild(i);
  1296. assertex(curArg != NULL);
  1297. ITypeInfo * paramType = curArg->queryType();
  1298. switch (paramType->getTypeCode())
  1299. {
  1300. case type_row:
  1301. case type_table:
  1302. case type_groupedtable:
  1303. // Can't do as yet without the type info
  1304. return false;
  1305. }
  1306. }
  1307. return true;
  1308. }
  1309. class DummyContext: implements ICodeContext
  1310. {
  1311. // Perhaps this should go into eclrtl - address cleaner uses it too
  1312. virtual const char *loadResource(unsigned id) { throwUnexpected(); }
  1313. // Fetching interim results from workunit/query context
  1314. virtual bool getResultBool(const char * name, unsigned sequence) { throwUnexpected(); }
  1315. virtual void getResultData(unsigned & tlen, void * & tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  1316. virtual void getResultDecimal(unsigned tlen, int precision, bool isSigned, void * tgt, const char * stepname, unsigned sequence) { throwUnexpected(); }
  1317. virtual void getResultDictionary(size32_t & tcount, byte * * & tgt, IEngineRowAllocator * _rowAllocator, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer, IHThorHashLookupInfo * hasher) { throwUnexpected(); }
  1318. virtual void getResultRaw(unsigned & tlen, void * & tgt, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  1319. virtual void getResultSet(bool & isAll, size32_t & tlen, void * & tgt, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  1320. virtual __int64 getResultInt(const char * name, unsigned sequence) { throwUnexpected(); }
  1321. virtual double getResultReal(const char * name, unsigned sequence) { throwUnexpected(); }
  1322. virtual void getResultRowset(size32_t & tcount, byte * * & tgt, const char * name, unsigned sequence, IEngineRowAllocator * _rowAllocator, bool isGrouped, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  1323. virtual void getResultString(unsigned & tlen, char * & tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  1324. virtual void getResultStringF(unsigned tlen, char * tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  1325. virtual void getResultUnicode(unsigned & tlen, UChar * & tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  1326. virtual char *getResultVarString(const char * name, unsigned sequence) { throwUnexpected(); }
  1327. virtual UChar *getResultVarUnicode(const char * name, unsigned sequence) { throwUnexpected(); }
  1328. // Writing results to workunit/query context/output
  1329. virtual void setResultBool(const char *name, unsigned sequence, bool value) { throwUnexpected(); }
  1330. virtual void setResultData(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
  1331. virtual void setResultDecimal(const char * stepname, unsigned sequence, int len, int precision, bool isSigned, const void *val) { throwUnexpected(); }
  1332. virtual void setResultInt(const char *name, unsigned sequence, __int64 value, unsigned size) { throwUnexpected(); }
  1333. virtual void setResultRaw(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
  1334. virtual void setResultReal(const char * stepname, unsigned sequence, double value) { throwUnexpected(); }
  1335. virtual void setResultSet(const char *name, unsigned sequence, bool isAll, size32_t len, const void * data, ISetToXmlTransformer * transformer) { throwUnexpected(); }
  1336. virtual void setResultString(const char *name, unsigned sequence, int len, const char * str) { throwUnexpected(); }
  1337. virtual void setResultUInt(const char *name, unsigned sequence, unsigned __int64 value, unsigned size) { throwUnexpected(); }
  1338. virtual void setResultUnicode(const char *name, unsigned sequence, int len, UChar const * str) { throwUnexpected(); }
  1339. virtual void setResultVarString(const char * name, unsigned sequence, const char * value) { throwUnexpected(); }
  1340. virtual void setResultVarUnicode(const char * name, unsigned sequence, UChar const * value) { throwUnexpected(); }
  1341. // Checking persists etc are up to date
  1342. virtual unsigned getResultHash(const char * name, unsigned sequence) { throwUnexpected(); }
  1343. virtual unsigned getExternalResultHash(const char * wuid, const char * name, unsigned sequence) { throwUnexpected(); }
  1344. virtual unsigned __int64 getDatasetHash(const char * name, unsigned __int64 crc) { throwUnexpected(); }
  1345. // Fetching various environment information, typically accessed via std.system
  1346. virtual char *getClusterName() { throwUnexpected(); } // caller frees return string.
  1347. virtual char *getEnv(const char *name, const char *defaultValue) const { throwUnexpected(); }
  1348. virtual char *getGroupName() { throwUnexpected(); } // caller frees return string.
  1349. virtual char *getJobName() { throwUnexpected(); } // caller frees return string.
  1350. virtual char *getJobOwner() { throwUnexpected(); } // caller frees return string.
  1351. virtual unsigned getNodeNum() { throwUnexpected(); }
  1352. virtual unsigned getNodes() { throwUnexpected(); }
  1353. virtual char *getOS() { throwUnexpected(); } // caller frees return string
  1354. virtual char *getPlatform() { throwUnexpected(); } // caller frees return string.
  1355. virtual unsigned getPriority() const { throwUnexpected(); }
  1356. virtual char *getWuid() { throwUnexpected(); } // caller frees return string.
  1357. // Exception handling
  1358. virtual void addWuException(const char*, unsigned int, unsigned int, const char*) { throwUnexpected(); } //n.b. this might be better named: it should only be used for adding user-generated exceptions (via the logging plug-in) --- there's a call in IAgentContext which takes a source argument too
  1359. virtual void addWuAssertFailure(unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column, bool isAbort) { throwUnexpected(); }
  1360. // File resolution etc
  1361. virtual char * getExpandLogicalName(const char * logicalName) { throwUnexpected(); }
  1362. virtual unsigned __int64 getFileOffset(const char *logicalPart) { throwUnexpected(); }
  1363. virtual char *getFilePart(const char *logicalPart, bool create=false) { throwUnexpected(); } // caller frees return string.
  1364. virtual IDistributedFileTransaction *querySuperFileTransaction() { throwUnexpected(); }
  1365. virtual IUserDescriptor *queryUserDescriptor() { throwUnexpected(); }
  1366. // Graphs, child queries etc
  1367. virtual void executeGraph(const char * graphName, bool realThor, size32_t parentExtractSize, const void * parentExtract) { throwUnexpected(); }
  1368. virtual unsigned getGraphLoopCounter() const { return 0; }
  1369. virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal) { throwUnexpected(); }
  1370. virtual IEclGraphResults * resolveLocalQuery(__int64 activityId) { return NULL; }
  1371. // Logging etc
  1372. virtual unsigned logString(const char *text) const { throwUnexpected(); }
  1373. virtual IDebuggableContext *queryDebugContext() const { return NULL; }
  1374. // Memory management
  1375. virtual IEngineRowAllocator * getRowAllocator(IOutputMetaData * meta, unsigned activityId) const { throwUnexpected(); }
  1376. virtual const char * cloneVString(const char *str) const { throwUnexpected(); }
  1377. virtual const char * cloneVString(size32_t len, const char *str) const { throwUnexpected(); }
  1378. // Called from generated code for FROMXML/TOXML
  1379. virtual const void * fromXml(IEngineRowAllocator * _rowAllocator, size32_t len, const char * utf8, IXmlToRowTransformer * xmlTransformer, bool stripWhitespace) { throwUnexpected(); }
  1380. virtual void getRowXML(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags) { throwUnexpected(); }
  1381. // Miscellaneous
  1382. virtual void getExternalResultRaw(unsigned & tlen, void * & tgt, const char * wuid, const char * stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); } // shouldn't really be here, but it broke thor.
  1383. virtual char * queryIndexMetaData(char const * lfn, char const * xpath) { throwUnexpected(); }
  1384. // Called from generated code for FROMJSON
  1385. virtual const void * fromJson(IEngineRowAllocator * _rowAllocator, size32_t len, const char * utf8, IXmlToRowTransformer * xmlTransformer, bool stripWhitespace) { throwUnexpected(); }
  1386. virtual void getRowJSON(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags) { throwUnexpected(); }
  1387. virtual const IContextLogger &queryContextLogger() const
  1388. {
  1389. return queryDummyContextLogger();
  1390. }
  1391. virtual IEngineContext *queryEngineContext() { return NULL; }
  1392. virtual char *getDaliServers() { throwUnexpected(); }
  1393. virtual IWorkUnit* updateWorkUnit() const { throwUnexpected(); }
  1394. virtual ISectionTimer * registerTimer(unsigned activityId, const char * name) { throwUnexpected(); }
  1395. virtual IEngineRowAllocator * getRowAllocatorEx(IOutputMetaData * meta, unsigned activityId, unsigned flags) const { throwUnexpected(); }
  1396. };
  1397. IHqlExpression *deserializeConstantSet(ITypeInfo *type, bool isAll, size32_t len, const void *vdata)
  1398. {
  1399. ITypeInfo *childType = type->queryChildType();
  1400. if (isAll)
  1401. return createValue(no_all, LINK(childType));
  1402. else if (!len)
  1403. return createValue(no_null, LINK(childType));
  1404. else
  1405. {
  1406. const char *data = (const char *) vdata;
  1407. const char *end = data + len;
  1408. HqlExprArray values;
  1409. while (data < end)
  1410. {
  1411. size32_t size = childType->getSize();
  1412. size32_t numChars = childType->getStringLen();
  1413. switch (childType->getTypeCode())
  1414. {
  1415. case type_int:
  1416. case type_real:
  1417. case type_boolean:
  1418. values.append(*createConstant(createValueFromMem(LINK(childType), data)));
  1419. break;
  1420. case type_varstring:
  1421. values.append(*createConstant(data));
  1422. if (size==UNKNOWN_LENGTH)
  1423. size = (size32_t)(strlen(data)+1);
  1424. break;
  1425. case type_string:
  1426. if (size==UNKNOWN_LENGTH)
  1427. {
  1428. size = *(size32_t *) data;
  1429. data += sizeof(size32_t);
  1430. }
  1431. values.append(*createConstant(createStringValue(data, size)));
  1432. break;
  1433. case type_data:
  1434. if (size==UNKNOWN_LENGTH)
  1435. {
  1436. size = *(size32_t *) data;
  1437. data += sizeof(size32_t);
  1438. }
  1439. values.append(*createConstant(createDataValue(data, size)));
  1440. break;
  1441. case type_unicode:
  1442. if (size==UNKNOWN_LENGTH)
  1443. {
  1444. numChars = *(size32_t *) data; // in characters
  1445. data += sizeof(size32_t);
  1446. values.append(*createConstant(createUnicodeValue((const UChar *) data, numChars, LINK(childType))));
  1447. size = numChars * sizeof(UChar);
  1448. }
  1449. else
  1450. {
  1451. values.append(*createConstant(createUnicodeValue((const UChar *) data, numChars, LINK(childType))));
  1452. }
  1453. break;
  1454. case type_utf8:
  1455. // size is always UNKNOWN_LENGTH for uft8
  1456. assertex(size==UNKNOWN_LENGTH);
  1457. numChars = *(size32_t *) data; // in characters
  1458. data += sizeof(size32_t);
  1459. values.append(*createConstant(createUtf8Value(numChars, data, LINK(childType))));
  1460. size = rtlUtf8Size(numChars, data);
  1461. break;
  1462. default:
  1463. return NULL;
  1464. }
  1465. if (size != UNKNOWN_LENGTH)
  1466. data += size;
  1467. }
  1468. return createValue(no_list, LINK(type), values);
  1469. }
  1470. }
  1471. IHqlExpression * foldEmbeddedCall(IHqlExpression* expr, unsigned foldOptions, ITemplateContext *templateContext)
  1472. {
  1473. if (!checkEmbeddedFoldable(expr, foldOptions))
  1474. return NULL;
  1475. IHqlExpression * funcdef = expr->queryBody()->queryFunctionDefinition();
  1476. IHqlExpression * outofline = funcdef->queryChild(0);
  1477. assertex(outofline->getOperator() == no_outofline);
  1478. IHqlExpression * body = outofline->queryChild(0);
  1479. assertex(body->getOperator()==no_embedbody);
  1480. ITypeInfo * returnType = funcdef->queryType()->queryChildType();
  1481. bool isImport = body->hasAttribute(importAtom);
  1482. IHqlExpression * formals = funcdef->queryChild(1);
  1483. assertex(formals->numChildren() == expr->numChildren()); // MORE - do default params change this?
  1484. unsigned flags = isImport ? EFimport : EFembed;
  1485. if (formals->numChildren()==0)
  1486. flags |= EFnoparams;
  1487. if (returnType->getTypeCode()==type_void)
  1488. flags |= EFnoreturn;
  1489. StringBuffer optionsStr;
  1490. ForEachChild(idx, body)
  1491. {
  1492. IHqlExpression *child = body->queryChild(idx);
  1493. if (child->isAttribute() && !isInternalEmbedAttr(child->queryName()))
  1494. {
  1495. if (optionsStr.length())
  1496. optionsStr.append(",");
  1497. optionsStr.append(child->queryName());
  1498. IHqlExpression * value = child->queryChild(0);
  1499. if (value)
  1500. {
  1501. optionsStr.append("=");
  1502. value->queryValue()->getUTF8Value(optionsStr);
  1503. }
  1504. }
  1505. }
  1506. IHqlExpression *languageAttr = body->queryAttribute(languageAtom);
  1507. HqlExprArray noParams;
  1508. OwnedHqlExpr langLoadCall = createTranslatedExternalCall(NULL, languageAttr->queryChild(0), noParams);
  1509. Owned<IValue> plugin = foldExternalCall(langLoadCall, foldOptions, templateContext);
  1510. if (plugin == nullptr)
  1511. return NULL;
  1512. Owned<IEmbedContext> __plugin = (IEmbedContext *) plugin->getIntValue(); // We declared as int since ecl has no pointer type - not sure what the clean fix is here...
  1513. DummyContext dummyContext;
  1514. Owned<IEmbedFunctionContext> __ctx = __plugin->createFunctionContextEx(&dummyContext,flags,optionsStr.str());
  1515. IValue *query = body->queryChild(0)->queryValue();
  1516. assertex(query);
  1517. StringBuffer queryText;
  1518. query->getUTF8Value(queryText);
  1519. if (!body->hasAttribute(prebindAtom))
  1520. {
  1521. if (isImport)
  1522. __ctx->importFunction(queryText.lengthUtf8(), queryText.str());
  1523. else
  1524. __ctx->compileEmbeddedScript(queryText.lengthUtf8(), queryText.str());
  1525. }
  1526. // process all the parameters passed in
  1527. unsigned numParam = expr->numChildren();
  1528. for(unsigned i = 0; i < numParam; i++)
  1529. {
  1530. IHqlExpression * curParam = expr->queryChild(i); //NB: Already folded...
  1531. IHqlExpression * curArg = formals->queryChild(i);
  1532. assertex(curArg != NULL);
  1533. ITypeInfo * paramType = curArg->queryType();
  1534. assertex(paramType != NULL);
  1535. IValue * paramValue = curParam->queryValue();
  1536. assertex(curParam->isConstant());
  1537. unsigned paramSize = paramType->getSize();
  1538. IIdAtom * paramId = curArg->queryId();
  1539. const char * name = str(paramId);
  1540. switch (paramType->getTypeCode())
  1541. {
  1542. case type_int:
  1543. {
  1544. __int64 value = paramValue->getIntValue();
  1545. if (paramSize<8)
  1546. {
  1547. if (paramType->isSigned())
  1548. __ctx->bindSignedSizeParam(name, paramSize, value);
  1549. else
  1550. __ctx->bindUnsignedSizeParam(name, paramSize, value);
  1551. }
  1552. else
  1553. {
  1554. if (paramType->isSigned())
  1555. __ctx->bindSignedParam(name, value);
  1556. else
  1557. __ctx->bindUnsignedParam(name, value);
  1558. }
  1559. break;
  1560. }
  1561. case type_varstring:
  1562. {
  1563. StringBuffer value;
  1564. paramValue->getStringValue(value);
  1565. __ctx->bindVStringParam(name, value.str());
  1566. break;
  1567. }
  1568. case type_string:
  1569. {
  1570. StringBuffer value;
  1571. paramValue->getStringValue(value);
  1572. __ctx->bindStringParam(name, value.length(), value.str());
  1573. break;
  1574. }
  1575. case type_real:
  1576. {
  1577. double value = paramValue->getRealValue();
  1578. if (paramType->getSize()==4)
  1579. __ctx->bindFloatParam(name, (float)value);
  1580. else
  1581. __ctx->bindRealParam(name, value);
  1582. break;
  1583. }
  1584. case type_boolean:
  1585. __ctx->bindBooleanParam(name, paramValue->getBoolValue());
  1586. break;
  1587. case type_utf8:
  1588. {
  1589. StringBuffer value;
  1590. paramValue->getUTF8Value(value);
  1591. __ctx->bindUTF8Param(name, value.lengthUtf8(), value.str());
  1592. break;
  1593. }
  1594. case type_unicode:
  1595. {
  1596. unsigned len = paramValue->queryType()->getStringLen();
  1597. UChar * value = (UChar *)malloc(len*2);
  1598. paramValue->getUCharStringValue(len, value);
  1599. __ctx->bindUnicodeParam(name, len, value);
  1600. free(value);
  1601. break;
  1602. }
  1603. case type_data:
  1604. {
  1605. __ctx->bindDataParam(name, paramValue->getSize(), paramValue->queryValue());
  1606. break;
  1607. }
  1608. case type_row:
  1609. case type_table:
  1610. case type_groupedtable:
  1611. // Can't do as yet without the type info
  1612. return NULL;
  1613. case type_set:
  1614. {
  1615. MemoryBuffer setValue;
  1616. if (!createConstantField(setValue, curArg, curParam))
  1617. return NULL;
  1618. bool isAll;
  1619. size32_t totalSize;
  1620. setValue.read(isAll);
  1621. setValue.read(totalSize);
  1622. ITypeInfo *childType = paramType->queryChildType();
  1623. type_t typeCode = childType->getTypeCode();
  1624. if (childType->isInteger() && !childType->isSigned())
  1625. typeCode = type_unsigned;
  1626. __ctx->bindSetParam(name, (unsigned) typeCode, paramType->queryChildType()->getSize(), isAll, totalSize, setValue.readDirect(totalSize));
  1627. break;
  1628. }
  1629. default:
  1630. return NULL;
  1631. }
  1632. }
  1633. if (body->hasAttribute(prebindAtom))
  1634. {
  1635. if (isImport)
  1636. __ctx->importFunction(queryText.lengthUtf8(), queryText.str());
  1637. else
  1638. __ctx->compileEmbeddedScript(queryText.lengthUtf8(), queryText.str());
  1639. }
  1640. __ctx->callFunction();
  1641. switch (returnType->getTypeCode())
  1642. {
  1643. case type_int:
  1644. return createConstant(returnType->isSigned() ? __ctx->getSignedResult() : __ctx->getUnsignedResult(), LINK(returnType));
  1645. case type_varstring:
  1646. case type_string:
  1647. {
  1648. size32_t lenResult;
  1649. rtlDataAttr result;
  1650. __ctx->getStringResult(lenResult, result.refstr());
  1651. return createConstant(createStringValue(result.getstr(), lenResult));
  1652. }
  1653. case type_real:
  1654. return createConstant(createRealValue(__ctx->getRealResult(), LINK(returnType)));
  1655. case type_boolean:
  1656. return createConstant(__ctx->getBooleanResult());
  1657. case type_unicode:
  1658. {
  1659. size32_t lenResult;
  1660. rtlDataAttr result;
  1661. __ctx->getUnicodeResult(lenResult, result.refustr());
  1662. return createConstant(createUnicodeValue(result.getustr(), lenResult, LINK(returnType)));
  1663. }
  1664. case type_utf8:
  1665. {
  1666. size32_t lenResult;
  1667. rtlDataAttr result;
  1668. __ctx->getUTF8Result(lenResult, result.refstr());
  1669. return createConstant(createUtf8Value(lenResult, result.getstr(), LINK(returnType)));
  1670. }
  1671. case type_data:
  1672. {
  1673. size32_t lenResult;
  1674. rtlDataAttr result;
  1675. __ctx->getDataResult(lenResult, result.refdata());
  1676. return createConstant(createDataValue(result.getstr(), lenResult));
  1677. }
  1678. case type_set:
  1679. {
  1680. ITypeInfo *childType = returnType->queryChildType();
  1681. type_t typeCode = childType->getTypeCode();
  1682. if (childType->isInteger() && !childType->isSigned())
  1683. typeCode = type_unsigned;
  1684. bool isAllResult;
  1685. size32_t resultBytes;
  1686. rtlDataAttr result;
  1687. __ctx->getSetResult(isAllResult, resultBytes, result.refdata(), (unsigned) typeCode, returnType->queryChildType()->getSize());
  1688. return deserializeConstantSet(returnType, isAllResult,resultBytes, result.getdata());
  1689. }
  1690. case type_row:
  1691. case type_table:
  1692. case type_transform:
  1693. case type_void:
  1694. // Can't do yet, maybe never - should probably check this earlier!'
  1695. return NULL;
  1696. }
  1697. return NULL;
  1698. }
  1699. //------------------------------------------------------------------------------------------
  1700. // optimize ((a BAND b) <> 0) OR ((a BAND c) <> 0) to ((a BAND (b BOR c)) <> 0)
  1701. bool isFieldMask(IHqlExpression * expr)
  1702. {
  1703. if (expr->getOperator() != no_ne)
  1704. return false;
  1705. IHqlExpression * left = expr->queryChild(0);
  1706. if (left->getOperator() != no_band)
  1707. return false;
  1708. IValue * rightValue = expr->queryChild(1)->queryValue();
  1709. if (!rightValue || rightValue->getIntValue() != 0)
  1710. return false;
  1711. return true;
  1712. }
  1713. bool isFieldMask(IHqlExpression * field, IHqlExpression * expr)
  1714. {
  1715. return isFieldMask(expr) && (expr->queryChild(0)->queryChild(0) == field);
  1716. }
  1717. IHqlExpression * combineMask(IHqlExpression * left, IHqlExpression * right)
  1718. {
  1719. IHqlExpression * zero = left->queryChild(1);
  1720. IHqlExpression * field = left->queryChild(0)->queryChild(0);
  1721. IHqlExpression * mask1 = left->queryChild(0)->queryChild(1);
  1722. IHqlExpression * mask2 = right->queryChild(0)->queryChild(1);
  1723. ITypeInfo * borType = getBorType(mask1->queryType(), mask2->queryType());
  1724. ITypeInfo * bandType = getBandType(field->queryType(), borType);
  1725. OwnedHqlExpr newMask = createValue(no_bor, borType, ensureExprType(mask1, borType), ensureExprType(mask2, borType));
  1726. IHqlExpression * newTest = createValue(no_band, bandType, ensureExprType(field, bandType), ensureExprType(newMask, bandType));
  1727. return createBoolExpr(no_ne, newTest, ensureExprType(zero, bandType));
  1728. }
  1729. bool constantComparison(IHqlExpression * field, IHqlExpression * expr, HqlExprArray & values)
  1730. {
  1731. IHqlExpression * left = expr->queryChild(0);
  1732. IHqlExpression * right = expr->queryChild(1);
  1733. switch (expr->getOperator())
  1734. {
  1735. case no_eq:
  1736. if (field && field!= left)
  1737. return false;
  1738. if (!right->queryValue())
  1739. return false;
  1740. if (values.find(*right) == NotFound)
  1741. values.append(*LINK(right));
  1742. return true;
  1743. case no_in:
  1744. {
  1745. if (field && field != left)
  1746. return false;
  1747. if (right->getOperator() != no_list)
  1748. return false;
  1749. ForEachChild(i, right)
  1750. {
  1751. IHqlExpression * cur = right->queryChild(i);
  1752. if (values.find(*cur) == NotFound)
  1753. values.append(*LINK(cur));
  1754. }
  1755. return true;
  1756. }
  1757. }
  1758. return false;
  1759. }
  1760. bool isFilteredWithin(IHqlExpression * expr, IHqlExpression * dataset, HqlExprArray & filters)
  1761. {
  1762. bool invert = false;
  1763. if (expr->getOperator() == no_not)
  1764. {
  1765. invert = true;
  1766. expr = expr->queryChild(0);
  1767. }
  1768. if (expr->getOperator() != no_within)
  1769. return false;
  1770. IHqlExpression * child0 = expr->queryChild(0);
  1771. if (child0->getOperator() != no_filter)
  1772. return false;
  1773. if (dataset && dataset != child0->queryChild(0))
  1774. return false;
  1775. unsigned max = child0->numChildren();
  1776. for (unsigned idx=1; idx < max; idx++)
  1777. {
  1778. IHqlExpression * cur = LINK(child0->queryChild(idx));
  1779. if (invert)
  1780. cur = createValue(no_not, makeBoolType(), cur);
  1781. filters.append(*cur);
  1782. }
  1783. return true;
  1784. }
  1785. void mergeWithins(node_operator op, HqlExprArray & transformedArgs)
  1786. {
  1787. for (unsigned idxWithin = 0; idxWithin < transformedArgs.ordinality(); idxWithin++)
  1788. {
  1789. IHqlExpression & cur = transformedArgs.item(idxWithin);
  1790. HqlExprArray filters;
  1791. if (isFilteredWithin(&cur, NULL, filters))
  1792. {
  1793. IHqlExpression * dataset = cur.queryChild(0)->queryChild(0);
  1794. bool changed = false;
  1795. for (unsigned idxMatch = idxWithin+1; idxMatch < transformedArgs.ordinality();)
  1796. {
  1797. IHqlExpression & match = transformedArgs.item(idxMatch);
  1798. if (isFilteredWithin(&match, dataset, filters))
  1799. {
  1800. changed = true;
  1801. transformedArgs.remove(idxMatch);
  1802. }
  1803. else
  1804. idxMatch++;
  1805. }
  1806. if (changed)
  1807. {
  1808. HqlExprArray filterArgs;
  1809. filterArgs.append(*LINK(dataset));
  1810. filterArgs.append(*createBinaryList(op, filters));
  1811. IHqlExpression * filteredDataset = createDataset(no_filter, filterArgs);
  1812. IHqlExpression * within = createValue(no_within, makeBoolType(), filteredDataset);
  1813. transformedArgs.replace(*within, idxWithin);
  1814. }
  1815. }
  1816. }
  1817. }
  1818. IHqlExpression * foldOrExpr(IHqlExpression * expr, bool fold_x_op_not_x)
  1819. {
  1820. HqlExprArray args, transformedArgs;
  1821. expr->unwindList(args, expr->getOperator());
  1822. //First transform all the arguments, removing and always false, and short circuit if always true
  1823. //also remove duplicates a || a == a
  1824. ForEachItemIn(idx, args)
  1825. {
  1826. IHqlExpression * transformed = &args.item(idx);
  1827. IValue * value = transformed->queryValue();
  1828. if (value)
  1829. {
  1830. if (value->getBoolValue())
  1831. return LINK(transformed);
  1832. }
  1833. else
  1834. {
  1835. if (transformedArgs.find(*transformed) == NotFound)
  1836. {
  1837. if (fold_x_op_not_x)
  1838. {
  1839. //Check for x OR NOT x => always true...
  1840. //Needs to be done this way because the no_not often gets folded...
  1841. OwnedHqlExpr inverse = createValue(no_not, makeBoolType(), LINK(transformed));
  1842. if (transformedArgs.contains(*inverse))
  1843. return createConstant(true);
  1844. }
  1845. transformedArgs.append(*LINK(transformed));
  1846. }
  1847. }
  1848. }
  1849. if (transformedArgs.ordinality() == 0)
  1850. return createConstant(false);
  1851. // optimize ((a BAND b) <> 0) OR ((a BAND c) <> 0) to ((a BAND (b BOR c)) <> 0)
  1852. for (unsigned idx2 = 0; idx2 < transformedArgs.ordinality()-1; idx2++)
  1853. {
  1854. IHqlExpression & cur = transformedArgs.item(idx2);
  1855. if (isFieldMask(&cur))
  1856. {
  1857. IHqlExpression * masked = cur.queryChild(0)->queryChild(0);
  1858. LinkedHqlExpr combined = &cur;
  1859. for (unsigned idx3 = transformedArgs.ordinality()-1; idx3 != idx2; idx3--)
  1860. {
  1861. IHqlExpression & cur2 = transformedArgs.item(idx3);
  1862. if (isFieldMask(masked, &cur2))
  1863. {
  1864. combined.setown(combineMask(combined, &cur2));
  1865. transformedArgs.remove(idx3);
  1866. }
  1867. }
  1868. if (combined != &cur)
  1869. transformedArgs.replace(*combined.getClear(), idx2);
  1870. }
  1871. }
  1872. //optimize x=a|x=b|x=c to x in (a,b,c)
  1873. HqlExprArray constantValues;
  1874. for (unsigned idx4 = 0; idx4 < transformedArgs.ordinality()-1; idx4++)
  1875. {
  1876. IHqlExpression & cur = transformedArgs.item(idx4);
  1877. constantValues.kill();
  1878. if (constantComparison(NULL, &cur, constantValues))
  1879. {
  1880. bool merged = false;
  1881. IHqlExpression * compare = cur.queryChild(0);
  1882. for (unsigned idx5 = idx4+1; idx5 < transformedArgs.ordinality(); )
  1883. {
  1884. IHqlExpression & cur2 = transformedArgs.item(idx5);
  1885. if (constantComparison(compare, &cur2, constantValues))
  1886. {
  1887. merged = true;
  1888. transformedArgs.remove(idx5);
  1889. }
  1890. else
  1891. idx5++;
  1892. }
  1893. if (merged)
  1894. {
  1895. //MORE: Should promote all items in the list to the same type.
  1896. IHqlExpression & first = constantValues.item(0);
  1897. IHqlExpression * list = createValue(no_list, makeSetType(first.getType()), constantValues);
  1898. OwnedHqlExpr combined = createBoolExpr(no_in, LINK(compare), list);
  1899. transformedArgs.replace(*combined.getClear(), idx4);
  1900. }
  1901. }
  1902. }
  1903. #if 0
  1904. else
  1905. {
  1906. // optimize (( BOOL)(a BAND b) ) OR ((bool)(a BAND c) ) to ((bool)(a BAND (b BOR c)) )
  1907. // Lots of work for a very particular special case that happens a lot in DMS
  1908. assertex (leftChild->queryType() == rightChild->queryType());
  1909. assertex (leftChild->queryType()->getTypeCode() == type_boolean);
  1910. #if 0
  1911. dbglogExpr(leftChild->queryBody());
  1912. dbglogExpr(rightChild->queryBody());
  1913. #endif
  1914. IHqlExpression *select = NULL;
  1915. if (leftChild->getOperator()==no_select && rightChild->getOperator()==no_select && leftChild->queryChild(0)==rightChild->queryChild(0))
  1916. {
  1917. select = leftChild->queryChild(0);
  1918. leftChild.set(leftChild->queryChild(1));
  1919. rightChild.set(rightChild->queryChild(1));
  1920. }
  1921. while (leftChild && leftChild->getOperator()==no_field)
  1922. leftChild.set(leftChild->queryChild(0));
  1923. while (rightChild && rightChild->getOperator()==no_field)
  1924. rightChild.set(rightChild->queryChild(0));
  1925. if (leftChild && rightChild)
  1926. {
  1927. #if 0
  1928. dbglogExpr(leftChild->queryBody());
  1929. dbglogExpr(rightChild->queryBody());
  1930. #endif
  1931. if (isCast(leftChild) && isCast(rightChild))
  1932. {
  1933. IHqlExpression * lBand = leftChild->queryChild(0);
  1934. IHqlExpression * rBand = rightChild->queryChild(0);
  1935. if (lBand->getOperator() == no_band && rBand->getOperator() == no_band)
  1936. {
  1937. IHqlExpression * aLeft = lBand->queryChild(0);
  1938. IHqlExpression * aRight = rBand->queryChild(0);
  1939. if (aLeft == aRight)
  1940. {
  1941. IHqlExpression * bLeft = lBand->queryChild(1);
  1942. IHqlExpression * cRight = rBand->queryChild(1);
  1943. IHqlExpression * newBor = createValue(no_bor, getPromotedType(bLeft->queryType(), cRight->queryType()), LINK(bLeft), LINK(cRight));
  1944. IHqlExpression * newBand = createValue(no_band, getPromotedType(aLeft->queryType(), newBor->queryType()), LINK(aLeft), newBor);
  1945. OwnedHqlExpr newNode = createBoolExpr(no_cast, newBand);
  1946. if (select)
  1947. newNode.setown(createBoolExpr(no_select, LINK(select), newNode.getClear());
  1948. return transform(newNode);
  1949. }
  1950. }
  1951. }
  1952. }
  1953. }
  1954. #endif
  1955. //mergeWithins(no_or, transformedArgs);
  1956. if (arraysSame(args, transformedArgs))
  1957. return LINK(expr);
  1958. return createBinaryList(no_or, transformedArgs);
  1959. }
  1960. IHqlExpression * foldAndExpr(IHqlExpression * expr, bool fold_x_op_not_x)
  1961. {
  1962. HqlExprArray args, transformedArgs;
  1963. expr->unwindList(args, expr->getOperator());
  1964. //First transform all the arguments, removing if always true, and short circuit if always false
  1965. //also remove duplicates a && a == a
  1966. ForEachItemIn(idx, args)
  1967. {
  1968. IHqlExpression * cur = &args.item(idx);
  1969. IValue * value = cur->queryValue();
  1970. if (value)
  1971. {
  1972. if (!value->getBoolValue())
  1973. return LINK(cur);
  1974. }
  1975. else
  1976. {
  1977. if (transformedArgs.find(*cur) == NotFound)
  1978. {
  1979. if (fold_x_op_not_x)
  1980. {
  1981. //Check for x AND NOT x. => false
  1982. OwnedHqlExpr inverse = getInverse(cur);
  1983. if (transformedArgs.find(*inverse) != NotFound)
  1984. return createConstant(false);
  1985. }
  1986. transformedArgs.append(*LINK(cur));
  1987. }
  1988. }
  1989. }
  1990. //mergeWithins(no_and, transformedArgs);
  1991. if (transformedArgs.ordinality() == 0)
  1992. return createConstant(true);
  1993. if (arraysSame(args, transformedArgs))
  1994. return LINK(expr);
  1995. return createBinaryList(no_and, transformedArgs);
  1996. }
  1997. IHqlExpression * applyBinaryFold(IHqlExpression * expr, binaryFoldFunc folder)
  1998. {
  1999. IHqlExpression * leftChild = expr->queryChild(0);
  2000. IHqlExpression * rightChild = expr->queryChild(1);
  2001. IValue * leftValue = leftChild->queryValue();
  2002. IValue * rightValue = rightChild->queryValue();
  2003. if (leftValue && rightValue)
  2004. {
  2005. IValue * res = folder(leftValue, rightValue);
  2006. assertex(res);
  2007. #if 0
  2008. //A useful consistency test, but not always true for no_concat, so commented out for the moment
  2009. if (!isUnknownSize(expr->queryType()))
  2010. assertex(res->queryType() == expr->queryType());
  2011. #endif
  2012. return createConstant(res);
  2013. }
  2014. return LINK(expr);
  2015. }
  2016. static bool isStringOrUnicode(ITypeInfo * type)
  2017. {
  2018. switch (type->getTypeCode())
  2019. {
  2020. case type_data:
  2021. case type_string:
  2022. case type_varstring:
  2023. case type_qstring:
  2024. case type_unicode:
  2025. case type_varunicode:
  2026. case type_utf8:
  2027. return true;
  2028. }
  2029. return false;
  2030. }
  2031. static bool isNonAscii(ITypeInfo * type)
  2032. {
  2033. switch (type->getTypeCode())
  2034. {
  2035. case type_string:
  2036. case type_varstring:
  2037. return type->queryCharset()->queryName() != asciiAtom;
  2038. }
  2039. return false;
  2040. }
  2041. static bool castHidesConversion(ITypeInfo * t1, ITypeInfo * t2, ITypeInfo * t3)
  2042. {
  2043. return (t1->getTypeCode() == type_data) && (isNonAscii(t2) || isNonAscii(t3));
  2044. }
  2045. static IHqlExpression * optimizeConstInList(IValue * search, IHqlExpression * list)
  2046. {
  2047. if (!list) return NULL;
  2048. switch (list->getOperator())
  2049. {
  2050. case no_null:
  2051. case no_all:
  2052. return LINK(list);
  2053. case no_list:
  2054. {
  2055. HqlExprArray values;
  2056. bool same = true;
  2057. unsigned num = list->numChildren();
  2058. for (unsigned idx = 0; idx < num; idx++)
  2059. {
  2060. IHqlExpression * elem = list->queryChild(idx);
  2061. IValue * constValue = elem->queryValue();
  2062. if (constValue)
  2063. {
  2064. if (orderValues(search, constValue) == 0)
  2065. return createValue(no_all, list->getType());
  2066. same = false;
  2067. }
  2068. else
  2069. values.append(*LINK(elem));
  2070. }
  2071. if (same)
  2072. return LINK(list);
  2073. return list->clone(values);
  2074. }
  2075. case no_addsets:
  2076. {
  2077. IHqlExpression * lhs = list->queryChild(0);
  2078. IHqlExpression * rhs = list->queryChild(1);
  2079. OwnedHqlExpr newLhs = optimizeConstInList(search, lhs);
  2080. OwnedHqlExpr newRhs = optimizeConstInList(search, rhs);
  2081. if ((newLhs->getOperator() == no_all) || isNullList(newRhs))
  2082. return LINK(newLhs);
  2083. if ((newRhs->getOperator() == no_all) || isNullList(newLhs))
  2084. return LINK(newRhs);
  2085. if ((lhs == newLhs) && (rhs == newRhs))
  2086. return LINK(list);
  2087. if ((newLhs->getOperator() != no_list) || (newRhs->getOperator() != no_list))
  2088. return createValue(no_addsets, list->getType(), newLhs.getClear(), newRhs.getClear());
  2089. HqlExprArray args;
  2090. unwindChildren(args, newLhs);
  2091. unwindChildren(args, newRhs);
  2092. return createValue(no_list, list->getType(), args);
  2093. }
  2094. case no_if:
  2095. {
  2096. IHqlExpression * lhs = list->queryChild(1);
  2097. IHqlExpression * rhs = list->queryChild(2);
  2098. OwnedHqlExpr newLhs = optimizeConstInList(search, lhs);
  2099. OwnedHqlExpr newRhs = optimizeConstInList(search, rhs);
  2100. //might both turn out to be all/empty
  2101. if (newLhs->queryBody() == newRhs->queryBody())
  2102. return LINK(newLhs);
  2103. if ((lhs == newLhs) && (rhs == newRhs))
  2104. return LINK(list);
  2105. HqlExprArray args;
  2106. unwindChildren(args, list);
  2107. args.replace(*newLhs.getClear(), 1);
  2108. args.replace(*newRhs.getClear(), 2);
  2109. return list->clone(args);
  2110. }
  2111. }
  2112. return LINK(list);
  2113. }
  2114. static bool hashElement(node_operator op, IHqlExpression * expr, unsigned __int64 & hashCode)
  2115. {
  2116. IValue * value = expr->queryValue();
  2117. if (!value)
  2118. return false;
  2119. ITypeInfo * type = value->queryType();
  2120. switch (type->getTypeCode())
  2121. {
  2122. case type_qstring:
  2123. case type_string:
  2124. {
  2125. Owned<ITypeInfo> unknownLengthString = makeStringType(UNKNOWN_LENGTH);
  2126. Owned<IValue> castValue = value->castTo(unknownLengthString);
  2127. const char * cdata = static_cast<const char *>(castValue->queryValue());
  2128. size32_t len = rtlTrimStrLen(castValue->queryType()->getStringLen(), cdata);
  2129. hashCode = (op == no_hash32) ? rtlHash32Data(len, cdata, (unsigned)hashCode) : rtlHash64Data(len, cdata, hashCode);
  2130. return true;
  2131. }
  2132. case type_data:
  2133. {
  2134. size32_t len = type->getSize();
  2135. const char * cdata = static_cast<const char *>(value->queryValue());
  2136. hashCode = (op == no_hash32) ? rtlHash32Data(len, cdata, (unsigned)hashCode) : rtlHash64Data(len, cdata, hashCode);
  2137. return true;
  2138. }
  2139. case type_varstring:
  2140. {
  2141. const char * cdata = static_cast<const char *>(value->queryValue());
  2142. hashCode = (op == no_hash32) ? rtlHash32VStr(cdata, (unsigned)hashCode) : rtlHash64VStr(cdata, hashCode);
  2143. return true;
  2144. }
  2145. case type_unicode:
  2146. {
  2147. const UChar * udata = static_cast<const UChar *>(value->queryValue());
  2148. size32_t len = type->getStringLen();
  2149. hashCode = (op == no_hash32) ? rtlHash32Unicode(len, udata, (unsigned)hashCode) : rtlHash64Unicode(len, udata, hashCode);
  2150. return true;
  2151. }
  2152. case type_varunicode:
  2153. {
  2154. const UChar * udata = static_cast<const UChar *>(value->queryValue());
  2155. hashCode = (op == no_hash32) ? rtlHash32VUnicode(udata, (unsigned)hashCode) : rtlHash64VUnicode(udata, hashCode);
  2156. return true;
  2157. }
  2158. case type_utf8:
  2159. {
  2160. const char * udata = static_cast<const char *>(value->queryValue());
  2161. size32_t len = rtlTrimUtf8StrLen(type->getStringLen(), udata);
  2162. hashCode = (op == no_hash32) ? rtlHash32Utf8(len, udata, (unsigned)hashCode) : rtlHash64Utf8(len, udata, hashCode);
  2163. return true;
  2164. }
  2165. case type_int:
  2166. case type_swapint:
  2167. {
  2168. unsigned __int64 intValue = value->getIntValue();
  2169. hashCode = (op == no_hash32) ? rtlHash32Data(sizeof(intValue), &intValue, (unsigned)hashCode) : rtlHash64Data(sizeof(intValue), &intValue, hashCode);
  2170. return true;
  2171. }
  2172. break;
  2173. }
  2174. return false;
  2175. }
  2176. static IHqlExpression * foldHashXX(IHqlExpression * expr)
  2177. {
  2178. IHqlExpression * child = expr->queryChild(0);
  2179. node_operator op = expr->getOperator();
  2180. unsigned __int64 hashCode = 0;
  2181. switch (op)
  2182. {
  2183. case no_hash32:
  2184. hashCode = HASH32_INIT;
  2185. break;
  2186. case no_hash64:
  2187. hashCode = HASH64_INIT;
  2188. break;
  2189. }
  2190. if (child->getOperator() == no_sortlist)
  2191. {
  2192. ForEachChild(i, child)
  2193. {
  2194. if (!hashElement(op, child->queryChild(i), hashCode))
  2195. return NULL;
  2196. }
  2197. }
  2198. else
  2199. {
  2200. if (!hashElement(op, child, hashCode))
  2201. return NULL;
  2202. }
  2203. return createConstant(expr->queryType()->castFrom(true, (__int64)hashCode));
  2204. }
  2205. //---------------------------------------------------------------------------
  2206. IHqlExpression * foldConstantOperator(IHqlExpression * expr, unsigned foldOptions, ITemplateContext * templateContext)
  2207. {
  2208. DBZaction onZero = (foldOptions & HFOforcefold) ? DBZfail : DBZnone;
  2209. node_operator op = expr->getOperator();
  2210. switch (op)
  2211. {
  2212. case no_assertkeyed:
  2213. {
  2214. assertex(expr->hasAttribute(_selectors_Atom));
  2215. IHqlExpression * child = expr->queryChild(0);
  2216. IValue * value = child->queryValue();
  2217. if (value)
  2218. {
  2219. if (!value->getBoolValue())
  2220. return LINK(child);
  2221. IHqlExpression * opt = expr->queryAttribute(extendAtom);
  2222. IHqlExpression * selectors = expr->queryAttribute(_selectors_Atom);
  2223. return createValue(no_assertwild, makeBoolType(), createValue(no_all), LINK(selectors), LINK(opt));
  2224. }
  2225. break;
  2226. }
  2227. case no_or:
  2228. case no_and:
  2229. {
  2230. IHqlExpression * left = expr->queryChild(0);
  2231. IHqlExpression * right = expr->queryChild(1);
  2232. IValue * leftValue = left->queryValue();
  2233. if (leftValue)
  2234. {
  2235. bool leftBool = leftValue->getBoolValue();
  2236. if ((op == no_and) ? leftBool : !leftBool)
  2237. return LINK(right);
  2238. return LINK(left);
  2239. }
  2240. IValue * rightValue = right->queryValue();
  2241. if (rightValue)
  2242. {
  2243. bool rightBool = rightValue->getBoolValue();
  2244. if ((op == no_and) ? rightBool : !rightBool)
  2245. return LINK(left);
  2246. return LINK(right);
  2247. }
  2248. break;
  2249. }
  2250. case no_assertconstant:
  2251. case no_globalscope:
  2252. {
  2253. IHqlExpression * child = expr->queryChild(0);
  2254. if (child->queryValue())
  2255. return LINK(child);
  2256. break;
  2257. }
  2258. case no_not:
  2259. {
  2260. node_operator inverseOp = no_none;
  2261. IHqlExpression * child = expr->queryChild(0);
  2262. switch (child->getOperator())
  2263. {
  2264. case no_not:
  2265. return ensureExprType(child->queryChild(0), expr->queryType());
  2266. case no_constant:
  2267. return createConstant(!child->queryValue()->getBoolValue());
  2268. case no_notnot:
  2269. inverseOp = no_not;
  2270. break;
  2271. case no_eq:
  2272. inverseOp = no_ne;
  2273. break;
  2274. case no_ne:
  2275. inverseOp = no_eq;
  2276. break;
  2277. case no_lt:
  2278. inverseOp = no_ge;
  2279. break;
  2280. case no_le:
  2281. inverseOp = no_gt;
  2282. break;
  2283. case no_gt:
  2284. inverseOp = no_le;
  2285. break;
  2286. case no_ge:
  2287. inverseOp = no_lt;
  2288. break;
  2289. case no_in:
  2290. inverseOp = no_notin;
  2291. break;
  2292. case no_notin:
  2293. inverseOp = no_in;
  2294. break;
  2295. case no_between:
  2296. inverseOp = no_notbetween;
  2297. break;
  2298. case no_notbetween:
  2299. inverseOp = no_between;
  2300. break;
  2301. case no_if:
  2302. if (child->queryChild(1)->isConstant() || child->queryChild(2)->isConstant())
  2303. return getInverse(child);
  2304. break;
  2305. }
  2306. if (inverseOp)
  2307. {
  2308. HqlExprArray children;
  2309. unwindChildren(children, child);
  2310. return createValue(inverseOp, child->getType(), children);
  2311. }
  2312. break;
  2313. }
  2314. case no_add:
  2315. {
  2316. IHqlExpression * left = expr->queryChild(0);
  2317. IHqlExpression * right = expr->queryChild(1);
  2318. if (isZero(left))
  2319. return ensureExprType(right, expr->queryType());
  2320. if (isZero(right))
  2321. return ensureExprType(left, expr->queryType());
  2322. return applyBinaryFold(expr, addValues);
  2323. }
  2324. case no_sub:
  2325. {
  2326. IHqlExpression * left = expr->queryChild(0);
  2327. IHqlExpression * right = expr->queryChild(1);
  2328. if (isZero(right))
  2329. return ensureExprType(left, expr->queryType());
  2330. return applyBinaryFold(expr, subtractValues);
  2331. }
  2332. case no_hash32:
  2333. case no_hash64:
  2334. {
  2335. IHqlExpression * folded = foldHashXX(expr);
  2336. if (folded)
  2337. return folded;
  2338. break;
  2339. }
  2340. case no_mul:
  2341. {
  2342. IHqlExpression * left = expr->queryChild(0);
  2343. IHqlExpression * right = expr->queryChild(1);
  2344. //Multiply by zero (from constant folding count(ds)) can reduce a non-constant dataset to constant
  2345. if (isZero(left) || isZero(right))
  2346. {
  2347. OwnedHqlExpr zero = getSizetConstant(0);
  2348. return ensureExprType(zero, expr->queryType());
  2349. }
  2350. if (matchesConstantValue(left, 1))
  2351. return ensureExprType(right, expr->queryType());
  2352. if (matchesConstantValue(right, 1))
  2353. return ensureExprType(left, expr->queryType());
  2354. return applyBinaryFold(expr, multiplyValues);
  2355. }
  2356. case no_div:
  2357. if (matchesConstantValue(expr->queryChild(1), 1))
  2358. {
  2359. IHqlExpression * left = expr->queryChild(0);
  2360. if (left->queryType()->isInteger())
  2361. return ensureExprType(left, expr->queryType());
  2362. }
  2363. //fall through
  2364. case no_modulus:
  2365. {
  2366. IValue * leftValue = expr->queryChild(0)->queryValue();
  2367. IValue * rightValue = expr->queryChild(1)->queryValue();
  2368. if (leftValue && rightValue)
  2369. {
  2370. IValue * res;
  2371. if (op == no_div)
  2372. res = divideValues(leftValue, rightValue, onZero);
  2373. else
  2374. res = modulusValues(leftValue, rightValue, onZero);
  2375. if (res)
  2376. return createConstant(res);
  2377. }
  2378. return LINK(expr);
  2379. }
  2380. case no_concat:
  2381. return applyBinaryFold(expr, concatValues);
  2382. case no_band:
  2383. {
  2384. if (isZero(expr->queryChild(0)) || isZero(expr->queryChild(1)))
  2385. return createConstant(expr->queryType()->castFrom(true, I64C(0)));
  2386. OwnedHqlExpr ret = applyBinaryFold(expr, binaryAndValues);
  2387. if (ret->getOperator() == no_band)
  2388. {
  2389. // ((x BAND y) BAND z) == (x BAND (y BAND z)) - especially if y + z are constants.
  2390. IHqlExpression * leftChild = ret->queryChild(0);
  2391. if (leftChild->getOperator()==no_band)
  2392. {
  2393. IValue * rightValue = ret->queryChild(1)->queryValue();
  2394. if (rightValue)
  2395. {
  2396. IValue * grandValue = leftChild->queryChild(1)->queryValue();
  2397. if (grandValue)
  2398. {
  2399. IHqlExpression * mask = createConstant(binaryAndValues(grandValue, rightValue));
  2400. IHqlExpression * newBand = createValue(no_band, expr->getType(), LINK(leftChild->queryChild(0)), mask);
  2401. return newBand;
  2402. }
  2403. }
  2404. }
  2405. }
  2406. return ret.getClear();
  2407. }
  2408. case no_bor:
  2409. {
  2410. IHqlExpression * lhs = expr->queryChild(0);
  2411. IHqlExpression * rhs = expr->queryChild(1);
  2412. if (isZero(lhs))
  2413. return ensureExprType(rhs, expr->queryType());
  2414. if (isZero(rhs))
  2415. return ensureExprType(lhs, expr->queryType());
  2416. return applyBinaryFold(expr, binaryOrValues);
  2417. }
  2418. case no_bxor:
  2419. return applyBinaryFold(expr, binaryXorValues);
  2420. case no_power:
  2421. return applyBinaryFold(expr, powerValues);
  2422. case no_atan2:
  2423. return applyBinaryFold(expr, atan2Value);
  2424. case no_lshift:
  2425. return applyBinaryFold(expr, shiftLeftValues);
  2426. case no_rshift:
  2427. return applyBinaryFold(expr, shiftRightValues);
  2428. case no_regex_find:
  2429. {
  2430. IValue * t0 = expr->queryChild(0)->queryValue();
  2431. IValue * t1 = expr->queryChild(1)->queryValue();
  2432. IHqlExpression * c2 = queryRealChild(expr, 2);
  2433. IValue * t2 = c2 ? c2->queryValue() : NULL;
  2434. if (t0 && t1 && (!c2 || t2))
  2435. {
  2436. IValue * result;
  2437. if(isUnicodeType(t0->queryType()))
  2438. {
  2439. unsigned plen = t0->queryType()->getStringLen();
  2440. unsigned slen = t1->queryType()->getStringLen();
  2441. UChar * pattern = (UChar *)malloc((plen+1)*2);
  2442. UChar * search = (UChar *)malloc((slen)*2);
  2443. t0->getUCharStringValue(plen+1, pattern); //plen+1 so get null-terminated
  2444. t1->getUCharStringValue(slen, search);
  2445. ICompiledUStrRegExpr * compiled = rtlCreateCompiledUStrRegExpr(pattern, !expr->hasAttribute(noCaseAtom));
  2446. IUStrRegExprFindInstance * match = compiled->find(search, 0, slen);
  2447. ITypeInfo * type = expr->queryType();
  2448. if(type->getTypeCode() == type_boolean)
  2449. {
  2450. result = createBoolValue(match->found());
  2451. }
  2452. else
  2453. {
  2454. assertex(c2 && t2);
  2455. size32_t len;
  2456. UChar * data;
  2457. match->getMatchX(len, data, (unsigned)t2->getIntValue());
  2458. result = createUnicodeValue(len, data, LINK(type));
  2459. rtlFree(data);
  2460. }
  2461. rtlDestroyUStrRegExprFindInstance(match);
  2462. rtlDestroyCompiledUStrRegExpr(compiled);
  2463. free(pattern);
  2464. free(search);
  2465. }
  2466. else
  2467. {
  2468. StringBuffer pattern, search;
  2469. t0->getStringValue(pattern);
  2470. t1->getStringValue(search);
  2471. rtlCompiledStrRegex compiled;
  2472. compiled.setPattern(pattern.str(), !expr->hasAttribute(noCaseAtom));
  2473. IStrRegExprFindInstance * match = compiled->find(search.str(), 0, search.length(), false);
  2474. ITypeInfo * type = expr->queryType();
  2475. if(type->getTypeCode() == type_boolean)
  2476. {
  2477. result = createBoolValue(match->found());
  2478. }
  2479. else
  2480. {
  2481. assertex(c2 && t2);
  2482. size32_t len;
  2483. char * data;
  2484. match->getMatchX(len, data, (unsigned)t2->getIntValue());
  2485. result = type->castFrom(len, data);
  2486. rtlFree(data);
  2487. }
  2488. rtlDestroyStrRegExprFindInstance(match);
  2489. }
  2490. return createConstant(result);
  2491. }
  2492. break;
  2493. }
  2494. case no_regex_findset:
  2495. {
  2496. IValue * v0 = expr->queryChild(0)->queryValue();
  2497. IValue * v1 = expr->queryChild(1)->queryValue();
  2498. if (v0 && v1)
  2499. {
  2500. bool isAllResult;
  2501. size32_t resultBytes;
  2502. rtlDataAttr matchResults;
  2503. if(isUnicodeType(v0->queryType()))
  2504. {
  2505. size32_t plen = v0->queryType()->getStringLen();
  2506. OwnedMalloc<UChar> pattern (plen+1);
  2507. v0->getUCharStringValue(plen+1, pattern.get()); //plen+1 so get null-terminated
  2508. size32_t slen = v1->queryType()->getStringLen();
  2509. OwnedMalloc<UChar> search (slen);
  2510. v1->getUCharStringValue(slen, search);
  2511. ICompiledUStrRegExpr * compiled = rtlCreateCompiledUStrRegExpr(pattern, !expr->hasAttribute(noCaseAtom));
  2512. compiled->getMatchSet(isAllResult, resultBytes, matchResults.refdata(), slen, search.get());
  2513. rtlDestroyCompiledUStrRegExpr(compiled);
  2514. }
  2515. else
  2516. {
  2517. StringBuffer pattern, search;
  2518. v0->getStringValue(pattern);
  2519. v1->getStringValue(search);
  2520. rtlCompiledStrRegex compiled;
  2521. compiled.setPattern(pattern.str(), !expr->hasAttribute(noCaseAtom));
  2522. compiled->getMatchSet(isAllResult, resultBytes, matchResults.refdata(), search.length(), search.str());
  2523. }
  2524. return convertSetToExpression(isAllResult, resultBytes, matchResults.getdata(), expr->queryType());
  2525. }
  2526. break;
  2527. }
  2528. case no_regex_replace:
  2529. {
  2530. IValue * t0 = expr->queryChild(0)->queryValue();
  2531. IValue * t1 = expr->queryChild(1)->queryValue();
  2532. IValue * t2 = expr->queryChild(2)->queryValue();
  2533. if (t0 && t1 && t2)
  2534. {
  2535. IValue * result;
  2536. if(isUnicodeType(t0->queryType()))
  2537. {
  2538. unsigned plen = t0->queryType()->getStringLen();
  2539. unsigned slen = t1->queryType()->getStringLen();
  2540. unsigned rlen = t2->queryType()->getStringLen();
  2541. UChar * pattern = (UChar *)malloc((plen+1)*2);
  2542. UChar * search = (UChar *)malloc(slen*2);
  2543. UChar * replace = (UChar *)malloc(rlen*2);
  2544. t0->getUCharStringValue(plen+1, pattern); //plen+1 so null-terminated
  2545. t1->getUCharStringValue(slen, search);
  2546. t2->getUCharStringValue(rlen, replace);
  2547. size32_t outlen;
  2548. UChar * out;
  2549. ICompiledUStrRegExpr * compiled = rtlCreateCompiledUStrRegExpr(pattern, !expr->hasAttribute(noCaseAtom));
  2550. compiled->replace(outlen, out, slen, search, rlen, replace);
  2551. result = createUnicodeValue(outlen, out, expr->getType());
  2552. rtlFree(out);
  2553. rtlDestroyCompiledUStrRegExpr(compiled);
  2554. free(pattern);
  2555. free(search);
  2556. free(replace);
  2557. }
  2558. else
  2559. {
  2560. StringBuffer pattern, search, replace;
  2561. t0->getStringValue(pattern);
  2562. t1->getStringValue(search);
  2563. t2->getStringValue(replace);
  2564. size32_t outlen;
  2565. char * out;
  2566. rtlCompiledStrRegex compiled;
  2567. compiled.setPattern(pattern.str(), !expr->hasAttribute(noCaseAtom));
  2568. compiled->replace(outlen, out, search.length(), search.str(), replace.length(), replace.str());
  2569. result = createStringValue(out, outlen);
  2570. rtlFree(out);
  2571. }
  2572. return createConstant(result);
  2573. }
  2574. break;
  2575. }
  2576. case no_intformat:
  2577. {
  2578. IValue * c0 = expr->queryChild(0)->queryValue();
  2579. IValue * c1 = expr->queryChild(1)->queryValue();
  2580. IValue * c2 = expr->queryChild(2)->queryValue();
  2581. if (c0 && c1 && c2)
  2582. {
  2583. __int64 value = c0->getIntValue();
  2584. unsigned width = (unsigned)c1->getIntValue();
  2585. unsigned flags = (unsigned)c2->getIntValue();
  2586. if ((int) width < 0)
  2587. width = 0;
  2588. MemoryAttr tempBuffer(width);
  2589. holeIntFormat(width, (char *)tempBuffer.bufferBase(), value, width, flags);
  2590. return createConstant(createStringValue((char *)tempBuffer.bufferBase(), width));
  2591. }
  2592. break;
  2593. }
  2594. case no_realformat:
  2595. {
  2596. IValue * c0 = expr->queryChild(0)->queryValue();
  2597. IValue * c1 = expr->queryChild(1)->queryValue();
  2598. IValue * c2 = expr->queryChild(2)->queryValue();
  2599. if (c0 && c1 && c2)
  2600. {
  2601. double value = c0->getRealValue();
  2602. unsigned width = (unsigned)c1->getIntValue();
  2603. unsigned places = (unsigned)c2->getIntValue();
  2604. unsigned len;
  2605. char * ptr;
  2606. rtlRealFormat(len, ptr, value, width, places);
  2607. IHqlExpression * ret = createConstant(createStringValue(ptr, len));
  2608. rtlFree(ptr);
  2609. return ret;
  2610. }
  2611. break;
  2612. }
  2613. case no_indict:
  2614. if (isNull(expr->queryChild(1)))
  2615. return createConstant(false);
  2616. break;
  2617. case no_in:
  2618. case no_notin:
  2619. {
  2620. IHqlExpression * child = expr->queryChild(0);
  2621. IHqlExpression * originalList = expr->queryChild(1);
  2622. IValue * constValue = child->queryValue();
  2623. OwnedHqlExpr inList = normalizeListCasts(originalList);
  2624. if (constValue)
  2625. inList.setown(optimizeConstInList(constValue, inList));
  2626. switch (inList->getOperator())
  2627. {
  2628. case no_all:
  2629. return createConstant((op == no_in));
  2630. case no_null:
  2631. return createConstant((op != no_in));
  2632. case no_if:
  2633. {
  2634. IHqlExpression * lhs = inList->queryChild(1);
  2635. IHqlExpression * rhs = inList->queryChild(2);
  2636. if ((foldOptions & (HFOcanbreakshared|HFOforcefold)) || (lhs->isConstant() && rhs->isConstant()))
  2637. {
  2638. IHqlExpression * ret = querySimplifyInExpr(expr);
  2639. if (ret)
  2640. return ret;
  2641. }
  2642. break;
  2643. }
  2644. case no_addsets:
  2645. {
  2646. if (foldOptions & (HFOcanbreakshared|HFOforcefold))
  2647. {
  2648. IHqlExpression * ret = querySimplifyInExpr(expr);
  2649. if (ret)
  2650. return ret;
  2651. }
  2652. break;
  2653. }
  2654. }
  2655. if (inList->getOperator() == no_list)
  2656. {
  2657. if (inList->numChildren() == 0)
  2658. return createConstant((op != no_in));
  2659. bool allConst = inList->isConstant();
  2660. if (inList->numChildren() == 1)
  2661. {
  2662. op = (op==no_in) ? no_eq : no_ne;
  2663. IHqlExpression * item1 = inList->queryChild(0);
  2664. Owned<ITypeInfo> type = getPromotedCompareType(child->queryType(), item1->queryType());
  2665. return createBoolExpr(op, ensureExprType(child, type), ensureExprType(item1, type));
  2666. }
  2667. //MORE: Could still remove cases that were impossible to reduce the comparison time,
  2668. // even if the default value is included in the list.
  2669. if (allConst)
  2670. {
  2671. switch (child->getOperator())
  2672. {
  2673. case no_case:
  2674. {
  2675. // CASE(x,a1=>v1,a2=>v2,v3) IN [x1,x2,x3,x4]
  2676. // becomes CASE(x,a1=>v1 IN X,a2=>v2 IN X, v3 IN X)
  2677. // becomes x [NOT] IN [am] where vm is in x1..xn
  2678. HqlExprArray caseResults;
  2679. if (flattenConstantCase(child, caseResults, true))
  2680. {
  2681. IValue *defval = child->queryChild(child->numChildren()-1)->queryValue();
  2682. if (defval)
  2683. {
  2684. bool defaultInList = isInList(defval, inList);
  2685. HqlExprArray exceptions;
  2686. ForEachItemIn(i, caseResults)
  2687. {
  2688. IHqlExpression * inConst = &caseResults.item(i);
  2689. IValue * inValue = inConst->queryValue();
  2690. bool thisInList = isInList(inValue, inList);
  2691. if (thisInList != defaultInList)
  2692. exceptions.append(*LINK(child->queryChild(i+1)->queryChild(0)));
  2693. }
  2694. bool defaultReturn = (defaultInList && op==no_in) || (!defaultInList && op==no_notin);
  2695. if (exceptions.ordinality() == 0)
  2696. return createConstant(defaultReturn);
  2697. node_operator inOp = defaultReturn ? no_notin : no_in;
  2698. IHqlExpression * test = child->queryChild(0);
  2699. return createBoolExpr(inOp,
  2700. LINK(test),
  2701. createValue(no_list, makeSetType(test->getType()), exceptions));
  2702. }
  2703. }
  2704. }
  2705. break;
  2706. case no_cast:
  2707. case no_implicitcast:
  2708. {
  2709. HqlExprArray inConstants;
  2710. unwindChildren(inConstants, inList);
  2711. IHqlExpression * ret = optimizeCastList(child, inConstants, op);
  2712. if (ret)
  2713. return ret;
  2714. break;
  2715. }
  2716. }
  2717. }
  2718. if (inList != originalList)
  2719. return replaceChild(expr, 1, inList);
  2720. }
  2721. break;
  2722. }
  2723. case no_if:
  2724. {
  2725. IHqlExpression * child = expr->queryChild(0);
  2726. IValue * constValue = child->queryValue();
  2727. if (constValue)
  2728. {
  2729. unsigned idx = constValue->getBoolValue() ? 1 : 2;
  2730. IHqlExpression * branch = expr->queryChild(idx);
  2731. if (!branch)
  2732. {
  2733. assertex(expr->isAction());
  2734. return createValue(no_null, makeVoidType());
  2735. }
  2736. return LINK(branch);
  2737. }
  2738. if (expr->queryChild(2))
  2739. {
  2740. IHqlExpression * trueValue = expr->queryChild(1);
  2741. IHqlExpression * falseValue = expr->queryChild(2);
  2742. if (trueValue == falseValue) // occurs in generated code...
  2743. return LINK(trueValue);
  2744. if (expr->queryType()->getTypeCode() == type_boolean)
  2745. {
  2746. HqlExprAttr ret;
  2747. if (trueValue->queryValue())
  2748. {
  2749. //IF(cond1, true, cond2) == cond1 || cond2
  2750. //if(cond1, false, cond2) == !cond1 && cond2
  2751. if (trueValue->queryValue()->getBoolValue())
  2752. ret.setown(createBoolExpr(no_or, LINK(child), LINK(falseValue)));
  2753. else
  2754. ret.setown(createBoolExpr(no_and, getInverse(child), LINK(falseValue)));
  2755. }
  2756. else if (falseValue->queryValue())
  2757. {
  2758. //IF(cond1, cond2, true) == !cond1 || cond2
  2759. //if(cond1, cond2, false) == cond1 && cond2
  2760. if (falseValue->queryValue()->getBoolValue())
  2761. ret.setown(createBoolExpr(no_or, getInverse(child), LINK(trueValue)));
  2762. else
  2763. ret.setown(createBoolExpr(no_and, LINK(child), LINK(trueValue)));
  2764. }
  2765. if (ret)
  2766. return ret.getClear();
  2767. }
  2768. }
  2769. break;
  2770. }
  2771. case no_choose:
  2772. case no_chooseds:
  2773. {
  2774. IHqlExpression * child = expr->queryChild(0);
  2775. IValue * constValue = child->queryValue();
  2776. unsigned last = numNonAttributes(expr)-1;
  2777. if (constValue)
  2778. {
  2779. unsigned idx = (unsigned)constValue->getIntValue();
  2780. if (idx > last || idx == 0)
  2781. idx = last;
  2782. return LINK(expr->queryChild(idx));
  2783. }
  2784. //Remove any trailing conditions which match the default condition
  2785. IHqlExpression * defaultExpr = expr->queryChild(last);
  2786. unsigned cur = last-1;
  2787. while (cur != 0)
  2788. {
  2789. if (expr->queryChild(cur)->queryBody() != defaultExpr->queryBody())
  2790. break;
  2791. cur--;
  2792. }
  2793. if (cur != last-1)
  2794. {
  2795. //All match default => just return the default
  2796. if (cur == 0)
  2797. return LINK(defaultExpr);
  2798. HqlExprArray args;
  2799. for (unsigned i=0; i <= cur; i++)
  2800. args.append(*LINK(expr->queryChild(i)));
  2801. args.append(*LINK(defaultExpr));
  2802. return expr->clone(args);
  2803. }
  2804. break;
  2805. }
  2806. case no_nameof:
  2807. {
  2808. IHqlExpression *ds = expr->queryChild(0);
  2809. switch (ds->getOperator())
  2810. {
  2811. case no_newkeyindex:
  2812. return LINK(ds->queryChild(3));
  2813. case no_table:
  2814. return LINK(ds->queryChild(0));
  2815. }
  2816. break;
  2817. }
  2818. case no_charlen:
  2819. {
  2820. IHqlExpression * child = expr->queryChild(0);
  2821. ITypeInfo * type = child->queryType();
  2822. size32_t len = type->getStringLen();
  2823. if (len != UNKNOWN_LENGTH)
  2824. return getSizetConstant(len);
  2825. if (child->getOperator() == no_substring)
  2826. {
  2827. IHqlExpression * range = child->queryChild(1);
  2828. switch (range->getOperator())
  2829. {
  2830. case no_range:
  2831. {
  2832. IValue * lowValue = range->queryChild(0)->queryValue();
  2833. IValue * highValue = range->queryChild(1)->queryValue();
  2834. if (lowValue && highValue)
  2835. {
  2836. __int64 low = lowValue->getIntValue();
  2837. __int64 high = highValue->getIntValue()+1;
  2838. if (low < 1)
  2839. low = 1;
  2840. if (high < low)
  2841. high = low;
  2842. return getSizetConstant((unsigned)(high - low));
  2843. }
  2844. break;
  2845. }
  2846. case no_rangeto:
  2847. {
  2848. IValue * highValue = range->queryChild(0)->queryValue();
  2849. if (highValue)
  2850. {
  2851. __int64 high = highValue->getIntValue();
  2852. if (high < 0)
  2853. high = 0;
  2854. return getSizetConstant((unsigned)high);
  2855. }
  2856. break;
  2857. }
  2858. case no_constant:
  2859. return getSizetConstant(1);
  2860. }
  2861. }
  2862. }
  2863. break;
  2864. case no_negate:
  2865. case no_roundup:
  2866. case no_truncate:
  2867. case no_exp:
  2868. case no_ln:
  2869. case no_sin:
  2870. case no_cos:
  2871. case no_tan:
  2872. case no_asin:
  2873. case no_acos:
  2874. case no_atan:
  2875. case no_sinh:
  2876. case no_cosh:
  2877. case no_tanh:
  2878. case no_log10:
  2879. case no_sqrt:
  2880. case no_abs:
  2881. {
  2882. //MORE: I'm sure this could be cleaned up.... e.g., have a function passed a pointer to function
  2883. IHqlExpression * child = expr->queryChild(0);
  2884. IValue * constValue = child->queryValue();
  2885. if (constValue)
  2886. {
  2887. switch (op)
  2888. {
  2889. case no_negate:
  2890. if (isNumericType(child->queryType()))
  2891. return createConstant(negateValue(constValue));
  2892. break;
  2893. case no_roundup:
  2894. return createConstant(roundUpValue(constValue));
  2895. case no_truncate:
  2896. return createConstant(truncateValue(constValue));
  2897. case no_exp:
  2898. return createConstant(expValue(constValue));
  2899. case no_ln:
  2900. if (onZero == DBZnone && constValue->getRealValue() <= 0)
  2901. break;
  2902. return createConstant(lnValue(constValue, onZero));
  2903. case no_sin:
  2904. return createConstant(sinValue(constValue));
  2905. case no_cos:
  2906. return createConstant(cosValue(constValue));
  2907. case no_tan:
  2908. return createConstant(tanValue(constValue));
  2909. case no_asin:
  2910. if (onZero == DBZnone && fabs(constValue->getRealValue()) > 1.0)
  2911. break;
  2912. return createConstant(asinValue(constValue, onZero));
  2913. case no_acos:
  2914. if (onZero == DBZnone && fabs(constValue->getRealValue()) > 1.0)
  2915. break;
  2916. return createConstant(acosValue(constValue, onZero));
  2917. case no_atan:
  2918. return createConstant(atanValue(constValue));
  2919. case no_sinh:
  2920. return createConstant(sinhValue(constValue));
  2921. case no_cosh:
  2922. return createConstant(coshValue(constValue));
  2923. case no_tanh:
  2924. return createConstant(tanhValue(constValue));
  2925. case no_log10:
  2926. if (onZero == DBZnone && constValue->getRealValue() <= 0)
  2927. break;
  2928. return createConstant(log10Value(constValue, onZero));
  2929. case no_sqrt:
  2930. if (onZero == DBZnone && constValue->getRealValue() < 0)
  2931. break;
  2932. return createConstant(sqrtValue(constValue, onZero));
  2933. case no_abs:
  2934. return createConstant(absValue(constValue));
  2935. }
  2936. }
  2937. break;
  2938. }
  2939. case no_round:
  2940. {
  2941. //MORE: I'm sure this could be cleaned up.... e.g., have a function passed a pointer to function
  2942. IHqlExpression * arg = expr->queryChild(0);
  2943. IHqlExpression * places = expr->queryChild(1);
  2944. IValue * constValue = arg->queryValue();
  2945. if (constValue)
  2946. {
  2947. if (places)
  2948. {
  2949. if (places->queryValue())
  2950. return createConstant(roundToValue(constValue, (int)getIntValue(places)));
  2951. }
  2952. else
  2953. return createConstant(roundValue(constValue));
  2954. }
  2955. break;
  2956. }
  2957. case no_eq:
  2958. case no_ne:
  2959. case no_lt:
  2960. case no_le:
  2961. case no_gt:
  2962. case no_ge:
  2963. case no_order:
  2964. {
  2965. IHqlExpression * ret = optimizeCompare(expr);
  2966. if (ret)
  2967. return ret;
  2968. //Note, don't optimize IF(a,b,c) op x to IF(a,b op x, c OP x) because it uncommons attributes increasing the size of the queries.
  2969. break;
  2970. }
  2971. case no_unicodeorder:
  2972. {
  2973. IHqlExpression * left = expr->queryChild(0);
  2974. IHqlExpression * right = expr->queryChild(1);
  2975. IHqlExpression * locale = expr->queryChild(2);
  2976. IHqlExpression * strength = expr->queryChild(3);
  2977. IValue * leftv = left->queryValue();
  2978. IValue * rightv = right->queryValue();
  2979. IValue * locv = locale->queryValue();
  2980. IValue * strv = strength->queryValue();
  2981. if(leftv && rightv && locv && strv)
  2982. {
  2983. unsigned leftsz = leftv->queryType()->getStringLen()+1;
  2984. unsigned rightsz = rightv->queryType()->getStringLen()+1;
  2985. UChar * leftstr = new UChar[leftsz];
  2986. UChar * rightstr = new UChar[rightsz];
  2987. leftv->getUCharStringValue(leftsz, leftstr);
  2988. rightv->getUCharStringValue(rightsz, rightstr);
  2989. StringBuffer locstr;
  2990. locv->getStringValue(locstr);
  2991. int val = rtlCompareVUnicodeVUnicodeStrength(leftstr, rightstr, locstr.str(), (unsigned)strv->getIntValue());
  2992. delete [] leftstr;
  2993. delete [] rightstr;
  2994. return createConstant(val);
  2995. }
  2996. break;
  2997. }
  2998. case no_notnot:
  2999. {
  3000. return ensureExprType(expr->queryChild(0), expr->queryType());
  3001. }
  3002. case no_cast:
  3003. case no_implicitcast:
  3004. {
  3005. IHqlExpression * child = expr->queryChild(0);
  3006. ITypeInfo * exprType = expr->queryType();
  3007. if (exprType == child->queryType())
  3008. return LINK(child);
  3009. node_operator childOp = child->getOperator();
  3010. switch (childOp)
  3011. {
  3012. case no_constant:
  3013. return createConstant(child->queryValue()->castTo(exprType));
  3014. case no_cast:
  3015. case no_implicitcast:
  3016. {
  3017. //MORE: Not sure if this is a good idea because it loses commonality between attributes.
  3018. // (T1)((T2)(X:T3))
  3019. // Can remove the cast to T2 if T3->T2 doesn't lose any information,
  3020. // and if the conversion from T2->T1 produces same results as converting T3->T1
  3021. // (For the moment only assume this is true if target is numeric)
  3022. // could possibly remove if T3-T2 and T2->T1 lose information, but they might
  3023. // lose different information
  3024. IHqlExpression * grand = child->queryChild(0);
  3025. ITypeInfo * g_type = grand->queryType();
  3026. ITypeInfo * c_type = child->queryType();
  3027. ITypeInfo * e_type = exprType;
  3028. bool preserveValueG2C = preservesValue(c_type, g_type);
  3029. if (preserveValueG2C)
  3030. {
  3031. bool sameResults = false;
  3032. if (isNumericType(e_type))
  3033. sameResults = true;
  3034. else if (isStringOrUnicode(e_type) && isStringOrUnicode(c_type) && isStringOrUnicode(g_type))
  3035. sameResults = true;
  3036. // Don't allow casts involving data and non-ascii datasets because it can cause ascii conversions to get lost
  3037. if (castHidesConversion(e_type, c_type, g_type) ||
  3038. castHidesConversion(c_type, e_type, g_type) ||
  3039. castHidesConversion(g_type, c_type, e_type))
  3040. sameResults = false;
  3041. if (sameResults)
  3042. {
  3043. if (e_type == g_type)
  3044. return LINK(grand);
  3045. if (isUnknownSize(e_type))
  3046. {
  3047. //(string)(string200)string50 => (string200)string50
  3048. if ((e_type->getTypeCode() == c_type->getTypeCode()) &&
  3049. (e_type->queryCharset() == c_type->queryCharset()))
  3050. return LINK(child);
  3051. //(string)(ebcdic20)string50 => (string20)string50
  3052. ITypeInfo * shrunkType = getStretchedType(c_type->getStringLen(), e_type);
  3053. return createValue(op, shrunkType, LINK(grand));
  3054. }
  3055. else
  3056. return createValue(op, LINK(e_type), LINK(grand));
  3057. }
  3058. }
  3059. break;
  3060. }
  3061. case no_case:
  3062. {
  3063. //Don't allow variable size string returns to be lost...
  3064. if (((child->queryType()->getTypeCode() == type_varstring) ||
  3065. (child->queryType()->getTypeCode() == type_varunicode)) &&
  3066. (exprType->getSize() == UNKNOWN_LENGTH))
  3067. break;
  3068. HqlExprArray caseResults;
  3069. if (flattenConstantCase(child, caseResults, true))
  3070. {
  3071. IValue * defVal = child->queryChild(child->numChildren()-1)->queryValue();
  3072. if (defVal)
  3073. {
  3074. HqlExprArray newCaseMaps;
  3075. ITypeInfo * newType = exprType;
  3076. for (unsigned i=0; i<caseResults.ordinality(); i++)
  3077. {
  3078. IHqlExpression * result = (IHqlExpression *)&caseResults.item(i);
  3079. IValue * castRes = result->queryValue()->castTo(newType);
  3080. IHqlExpression * newMapping = createValue(no_mapto, LINK(child->queryChild(i+1)->queryChild(0)), createConstant(castRes));
  3081. newCaseMaps.append(*newMapping);
  3082. }
  3083. newCaseMaps.append(*createConstant(defVal->castTo(newType)));
  3084. newCaseMaps.add(*LINK(child->queryChild(0)), 0);
  3085. IHqlExpression * newCase = createValue(no_case, LINK(newType), newCaseMaps);
  3086. return newCase;
  3087. }
  3088. }
  3089. break;
  3090. }
  3091. #if 0
  3092. case no_if:
  3093. {
  3094. if (isStringType(exprType) && (exprType->getSize() != UNKNOWN_LENGTH) && (child->queryType()->getSize() == UNKNOWN_LENGTH))
  3095. {
  3096. HqlExprArray args;
  3097. unwindChildren(args, child);
  3098. args.replace(*ensureExprType(&args.item(1), exprType, op), 1);
  3099. if (queryRealChild(child, 2))
  3100. args.replace(*ensureExprType(&args.item(2), exprType, op), 2);
  3101. return child->clone(args);
  3102. }
  3103. break;
  3104. }
  3105. #endif
  3106. case no_all:
  3107. case no_list:
  3108. return ensureExprType(child, exprType);
  3109. case no_substring:
  3110. {
  3111. //(stringN)(X[1..m]) -> (stringN)X if m >= N
  3112. unsigned castLen = exprType->getStringLen();
  3113. type_t tc = exprType->getTypeCode();
  3114. if ((castLen != UNKNOWN_LENGTH) && ((tc == type_string) || (tc == type_data) || (tc == type_qstring) || (tc == type_unicode) || (tc == type_utf8)))
  3115. {
  3116. IHqlExpression * range = child->queryChild(1);
  3117. bool simplify = false;
  3118. if (range->getOperator() == no_range)
  3119. simplify = (getIntValue(range->queryChild(0), 0) == 1) && (getIntValue(range->queryChild(1), 0) >= castLen);
  3120. else if (range->getOperator() == no_rangeto)
  3121. simplify = (getIntValue(range->queryChild(0), 0) >= castLen);
  3122. else if (range->getOperator() == no_constant)
  3123. simplify = (castLen == 1) && (getIntValue(range, 0) == castLen);
  3124. if (simplify)
  3125. {
  3126. HqlExprArray children;
  3127. children.append(*LINK(child->queryChild(0)));
  3128. return expr->clone(children);
  3129. }
  3130. }
  3131. break;
  3132. }
  3133. }
  3134. break;
  3135. }
  3136. case no_typetransfer:
  3137. {
  3138. IHqlExpression * child = expr->queryChild(0);
  3139. IValue * childValue = child->queryValue();
  3140. if (childValue)
  3141. {
  3142. Linked<ITypeInfo> exprType = expr->queryType();
  3143. ITypeInfo * childType = child->queryType();
  3144. size32_t childSize = childValue->getSize();
  3145. const void * rawvalue = childValue->queryValue();
  3146. unsigned newSize = exprType->getSize();
  3147. if (newSize == UNKNOWN_LENGTH)
  3148. {
  3149. unsigned newLen = UNKNOWN_LENGTH;
  3150. switch (exprType->getTypeCode())
  3151. {
  3152. case type_string:
  3153. case type_varstring:
  3154. newLen = childSize;
  3155. break;
  3156. case type_unicode:
  3157. newLen = childSize / sizeof(UChar);
  3158. break;
  3159. case type_utf8:
  3160. newLen = rtlUtf8Length(childSize, rawvalue);
  3161. break;
  3162. }
  3163. if (newLen != UNKNOWN_LENGTH)
  3164. {
  3165. newSize = childSize;
  3166. exprType.setown(getStretchedType(newLen, exprType));
  3167. }
  3168. }
  3169. if (newSize <= childSize)
  3170. {
  3171. IValue * transferred = createValueFromMem(LINK(exprType), rawvalue);
  3172. if (transferred && transferred->isValid())
  3173. return createConstant(transferred);
  3174. }
  3175. }
  3176. break;
  3177. }
  3178. case no_case:
  3179. {
  3180. IHqlExpression * leftExpr = expr->queryChild(0);
  3181. unsigned max = expr->numChildren();
  3182. unsigned numCases = max-2;
  3183. IValue * leftValue = leftExpr->queryValue();
  3184. if (leftValue)
  3185. {
  3186. HqlExprArray args;
  3187. args.append(*LINK(leftExpr));
  3188. for (unsigned idx = 1; idx <= numCases; idx++)
  3189. {
  3190. IHqlExpression * child = expr->queryChild(idx);
  3191. IHqlExpression * grand = child->queryChild(0);
  3192. IValue * grandValue = grand->queryValue();
  3193. if (grandValue)
  3194. {
  3195. if (orderValues(leftValue, grandValue) == 0)
  3196. {
  3197. if (args.ordinality() == 1)
  3198. return LINK(child->queryChild(1));
  3199. args.append(*LINK(child->queryChild(1)));
  3200. return expr->clone(args);
  3201. }
  3202. }
  3203. else
  3204. args.append(*LINK(child));
  3205. }
  3206. IHqlExpression * defaultValue = expr->queryChild(numCases+1);
  3207. if (args.ordinality()==1)
  3208. return LINK(defaultValue);
  3209. if (args.ordinality() != numCases+1)
  3210. {
  3211. args.append(*LINK(defaultValue));
  3212. return expr->clone(args);
  3213. }
  3214. }
  3215. else if (leftExpr->getOperator() == no_case)
  3216. {
  3217. HqlExprArray caseResults1;
  3218. HqlExprArray caseInput2;
  3219. HqlExprArray newCaseMaps;
  3220. if (flattenConstantCase(leftExpr, caseResults1, true) &&
  3221. flattenConstantCase(expr, caseInput2, false))
  3222. {
  3223. IHqlExpression * defCase2 = leftExpr->queryChild(leftExpr->numChildren()-1);
  3224. IValue * defVal2 = defCase2->queryValue();
  3225. if (defVal2)
  3226. {
  3227. unsigned inRes = 0;
  3228. unsigned numInput = caseInput2.ordinality();
  3229. unsigned i;
  3230. for (i=0; i<numInput; i++)
  3231. {
  3232. IHqlExpression * val = (IHqlExpression*)&caseInput2.item(i);
  3233. if (val->queryValue()->compare(defVal2) == 0)
  3234. {
  3235. inRes = i+1;
  3236. break;
  3237. }
  3238. }
  3239. IHqlExpression * defCase1 = expr->queryChild(expr->numChildren()-1);
  3240. for (i=0; i<caseResults1.ordinality(); i++)
  3241. {
  3242. bool found = false;
  3243. IHqlExpression * val1 = (IHqlExpression*)&caseResults1.item(i);
  3244. for (unsigned k=0; k<numInput; k++)
  3245. {
  3246. IHqlExpression * val2 = (IHqlExpression*)&caseInput2.item(k);
  3247. if (val1->queryValue()->compare(val2->queryValue()) == 0)
  3248. {
  3249. IHqlExpression * newMapping = createValue(no_mapto, LINK(leftExpr->queryChild(i+1)->queryChild(0)), LINK(expr->queryChild(k+1)->queryChild(1)));
  3250. newCaseMaps.append(*newMapping);
  3251. found = true;
  3252. break;
  3253. }
  3254. }
  3255. if (inRes && !found)
  3256. {
  3257. IHqlExpression * newMapping = createValue(no_mapto, LINK(leftExpr->queryChild(i+1)->queryChild(0)), LINK(defCase1));
  3258. newCaseMaps.append(*newMapping);
  3259. }
  3260. }
  3261. if (inRes)
  3262. newCaseMaps.append(*LINK(expr->queryChild(inRes)->queryChild(1)));
  3263. else
  3264. newCaseMaps.append(*LINK(defCase1));
  3265. newCaseMaps.add(*LINK(leftExpr->queryChild(0)), 0);
  3266. return createValue(no_case, expr->getType(), newCaseMaps);
  3267. }
  3268. }
  3269. }
  3270. IHqlExpression * defaultValue = expr->queryChild(max-1);
  3271. bool allMatchDefault = true;
  3272. for (unsigned i=1; i < max-1; i++)
  3273. {
  3274. if (expr->queryChild(i)->queryChild(1) != defaultValue)
  3275. {
  3276. allMatchDefault = false;
  3277. break;
  3278. }
  3279. }
  3280. if (allMatchDefault)
  3281. return LINK(defaultValue);
  3282. if (numCases == 1)
  3283. {
  3284. IHqlExpression * mapto = expr->queryChild(1);
  3285. IHqlExpression * key = mapto->queryChild(0);
  3286. OwnedITypeInfo type = getPromotedCompareType(leftExpr->queryType(), key->queryType());
  3287. IHqlExpression * newEqual = createBoolExpr(no_eq, ensureExprType(leftExpr, type), ensureExprType(key, type));
  3288. return createIf(newEqual, LINK(mapto->queryChild(1)), LINK(expr->queryChild(2)));
  3289. }
  3290. break;
  3291. }
  3292. case no_map:
  3293. {
  3294. assertex(expr->numChildren()>=1);
  3295. unsigned num = expr->numChildren()-1;
  3296. LinkedHqlExpr defaultResult = expr->queryChild(num);
  3297. HqlExprArray args;
  3298. bool allAreIn = true;
  3299. bool changed = false;
  3300. IHqlExpression * allTestField = NULL;
  3301. for (unsigned idx = 0; idx < num; idx++)
  3302. {
  3303. IHqlExpression * child = expr->queryChild(idx);
  3304. IHqlExpression * cond = child->queryChild(0);
  3305. IValue * value = cond->queryValue();
  3306. if (value)
  3307. {
  3308. changed = true;
  3309. if (value->getBoolValue())
  3310. {
  3311. //New default condition - don't check any more arguments.
  3312. defaultResult.set(child->queryChild(1));
  3313. break;
  3314. }
  3315. //otherwise ignore that argument...
  3316. }
  3317. else if (isDuplicateMapCondition(args, cond))
  3318. {
  3319. //Can occur when other earlier conditions have been simplified by constant foldeding
  3320. changed = true;
  3321. }
  3322. else
  3323. {
  3324. if (allAreIn && (cond->getOperator() == no_in))
  3325. {
  3326. IHqlExpression * condSearch = cond->queryChild(0);
  3327. IHqlExpression * condSet = cond->queryChild(1);
  3328. if ((allTestField && (allTestField != condSearch)) || !condSet->isConstant() || (condSet->getOperator() != no_list))
  3329. allAreIn = false;
  3330. else
  3331. allTestField = condSearch;
  3332. }
  3333. else if (allAreIn && (cond->getOperator() == no_eq))
  3334. {
  3335. IHqlExpression * condSearch = cond->queryChild(0);
  3336. IHqlExpression * condSet = cond->queryChild(1);
  3337. if ((allTestField && (allTestField != condSearch)) || (condSet->getOperator() != no_constant))
  3338. allAreIn = false;
  3339. else
  3340. allTestField = condSearch;
  3341. }
  3342. else
  3343. allAreIn = false;
  3344. args.append(*LINK(child));
  3345. }
  3346. }
  3347. //If no conditions yet, then the true value is the result, otherwise it is the default...
  3348. if (args.ordinality() == 0 || areIndenticalMapResults(args, defaultResult))
  3349. return defaultResult.getLink();
  3350. if (allAreIn)
  3351. {
  3352. //Transform this map to a case - it will be much more efficient.
  3353. HqlExprArray args2;
  3354. ICopyArray alreadyDone;
  3355. args2.append(*LINK(allTestField));
  3356. ForEachItemIn(i, args)
  3357. {
  3358. IHqlExpression & cur = args.item(i);
  3359. IHqlExpression * cond = cur.queryChild(0);
  3360. IHqlExpression * condValue = cond->queryChild(1);
  3361. IHqlExpression * mapValue = cur.queryChild(1);
  3362. if (cond->getOperator() == no_in)
  3363. {
  3364. ForEachChild(j, condValue)
  3365. {
  3366. IHqlExpression * value = condValue->queryChild(j);
  3367. if (alreadyDone.find(*value) == NotFound)
  3368. {
  3369. alreadyDone.append(*value);
  3370. args2.append(*createValue(no_mapto, LINK(value), LINK(mapValue)));
  3371. }
  3372. }
  3373. }
  3374. else
  3375. {
  3376. if (alreadyDone.find(*condValue) == NotFound)
  3377. {
  3378. alreadyDone.append(*condValue);
  3379. args2.append(*createValue(no_mapto, mapValue->getType(), LINK(condValue), LINK(mapValue)));
  3380. }
  3381. }
  3382. }
  3383. args2.append(*defaultResult.getLink());
  3384. return createWrapper(no_case, expr->queryType(), args2);
  3385. }
  3386. if (changed)
  3387. {
  3388. args.append(*defaultResult.getLink());
  3389. return expr->clone(args);
  3390. }
  3391. #if 0
  3392. //This is a sensible change - but it causes a bit too much code to be included in expressions at the moment
  3393. if (num == 1)
  3394. {
  3395. IHqlExpression * child = expr->queryChild(0);
  3396. return createIf(LINK(child->queryChild(0)), LINK(child->queryChild(1)), LINK(expr->queryChild(1)));
  3397. }
  3398. #endif
  3399. return LINK(expr);
  3400. }
  3401. case no_between:
  3402. case no_notbetween:
  3403. {
  3404. IHqlExpression * child = expr->queryChild(0);
  3405. IHqlExpression * lowExpr = expr->queryChild(1);
  3406. IHqlExpression * highExpr = expr->queryChild(2);
  3407. IValue * constValue = child->queryValue();
  3408. IValue * low = lowExpr->queryValue();
  3409. IValue * high = highExpr->queryValue();
  3410. if (constValue && low && high)
  3411. {
  3412. bool ret = false;
  3413. if (orderValues(constValue, low) >= 0)
  3414. {
  3415. if (orderValues(constValue, high) <= 0)
  3416. ret = true;
  3417. }
  3418. return createConstant(op == no_between ? ret : !ret);
  3419. }
  3420. if (lowExpr == highExpr)
  3421. return createValue(op == no_between ? no_eq : no_ne, makeBoolType(), LINK(child), LINK(lowExpr));
  3422. break;
  3423. }
  3424. case no_substring:
  3425. {
  3426. IHqlExpression * child = expr->queryChild(0);
  3427. IValue * constValue = child->queryValue();
  3428. if (constValue)
  3429. {
  3430. IHqlExpression * limit = expr->queryChild(1);
  3431. IValue * subString = NULL;
  3432. if (limit->isConstant())
  3433. {
  3434. switch (limit->getOperator())
  3435. {
  3436. case no_range:
  3437. {
  3438. IValue * lower = limit->queryChild(0)->queryValue();
  3439. IValue * upper = limit->queryChild(1)->queryValue();
  3440. if (lower && upper)
  3441. subString = substringValue(constValue, lower, upper);
  3442. break;
  3443. }
  3444. case no_rangeto:
  3445. {
  3446. IValue * upper = limit->queryChild(0)->queryValue();
  3447. if (upper)
  3448. subString = substringValue(constValue, NULL, upper);
  3449. break;
  3450. }
  3451. case no_rangefrom:
  3452. {
  3453. IValue * lower = limit->queryChild(0)->queryValue();
  3454. if (lower)
  3455. subString = substringValue(constValue, lower, NULL);
  3456. break;
  3457. }
  3458. case no_constant:
  3459. {
  3460. IValue * v = limit->queryValue();
  3461. subString = substringValue(constValue, v, v);
  3462. break;
  3463. }
  3464. }
  3465. }
  3466. if (subString)
  3467. return createConstant(subString);
  3468. }
  3469. //((stringN)X)[1..m] -> (stringN)X if m == N
  3470. if (isCast(child))
  3471. {
  3472. ITypeInfo * type = child->queryType();
  3473. unsigned castLen = type->getStringLen();
  3474. type_t tc = type->getTypeCode();
  3475. if ((castLen != UNKNOWN_LENGTH) && ((tc == type_string) || (tc == type_data) || (tc == type_qstring) || (tc == type_unicode) || (tc == type_utf8)))
  3476. {
  3477. IHqlExpression * range = expr->queryChild(1);
  3478. bool simplify = false;
  3479. if (range->getOperator() == no_range)
  3480. simplify = (getIntValue(range->queryChild(0), 0) == 1) && (getIntValue(range->queryChild(1), 0) == castLen);
  3481. else if (range->getOperator() == no_rangeto)
  3482. simplify = (getIntValue(range->queryChild(0), 0) == castLen);
  3483. else if (range->getOperator() == no_constant)
  3484. simplify = (castLen == 1) && (getIntValue(range, 0) == castLen);
  3485. if (simplify)
  3486. return LINK(child);
  3487. }
  3488. }
  3489. //x[n..0], x[m..n] n<m == ''
  3490. IHqlExpression * range = expr->queryChild(1);
  3491. if (range->getOperator() == no_range)
  3492. {
  3493. IHqlExpression * rangeLow = range->queryChild(0);
  3494. IHqlExpression * rangeHigh = range->queryChild(1);
  3495. if (isZero(rangeHigh))
  3496. return createNullExpr(expr);
  3497. if (getIntValue(rangeLow, 1) > getIntValue(rangeHigh, I64C(0x7fffffffffffffff)))
  3498. return createNullExpr(expr);
  3499. }
  3500. break;
  3501. }
  3502. case no_externalcall:
  3503. { //external function folding.
  3504. IValue * result = foldExternalCall(expr, foldOptions, templateContext);
  3505. if (result)
  3506. return createConstant(result);
  3507. break;
  3508. }
  3509. case no_call:
  3510. {
  3511. ForEachChild(i, expr)
  3512. {
  3513. if (!expr->queryChild(i)->isConstant())
  3514. return LINK(expr);
  3515. }
  3516. IHqlExpression * def = expr->queryBody()->queryFunctionDefinition();
  3517. IHqlExpression * body = def->queryChild(0);
  3518. if (body->getOperator() == no_outofline && body->queryChild(0)->getOperator()==no_embedbody)
  3519. {
  3520. IHqlExpression * result = foldEmbeddedCall(expr, foldOptions, templateContext);
  3521. if (result)
  3522. return result;
  3523. break;
  3524. }
  3525. OwnedHqlExpr folded = expandOutOfLineFunctionCall(expr);
  3526. if ((folded != expr) && folded->isConstant())
  3527. return folded.getClear();
  3528. if (foldOptions & HFOforcefold)
  3529. {
  3530. OwnedHqlExpr transformed = expandDelayedFunctionCalls(nullptr, expr);
  3531. if (expr != transformed)
  3532. return transformed.getClear();
  3533. }
  3534. break;
  3535. }
  3536. case no_trim:
  3537. {
  3538. IHqlExpression * child = expr->queryChild(0);
  3539. // 'R' - trim right, 'L' - Left, 'B' - Left and Right, 'A' - All
  3540. char typecode = 'R';
  3541. if(expr->hasAttribute(allAtom))
  3542. typecode = 'A';
  3543. else if(expr->hasAttribute(leftAtom) && expr->hasAttribute(rightAtom))
  3544. typecode = 'B';
  3545. else if(expr->hasAttribute(leftAtom))
  3546. typecode = 'L';
  3547. IValue * constValue = child->queryValue();
  3548. IValue* resultstr = NULL;
  3549. if (constValue)
  3550. resultstr = trimStringValue(constValue, typecode);
  3551. if (resultstr)
  3552. return createConstant(resultstr);
  3553. //extendin a string won't change the alue of trim(x), unless not trimming the rhs
  3554. //i.e., trim((string60)string12expression) => trim(string12expression);
  3555. if ((typecode != 'L') && isCast(child))
  3556. {
  3557. IHqlExpression * uncast = child->queryChild(0);
  3558. ITypeInfo * castType = child->queryType();
  3559. ITypeInfo * uncastType = uncast->queryType();
  3560. if ((castType->getSize() >= uncastType->getSize()) && (castType->getTypeCode() == uncastType->getTypeCode()))
  3561. {
  3562. OwnedITypeInfo stretched = getStretchedType(castType->getStringLen(), uncastType);
  3563. if (stretched == castType)
  3564. {
  3565. HqlExprArray args;
  3566. args.append(*LINK(uncast));
  3567. unwindChildren(args, expr, 1);
  3568. return expr->clone(args);
  3569. }
  3570. }
  3571. }
  3572. break;
  3573. }
  3574. case no_which:
  3575. case no_rejected:
  3576. {
  3577. bool isWhich = (op == no_which);
  3578. unsigned num = expr->numChildren();
  3579. ITypeInfo * exprType = expr->queryType();
  3580. switch (num)
  3581. {
  3582. case 1:
  3583. {
  3584. int trueValue = isWhich ? 1 : 0;
  3585. return createValue(no_if, LINK(exprType), LINK(expr->queryChild(0)), createConstant(trueValue, LINK(exprType)), createConstant(1 - trueValue, LINK(exprType)));
  3586. }
  3587. }
  3588. bool allConst = true;
  3589. IHqlExpression * newWhich = createOpenValue(op, expr->getType());
  3590. for (unsigned idx = 0; idx < num; idx++)
  3591. {
  3592. IHqlExpression * child = expr->queryChild(idx);
  3593. IValue * constValue = child->queryValue();
  3594. if (constValue)
  3595. {
  3596. bool bVal = constValue->getBoolValue();
  3597. if (isWhich ? bVal : !bVal)
  3598. {
  3599. if (allConst)
  3600. {
  3601. newWhich->closeExpr()->Release();
  3602. return createConstant((__int64)idx+1, LINK(exprType));
  3603. }
  3604. else
  3605. {
  3606. //Add a value which will always match
  3607. newWhich->addOperand(createConstant(isWhich));
  3608. return newWhich->closeExpr();
  3609. }
  3610. }
  3611. else
  3612. newWhich->addOperand(LINK(child));
  3613. }
  3614. else
  3615. {
  3616. allConst = false;
  3617. newWhich->addOperand(LINK(child));
  3618. }
  3619. }
  3620. newWhich->closeExpr()->Release();
  3621. if (allConst)
  3622. return createConstant(0, LINK(exprType));
  3623. break;
  3624. }
  3625. case no_index:
  3626. case no_rowsetindex:
  3627. {
  3628. IHqlExpression * leftChild = expr->queryChild(0);
  3629. IHqlExpression * rightChild = expr->queryChild(1);
  3630. node_operator leftOp = leftChild->getOperator();
  3631. if (leftOp == no_null)
  3632. return createNullValue(expr);
  3633. if ((leftOp != no_list) && (leftOp != no_datasetlist))
  3634. break;
  3635. IValue * rightValue = rightChild->queryValue();
  3636. if(rightValue)
  3637. {
  3638. unsigned idx = (unsigned)rightValue->getIntValue();
  3639. if ((idx != 0) && (leftChild->numChildren()>=idx))
  3640. return LINK(leftChild->queryChild(idx-1));
  3641. else
  3642. return createNullValue(expr);
  3643. }
  3644. else if (!leftChild->numChildren())
  3645. return createNullValue(expr);
  3646. }
  3647. break;
  3648. case no_addsets:
  3649. {
  3650. IHqlExpression * left = expr->queryChild(0);
  3651. IHqlExpression * right = expr->queryChild(1);
  3652. if (left->getOperator() == no_all)
  3653. return LINK(left);
  3654. if (right->getOperator() == no_all)
  3655. return LINK(right);
  3656. if ((left->getOperator() == no_list) && (right->getOperator() == no_list))
  3657. {
  3658. HqlExprArray args;
  3659. unwindChildren(args, left);
  3660. unwindChildren(args, right);
  3661. return left->clone(args);
  3662. }
  3663. break;
  3664. }
  3665. case no_max:
  3666. case no_min:
  3667. case no_ave:
  3668. case no_evaluate:
  3669. {
  3670. IHqlExpression * dataset = expr->queryChild(0);
  3671. if (dataset->getOperator() == no_null)
  3672. return createNullValue(expr);
  3673. //MORE: Not so sure about this - what if the dataset turns out to have 0 elements???
  3674. IHqlExpression * child = expr->queryChild(1);
  3675. IValue * value = child->queryValue();
  3676. if (value)
  3677. return createConstant(value->castTo(expr->queryType()));
  3678. if (dataset->getOperator() == no_datasetfromrow)
  3679. return replaceSelector(child, dataset, dataset->queryChild(0));
  3680. }
  3681. break;
  3682. case no_countdict:
  3683. {
  3684. IHqlExpression * child = expr->queryChild(0);
  3685. node_operator childOp = child->getOperator();
  3686. // Can't optimize count of a dictionary in general, since the input dataset may contain duplicates which will be removed.
  3687. switch (child->getOperator())
  3688. {
  3689. case no_null:
  3690. return createConstant(0);
  3691. }
  3692. break;
  3693. }
  3694. case no_existsdict:
  3695. {
  3696. IHqlExpression * child = expr->queryChild(0);
  3697. node_operator childOp = child->getOperator();
  3698. switch (child->getOperator())
  3699. {
  3700. case no_null:
  3701. return createConstant(false);
  3702. }
  3703. break;
  3704. }
  3705. case no_countlist:
  3706. {
  3707. IHqlExpression * child = expr->queryChild(0);
  3708. switch (child->getOperator())
  3709. {
  3710. case no_null:
  3711. case no_list:
  3712. return createConstant(createIntValue(child->numChildren(), LINK(expr->queryType())));
  3713. }
  3714. break;
  3715. }
  3716. case no_existslist:
  3717. {
  3718. IHqlExpression * child = expr->queryChild(0);
  3719. switch (child->getOperator())
  3720. {
  3721. case no_null:
  3722. return createConstant(false);
  3723. case no_list:
  3724. return createConstant(child->numChildren() != 0);
  3725. }
  3726. break;
  3727. }
  3728. case no_minlist:
  3729. case no_maxlist:
  3730. {
  3731. IHqlExpression * child = expr->queryChild(0);
  3732. bool isUnsigned = expr->queryType()->isUnsignedNumeric();
  3733. switch (child->getOperator())
  3734. {
  3735. case no_null:
  3736. return createNullExpr(expr);
  3737. case no_list:
  3738. {
  3739. IValue * best = NULL;
  3740. bool allConstant = true;
  3741. HqlExprArray values;
  3742. bool same = true;
  3743. ForEachChild(i, child)
  3744. {
  3745. IHqlExpression * cur = child->queryChild(i);
  3746. IValue * value = cur->queryValue();
  3747. if (value)
  3748. {
  3749. if (isUnsigned && isZero(cur))
  3750. {
  3751. if (op==no_minlist)
  3752. return LINK(cur); // Nothing can be lower than zero in an unsigned minlist...
  3753. else
  3754. {
  3755. same = false;
  3756. continue;
  3757. }
  3758. }
  3759. if (best)
  3760. {
  3761. int c = value->compare(best);
  3762. if (op == no_minlist ? c < 0 : c > 0)
  3763. best = value;
  3764. }
  3765. else
  3766. best = value;
  3767. values.append(*LINK(cur));
  3768. }
  3769. else
  3770. {
  3771. if (!values.containsBody(*cur))
  3772. values.append(*LINK(cur));
  3773. else
  3774. same = false;
  3775. allConstant = false;
  3776. }
  3777. }
  3778. if (allConstant)
  3779. {
  3780. if (!best)
  3781. return createNullExpr(expr);
  3782. return createConstant(LINK(best));
  3783. }
  3784. if (values.ordinality() == 1)
  3785. return expr->cloneAllAnnotations(&values.item(0));
  3786. if (!same)
  3787. {
  3788. OwnedHqlExpr newList = child->clone(values);
  3789. return replaceChild(expr, 0, newList);
  3790. }
  3791. }
  3792. break;
  3793. }
  3794. break;
  3795. }
  3796. case no_sumlist:
  3797. {
  3798. IHqlExpression * child = expr->queryChild(0);
  3799. OwnedHqlExpr folded;
  3800. switch (child->getOperator())
  3801. {
  3802. case no_null:
  3803. return createNullExpr(expr);
  3804. case no_list:
  3805. if (child->isConstant())
  3806. {
  3807. ITypeInfo * exprType = expr->queryType();
  3808. Owned<IValue> sum = createNullValue(exprType);
  3809. bool ok = true;
  3810. ForEachChild(i, child)
  3811. {
  3812. IHqlExpression * cur = child->queryChild(i);
  3813. IValue * value = cur->queryValue();
  3814. if (value)
  3815. {
  3816. Owned<IValue> castValue = value->castTo(exprType);
  3817. sum.setown(addValues(sum, castValue));
  3818. }
  3819. else
  3820. {
  3821. ok = false;
  3822. break;
  3823. }
  3824. }
  3825. if (ok)
  3826. folded.setown(createConstant(sum.getClear()));
  3827. }
  3828. if (child->numChildren() == 1)
  3829. folded.set(child->queryChild(0));
  3830. if (folded)
  3831. {
  3832. OwnedHqlExpr cast = ensureExprType(folded, expr->queryType());
  3833. return expr->cloneAllAnnotations(cast);
  3834. }
  3835. break;
  3836. }
  3837. break;
  3838. }
  3839. break;
  3840. case no_notwithin:
  3841. {
  3842. IHqlExpression * child = expr->queryChild(0);
  3843. if (child->getOperator() == no_null)
  3844. return createConstant(true);
  3845. }
  3846. break;
  3847. case no_createset:
  3848. {
  3849. //If constant folding has caused the argument to be a constant then can convert this to a simple list
  3850. IHqlExpression * ds = expr->queryChild(0);
  3851. IHqlExpression * value = expr->queryChild(1);
  3852. if (value->isConstant() && hasSingleRow(ds))
  3853. return createValue(no_list, expr->getType(), LINK(value));
  3854. break;
  3855. }
  3856. case no_list:
  3857. break;
  3858. case no_tounicode:
  3859. {
  3860. IHqlExpression * dataChild = expr->queryChild(0);
  3861. IHqlExpression * codepageChild = expr->queryChild(1);
  3862. IValue * dataValue = dataChild->queryValue();
  3863. IValue * codepageValue = codepageChild->queryValue();
  3864. if(dataValue && codepageValue)
  3865. {
  3866. unsigned unicodeLength;
  3867. UChar * unicode;
  3868. StringBuffer buff;
  3869. rtlCodepageToUnicodeX(unicodeLength, unicode, dataValue->getSize(), (char const *)dataValue->queryValue(), codepageValue->getStringValue(buff));
  3870. ITypeInfo * unicodeType = makeUnicodeType(unicodeLength, 0);
  3871. IValue * unicodeValue = createUnicodeValue(unicodeLength, unicode, unicodeType);
  3872. rtlFree(unicode);
  3873. return createConstant(unicodeValue);
  3874. }
  3875. break;
  3876. }
  3877. case no_fromunicode:
  3878. {
  3879. IHqlExpression * unicodeChild = expr->queryChild(0);
  3880. IHqlExpression * codepageChild = expr->queryChild(1);
  3881. IValue * unicodeValue = unicodeChild->queryValue();
  3882. IValue * codepageValue = codepageChild->queryValue();
  3883. if(unicodeValue && codepageValue)
  3884. {
  3885. unsigned dataLength;
  3886. char * data;
  3887. StringBuffer buff;
  3888. rtlUnicodeToCodepageX(dataLength, data, unicodeValue->queryType()->getStringLen(), (UChar const *)unicodeValue->queryValue(), codepageValue->getStringValue(buff));
  3889. IValue * dataValue = createDataValue(data, dataLength);
  3890. rtlFree(data);
  3891. return createConstant(dataValue);
  3892. }
  3893. break;
  3894. }
  3895. case no_keyunicode:
  3896. {
  3897. IHqlExpression * val = expr->queryChild(0);
  3898. IHqlExpression * locale = expr->queryChild(1);
  3899. IHqlExpression * strength = expr->queryChild(2);
  3900. IValue * valv = val->queryValue();
  3901. IValue * locv = locale->queryValue();
  3902. IValue * strv = strength->queryValue();
  3903. if(valv && locv && strv)
  3904. {
  3905. unsigned outlen;
  3906. void * out;
  3907. unsigned vallen = valv->queryType()->getStringLen();
  3908. UChar * valstr = new UChar[vallen];
  3909. valv->getUCharStringValue(vallen, valstr);
  3910. StringBuffer locstr;
  3911. locv->getStringValue(locstr);
  3912. rtlKeyUnicodeStrengthX(outlen, out, vallen, valstr, locstr.str(), (unsigned)strv->getIntValue());
  3913. delete [] valstr;
  3914. IValue * dataValue = createDataValue((char *)out, outlen);
  3915. rtlFree(out);
  3916. return createConstant(dataValue);
  3917. }
  3918. break;
  3919. }
  3920. case no_random:
  3921. if (foldOptions & (HFOfoldimpure|HFOforcefold))
  3922. return createConstant(expr->queryType()->castFrom(true, (__int64)rtlRandom()));
  3923. break;
  3924. case no_catch:
  3925. if (expr->isConstant())
  3926. {
  3927. try
  3928. {
  3929. return LINK(expr->queryChild(0));
  3930. }
  3931. catch (IException * e)
  3932. {
  3933. e->Release();
  3934. return LINK(expr->queryChild(1));
  3935. }
  3936. }
  3937. //maybe we should stop folding of the children.
  3938. break;
  3939. case no_section:
  3940. if (expr->queryChild(0)->isConstant())
  3941. return LINK(expr->queryChild(0));
  3942. break;
  3943. case no_sizeof:
  3944. {
  3945. IHqlExpression * child = expr->queryChild(0);
  3946. if (child->isRecord())
  3947. {
  3948. //Need to be careful to use the serialized record - otherwise record size can be inconsistent
  3949. OwnedHqlExpr record = getSerializedForm(child, diskAtom);
  3950. if (expr->hasAttribute(maxAtom))
  3951. {
  3952. if (maxRecordSizeCanBeDerived(record))
  3953. return getSizetConstant(getMaxRecordSize(record, 0));
  3954. }
  3955. else if (expr->hasAttribute(minAtom))
  3956. {
  3957. return getSizetConstant(getMinRecordSize(record));
  3958. }
  3959. else
  3960. {
  3961. if (!isVariableSizeRecord(record))
  3962. return getSizetConstant(getMaxRecordSize(record, 0));
  3963. }
  3964. }
  3965. //MORE: Handle types - but be very careful about maxlength attributes... (no_typeof doesn't exist yet either)
  3966. //else if (child->getOperator() == no_typeof)
  3967. break;
  3968. }
  3969. case no_actionlist:
  3970. case no_orderedactionlist:
  3971. {
  3972. bool same = true;
  3973. HqlExprArray args;
  3974. ForEachChild(i, expr)
  3975. {
  3976. IHqlExpression * cur = expr->queryChild(i);
  3977. if (isNull(cur))
  3978. {
  3979. if (same)
  3980. unwindChildren(args, expr, 0, i);
  3981. same = false;
  3982. }
  3983. else
  3984. {
  3985. if (!same)
  3986. args.append(*LINK(cur));
  3987. }
  3988. }
  3989. if (!same)
  3990. return createActionList(op, args);
  3991. break;
  3992. }
  3993. case no_exists:
  3994. if (isNull(expr->queryChild(0)))
  3995. return createConstant(false);
  3996. break;
  3997. case no_alias:
  3998. {
  3999. IHqlExpression * arg = expr->queryChild(0);
  4000. if (arg->getOperator() == no_constant)
  4001. return LINK(arg);
  4002. break;
  4003. }
  4004. }
  4005. return LINK(expr);
  4006. }
  4007. //---------------------------------------------------------------------------
  4008. bool isNullRowDs(IHqlExpression * expr)
  4009. {
  4010. return ((expr->getOperator() == no_datasetfromrow) && isNull(expr->queryChild(0)));
  4011. }
  4012. IHqlExpression * preserveGrouping(IHqlExpression * child, IHqlExpression * expr)
  4013. {
  4014. if (!isGrouped(expr))
  4015. {
  4016. if (isGrouped(child))
  4017. return createDataset(no_group, LINK(child));
  4018. }
  4019. else
  4020. {
  4021. //weird, but just about possible if grouped keyed join was replaced with rhs, check just in case
  4022. assertex(isGrouped(child));
  4023. }
  4024. return LINK(child);
  4025. }
  4026. static bool matchesAtmost1(IHqlExpression * expr)
  4027. {
  4028. IHqlExpression * atmost = expr->queryAttribute(atmostAtom);
  4029. if (!atmost)
  4030. return false;
  4031. if (!matchesConstantValue(atmost->queryChild(0), 1))
  4032. return false;
  4033. return true;
  4034. }
  4035. static bool hasRowLimit(IHqlExpression * expr)
  4036. {
  4037. IHqlExpression * limit = expr->queryAttribute(rowLimitAtom);
  4038. return limit && !matchesConstantValue(limit->queryChild(0), 0);
  4039. }
  4040. IHqlExpression * NullFolderMixin::foldNullDataset(IHqlExpression * expr)
  4041. {
  4042. IHqlExpression * child = expr->queryChild(0);
  4043. //These items remove the current node - so don't need to check if the children are shared.
  4044. node_operator op = expr->getOperator();
  4045. switch (op)
  4046. {
  4047. case no_distribute:
  4048. case no_distributed:
  4049. {
  4050. if (isNull(child))
  4051. return replaceWithNull(expr);
  4052. if (isFail(child))
  4053. return removeParentNode(expr);
  4054. if (expr->hasAttribute(skewAtom))
  4055. break;
  4056. //Careful - distribute also destroys grouping, so don't remove if input is grouped.
  4057. if ((queryDistribution(expr) == queryDistribution(child)) && !isGrouped(child))
  4058. return removeParentNode(expr);
  4059. break;
  4060. }
  4061. case no_sort:
  4062. case no_subsort:
  4063. case no_sorted:
  4064. {
  4065. //Subsort is unusual because the order applied to an unsorted dataset will also be unsorted
  4066. if ((op != no_subsort) || hasKnownSortGroupDistribution(child, expr->hasAttribute(localAtom)))
  4067. {
  4068. //If action does not change the type information, then it can't have done anything...
  4069. if (hasSameSortGroupDistribution(expr, child))
  4070. return removeParentNode(expr);
  4071. }
  4072. if (isNull(child) || hasNoMoreRowsThan(child, 1))
  4073. return removeParentNode(expr);
  4074. //If all arguments to sort are constant then remove it, otherwise the activities will not like it.
  4075. //NOTE: MERGE has its sort order preserved, so it won't cause issues there.
  4076. bool allConst = true;
  4077. ForEachChildFrom(i, expr, 1)
  4078. {
  4079. IHqlExpression * cur = expr->queryChild(i);
  4080. if (!cur->isAttribute() && !cur->isConstant())
  4081. {
  4082. allConst = false;
  4083. break;
  4084. }
  4085. }
  4086. if (allConst && (op == no_sort))
  4087. return removeParentNode(expr);
  4088. break;
  4089. }
  4090. case no_if:
  4091. {
  4092. //Processed hereThis won't split shared nodes, but one of the children may be shared - so proce
  4093. if (isNull(expr->queryChild(1)))
  4094. {
  4095. //A no_null action is treated the same as a non existant action.
  4096. IHqlExpression * falseBranch = expr->queryChild(2);
  4097. if (!falseBranch || isNull(falseBranch))
  4098. return replaceWithNull(expr);
  4099. }
  4100. break;
  4101. }
  4102. case no_group:
  4103. case no_grouped:
  4104. // case no_preservemeta:
  4105. {
  4106. //If action does not change the type information, then it can't have done anything...
  4107. if (hasSameSortGroupDistribution(expr, child))
  4108. return removeParentNode(expr);
  4109. if (isNull(child))
  4110. return replaceWithNull(expr);
  4111. break;
  4112. }
  4113. case no_denormalize:
  4114. case no_denormalizegroup:
  4115. case no_join:
  4116. {
  4117. IHqlExpression * rhs = expr->queryChild(1);
  4118. bool leftIsNull = isNull(child);
  4119. bool rightIsNull = isNull(rhs);
  4120. bool cvtLeftProject = false;
  4121. bool cvtRightProject = false;
  4122. const char * reason = NULL;
  4123. if (leftIsNull || rightIsNull)
  4124. {
  4125. bool createNull = false;
  4126. if (isFullJoin(expr))
  4127. createNull = leftIsNull && rightIsNull;
  4128. else if (isLeftJoin(expr))
  4129. createNull = leftIsNull;
  4130. else if (isRightJoin(expr))
  4131. createNull = rightIsNull;
  4132. else
  4133. createNull = leftIsNull || rightIsNull;
  4134. if (createNull)
  4135. return replaceWithNull(expr);
  4136. if (leftIsNull)
  4137. cvtRightProject = true;
  4138. else if (rightIsNull)
  4139. {
  4140. //JOIN(ds,<null>) becomes a project
  4141. //DENORMALIZE(ds, <null>) becomes a nop (since the transform will not be called)
  4142. //DENORMALIZE(ds, <null>, GROUP) becomes a project
  4143. if (op == no_denormalize)
  4144. return removeParentNode(expr); // ok because this returns queryChild(0)
  4145. cvtLeftProject = true;
  4146. reason = "(ds,<empty>)";
  4147. }
  4148. }
  4149. //JOIN with false condition - can occur once constants are folded.
  4150. IValue * condValue = expr->queryChild(2)->queryValue();
  4151. if (condValue && !condValue->getBoolValue())
  4152. {
  4153. //Never matches, so either LHS is modified by the transform - like a project, or it never returns anything.
  4154. if (isLeftJoin(expr))
  4155. {
  4156. if (op == no_denormalize)
  4157. return removeParentNode(expr); // ok because this returns queryChild(0)
  4158. cvtLeftProject = true;
  4159. reason = "(false)";
  4160. }
  4161. else if (isInnerJoin(expr))
  4162. return replaceWithNull(expr);
  4163. }
  4164. //JOIN, left outer, keep(1) with no reference to RIGHT in the transform => convert to a project!
  4165. //again can occur once the implicit project has started getting to work.
  4166. if (!cvtLeftProject)
  4167. {
  4168. const char * potentialLeftProjectReason = NULL;
  4169. if (isSpecificJoin(expr, leftouterAtom))
  4170. {
  4171. if (matchesConstantValue(queryAttributeChild(expr, keepAtom, 0), 1) && !hasRowLimit(expr))
  4172. potentialLeftProjectReason = "(,LEFT OUTER,KEEP(1))";
  4173. else if (matchesAtmost1(expr) && !hasRowLimit(expr))
  4174. potentialLeftProjectReason = "(,LEFT OUTER,ATMOST(1))";
  4175. else if (expr->hasAttribute(lookupAtom) && !expr->hasAttribute(manyAtom))
  4176. potentialLeftProjectReason = "(,LEFT OUTER,SINGLE LOOKUP)";
  4177. else if (hasNoMoreRowsThan(expr, 1))
  4178. potentialLeftProjectReason = "(<single-row>,LEFT OUTER)";
  4179. }
  4180. if (potentialLeftProjectReason)
  4181. {
  4182. //This cannot match if the transform contains a skip - since that would
  4183. IHqlExpression * selSeq = querySelSeq(expr);
  4184. OwnedHqlExpr right = createSelector(no_right, rhs, selSeq);
  4185. IHqlExpression * transform = expr->queryChild(3);
  4186. if (!exprReferencesDataset(transform, right))
  4187. {
  4188. cvtLeftProject = true;
  4189. reason = potentialLeftProjectReason;
  4190. }
  4191. if (cvtLeftProject && (expr->getOperator() == no_denormalize))
  4192. {
  4193. OwnedHqlExpr left = createSelector(no_left, child, selSeq);
  4194. //Denormalize with no match will not call the transform, so we can't convert that to a project
  4195. //unless the transform is a nop
  4196. if (!transformReturnsSide(expr, no_left, 0))
  4197. cvtLeftProject = false;
  4198. }
  4199. }
  4200. }
  4201. if (cvtLeftProject)
  4202. {
  4203. IHqlExpression * selSeq = querySelSeq(expr);
  4204. OwnedHqlExpr right = createSelector(no_right, rhs, selSeq);
  4205. OwnedHqlExpr null = createRow(no_newrow, createNullExpr(right));
  4206. OwnedHqlExpr newTransform = replaceSelector(expr->queryChild(3), right, null);
  4207. if (op == no_denormalizegroup)
  4208. {
  4209. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  4210. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(right), LINK(rowsid));
  4211. OwnedHqlExpr nullExpr = createDataset(no_null, LINK(rhs->queryRecord()));
  4212. newTransform.setown(replaceExpression(newTransform, rowsExpr, nullExpr));
  4213. }
  4214. if (op == no_denormalize)
  4215. {
  4216. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  4217. if (counter)
  4218. {
  4219. OwnedHqlExpr one = createConstant(counter->queryType()->castFrom(false, I64C(1)));
  4220. //Remove the annotations from the transform, otherwise it may say t(LEFT,COUNTER) which is confusing.
  4221. newTransform.setown(replaceExpression(newTransform->queryBody(), counter, one));
  4222. }
  4223. }
  4224. HqlExprArray args;
  4225. args.append(*preserveGrouping(child, expr));
  4226. args.append(*newTransform.getClear());
  4227. args.append(*LINK(selSeq));
  4228. OwnedHqlExpr ret = createDataset(no_hqlproject, args);
  4229. DBGLOG("Folder: Replace %s%s with PROJECT", getOpString(op), reason);
  4230. return ret.getClear();
  4231. }
  4232. #if 0
  4233. //This is pretty unlikely, and may introduce an ambiguity in LEFT (if selector sequences aren't unique)
  4234. if (cvtRightProject && !isGrouped(expr))
  4235. {
  4236. IHqlExpression * selSeq = querySelSeq(expr);
  4237. OwnedHqlExpr left = createSelector(no_left, child, selSeq);
  4238. OwnedHqlExpr null = createRow(no_newrow, createNullExpr(left));
  4239. OwnedHqlExpr transformNoLeft = replaceSelector(expr->queryChild(3), left, null);
  4240. OwnedHqlExpr right = createSelector(no_right, rhs, selSeq);
  4241. OwnedHqlExpr newLeft = createSelector(no_left, child, selSeq);
  4242. OwnedHqlExpr newTransform = replaceSelector(transformNoLeft, right, newLeft);
  4243. HqlExprArray args;
  4244. args.append(*preserveGrouping(rhs, expr));
  4245. args.append(*newTransform.getClear());
  4246. args.append(*LINK(selSeq));
  4247. OwnedHqlExpr ret = createDataset(no_hqlproject, args);
  4248. DBGLOG("Folder: Replace JOIN(<empty>, ds) with PROJECT");
  4249. return ret.getClear();
  4250. }
  4251. #endif
  4252. break;
  4253. }
  4254. case no_merge:
  4255. case no_addfiles:
  4256. case no_regroup:
  4257. case no_nonempty:
  4258. case no_cogroup:
  4259. {
  4260. HqlExprArray args;
  4261. bool changed = false;
  4262. IHqlExpression * lastInput = NULL;
  4263. unsigned inputCount = 0;
  4264. //Careful - the node may have attributes, which we want to preserve if the node is preserved.
  4265. ForEachChild(i, expr)
  4266. {
  4267. IHqlExpression * cur = expr->queryChild(i);
  4268. if ((cur->getOperator() != no_null) && ((op != no_nonempty) || !args.contains(*cur)))
  4269. {
  4270. if (!cur->isAttribute())
  4271. {
  4272. lastInput = cur;
  4273. inputCount++;
  4274. }
  4275. args.append(*LINK(cur));
  4276. }
  4277. else
  4278. changed = true;
  4279. }
  4280. if (changed || (inputCount == 1))
  4281. {
  4282. //NOTE: The only branches removed are no_null, so don't need to worry about decrementing their link counts.
  4283. switch (inputCount)
  4284. {
  4285. case 0:
  4286. return replaceWithNull(expr);
  4287. case 1:
  4288. if (op == no_cogroup)
  4289. {
  4290. DBGLOG("Folder: Replace %s with group", getOpString(op));
  4291. IHqlExpression * grouping = queryAttributeChild(expr, groupAtom, 0);
  4292. IHqlExpression * mappedGrouping = replaceSelector(grouping, queryActiveTableSelector(), lastInput);
  4293. OwnedHqlExpr group = createDataset(no_group, LINK(lastInput), mappedGrouping);
  4294. return expr->cloneAllAnnotations(group);
  4295. }
  4296. else
  4297. {
  4298. DBGLOG("Folder: Replace %s with child", getOpString(op));
  4299. return LINK(lastInput);
  4300. }
  4301. default:
  4302. DBGLOG("Folder: Remove %d inputs from %s", expr->numChildren()-args.ordinality(), getOpString(op));
  4303. return expr->clone(args);
  4304. }
  4305. }
  4306. break;
  4307. }
  4308. case no_fetch:
  4309. if (isNull(expr->queryChild(1)))
  4310. return replaceWithNull(expr);
  4311. break;
  4312. case no_aggregate:
  4313. case no_newaggregate:
  4314. if (isNull(child))
  4315. {
  4316. if (isGrouped(child) || queryRealChild(expr, 3))
  4317. return replaceWithNull(expr);
  4318. return replaceWithNullRowDs(expr);
  4319. }
  4320. break;
  4321. case no_inlinetable:
  4322. if (expr->queryChild(0)->numChildren() == 0)
  4323. return replaceWithNull(expr);
  4324. break;
  4325. case no_dataset_from_transform:
  4326. if (isZero(expr->queryChild(0)))
  4327. return replaceWithNull(expr);
  4328. break;
  4329. case no_temptable:
  4330. {
  4331. IHqlExpression * values = expr->queryChild(0);
  4332. if (isNull(values) || ((values->getOperator() == no_list) && (values->numChildren() == 0)))
  4333. return replaceWithNull(expr);
  4334. break;
  4335. }
  4336. case no_newusertable:
  4337. if (isNullProject(expr, false, false))
  4338. return removeParentNode(expr);
  4339. if (isNull(child))
  4340. {
  4341. //a grouped aggregate is ok - will generate no rows, as will a non-aggregate
  4342. if (datasetHasGroupBy(expr) || !isAggregateDataset(expr))
  4343. return replaceWithNull(expr);
  4344. }
  4345. break;
  4346. case no_compound_diskread:
  4347. case no_compound_disknormalize:
  4348. case no_compound_diskgroupaggregate:
  4349. case no_compound_diskcount:
  4350. case no_compound_indexread:
  4351. case no_compound_indexnormalize:
  4352. case no_compound_indexgroupaggregate:
  4353. case no_compound_indexcount:
  4354. case no_compound_childread:
  4355. case no_compound_childnormalize:
  4356. case no_compound_childgroupaggregate:
  4357. case no_compound_childcount:
  4358. case no_compound_inline:
  4359. case no_compound_selectnew:
  4360. {
  4361. node_operator childOp = child->getOperator();
  4362. if ((op == childOp) || (childOp == no_null))
  4363. return removeParentNode(expr);
  4364. break;
  4365. }
  4366. case no_compound_diskaggregate:
  4367. case no_compound_indexaggregate:
  4368. case no_compound_childaggregate:
  4369. {
  4370. if (isNullRowDs(child))
  4371. return removeParentNode(expr);
  4372. node_operator childOp = child->getOperator();
  4373. if ((op == childOp) || (childOp == no_null))
  4374. return removeParentNode(expr);
  4375. break;
  4376. }
  4377. case no_assert_ds:
  4378. {
  4379. if (isNull(child))
  4380. return removeParentNode(expr);
  4381. bool hasAssert = false;
  4382. ForEachChildFrom(i, expr, 1)
  4383. {
  4384. IHqlExpression * cur = queryRealChild(expr, i);
  4385. if (cur && (cur->getOperator() != no_null))
  4386. {
  4387. hasAssert = true;
  4388. break;
  4389. }
  4390. }
  4391. //All asserts have constant folded away...
  4392. if (!hasAssert)
  4393. return removeParentNode(expr);
  4394. break;
  4395. }
  4396. case no_choosen:
  4397. {
  4398. if (isNull(child) || isFail(child))
  4399. return removeParentNode(expr);
  4400. IHqlExpression * choosenLimit = expr->queryChild(1);
  4401. IValue * choosenValue = choosenLimit->queryValue();
  4402. if (choosenValue)
  4403. {
  4404. __int64 v = choosenValue->getIntValue();
  4405. if (v == 0)
  4406. return replaceWithNull(expr);
  4407. ITypeInfo * type = choosenLimit->queryType();
  4408. if (type->isSigned() && (v < 0))
  4409. return replaceWithNull(expr);
  4410. if (!queryRealChild(expr, 2))
  4411. {
  4412. //choosen(x, n) n>0 on a single row is same as the single row
  4413. if (hasNoMoreRowsThan(child, 1)) // could use v
  4414. return removeParentNode(expr);
  4415. if (!isGrouped(expr))
  4416. {
  4417. if (v == CHOOSEN_ALL_LIMIT)
  4418. return removeParentNode(expr);
  4419. if (!isLocalActivity(expr) && hasNoMoreRowsThan(child, v))
  4420. return removeParentNode(expr);
  4421. }
  4422. }
  4423. }
  4424. break;
  4425. }
  4426. case no_dedup:
  4427. case no_rollup: // rollup on a single row does not call the transform => can be removed.
  4428. if (isNull(child) || hasNoMoreRowsThan(child, 1) || isFail(child))
  4429. return removeParentNode(expr);
  4430. break;
  4431. case no_limit:
  4432. {
  4433. if (isNull(child) || isFail(child))
  4434. return removeParentNode(expr);
  4435. __int64 limit = getIntValue(expr->queryChild(1), 0);
  4436. if (limit >= 1)
  4437. {
  4438. if (hasNoMoreRowsThan(child, 1))
  4439. return removeParentNode(expr);
  4440. if (!isGrouped(expr) && !isLocalActivity(expr) && hasNoMoreRowsThan(child, limit))
  4441. return removeParentNode(expr);
  4442. }
  4443. break;
  4444. }
  4445. case no_catchds:
  4446. {
  4447. if (isNull(child))
  4448. return removeParentNode(expr);
  4449. break;
  4450. }
  4451. case no_filter:
  4452. case no_keyeddistribute:
  4453. case no_choosesets:
  4454. case no_enth:
  4455. case no_sample:
  4456. case no_keyedlimit:
  4457. case no_cosort:
  4458. case no_topn:
  4459. case no_iterate:
  4460. case no_preload:
  4461. case no_alias:
  4462. case no_forcelocal:
  4463. case no_nothor:
  4464. case no_cluster:
  4465. case no_forcenolocal:
  4466. case no_assertsorted:
  4467. case no_assertgrouped:
  4468. case no_assertdistributed:
  4469. case no_stepped:
  4470. case no_filtergroup:
  4471. case no_section:
  4472. case no_related:
  4473. case no_unordered:
  4474. case no_preservemeta:
  4475. if (isNull(child) || isFail(child))
  4476. return removeParentNode(expr);
  4477. break;
  4478. case no_transformebcdic:
  4479. case no_transformascii:
  4480. case no_rollupgroup:
  4481. case no_normalizegroup:
  4482. case no_parse:
  4483. case no_newparse:
  4484. case no_xmlparse:
  4485. case no_newxmlparse:
  4486. case no_selfjoin:
  4487. case no_process:
  4488. if (isNull(child))
  4489. return replaceWithNull(expr);
  4490. break;
  4491. case no_normalize:
  4492. if (isNull(child) || matchesConstantValue(expr->queryChild(1), 0))
  4493. return replaceWithNull(expr);
  4494. break;
  4495. case no_allnodes:
  4496. case no_thisnode:
  4497. if (isNull(child) && expr->isDataset())
  4498. return replaceWithNull(expr);
  4499. break;
  4500. case no_combine:
  4501. case no_combinegroup:
  4502. if (isNull(child) && isNull(expr->queryChild(1)))
  4503. return replaceWithNull(expr);
  4504. break;
  4505. case no_createdictionary:
  4506. if (isNull(child))
  4507. return replaceWithNull(expr);
  4508. break;
  4509. case no_selectmap:
  4510. if (isNull(child))
  4511. return replaceWithNullRow(child);
  4512. break;
  4513. case no_selectnth:
  4514. // if (isNull(child) || isZero(expr->queryChild(1)))
  4515. if (isNull(child))
  4516. return replaceWithNullRow(child);
  4517. break;
  4518. case no_select:
  4519. if (isNull(child) && expr->hasAttribute(newAtom))
  4520. return replaceWithNull(expr);
  4521. break;
  4522. case no_createset:
  4523. if (isNull(child))
  4524. return replaceWithNull(expr);
  4525. break;
  4526. case no_hqlproject:
  4527. case no_projectrow:
  4528. {
  4529. if (isNullProject(expr, false, false))
  4530. return removeParentNode(expr);
  4531. if (isNull(child))
  4532. return replaceWithNull(expr);
  4533. break;
  4534. }
  4535. case no_output:
  4536. {
  4537. //Appending a null dataset to an output does nothing (sometimes occurs as a kind of nop)
  4538. if (!queryRealChild(expr, 1) && expr->hasAttribute(extendAtom))
  4539. {
  4540. if (isNull(child) && child->isDataset())
  4541. return replaceWithNull(expr);
  4542. }
  4543. break;
  4544. }
  4545. case no_compound:
  4546. if (isNull(child) && child->isAction())
  4547. return LINK(expr->queryChild(1)); // Could cause overlinking of child when called from HqlOpt
  4548. break;
  4549. case no_executewhen:
  4550. {
  4551. IHqlExpression * action = expr->queryChild(1);
  4552. if (isNull(action) && action->isAction())
  4553. return removeParentNode(expr);
  4554. break;
  4555. }
  4556. case no_globalscope:
  4557. if (isRedundantGlobalScope(expr))
  4558. return removeParentNode(expr);
  4559. break;
  4560. case no_evaluate_stmt:
  4561. {
  4562. IHqlExpression * arg = expr->queryChild(0);
  4563. if (arg->isConstant() || arg->getOperator() == no_table)
  4564. return createNullExpr(expr);
  4565. break;
  4566. }
  4567. }
  4568. return NULL;
  4569. }
  4570. IHqlExpression * NullFolderMixin::queryOptimizeAggregateInline(IHqlExpression * expr, __int64 numRows)
  4571. {
  4572. node_operator specialOp = querySimpleAggregate(expr, false, true);
  4573. IHqlExpression * transform = expr->queryChild(2);
  4574. IHqlExpression * assign = transform->queryChild(0); // guaranteed to be in simple form
  4575. LinkedHqlExpr value;
  4576. switch (specialOp)
  4577. {
  4578. case no_existsgroup:
  4579. value.setown(createConstant(numRows != 0));
  4580. break;
  4581. case no_countgroup:
  4582. {
  4583. ITypeInfo * type = assign->queryChild(0)->queryType();
  4584. value.setown(createConstant(type->castFrom(true, numRows)));
  4585. break;
  4586. }
  4587. //could do max/min/sum if really wanted to
  4588. }
  4589. if (!value)
  4590. return NULL;
  4591. HqlExprArray args;
  4592. args.append(*createAssign(LINK(assign->queryChild(0)), LINK(value)));
  4593. OwnedHqlExpr newTransform = createValue(no_transform, transform->getType(), args);
  4594. OwnedHqlExpr values = createValue(no_transformlist, newTransform.getClear());
  4595. return createDataset(no_inlinetable, values.getClear(), LINK(expr->queryRecord()));
  4596. }
  4597. //---------------------------------------------------------------------------
  4598. static IHqlExpression * getLowerCaseConstant(IHqlExpression * expr)
  4599. {
  4600. IValue * value = expr->queryValue();
  4601. assertex(value);
  4602. ITypeInfo * type = expr->queryType();
  4603. switch (type->getTypeCode())
  4604. {
  4605. case type_unicode:
  4606. case type_varunicode:
  4607. case type_string:
  4608. case type_data:
  4609. case type_varstring:
  4610. case type_utf8:
  4611. break;
  4612. default:
  4613. return LINK(expr);
  4614. }
  4615. const void * data = value->queryValue();
  4616. unsigned size = type->getSize();
  4617. unsigned stringLen = type->getStringLen();
  4618. MemoryAttr lower(size);
  4619. memcpy(lower.bufferBase(), data, size);
  4620. if (type->getTypeCode() == type_utf8)
  4621. rtlUtf8ToLower(stringLen, (char *)lower.get(), str(type->queryLocale()));
  4622. else if (isUnicodeType(type))
  4623. rtlUnicodeToLower(stringLen, (UChar *)lower.get(), str(type->queryLocale()));
  4624. else
  4625. {
  4626. if (type->queryCharset()->queryName() == ebcdicAtom)
  4627. rtlEStrToStr(stringLen, (char*)lower.get(), stringLen, (char*)lower.get()); // Yes it does work in place.
  4628. rtlStringToLower(stringLen, (char *)lower.get());
  4629. if (type->queryCharset()->queryName() == ebcdicAtom)
  4630. rtlStrToEStr(stringLen, (char*)lower.get(), stringLen, (char*)lower.get()); // Yes it does work in place.
  4631. }
  4632. if (memcmp(lower.get(), data, size) == 0)
  4633. return LINK(expr);
  4634. return createConstant(createValueFromMem(LINK(type), lower.get()));
  4635. }
  4636. IHqlExpression * getLowerCaseConstantExpr(IHqlExpression * expr)
  4637. {
  4638. OwnedHqlExpr folded = foldHqlExpression(expr);
  4639. return getLowerCaseConstant(folded);
  4640. }
  4641. //---------------------------------------------------------------------------
  4642. static HqlTransformerInfo constantReplacingTransformerInfo("ConstantReplacingTransformer");
  4643. class HQL_API ConstantReplacingTransformer : public NewHqlTransformer
  4644. {
  4645. public:
  4646. ConstantReplacingTransformer(IHqlExpression * _selector) : NewHqlTransformer(constantReplacingTransformerInfo) { selector = _selector; }
  4647. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  4648. {
  4649. node_operator op = expr->getOperator();
  4650. //Special case for things that really shouldn't have substitutions
  4651. switch (op)
  4652. {
  4653. case no_attr:
  4654. case no_attr_link:
  4655. case no_attr_expr:
  4656. {
  4657. IAtom * name = expr->queryName();
  4658. if (name == _selectors_Atom)
  4659. {
  4660. HqlExprArray args;
  4661. ForEachChild(i, expr)
  4662. args.append(*transformSelector(expr->queryChild(i)));
  4663. return expr->clone(args);
  4664. }
  4665. break;
  4666. }
  4667. case no_selectnth:
  4668. case NO_AGGREGATE:
  4669. case no_createset:
  4670. //Selectively check to see if this subtree needs to be transformed - only transform if it contains
  4671. //the selector being substituted, or if it needs transforming to update selectors that have changed
  4672. if (!expr->usesSelector(selector) && !needToUpdateSelectors(expr))
  4673. return LINK(expr);
  4674. break;
  4675. }
  4676. if (expr->isConstant())
  4677. return LINK(expr);
  4678. unsigned numNonHidden = activityHidesSelectorGetNumNonHidden(expr, selector);
  4679. if (numNonHidden == 0)
  4680. return NewHqlTransformer::createTransformed(expr);
  4681. bool same = true;
  4682. HqlExprArray children;
  4683. for (unsigned i=0; i < numNonHidden; i++)
  4684. {
  4685. IHqlExpression * cur = expr->queryChild(i);
  4686. IHqlExpression * mapped = transform(cur);
  4687. children.append(*mapped);
  4688. if (cur != mapped)
  4689. same = false;
  4690. }
  4691. if (same)
  4692. return LINK(expr);
  4693. unwindChildren(children, expr, numNonHidden);
  4694. return expr->clone(children);
  4695. }
  4696. void setMapping(IHqlExpression * oldValue, IHqlExpression * newValue)
  4697. {
  4698. NewHqlTransformer::setMapping(oldValue, newValue);
  4699. //Nasty... I'm not sure if this should really happen, but...
  4700. //if we are replacing a row, then the old active selector needs to become an inline row (e.g., prwo.xhql)
  4701. if (oldValue->isDatarow())
  4702. {
  4703. OwnedHqlExpr newRow = createRow(no_newrow, LINK(newValue));
  4704. setSelectorMapping(oldValue, newRow);
  4705. }
  4706. }
  4707. protected:
  4708. IHqlExpression * selector;
  4709. };
  4710. static bool isWorthPercolating(IHqlExpression * expr)
  4711. {
  4712. switch (expr->getOperator())
  4713. {
  4714. case no_attr:
  4715. case no_attr_link:
  4716. case no_constant:
  4717. case no_getresult:
  4718. case no_record:
  4719. case no_all:
  4720. return false;
  4721. }
  4722. return !expr->isConstant();
  4723. }
  4724. static bool isWorthPercolating(const HqlExprArray & exprs)
  4725. {
  4726. ForEachItemIn(i, exprs)
  4727. if (isWorthPercolating(&exprs.item(i)))
  4728. return true;
  4729. return false;
  4730. }
  4731. bool expressionsEquivalent(IHqlExpression * left, IHqlExpression * right)
  4732. {
  4733. if (left->queryBody() == right->queryBody())
  4734. return true;
  4735. if ((left->getOperator() == no_null) && (right->getOperator() == no_null))
  4736. return recordTypesMatch(left, right);
  4737. return false;
  4738. }
  4739. bool exprsReferencesDataset(const HqlExprArray & source, IHqlExpression * exprSelector)
  4740. {
  4741. ForEachItemIn(i, source)
  4742. {
  4743. if (exprReferencesDataset(&source.item(i), exprSelector))
  4744. return true;
  4745. }
  4746. return false;
  4747. }
  4748. class HqlConstantPercolator : public CInterface
  4749. {
  4750. public:
  4751. HqlConstantPercolator(IHqlExpression *ds = NULL)
  4752. {
  4753. if (ds)
  4754. self.setown(getSelf(ds));
  4755. }
  4756. void addEquality(IHqlExpression * target, IHqlExpression * source)
  4757. {
  4758. addTransformMapping(target, source);
  4759. }
  4760. bool empty() { return targets.empty(); }
  4761. IHqlExpression * expandFields(IHqlExpression * expr, IHqlExpression * exprSelector)
  4762. {
  4763. if (!isWorthPercolating(expr))
  4764. return LINK(expr);
  4765. if (!exprReferencesDataset(expr, exprSelector))
  4766. return LINK(expr);
  4767. ConstantReplacingTransformer transformer(exprSelector);
  4768. initTransformer(exprSelector, transformer);
  4769. return transformer.transformRoot(expr);
  4770. }
  4771. IHqlExpression * expandField(IHqlExpression * field)
  4772. {
  4773. ForEachItemIn(i, targets)
  4774. {
  4775. if (targets.item(i).queryChild(1) == field)
  4776. return LINK(&sources.item(i));
  4777. }
  4778. return NULL;
  4779. }
  4780. bool expandFields(HqlExprArray & target, const HqlExprArray & source, IHqlExpression * exprSelector)
  4781. {
  4782. if (!isWorthPercolating(source))
  4783. return false;
  4784. if (!exprsReferencesDataset(source, exprSelector))
  4785. return false;
  4786. ConstantReplacingTransformer transformer(exprSelector);
  4787. initTransformer(exprSelector, transformer);
  4788. ForEachItemIn(i, source)
  4789. {
  4790. IHqlExpression & cur = source.item(i);
  4791. if (exprReferencesDataset(&cur, exprSelector))
  4792. target.append(*transformer.transformRoot(&cur));
  4793. else
  4794. target.append(*LINK(&cur));
  4795. }
  4796. return true;
  4797. }
  4798. void inheritMapping(const HqlConstantPercolator * other)
  4799. {
  4800. assertex(other);
  4801. if (other->self)
  4802. {
  4803. assertex(!self || self == other->self);
  4804. self.set(other->self);
  4805. }
  4806. ForEachItemIn(i, other->targets)
  4807. {
  4808. targets.append(OLINK(other->targets.item(i)));
  4809. sources.append(OLINK(other->sources.item(i)));
  4810. }
  4811. }
  4812. void intersectMapping(const HqlConstantPercolator * other)
  4813. {
  4814. assertex(other);
  4815. ForEachItemInRev(i, targets)
  4816. {
  4817. unsigned match = other->targets.find(targets.item(i));
  4818. if ((match == NotFound) || !expressionsEquivalent(&sources.item(i), &other->sources.item(match)))
  4819. {
  4820. sources.remove(i);
  4821. targets.remove(i);
  4822. }
  4823. }
  4824. }
  4825. IHqlExpression * querySelf() { return self; }
  4826. IHqlExpression * resolveField(IHqlExpression * search)
  4827. {
  4828. ForEachItemIn(i, targets)
  4829. {
  4830. IHqlExpression & cur = targets.item(i);
  4831. if ((cur.queryChild(1) == search) && (cur.queryChild(0) == self))
  4832. return &sources.item(i);
  4833. }
  4834. return NULL;
  4835. }
  4836. static HqlConstantPercolator * extractConstantMapping(IHqlExpression * transform)
  4837. {
  4838. if (!isKnownTransform(transform))
  4839. return NULL;
  4840. Owned<HqlConstantPercolator> mapping = new HqlConstantPercolator;
  4841. mapping->extractConstantTransform(transform);
  4842. if (mapping->empty())
  4843. return NULL;
  4844. return mapping.getClear();
  4845. }
  4846. static HqlConstantPercolator * extractNullMapping(IHqlExpression * record)
  4847. {
  4848. Owned<HqlConstantPercolator> mapping = new HqlConstantPercolator;
  4849. mapping->extractNullTransform(record);
  4850. if (mapping->empty())
  4851. return NULL;
  4852. return mapping.getClear();
  4853. }
  4854. protected:
  4855. void addMapping(IHqlExpression * select, IHqlExpression * expr)
  4856. {
  4857. assertex(select->getOperator() == no_select);
  4858. targets.append(*LINK(select));
  4859. sources.append(*LINK(expr));
  4860. // if (select->isDatarow() && !expr->isDatarow())
  4861. }
  4862. void addTransformMapping(IHqlExpression * tgt, IHqlExpression * src)
  4863. {
  4864. #ifdef _DEBUG
  4865. assertex(tgt->getOperator() == no_select);
  4866. IHqlExpression * sel = queryDatasetCursor(tgt->queryChild(0));
  4867. assertex(sel == self);
  4868. #endif
  4869. OwnedHqlExpr castRhs = ensureExprType(src, tgt->queryType());
  4870. addMapping(tgt, castRhs);
  4871. }
  4872. void doExtractConstantTransform(IHqlExpression * transform, IHqlExpression * selector);
  4873. void expandNullRowMapping(IHqlExpression * selector, IHqlExpression * record);
  4874. void extractConstantTransform(IHqlExpression * transform);
  4875. void initTransformer(IHqlExpression * selector, ConstantReplacingTransformer & transformer) const;
  4876. void extractNullTransform(IHqlExpression * record)
  4877. {
  4878. self.setown(getSelf(record));
  4879. expandNullRowMapping(self, record);
  4880. }
  4881. protected:
  4882. OwnedHqlExpr self;
  4883. HqlExprArray targets;
  4884. HqlExprArray sources;
  4885. };
  4886. void HqlConstantPercolator::extractConstantTransform(IHqlExpression * transform)
  4887. {
  4888. self.setown(getSelf(transform));
  4889. doExtractConstantTransform(transform, NULL);
  4890. }
  4891. void HqlConstantPercolator::expandNullRowMapping(IHqlExpression * selector, IHqlExpression * record)
  4892. {
  4893. ForEachChild(i, record)
  4894. {
  4895. IHqlExpression * cur = record->queryChild(i);
  4896. switch (cur->getOperator())
  4897. {
  4898. case no_record:
  4899. expandNullRowMapping(selector, cur);
  4900. break;
  4901. case no_ifblock:
  4902. //valid - since if protecting fields are false, the fields will also be null
  4903. expandNullRowMapping(selector, cur->queryChild(1));
  4904. break;
  4905. case no_field:
  4906. {
  4907. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  4908. try
  4909. {
  4910. OwnedHqlExpr null = createNullExpr(selected);
  4911. addMapping(selected, null);
  4912. }
  4913. catch (IException * e)
  4914. {
  4915. e->Release();
  4916. }
  4917. if (selected->isDatarow())
  4918. expandNullRowMapping(selected, selected->queryRecord());
  4919. break;
  4920. }
  4921. }
  4922. }
  4923. }
  4924. void HqlConstantPercolator::doExtractConstantTransform(IHqlExpression * transform, IHqlExpression * selector)
  4925. {
  4926. unsigned max = transform->numChildren();
  4927. for (unsigned idx = 0; idx < max; idx++)
  4928. {
  4929. IHqlExpression * cur = transform->queryChild(idx);
  4930. switch (cur->getOperator())
  4931. {
  4932. case no_assign:
  4933. {
  4934. IHqlExpression * lhs = cur->queryChild(0);
  4935. IHqlExpression * rhs = cur->queryChild(1);
  4936. IHqlExpression * lf = lhs->queryChild(1);
  4937. IHqlExpression * self = lhs->queryChild(0);
  4938. assertex(self->getOperator() == no_self);
  4939. OwnedHqlExpr selected = selector ? createSelectExpr(LINK(selector), LINK(lf)) : LINK(lhs);
  4940. if (rhs->isConstant())
  4941. addTransformMapping(selected, rhs);
  4942. if (lhs->isDatarow())
  4943. {
  4944. if (rhs->getOperator() == no_null)
  4945. expandNullRowMapping(selected, selected->queryRecord());
  4946. else if (rhs->getOperator() == no_createrow)
  4947. doExtractConstantTransform(rhs->queryChild(0), selected);
  4948. }
  4949. }
  4950. break;
  4951. case no_assignall:
  4952. doExtractConstantTransform(cur, selector);
  4953. break;
  4954. case no_attr:
  4955. case no_attr_link:
  4956. case no_attr_expr:
  4957. case no_alias_scope:
  4958. case no_skip:
  4959. case no_assert:
  4960. break;
  4961. default:
  4962. assertex(!"Transforms should only contain assignments");
  4963. break;
  4964. }
  4965. }
  4966. }
  4967. void HqlConstantPercolator::initTransformer(IHqlExpression * selector, ConstantReplacingTransformer & transformer) const
  4968. {
  4969. ForEachItemIn(i, sources)
  4970. {
  4971. OwnedHqlExpr value = replaceSelector(&targets.item(i), self, selector);
  4972. transformer.setMapping(value, &sources.item(i));
  4973. }
  4974. }
  4975. IHqlExpression * CExprFolderTransformer::doFoldTransformed(IHqlExpression * unfolded, IHqlExpression * original)
  4976. {
  4977. IHqlExpression * nullFolded = foldNullDataset(unfolded);
  4978. if (nullFolded)
  4979. return nullFolded;
  4980. #if 0
  4981. IHqlExpression * body = unfolded->queryBody();
  4982. OwnedHqlExpr expr = foldConstantOperator(body, foldOptions, templateContext);
  4983. if ((unfolded != body) && !expr->isAnnotation() && !expr->queryValue())
  4984. expr.setown(unfolded->cloneAllAnnotations(expr));
  4985. #else
  4986. OwnedHqlExpr expr = foldConstantOperator(unfolded, foldOptions, templateContext);
  4987. #endif
  4988. node_operator op = expr->getOperator();
  4989. switch (op)
  4990. {
  4991. //Scalar operators that are not handled in foldConstantOperator()
  4992. case no_or:
  4993. return foldOrExpr(expr, (foldOptions & HFOx_op_not_x) != 0);
  4994. case no_and:
  4995. return foldAndExpr(expr, (foldOptions & HFOx_op_not_x) != 0);
  4996. //Operations that involve constant folding on datasets.
  4997. case no_normalize:
  4998. {
  4999. // Identify expressions
  5000. IHqlExpression * ds = expr->queryChild(0);
  5001. IHqlExpression * count = expr->queryChild(1);
  5002. IHqlExpression * transform = expr->queryChild(2);
  5003. OwnedHqlExpr left = createSelector(no_left, ds, querySelSeq(expr));
  5004. if (!hasSingleRow(ds) || exprReferencesDataset(count, left)) // Complicate things more
  5005. break;
  5006. // Replace LEFT from normalize transform (if used) by ROW's contents
  5007. OwnedHqlExpr newTransform;
  5008. if (exprReferencesDataset(transform, left)) {
  5009. OwnedHqlExpr newRow;
  5010. // Make sure it's one of the recognised formats
  5011. switch (ds->getOperator())
  5012. {
  5013. case no_datasetfromrow: // DATASET(ROW(transform))
  5014. {
  5015. IHqlExpression * row = ds->queryChild(0);
  5016. if (row->getOperator() == no_createrow)
  5017. newRow.set(row);
  5018. break;
  5019. }
  5020. case no_inlinetable: // DATASET([transform()]) or DATASET([value],{ myfield })
  5021. {
  5022. IHqlExpression * transformList = ds->queryChild(0);
  5023. assertex(transformList->getOperator() == no_transformlist);
  5024. newRow.setown(createRow(no_createrow, LINK(transformList->queryChild(0))));
  5025. break;
  5026. }
  5027. }
  5028. if (!newRow)
  5029. break;
  5030. //Instead of evaluating once newRow will be evaluated multiple times. Is that ok (e.g., volatile)
  5031. if (!canDuplicateActivity(newRow))
  5032. break;
  5033. OwnedHqlExpr replacementRow = createRow(no_newrow, LINK(newRow));
  5034. newTransform.setown(replaceSelector(transform, left, replacementRow));
  5035. }
  5036. HqlExprArray args;
  5037. unwindChildren(args, expr, 1); // (count, trans)
  5038. if (newTransform)
  5039. args.replace(*newTransform.getClear(), 1);
  5040. removeAttribute(args, _selectorSequence_Atom);
  5041. return createDataset(no_dataset_from_transform, args);
  5042. }
  5043. case no_filter:
  5044. {
  5045. IHqlExpression * child = expr->queryChild(0);
  5046. HqlExprArray args;
  5047. args.append(*LINK(child));
  5048. unsigned num = expr->numChildren();
  5049. for (unsigned idx = 1; idx < num; idx++)
  5050. {
  5051. IHqlExpression * cur = expr->queryChild(idx);
  5052. IValue * value = cur->queryValue();
  5053. if (value)
  5054. {
  5055. if (!value->getBoolValue())
  5056. return createNullDataset(child);
  5057. }
  5058. else
  5059. args.append(*LINK(cur));
  5060. }
  5061. if (args.ordinality() == 1)
  5062. return removeParentNode(expr);
  5063. //Fold filter conditions with previous projects to see if they are always true, or always false.
  5064. //Similar code also appears in the optimizer...
  5065. switch (child->getOperator())
  5066. {
  5067. case no_newusertable:
  5068. case no_hqlproject:
  5069. if ((foldOptions & HFOfoldfilterproject) && !(foldOptions & HFOpercolateconstants))
  5070. {
  5071. // Following are possibilities, but aren't worth the extra cycles....
  5072. //case no_join:
  5073. //case no_iterate:
  5074. //case no_denormalize:
  5075. //case no_normalize:
  5076. //case no_selfjoin:
  5077. if (!isAggregateDataset(child) && (args.ordinality() > 1))
  5078. {
  5079. NewProjectMapper2 mapper;
  5080. mapper.setMapping(queryNewColumnProvider(child));
  5081. //Iterate all but last
  5082. for (unsigned i = args.ordinality(); --i != 0; )
  5083. {
  5084. IHqlExpression * cur = &args.item(i);
  5085. OwnedHqlExpr expandedFilter = mapper.expandFields(cur, child, NULL, NULL);
  5086. if (expandedFilter->isConstant())
  5087. {
  5088. //Following would be sensible, but can't call transform at this point, so replace arg, and wait for it to re-iterate
  5089. IIdAtom * nameF = expr->queryId();
  5090. IIdAtom * nameP = child->queryId();
  5091. DBGLOG("Folder: Combining FILTER %s with %s %s produces constant filter", nameF ? str(nameF) : "", getOpString(child->getOperator()), nameP ? str(nameP) : "");
  5092. expandedFilter.setown(transformExpanded(expandedFilter));
  5093. IValue * value = expandedFilter->queryValue();
  5094. if (value)
  5095. {
  5096. if (!value->getBoolValue())
  5097. return replaceWithNull(expr);
  5098. args.remove(i);
  5099. }
  5100. else
  5101. args.replace(*LINK(expandedFilter), i);
  5102. }
  5103. }
  5104. }
  5105. }
  5106. break;
  5107. case no_inlinetable:
  5108. if (foldOptions & HFOconstantdatasets)
  5109. {
  5110. OwnedITypeInfo boolType = makeBoolType();
  5111. OwnedHqlExpr filterCondition = createBalanced(no_and, boolType, args, 1, args.ordinality());
  5112. HqlExprArray filtered;
  5113. bool allFilteredOk = true;
  5114. IHqlExpression * values = child->queryChild(0);
  5115. ForEachChild(i, values)
  5116. {
  5117. IHqlExpression * curTransform = values->queryChild(i);
  5118. NewProjectMapper2 mapper;
  5119. mapper.setMapping(curTransform);
  5120. OwnedHqlExpr expandedFilter = mapper.expandFields(filterCondition, child, NULL, NULL);
  5121. OwnedHqlExpr folded = transformExpanded(expandedFilter);
  5122. IValue * value = folded->queryValue();
  5123. if (value)
  5124. {
  5125. if (value->getBoolValue())
  5126. filtered.append(*LINK(curTransform));
  5127. }
  5128. else
  5129. {
  5130. allFilteredOk = false;
  5131. break;
  5132. }
  5133. }
  5134. if (allFilteredOk)
  5135. {
  5136. if (filtered.ordinality() == 0)
  5137. return replaceWithNull(expr);
  5138. if (filtered.ordinality() == values->numChildren())
  5139. return removeParentNode(expr);
  5140. StringBuffer s1, s2;
  5141. DBGLOG("Folder: Node %s reduce values in child: %s from %d to %d", queryChildNodeTraceText(s1, expr), queryChildNodeTraceText(s2, child), values->numChildren(), filtered.ordinality());
  5142. HqlExprArray args;
  5143. args.append(*values->clone(filtered));
  5144. unwindChildren(args, child, 1);
  5145. return child->clone(args);
  5146. }
  5147. }
  5148. break;
  5149. }
  5150. if (args.ordinality() == 1)
  5151. return removeParentNode(expr);
  5152. return cloneOrLink(expr, args);
  5153. }
  5154. case no_newaggregate:
  5155. {
  5156. //Duplicated in constant folder and optimizer
  5157. IHqlExpression * child = expr->queryChild(0);
  5158. node_operator childOp = child->getOperator();
  5159. IHqlExpression * ret = NULL;
  5160. switch (childOp)
  5161. {
  5162. case no_inlinetable:
  5163. if ((foldOptions & HFOconstantdatasets) && isNoSkipInlineDataset(child))
  5164. ret = queryOptimizeAggregateInline(expr, child->queryChild(0)->numChildren());
  5165. break;
  5166. default:
  5167. if ((foldOptions & HFOconstantdatasets) && hasSingleRow(child))
  5168. ret = queryOptimizeAggregateInline(expr, 1);
  5169. break;
  5170. }
  5171. if (ret)
  5172. return ret;
  5173. break;
  5174. }
  5175. case no_count:
  5176. {
  5177. IHqlExpression * child = expr->queryChild(0);
  5178. node_operator childOp = child->getOperator();
  5179. switch (childOp)
  5180. {
  5181. case no_inlinetable:
  5182. if (isNoSkipInlineDataset(child))
  5183. return createConstant(expr->queryType()->castFrom(false, (__int64)child->queryChild(0)->numChildren()));
  5184. break;
  5185. case no_temptable:
  5186. {
  5187. IHqlExpression * values = child->queryChild(0);
  5188. if (values->isList())
  5189. return createValue(no_countlist, expr->getType(), LINK(values));
  5190. break;
  5191. }
  5192. case no_null:
  5193. return createNullValue(expr);
  5194. #if 0
  5195. // Enabling this generally makes code worse because of count(file), count(x) > n, and extra hoisting.
  5196. case no_addfiles:
  5197. {
  5198. OwnedHqlExpr lhs = replaceChild(expr, 0, child->queryChild(0));
  5199. OwnedHqlExpr rhs = replaceChild(expr, 0, child->queryChild(1));
  5200. return createValue(no_add, expr->getType(), LINK(lhs), LINK(rhs));
  5201. }
  5202. case no_if:
  5203. {
  5204. OwnedHqlExpr lhs = replaceChild(expr, 0, child->queryChild(1));
  5205. OwnedHqlExpr rhs = replaceChild(expr, 0, child->queryChild(2));
  5206. return createValue(no_if, expr->getType(), LINK(child->queryChild(0)), LINK(lhs), LINK(rhs));
  5207. }
  5208. #endif
  5209. default:
  5210. if (hasSingleRow(child))
  5211. return createConstant(expr->queryType()->castFrom(false, I64C(1)));
  5212. break;
  5213. }
  5214. break;
  5215. }
  5216. case no_exists:
  5217. {
  5218. IHqlExpression * child = expr->queryChild(0);
  5219. node_operator childOp = child->getOperator();
  5220. switch (childOp)
  5221. {
  5222. case no_inlinetable:
  5223. if (isNoSkipInlineDataset(child))
  5224. {
  5225. bool hasChildren = (child->queryChild(0)->numChildren() != 0);
  5226. return createConstant(hasChildren);
  5227. }
  5228. break;
  5229. #if 0
  5230. case no_addfiles:
  5231. {
  5232. OwnedHqlExpr lhs = replaceChild(expr, 0, child->queryChild(0));
  5233. OwnedHqlExpr rhs = replaceChild(expr, 0, child->queryChild(1));
  5234. return createValue(no_or, expr->getType(), LINK(lhs), LINK(rhs));
  5235. }
  5236. case no_if:
  5237. {
  5238. OwnedHqlExpr lhs = replaceChild(expr, 0, child->queryChild(1));
  5239. OwnedHqlExpr rhs = replaceChild(expr, 0, child->queryChild(2));
  5240. return createValue(no_if, expr->getType(), LINK(child->queryChild(0)), LINK(lhs), LINK(rhs));
  5241. }
  5242. #endif
  5243. case no_null:
  5244. return createConstant(op != no_exists);
  5245. default:
  5246. if (hasSingleRow(child))
  5247. return createConstant(op == no_exists);
  5248. break;
  5249. }
  5250. break;
  5251. }
  5252. case no_within:
  5253. case no_sum:
  5254. {
  5255. IHqlExpression * dataset = expr->queryChild(0);
  5256. if (dataset->getOperator() == no_null)
  5257. return createNullValue(expr);
  5258. if (op == no_sum && dataset->getOperator() == no_addfiles)
  5259. {
  5260. IHqlExpression * arg = expr->queryChild(1);
  5261. IHqlExpression * addLeft = dataset->queryChild(0);
  5262. IHqlExpression * addRight = dataset->queryChild(1);
  5263. OwnedHqlExpr sumLeft = createValue(op, expr->getType(), LINK(addLeft), replaceSelector(arg, dataset, addLeft));
  5264. OwnedHqlExpr sumRight = createValue(op, expr->getType(), LINK(addRight), replaceSelector(arg, dataset, addRight));
  5265. return createValue(no_add, expr->getType(), LINK(sumLeft), LINK(sumRight));
  5266. }
  5267. }
  5268. break;
  5269. #if 0
  5270. //Following are not enabled because they have a strange side-effect of stopping the dataset being hoisted
  5271. //since an inline dataset (which is hoisted) is converted to a no_list, which isn't.
  5272. //If the key segment monitors for IN were improved then it may be worth
  5273. case no_createset:
  5274. {
  5275. IHqlExpression * child = expr->queryChild(0);
  5276. switch (child->getOperator())
  5277. {
  5278. case no_inlinetable:
  5279. {
  5280. IHqlExpression * select = expr->queryChild(1);
  5281. //check a simple select from the dataset
  5282. if ((select->getOperator() == no_select) && (select->queryChild(0) == child->queryNormalizedSelector()))
  5283. {
  5284. HqlExprArray args;
  5285. bool ok = true;
  5286. IHqlExpression * transforms = child->queryChild(0);
  5287. IHqlExpression * field = select->queryChild(1);
  5288. ForEachChild(i, transforms)
  5289. {
  5290. IHqlExpression * cur = transforms->queryChild(i);
  5291. if (!cur->isPure() || containsSkip(cur))
  5292. {
  5293. ok = false;
  5294. break;
  5295. }
  5296. IHqlExpression * match = getExtractSelect(cur, field, false);
  5297. if (!match)
  5298. {
  5299. ok = false;
  5300. break;
  5301. }
  5302. args.append(*match);
  5303. }
  5304. if (ok)
  5305. return createValue(no_list, expr->getType(), args);
  5306. }
  5307. break;
  5308. }
  5309. case no_temptable:
  5310. {
  5311. IHqlExpression * list = child->queryChild(0);
  5312. if (list->getOperator() == no_list)
  5313. return ensureExprType(list, expr->queryType());
  5314. break;
  5315. }
  5316. }
  5317. break;
  5318. }
  5319. #endif
  5320. case no_select:
  5321. {
  5322. //Don't fold dataset references that are in scope,
  5323. //otherwise the dataset will fail to match...
  5324. if (expr->hasAttribute(newAtom))
  5325. {
  5326. IHqlExpression * left = expr->queryChild(0);
  5327. switch (left->getOperator())
  5328. {
  5329. case no_null:
  5330. return createNullExpr(expr);
  5331. case no_datasetfromrow:
  5332. if (left->queryChild(0)->getOperator() == no_null)
  5333. return createNullExpr(expr);
  5334. break;
  5335. case no_createrow:
  5336. #if 1
  5337. if (!expr->isDataset() && !expr->isDatarow())
  5338. {
  5339. OwnedHqlExpr match = getExtractSelect(left->queryChild(0), expr->queryChild(1), false);
  5340. if (match && match->isConstant())
  5341. return match.getClear();
  5342. }
  5343. #else
  5344. //This generates better code most of the time, but causes worse code for a few examples
  5345. //e.g., bug74112 cmorton47 ncferr
  5346. //Should enable once I've had time to investigate
  5347. if (!expr->isDataset())// && !expr->isDatarow())
  5348. {
  5349. OwnedHqlExpr match = getExtractSelect(left->queryChild(0), expr->queryChild(1), false);
  5350. if (match)// && match->isConstant())
  5351. return match.getClear();
  5352. }
  5353. #endif
  5354. break;
  5355. case no_selectnth:
  5356. if (foldOptions & HFOpercolateconstants)
  5357. {
  5358. IHqlExpression * ds = left->queryChild(0);
  5359. IHqlExpression * elem = left->queryChild(1);
  5360. if ((ds->getOperator() == no_inlinetable) && elem->queryValue())
  5361. {
  5362. __int64 idx = elem->queryValue()->getIntValue() - 1;
  5363. IHqlExpression * transforms = ds->queryChild(0);
  5364. if (idx >= 0 && idx < transforms->numChildren())
  5365. {
  5366. IHqlExpression * transform = transforms->queryChild((unsigned)idx);
  5367. HqlConstantPercolator * mapping = gatherConstants(transform);
  5368. if (mapping)
  5369. {
  5370. IHqlExpression * resolved = mapping->resolveField(expr->queryChild(1));
  5371. if (resolved)
  5372. return LINK(resolved);
  5373. }
  5374. }
  5375. else
  5376. return createNullExpr(expr);
  5377. }
  5378. }
  5379. }
  5380. }
  5381. // default is to call transformSelector() if not new
  5382. break;
  5383. }
  5384. case no_sample:
  5385. {
  5386. IHqlExpression * limit = expr->queryChild(1);
  5387. IValue * value = limit->queryValue();
  5388. if (value && (value->getIntValue() == 1))
  5389. return removeParentNode(expr);
  5390. break;
  5391. }
  5392. /*
  5393. case no_alias_scope:
  5394. {
  5395. IHqlExpression * child = expr->queryChild(0);
  5396. if (child->queryValue())
  5397. return LINK(child);
  5398. break;
  5399. }
  5400. */
  5401. /*
  5402. no_table,
  5403. no_temptable,
  5404. no_pipe:
  5405. no_fetch,
  5406. no_join,
  5407. no_joined,
  5408. */
  5409. case no_usertable:
  5410. //These should have been removed by the time we get called, but can very occasionally occur
  5411. //if it is called in the parser (e.g., when folding a filename)
  5412. break;
  5413. case no_selectfields:
  5414. {
  5415. //These should have been removed by the time we get called.
  5416. //This is sometimes added by the SQL generator, but it shouldn't perform a project
  5417. assertex(expr->queryChild(1)->getOperator() == no_null);
  5418. IHqlExpression * dataset = expr->queryChild(0);
  5419. if (isNull(dataset))
  5420. return LINK(dataset);
  5421. break;
  5422. }
  5423. case no_compound:
  5424. if (foldOptions & HFOforcefold)
  5425. return LINK(expr->queryChild(1));
  5426. break;
  5427. case no_hqlproject:
  5428. if (expr != original)
  5429. {
  5430. //Could have removed whether or not somethin needs to be a count project
  5431. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  5432. if (counter && !transformContainsCounter(expr->queryChild(1), counter))
  5433. return removeAttribute(expr, _countProject_Atom);
  5434. }
  5435. break;
  5436. case no_temptable:
  5437. {
  5438. if (expr->queryChild(0)->getOperator() == no_list)
  5439. {
  5440. ECLlocation dummyLocation(0, 0, 0, NULL);
  5441. OwnedHqlExpr inlineTable = convertTempTableToInlineTable(errorProcessor, dummyLocation, expr);
  5442. if (expr != inlineTable)
  5443. return inlineTable.getClear();
  5444. }
  5445. break;
  5446. }
  5447. case no_assert:
  5448. if (getBoolValue(expr->queryChild(0), false))
  5449. return createValue(no_null, makeVoidType());
  5450. break;
  5451. case no_sequential:
  5452. case no_parallel:
  5453. case no_orderedactionlist:
  5454. if (expr->numChildren() == 1)
  5455. {
  5456. if (expr->queryChild(0)->isAttribute())
  5457. return createValue(no_null, makeVoidType());
  5458. return removeParentNode(expr);
  5459. }
  5460. break;
  5461. case no_likely:
  5462. case no_unlikely:
  5463. {
  5464. IHqlExpression * child = expr->queryChild(0);
  5465. switch(child->getOperator())
  5466. {
  5467. case no_likely:
  5468. case no_unlikely:
  5469. return replaceChild(expr, 0, child->queryChild(0));
  5470. case no_constant:
  5471. return LINK(child);
  5472. }
  5473. break;
  5474. }
  5475. }
  5476. return LINK(expr);
  5477. }
  5478. //---------------------------------------------------------------------------
  5479. FolderTransformInfo::~FolderTransformInfo()
  5480. {
  5481. ::Release(mapping);
  5482. }
  5483. static HqlTransformerInfo cExprFolderTransformerInfo("CExprFolderTransformer");
  5484. CExprFolderTransformer::CExprFolderTransformer(IErrorReceiver & _errorProcessor, ITemplateContext * _templateContext, unsigned _options)
  5485. : NewHqlTransformer(cExprFolderTransformerInfo), templateContext(_templateContext), errorProcessor(_errorProcessor)
  5486. {
  5487. foldOptions = _options;
  5488. }
  5489. IHqlExpression * CExprFolderTransformer::createTransformedAnnotation(IHqlExpression * expr)
  5490. {
  5491. return CExprFolderTransformer::createTransformed(expr);
  5492. }
  5493. ANewTransformInfo * CExprFolderTransformer::createTransformInfo(IHqlExpression * expr)
  5494. {
  5495. return CREATE_NEWTRANSFORMINFO(FolderTransformInfo, expr);
  5496. }
  5497. IHqlExpression * createListMatchStructure(node_operator op, IHqlExpression * expr, const HqlExprArray & args, unsigned & idx)
  5498. {
  5499. if (expr->getOperator() != op)
  5500. return &OLINK(args.item(idx++));
  5501. IHqlExpression * lhs = expr->queryChild(0);
  5502. IHqlExpression * rhs = expr->queryChild(1);
  5503. OwnedHqlExpr newLhs = createListMatchStructure(op, lhs, args, idx);
  5504. OwnedHqlExpr newRhs = createListMatchStructure(op, rhs, args, idx);
  5505. if ((lhs == newLhs) && (rhs == newRhs))
  5506. return LINK(expr);
  5507. if (op == no_and)
  5508. {
  5509. if (matchesBoolean(newLhs, true))
  5510. return newRhs.getClear();
  5511. if (matchesBoolean(newRhs, true))
  5512. return newLhs.getClear();
  5513. }
  5514. else
  5515. {
  5516. if (matchesBoolean(newLhs, false))
  5517. return newRhs.getClear();
  5518. if (matchesBoolean(newRhs, false))
  5519. return newLhs.getClear();
  5520. }
  5521. OwnedHqlExpr value = createValue(op, expr->getType(), newLhs.getClear(), newRhs.getClear());
  5522. return expr->cloneAllAnnotations(value);
  5523. }
  5524. IHqlExpression * createListMatchStructure(node_operator op, IHqlExpression * expr, const HqlExprArray & args)
  5525. {
  5526. unsigned idx = 0;
  5527. OwnedHqlExpr ret = createListMatchStructure(op, expr, args, idx);
  5528. assertex(idx == args.ordinality());
  5529. return ret.getClear();
  5530. }
  5531. //dedup and rollup need to be very careful substituting constants for the rollup conditions.
  5532. //If the original condition is something like right.combine, which is then replaced with false
  5533. //it would then be processed as an equality false=false condition, causing extra dedups.
  5534. //If it is substitued with true it will behave the same, so don't do anything.
  5535. static IHqlExpression * preserveRollupConditions(IHqlExpression * update, IHqlExpression * original, unsigned from, unsigned to)
  5536. {
  5537. HqlExprArray args;
  5538. unwindChildren(args, update);
  5539. bool same = true;
  5540. for (unsigned i=from; i < to; i++)
  5541. {
  5542. IHqlExpression * cur = &args.item(i);
  5543. IHqlExpression * curOriginal = original->queryChild(i);
  5544. LinkedHqlExpr mapped;
  5545. if (cur->queryValue() && cur->queryType()->getTypeCode() == type_boolean && (cur->queryValue()->getBoolValue() == false))
  5546. {
  5547. if (!curOriginal->queryValue())
  5548. mapped.set(curOriginal);
  5549. }
  5550. if (mapped && (cur != mapped))
  5551. {
  5552. args.replace(*mapped.getClear(), i);
  5553. same = false;
  5554. }
  5555. }
  5556. if (same)
  5557. return LINK(update);
  5558. return update->clone(args);
  5559. }
  5560. static IHqlExpression * stripDedupConditions(IHqlExpression * update, IHqlExpression * original)
  5561. {
  5562. HqlExprArray args;
  5563. unwindChildren(args, update);
  5564. unsigned max = args.ordinality();
  5565. bool same = true;
  5566. bool hadCriteria = false;
  5567. for (unsigned i=max-1; i != 0; i--)
  5568. {
  5569. IHqlExpression * cur = &args.item(i);
  5570. LinkedHqlExpr mapped;
  5571. switch (cur->getOperator())
  5572. {
  5573. case no_left:
  5574. case no_right:
  5575. case no_attr:
  5576. case no_attr_expr:
  5577. case no_attr_link:
  5578. case no_record:
  5579. break;
  5580. default:
  5581. if (cur->isConstant())
  5582. {
  5583. args.remove(i);
  5584. same = false;
  5585. }
  5586. else
  5587. hadCriteria = true;
  5588. break;
  5589. }
  5590. }
  5591. if (same)
  5592. return LINK(update);
  5593. if (!hadCriteria)
  5594. args.add(*createConstant(true), 1);
  5595. return update->clone(args);
  5596. }
  5597. IHqlExpression * CExprFolderTransformer::percolateConstants(IHqlExpression * expr)
  5598. {
  5599. IHqlExpression * child = expr->queryChild(0);
  5600. LinkedHqlExpr updated = expr;
  5601. node_operator op = expr->getOperator();
  5602. switch (op)
  5603. {
  5604. case no_iterate:
  5605. //only sustitute for right, left contains rolled up record.
  5606. updated.setown(percolateConstants(updated, child, no_right));
  5607. //could call gatherconstants() on updated, and then substitude for no_left
  5608. //But unlikely to matching anything that was constant, and if it was, the subsitution may well be wrong.
  5609. break;
  5610. case no_rollup:
  5611. {
  5612. //only sustitute for right, left contains rolled up record.
  5613. updated.setown(percolateConstants(updated, child, no_right));
  5614. //If any assignments of the form
  5615. //self.x := left.x then the constant can be percolated from the input, but
  5616. //self.x := left.x + 1 would cause invalid results.
  5617. //updated.setown(percolateRollupInvariantConstants(updated, child, no_left));
  5618. //changing the grouping conditions may confuse the code generator exactly what kind of dedup is going on,
  5619. //so preserve any that would cause complications..
  5620. OwnedHqlExpr fixed = preserveRollupConditions(updated, expr, 1, updated->numChildren());
  5621. if (fixed != updated)
  5622. {
  5623. //If these are false then we should be able to turn the rollup into a project
  5624. updated.set(fixed);
  5625. }
  5626. }
  5627. break;
  5628. case no_dedup:
  5629. {
  5630. //Need to be very careful about dedup criteria
  5631. updated.setown(percolateConstants(updated, child, no_left));
  5632. updated.setown(percolateConstants(updated, child, no_right));
  5633. //Check if any conditions are now always false - that weren't before
  5634. //if so it means the condition is always false, => will never dedup, => can just use the input
  5635. OwnedHqlExpr fixed = preserveRollupConditions(updated, expr, 1, updated->numChildren());
  5636. if (fixed != updated)
  5637. return removeParentNode(expr);
  5638. updated.setown(percolateConstants(updated, child, no_none));
  5639. //any conditions just made constant, can be removed, if there are no conditions left then we'll add,true
  5640. updated.setown(stripDedupConditions(updated, fixed));
  5641. //updated.setown(preserveRollupConditions(updated, expr, 1, updated->numChildren()));
  5642. }
  5643. break;
  5644. case no_selfjoin:
  5645. case no_join:
  5646. case no_denormalize:
  5647. case no_denormalizegroup:
  5648. {
  5649. //The constants can only be percolated into the transform if certain conditions are met,
  5650. //However they can always be percolated into the join condition... (test separately)
  5651. IAtom * joinKind = queryJoinKind(expr);
  5652. IHqlExpression * rhs = expr->queryChild(1);
  5653. IHqlExpression * oldCond = updated->queryChild(2);
  5654. IHqlExpression * atmost = updated->queryAttribute(atmostAtom);
  5655. switch (op)
  5656. {
  5657. case no_denormalize:
  5658. {
  5659. //Nasty: left is repeated, and likely to be left outer => only replace join condition
  5660. updated.setown(percolateConstants(updated, child, no_left, 2));
  5661. updated.setown(percolateConstants(updated, rhs, no_right, 2));
  5662. break;
  5663. }
  5664. case no_denormalizegroup:
  5665. {
  5666. if ((joinKind == innerAtom) || (joinKind == leftonlyAtom) || (joinKind == leftouterAtom))
  5667. updated.setown(percolateConstants(updated, child, no_left));
  5668. else
  5669. updated.setown(percolateConstants(updated, child, no_left, 2));
  5670. updated.setown(percolateConstants(updated, rhs, no_right, 2));
  5671. break;
  5672. }
  5673. case no_selfjoin:
  5674. rhs = child;
  5675. // fallthrough
  5676. case no_join:
  5677. {
  5678. if (joinKind == innerAtom)
  5679. {
  5680. updated.setown(percolateConstants(updated, child, no_left));
  5681. updated.setown(percolateConstants(updated, rhs, no_right));
  5682. }
  5683. else if ((joinKind == leftonlyAtom) || (joinKind == leftouterAtom))
  5684. {
  5685. updated.setown(percolateConstants(updated, child, no_left));
  5686. updated.setown(percolateConstants(updated, rhs, no_right, 2));
  5687. //MORE: Could also replace intersection of rhs constants with a NULL row
  5688. }
  5689. else if ((joinKind == rightonlyAtom) || (joinKind == rightouterAtom))
  5690. {
  5691. updated.setown(percolateConstants(updated, child, no_left, 2));
  5692. updated.setown(percolateConstants(updated, rhs, no_right));
  5693. }
  5694. else
  5695. {
  5696. updated.setown(percolateConstants(updated, child, no_left, 2));
  5697. updated.setown(percolateConstants(updated, rhs, no_right, 2));
  5698. }
  5699. break;
  5700. }
  5701. }
  5702. //If we've turned a fake all join into a join(true), then add an all attribute
  5703. IHqlExpression * updatedCond = updated->queryChild(2);
  5704. if (updatedCond != oldCond)
  5705. {
  5706. //At most is too complicated - either remove the atmost, or restore the join condition, and old atmost
  5707. if (atmost)
  5708. {
  5709. if (matchesBoolean(updatedCond, false))
  5710. updated.setown(removeAttribute(updated, atmostAtom));
  5711. else
  5712. {
  5713. //KEYED joins support ATMOST and RIGHT.xxx = value
  5714. if (!isKeyedJoin(updated) && joinHasRightOnlyHardMatch(updated, false))
  5715. {
  5716. HqlExprArray args;
  5717. unwindChildren(args, updated);
  5718. args.replace(*LINK(oldCond), 2);
  5719. removeAttribute(args, atmostAtom);
  5720. args.append(*LINK(atmost));
  5721. updated.setown(updated->clone(args));
  5722. }
  5723. else
  5724. updated.setown(appendOwnedOperand(updated, createAttribute(_conditionFolded_Atom)));
  5725. }
  5726. }
  5727. //otherwise this might convert to an all join, accept variants that are supported by all joins
  5728. //We don't currently have a self-join all. Would possibly be a good idea...
  5729. else if ((joinKind == innerAtom || joinKind == leftouterAtom || joinKind == leftonlyAtom) && (op != no_selfjoin))
  5730. updated.setown(appendOwnedOperand(updated, createAttribute(_conditionFolded_Atom)));
  5731. else
  5732. {
  5733. //check there is still some kind of join condition left
  5734. IHqlExpression * selSeq = querySelSeq(updated);
  5735. IHqlExpression * updatedLhs = updated->queryChild(0);
  5736. IHqlExpression * updatedRhs = (op == no_selfjoin) ? updatedLhs : updated->queryChild(1);
  5737. JoinSortInfo joinInfo(updatedCond, updatedLhs, updatedRhs, selSeq, atmost);
  5738. joinInfo.findJoinSortOrders(false);
  5739. //if will convert to an all join, then restore the old condition,
  5740. if (!joinInfo.hasRequiredEqualities())
  5741. updated.setown(replaceChild(updated, 2, oldCond));
  5742. else
  5743. updated.setown(appendOwnedOperand(updated, createAttribute(_conditionFolded_Atom)));
  5744. }
  5745. }
  5746. break;
  5747. }
  5748. case no_process:
  5749. {
  5750. //only substitute left; right contains iterated values
  5751. updated.setown(percolateConstants(updated, child, no_left));
  5752. break;
  5753. }
  5754. case no_merge:
  5755. {
  5756. HqlConstantPercolator * mapping = gatherConstants(expr);
  5757. if (mapping)
  5758. {
  5759. IHqlExpression * sorted = expr->queryAttribute(sortedAtom);
  5760. assertex(sorted);
  5761. OwnedHqlExpr newSorted = percolateConstants(mapping, sorted, child, no_activetable);
  5762. updated.setown(replaceOwnedAttribute(updated, newSorted.getClear()));
  5763. }
  5764. break;
  5765. }
  5766. case no_loop:
  5767. case no_graphloop:
  5768. case no_keyeddistribute:
  5769. //Safer to do nothing...
  5770. break;
  5771. case no_select:
  5772. {
  5773. //E.g., Substitute ds[1].x if x is fixed. Useful in addition to the inline[n].x below
  5774. //Useful in its own right, but latestcompreport.xhql required it because it was using it as a highly
  5775. //unusual guard condition.
  5776. //MORE: This needs more work to allow ds[1].x.y to be substituted, but that is very unusual
  5777. //simplest would be to recurse, build up for a list of fields, and then pass to resolveFields()
  5778. if (expr->hasAttribute(newAtom))
  5779. {
  5780. IHqlExpression * field = expr->queryChild(1);
  5781. OwnedHqlExpr transformedDs = transform(expr->queryChild(0));
  5782. HqlConstantPercolator * mapping = gatherConstants(transformedDs);
  5783. if (mapping)
  5784. {
  5785. IHqlExpression * resolved = mapping->resolveField(field);
  5786. if (resolved)
  5787. updated.set(resolved);
  5788. }
  5789. }
  5790. break;
  5791. }
  5792. break;
  5793. default:
  5794. {
  5795. childDatasetType type = getChildDatasetType(expr);
  5796. switch (type)
  5797. {
  5798. case childdataset_none:
  5799. case childdataset_nway_left_right:
  5800. case childdataset_many_noscope:
  5801. case childdataset_many:
  5802. case childdataset_if:
  5803. case childdataset_case:
  5804. case childdataset_map:
  5805. case childdataset_evaluate:
  5806. break;
  5807. case childdataset_dataset_noscope:
  5808. case childdataset_dataset:
  5809. updated.setown(percolateConstants(updated, child, no_none));
  5810. break;
  5811. case childdataset_datasetleft:
  5812. updated.setown(percolateConstants(updated, child, no_none));
  5813. updated.setown(percolateConstants(updated, child, no_left));
  5814. break;
  5815. case childdataset_left:
  5816. updated.setown(percolateConstants(updated, child, no_left));
  5817. break;
  5818. case childdataset_same_left_right:
  5819. updated.setown(percolateConstants(updated, child, no_left));
  5820. updated.setown(percolateConstants(updated, child, no_right));
  5821. break;
  5822. case childdataset_top_left_right:
  5823. updated.setown(percolateConstants(updated, child, no_none));
  5824. updated.setown(percolateConstants(updated, child, no_left));
  5825. updated.setown(percolateConstants(updated, child, no_right));
  5826. break;
  5827. case childdataset_leftright:
  5828. updated.setown(percolateConstants(updated, child, no_left));
  5829. updated.setown(percolateConstants(updated, expr->queryChild(1), no_right));
  5830. break;
  5831. default:
  5832. UNIMPLEMENTED;
  5833. }
  5834. break;
  5835. }
  5836. }
  5837. return updated.getClear();
  5838. }
  5839. IHqlExpression * CExprFolderTransformer::createTransformed(IHqlExpression * expr)
  5840. {
  5841. if (foldOptions & HFOloseannotations)
  5842. expr = expr->queryBody();
  5843. //Special cases which don't want children to be transformed first...
  5844. OwnedHqlExpr dft;
  5845. node_operator op = expr->getOperator();
  5846. switch (op)
  5847. {
  5848. case no_alias:
  5849. {
  5850. OwnedHqlExpr folded = transform(expr->queryChild(0));
  5851. if (folded->getOperator() == no_alias || folded->queryValue())
  5852. return folded.getClear();
  5853. break;
  5854. }
  5855. case no_or:
  5856. case no_and:
  5857. {
  5858. //Transform all children that do not match the operator - otherwise we get an n^2 (or n^3) algorithm
  5859. HqlExprArray args, transformedArgs;
  5860. expr->unwindList(args, op);
  5861. bool same = true;
  5862. ForEachItemIn(i, args)
  5863. {
  5864. IHqlExpression * cur = &args.item(i);
  5865. IHqlExpression * t = transform(cur);
  5866. transformedArgs.append(*t);
  5867. if (t != cur)
  5868. same = false;
  5869. //Sort circuit always-true or always-false early to avoid subsequent transforms..
  5870. IValue * value = t->queryValue();
  5871. if (value)
  5872. {
  5873. if (value->getBoolValue())
  5874. {
  5875. if (op == no_or)
  5876. return LINK(t);
  5877. }
  5878. else
  5879. {
  5880. if (op == no_and)
  5881. return LINK(t);
  5882. }
  5883. }
  5884. }
  5885. if (same)
  5886. dft.set(expr);
  5887. else
  5888. {
  5889. //Need to preserve the no_and/no_or structure so that cse/alias opportunities aren't lost.
  5890. //e.g. x := a and b; if (d and x and c, f(x), ...)
  5891. dft.setown(createListMatchStructure(op, expr, transformedArgs));
  5892. }
  5893. break;
  5894. }
  5895. case no_if:
  5896. {
  5897. //transform this early - to short circuit lots of other work...
  5898. OwnedHqlExpr child = transform(expr->queryChild(0));
  5899. IValue * constValue = child->queryValue();
  5900. if (constValue)
  5901. {
  5902. unsigned idx = constValue->getBoolValue() ? 1 : 2;
  5903. IHqlExpression * branch = expr->queryChild(idx);
  5904. OwnedHqlExpr ret;
  5905. if (!branch)
  5906. {
  5907. assertex(expr->isAction());
  5908. ret.setown(createValue(no_null, makeVoidType()));
  5909. }
  5910. else
  5911. ret.setown(transform(branch));
  5912. if (hasNamedSymbol(ret))
  5913. return ret.getClear();
  5914. return expr->cloneAllAnnotations(ret);
  5915. }
  5916. break;
  5917. }
  5918. case no_case:
  5919. {
  5920. OwnedHqlExpr leftExpr = transform(expr->queryChild(0));
  5921. IValue * leftValue = leftExpr->queryValue();
  5922. if (leftValue)
  5923. {
  5924. unsigned numCases = expr->numChildren()-2;
  5925. IHqlExpression * result = expr->queryChild(numCases+1);
  5926. for (unsigned idx = 1; idx <= numCases; idx++)
  5927. {
  5928. IHqlExpression * map = expr->queryChild(idx);
  5929. OwnedHqlExpr grand = transform(map->queryChild(0));
  5930. IValue * grandValue = grand->queryValue();
  5931. if (grandValue)
  5932. {
  5933. if (orderValues(leftValue, grandValue) == 0)
  5934. {
  5935. result = map->queryChild(1);
  5936. break;
  5937. }
  5938. }
  5939. else
  5940. {
  5941. result = NULL;
  5942. break;
  5943. }
  5944. }
  5945. if (result)
  5946. return cloneAnnotationAndTransform(expr, result);
  5947. }
  5948. break;
  5949. }
  5950. case no_map:
  5951. {
  5952. unsigned num = expr->numChildren()-1;
  5953. IHqlExpression * result = expr->queryChild(num);
  5954. for (unsigned idx = 0; idx < num; idx++)
  5955. {
  5956. IHqlExpression * map = expr->queryChild(idx);
  5957. OwnedHqlExpr cond = transform(map->queryChild(0));
  5958. IValue * value = cond->queryValue();
  5959. if (value)
  5960. {
  5961. if (value->getBoolValue())
  5962. {
  5963. result = map->queryChild(1);
  5964. break;
  5965. }
  5966. }
  5967. else
  5968. {
  5969. result = NULL;
  5970. break;
  5971. }
  5972. }
  5973. if (result)
  5974. return cloneAnnotationAndTransform(expr, result);
  5975. break;
  5976. }
  5977. case no_call:
  5978. {
  5979. //Ensure the bodies of out of line function calls are also folded.
  5980. IHqlExpression * funcDef = expr->queryDefinition();
  5981. Owned<IHqlExpression> newFuncDef = transform(funcDef);
  5982. if (funcDef != newFuncDef)
  5983. {
  5984. HqlExprArray children;
  5985. transformChildren(expr, children);
  5986. dft.setown(createReboundFunction(newFuncDef, children));
  5987. }
  5988. break;
  5989. }
  5990. }
  5991. if (!dft)
  5992. dft.setown(PARENT::createTransformed(expr));
  5993. //If the parent has changed to no_null, then the active selector may have changed out of step with the parent dataset
  5994. //so need to explcitly remap the dataset
  5995. updateOrphanedSelectors(dft, expr);
  5996. OwnedHqlExpr updated = (foldOptions & HFOpercolateconstants) ? percolateConstants(dft) : LINK(dft);
  5997. OwnedHqlExpr transformed = doFoldTransformed(updated, expr);
  5998. #ifdef LOG_ALL_FOLDING
  5999. if ((op != transformed->getOperator()) || (expr->numChildren() != transformed->numChildren()))
  6000. DBGLOG("Folding %s to %s", getOpString(updated->getOperator()), getOpString(transformed->getOperator()));
  6001. #endif
  6002. #ifdef _DEBUG
  6003. if (expr->isConstant() && !transformed->queryValue())
  6004. {
  6005. ITypeInfo * type = expr->queryType();
  6006. if (type && type->isScalar())
  6007. {
  6008. switch (op)
  6009. {
  6010. case no_none:
  6011. case no_mapto:
  6012. case no_negate:
  6013. case no_comma:
  6014. case no_assign:
  6015. case no_assignall:
  6016. case no_transform:
  6017. case no_newtransform:
  6018. break;
  6019. /*
  6020. case no_count:
  6021. case no_max:
  6022. case no_min:
  6023. case no_sum:
  6024. case no_exists:
  6025. case no_ave:
  6026. //Could implement this on a temp table, or at least count...
  6027. //not sufficient to just fix these, because functions of these also fail.
  6028. break;
  6029. */
  6030. #if 0
  6031. default:
  6032. {
  6033. DBGLOG("Error - expression is marked as constant but did not fold");
  6034. OwnedHqlExpr again = doFoldTransformed(dft, expr);
  6035. StringBuffer s;
  6036. expr->toString(s);
  6037. DBGLOG("%s", s.str());
  6038. throw MakeStringException(0, "Internal error - expression is marked as constant but did not fold");
  6039. }
  6040. #endif
  6041. }
  6042. }
  6043. }
  6044. #endif
  6045. //No folding operation=>return
  6046. if (transformed == dft)
  6047. return transformed.getClear();
  6048. //Just lost named symbol for some reason
  6049. if (transformed->queryBody() == dft->queryBody())
  6050. return LINK(dft);
  6051. //Folded to a constant, or stripped parent node=>return
  6052. if ((transformed->getOperator() == no_constant) || (transformed == dft->queryChild(0)))
  6053. return transformed.getClear();
  6054. return cloneAnnotationAndTransform(expr, transformed);
  6055. }
  6056. //Could handle NOT and OR, but generally makes it worse (it just messes up code generated for a few transforms)
  6057. //Could also handle skip attributes on transforms.
  6058. static void gatherConstantFilterMappings(HqlConstantPercolator & mappings, IHqlExpression * selector, IHqlExpression * expr)
  6059. {
  6060. switch (expr->getOperator())
  6061. {
  6062. case no_and:
  6063. gatherConstantFilterMappings(mappings, selector, expr->queryChild(0));
  6064. gatherConstantFilterMappings(mappings, selector, expr->queryChild(1));
  6065. break;
  6066. case no_eq:
  6067. {
  6068. IHqlExpression * lhs = expr->queryChild(0);
  6069. //MORE: Should also handle subselects now that the constant percolator does
  6070. if ((lhs->getOperator() != no_select) || isNewSelector(lhs) || lhs->queryChild(0) != selector)
  6071. break;
  6072. IHqlExpression * rhs = expr->queryChild(1);
  6073. if (!rhs->isConstant())
  6074. break;
  6075. OwnedHqlExpr newSelect = createSelectExpr(LINK(mappings.querySelf()), LINK(lhs->queryChild(1)));
  6076. mappings.addEquality(newSelect, rhs);
  6077. break;
  6078. }
  6079. case no_assertkeyed:
  6080. gatherConstantFilterMappings(mappings, selector, expr->queryChild(0));
  6081. break;
  6082. }
  6083. }
  6084. static void gatherConstantFilterMappings(HqlConstantPercolator & mappings, IHqlExpression * expr)
  6085. {
  6086. IHqlExpression * selector = expr->queryChild(0)->queryNormalizedSelector();
  6087. ForEachChildFrom(i, expr, 1)
  6088. {
  6089. IHqlExpression * cur = expr->queryChild(i);
  6090. if (!cur->isAttribute())
  6091. gatherConstantFilterMappings(mappings, selector, cur);
  6092. }
  6093. }
  6094. HqlConstantPercolator * CExprFolderTransformer::gatherConstants(IHqlExpression * expr)
  6095. {
  6096. FolderTransformInfo * extra = queryBodyExtra(expr);
  6097. if (extra->queryGatheredConstants())
  6098. return extra->mapping;
  6099. //gather constants for this particular activity.....
  6100. Owned<HqlConstantPercolator> exprMapping;
  6101. switch (expr->getOperator())
  6102. {
  6103. //The following can tell nothing about the values they contain
  6104. case no_table:
  6105. case no_anon:
  6106. case no_pseudods:
  6107. case no_fail:
  6108. case no_skip:
  6109. case no_all:
  6110. case no_activetable:
  6111. case no_workunit_dataset:
  6112. case no_getgraphresult:
  6113. case no_getgraphloopresult:
  6114. case no_getresult:
  6115. case no_rows:
  6116. case no_internalselect:
  6117. case no_delayedselect:
  6118. case no_unboundselect:
  6119. case no_libraryselect:
  6120. case no_purevirtual:
  6121. case no_libraryinput:
  6122. case no_translated:
  6123. case no_id2blob:
  6124. case no_embedbody:
  6125. case no_pipe:
  6126. case no_keyindex:
  6127. case no_newkeyindex:
  6128. case no_colon:
  6129. case no_keyed:
  6130. case no_nofold: // stop folding...
  6131. case no_nohoist:
  6132. case no_activerow:
  6133. case no_newrow:
  6134. case no_loop:
  6135. case no_graphloop:
  6136. case no_rowsetindex:
  6137. case no_rowsetrange:
  6138. case no_mergejoin:
  6139. case no_nwaymerge:
  6140. case no_temptable:
  6141. case no_left:
  6142. case no_right:
  6143. case no_top:
  6144. case no_externalcall:
  6145. case no_call:
  6146. case no_matchattr:
  6147. case no_param:
  6148. case no_deserialize:
  6149. case no_serialize:
  6150. case no_typetransfer:
  6151. case no_fromxml:
  6152. case no_fromjson:
  6153. case no_httpcall:
  6154. break;
  6155. case no_null:
  6156. //if (expr->isDatarow())
  6157. // exprMapping.setown(HqlConstantPercolator::extractNullMapping(expr->queryRecord()));
  6158. break;
  6159. case no_rollup:
  6160. {
  6161. // transform may or may not be called, so can't just extract constants from the transform.
  6162. // can only mark as constant if the inputDataset and the transform both assign them the same constant value
  6163. IHqlExpression * dataset = expr->queryChild(0);
  6164. IHqlExpression * transformExpr = queryNewColumnProvider(expr);
  6165. OwnedHqlExpr invarientTransformExpr = percolateRollupInvariantConstants(transformExpr, dataset, no_left, querySelSeq(expr));
  6166. exprMapping.setown(HqlConstantPercolator::extractConstantMapping(invarientTransformExpr));
  6167. if (exprMapping)
  6168. {
  6169. HqlConstantPercolator * inputMapping = gatherConstants(dataset);
  6170. if (inputMapping)
  6171. exprMapping->intersectMapping(inputMapping);
  6172. else
  6173. exprMapping.clear();
  6174. }
  6175. break;
  6176. }
  6177. //The following get the values purely from the associated transform - if it contains constant entires
  6178. case no_xmlproject:
  6179. case no_combine:
  6180. case no_combinegroup:
  6181. case no_process:
  6182. case no_denormalizegroup:
  6183. case no_fetch:
  6184. case no_join:
  6185. case no_selfjoin:
  6186. case no_joincount:
  6187. case no_iterate:
  6188. case no_transformebcdic:
  6189. case no_transformascii:
  6190. case no_hqlproject:
  6191. case no_normalize:
  6192. case no_newparse:
  6193. case no_newxmlparse:
  6194. case no_rollupgroup:
  6195. case no_soapcall:
  6196. case no_newsoapcall:
  6197. case no_soapcall_ds:
  6198. case no_newsoapcall_ds:
  6199. case no_parse:
  6200. case no_xmlparse:
  6201. case no_selectfields:
  6202. case no_newaggregate:
  6203. case no_newusertable:
  6204. case no_usertable:
  6205. case no_nwayjoin:
  6206. case no_projectrow:
  6207. case no_createrow:
  6208. case no_dataset_from_transform:
  6209. case no_quantile:
  6210. {
  6211. IHqlExpression * transform = queryNewColumnProvider(expr);
  6212. exprMapping.setown(HqlConstantPercolator::extractConstantMapping(transform));
  6213. break;
  6214. }
  6215. case no_aggregate:
  6216. {
  6217. if (expr->hasAttribute(mergeTransformAtom))
  6218. break;
  6219. IHqlExpression * transform = queryNewColumnProvider(expr);
  6220. exprMapping.setown(HqlConstantPercolator::extractConstantMapping(transform));
  6221. break;
  6222. }
  6223. case no_newtransform:
  6224. case no_transform:
  6225. exprMapping.setown(HqlConstantPercolator::extractConstantMapping(expr));
  6226. break;
  6227. //The following inherit the constant of the parent without modification
  6228. case no_dedup:
  6229. case no_group:
  6230. case no_grouped:
  6231. case no_assertgrouped:
  6232. case no_distribute:
  6233. case no_distributed:
  6234. case no_unordered:
  6235. case no_preservemeta:
  6236. case no_assertdistributed:
  6237. case no_keyeddistribute:
  6238. case no_cosort:
  6239. case no_sort:
  6240. case no_subsort:
  6241. case no_sorted:
  6242. case no_assertsorted:
  6243. case no_topn:
  6244. case no_choosen:
  6245. case no_choosesets:
  6246. case no_enth:
  6247. case no_sample:
  6248. case no_alias_project:
  6249. case no_alias_scope:
  6250. case no_cachealias:
  6251. case no_cloned:
  6252. case no_globalscope:
  6253. case no_sub:
  6254. case no_thor:
  6255. case no_nothor:
  6256. case no_compound_indexread:
  6257. case no_compound_diskread:
  6258. case no_compound_disknormalize:
  6259. case no_compound_diskaggregate:
  6260. case no_compound_diskcount:
  6261. case no_compound_diskgroupaggregate:
  6262. case no_compound_indexnormalize:
  6263. case no_compound_indexaggregate:
  6264. case no_compound_indexcount:
  6265. case no_compound_indexgroupaggregate:
  6266. case no_compound_childread:
  6267. case no_compound_childnormalize:
  6268. case no_compound_childaggregate:
  6269. case no_compound_childcount:
  6270. case no_compound_childgroupaggregate:
  6271. case no_compound_selectnew:
  6272. case no_compound_inline:
  6273. case no_metaactivity:
  6274. case no_split:
  6275. case no_spill:
  6276. case no_readspill:
  6277. case no_writespill:
  6278. case no_commonspill:
  6279. case no_throughaggregate:
  6280. case no_limit:
  6281. case no_keyedlimit:
  6282. case no_compound_fetch:
  6283. case no_preload:
  6284. case no_alias:
  6285. case no_assert_ds:
  6286. case no_spillgraphresult:
  6287. case no_forcenolocal:
  6288. case no_allnodes:
  6289. case no_thisnode:
  6290. case no_forcelocal:
  6291. case no_stepped:
  6292. case no_cluster:
  6293. case no_datasetfromrow:
  6294. case no_datasetfromdictionary:
  6295. case no_filtergroup:
  6296. case no_section:
  6297. case no_sectioninput:
  6298. case no_forcegraph:
  6299. case no_related:
  6300. case no_executewhen:
  6301. case no_callsideeffect:
  6302. case no_outofline:
  6303. case no_owned_ds:
  6304. case no_dataset_alias:
  6305. case no_createdictionary:
  6306. case no_nocombine:
  6307. case no_likely:
  6308. case no_unlikely:
  6309. exprMapping.set(gatherConstants(expr->queryChild(0)));
  6310. break;
  6311. case no_normalizegroup:
  6312. exprMapping.set(gatherConstants(expr->queryChild(1)));
  6313. break;
  6314. case no_catchds:
  6315. case no_catch:
  6316. //all bets are off.
  6317. break;
  6318. case no_denormalize:
  6319. {
  6320. HqlConstantPercolator * leftMapping = gatherConstants(expr->queryChild(0));
  6321. IHqlExpression * transform = queryNewColumnProvider(expr);
  6322. exprMapping.setown(HqlConstantPercolator::extractConstantMapping(transform));
  6323. if (exprMapping)
  6324. {
  6325. if (leftMapping)
  6326. {
  6327. exprMapping->intersectMapping(leftMapping);
  6328. if (exprMapping->empty())
  6329. exprMapping.clear();
  6330. }
  6331. else
  6332. exprMapping.clear();
  6333. }
  6334. break;
  6335. }
  6336. case no_selectnth:
  6337. {
  6338. //Careful - this can create a null row if it is out of range.
  6339. bool inherit = false;
  6340. if (expr->hasAttribute(noBoundCheckAtom))
  6341. inherit = true;
  6342. else if (matchesConstantValue(expr->queryChild(1), 1) && hasSingleRow(expr->queryChild(0)))
  6343. inherit = true;
  6344. if (inherit)
  6345. exprMapping.set(gatherConstants(expr->queryChild(0)));
  6346. break;
  6347. }
  6348. //The following inherit the constant of second argument
  6349. case no_comma:
  6350. case no_compound:
  6351. case no_mapto:
  6352. exprMapping.set(gatherConstants(expr->queryChild(1)));
  6353. break;
  6354. //Intersections of the inputs...
  6355. case no_if:
  6356. {
  6357. IHqlExpression * rhs = expr->queryChild(2);
  6358. if (!rhs)
  6359. break;
  6360. //fall through
  6361. }
  6362. case no_addfiles:
  6363. case no_regroup:
  6364. case no_nonempty:
  6365. case no_case:
  6366. case no_map:
  6367. case no_merge:
  6368. case no_cogroup:
  6369. case no_chooseds:
  6370. {
  6371. unsigned from = getFirstActivityArgument(expr);
  6372. unsigned max = from + getNumActivityArguments(expr);
  6373. bool allMapped = true;
  6374. for (unsigned i=0; i < max; i++)
  6375. {
  6376. IHqlExpression * cur = expr->queryChild(i);
  6377. if (cur->isDataset() && !gatherConstants(cur))
  6378. {
  6379. allMapped = false;
  6380. break;
  6381. }
  6382. }
  6383. if (allMapped)
  6384. {
  6385. for (unsigned i=0; i < max; i++)
  6386. {
  6387. IHqlExpression * cur = expr->queryChild(i);
  6388. if (cur->isDataset())
  6389. {
  6390. HqlConstantPercolator * curMapping = gatherConstants(cur);
  6391. if (!exprMapping)
  6392. {
  6393. exprMapping.setown(new HqlConstantPercolator);
  6394. exprMapping->inheritMapping(curMapping);
  6395. }
  6396. else
  6397. {
  6398. exprMapping->intersectMapping(curMapping);
  6399. if (exprMapping->empty())
  6400. break;
  6401. }
  6402. }
  6403. }
  6404. }
  6405. break;
  6406. }
  6407. //Now follow the special cases/
  6408. case no_inlinetable:
  6409. {
  6410. IHqlExpression * transforms = expr->queryChild(0);
  6411. unsigned numRows = transforms->numChildren();
  6412. //MORE: Could theoretically create an intersection of the values, but not likely to be worth the processing time.
  6413. if (numRows == 1)
  6414. exprMapping.setown(HqlConstantPercolator::extractConstantMapping(transforms->queryChild(0)));
  6415. break;
  6416. }
  6417. case no_filter:
  6418. if (foldOptions & HFOpercolatefilters)
  6419. {
  6420. HqlConstantPercolator filterMappings(expr);
  6421. gatherConstantFilterMappings(filterMappings, expr);
  6422. HqlConstantPercolator * inheritedMappings = gatherConstants(expr->queryChild(0));
  6423. if (!filterMappings.empty())
  6424. {
  6425. exprMapping.setown(new HqlConstantPercolator);
  6426. if (inheritedMappings)
  6427. exprMapping->inheritMapping(inheritedMappings);
  6428. exprMapping->inheritMapping(&filterMappings);
  6429. }
  6430. else
  6431. exprMapping.set(inheritedMappings);
  6432. break;
  6433. }
  6434. else
  6435. exprMapping.set(gatherConstants(expr->queryChild(0)));
  6436. break;
  6437. case no_selectmap:
  6438. case no_select:
  6439. case no_record:
  6440. break;
  6441. default:
  6442. if (expr->isAction())
  6443. break;
  6444. DBGLOG("Missing entry: %s", getOpString(expr->getOperator()));
  6445. if (expr->isDatarow())
  6446. {
  6447. DBGLOG("Missing entry: %s", getOpString(expr->getOperator()));
  6448. break;
  6449. }
  6450. throwUnexpectedOp(expr->getOperator());
  6451. }
  6452. if (exprMapping)
  6453. {
  6454. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  6455. if (onFail)
  6456. {
  6457. HqlConstantPercolator * onFailMapping = gatherConstants(onFail->queryChild(0));
  6458. if (onFailMapping)
  6459. exprMapping->intersectMapping(onFailMapping);
  6460. else
  6461. exprMapping.clear();
  6462. }
  6463. if (exprMapping && !exprMapping->empty())
  6464. extra->mapping = exprMapping.getClear();
  6465. }
  6466. extra->setGatheredConstants(true);
  6467. return extra->mapping;
  6468. }
  6469. IHqlExpression * CExprFolderTransformer::percolateConstants(HqlConstantPercolator * mapping, IHqlExpression * expr, IHqlExpression * dataset, node_operator side)
  6470. {
  6471. OwnedHqlExpr selector = (side == no_none) ? LINK(dataset->queryNormalizedSelector()) : createSelector(side, dataset, querySelSeq(expr));
  6472. return mapping->expandFields(expr, selector);
  6473. }
  6474. IHqlExpression * CExprFolderTransformer::percolateConstants(IHqlExpression * expr, IHqlExpression * dataset, node_operator side)
  6475. {
  6476. OwnedHqlExpr transformedDs = transform(dataset);
  6477. HqlConstantPercolator * mapping = gatherConstants(transformedDs);
  6478. if (!mapping)
  6479. return LINK(expr);
  6480. unsigned from = getNumChildTables(expr);
  6481. unsigned max = expr->numChildren();
  6482. if (from >= max)
  6483. return LINK(expr);
  6484. HqlExprArray temp, args;
  6485. unwindChildren(temp, expr, from);
  6486. for (unsigned i=0; i < from; i++)
  6487. args.append(*LINK(expr->queryChild(i)));
  6488. OwnedHqlExpr selector = (side == no_none) ? LINK(dataset->queryNormalizedSelector()) : createSelector(side, dataset, querySelSeq(expr));
  6489. if (mapping->expandFields(args, temp, selector))
  6490. return expr->clone(args);
  6491. return LINK(expr);
  6492. }
  6493. IHqlExpression * CExprFolderTransformer::percolateRollupInvariantConstants(IHqlExpression * expr, HqlConstantPercolator * mapping, IHqlExpression * selector)
  6494. {
  6495. switch (expr->getOperator())
  6496. {
  6497. case no_newtransform:
  6498. case no_transform:
  6499. case no_assignall:
  6500. {
  6501. HqlExprArray children;
  6502. ForEachChild(i, expr)
  6503. children.append(*percolateRollupInvariantConstants(expr->queryChild(i), mapping, selector));
  6504. return cloneOrLink(expr, children);
  6505. }
  6506. break;
  6507. case no_assign:
  6508. {
  6509. //If the assignment is self.x := left.x, then it is ok to percolate the constant in from input dataset.
  6510. IHqlExpression * rhs = expr->queryChild(1);
  6511. if (rhs->getOperator() == no_select)
  6512. {
  6513. if (rhs->queryChild(0) == selector)
  6514. {
  6515. IHqlExpression * lhs = expr->queryChild(0);
  6516. IHqlExpression * field = lhs->queryChild(1);
  6517. if (field == rhs->queryChild(1))
  6518. {
  6519. OwnedHqlExpr mapped = mapping->expandField(field);
  6520. if (mapped)
  6521. return createAssign(LINK(lhs), mapped.getClear());
  6522. }
  6523. }
  6524. }
  6525. break;
  6526. }
  6527. }
  6528. return LINK(expr);
  6529. }
  6530. IHqlExpression * CExprFolderTransformer::percolateRollupInvariantConstants(IHqlExpression * expr, IHqlExpression * dataset, node_operator side, IHqlExpression * selSeq)
  6531. {
  6532. HqlConstantPercolator * mapping = gatherConstants(dataset);
  6533. if (!mapping)
  6534. return LINK(expr);
  6535. OwnedHqlExpr selector = (side == no_none) ? LINK(dataset->queryNormalizedSelector()) : createSelector(side, dataset, selSeq);
  6536. return percolateRollupInvariantConstants(expr, mapping, selector);
  6537. }
  6538. //Expand a single child (used for joins)
  6539. IHqlExpression * CExprFolderTransformer::percolateConstants(IHqlExpression * expr, IHqlExpression * dataset, node_operator side, unsigned whichChild)
  6540. {
  6541. OwnedHqlExpr transformedDs = transform(dataset);
  6542. HqlConstantPercolator * mapping = gatherConstants(transformedDs);
  6543. if (!mapping)
  6544. return LINK(expr);
  6545. OwnedHqlExpr selector = (side == no_none) ? LINK(dataset->queryNormalizedSelector()) : createSelector(side, dataset, querySelSeq(expr));
  6546. HqlExprArray args;
  6547. unwindChildren(args, expr);
  6548. args.replace(*mapping->expandFields(&args.item(whichChild), selector), whichChild);
  6549. return expr->clone(args);
  6550. }
  6551. IHqlExpression * CExprFolderTransformer::removeParentNode(IHqlExpression * expr)
  6552. {
  6553. IHqlExpression * child = expr->queryChild(0);
  6554. DBGLOG("Folder: Node %s remove self (now %s)", queryNode0Text(expr), queryNode1Text(child));
  6555. return LINK(child);
  6556. }
  6557. IHqlExpression * CExprFolderTransformer::replaceWithNull(IHqlExpression * expr)
  6558. {
  6559. IHqlExpression * ret = createNullExpr(expr);
  6560. DBGLOG("Folder: Replace %s with %s", queryNode0Text(expr), queryNode1Text(ret));
  6561. return ret;
  6562. }
  6563. IHqlExpression * CExprFolderTransformer::replaceWithNullRow(IHqlExpression * expr)
  6564. {
  6565. IHqlExpression * ret = createRow(no_null, LINK(expr->queryRecord()));
  6566. DBGLOG("Folder: Replace %s with %s", queryNode0Text(expr), queryNode1Text(ret));
  6567. return ret;
  6568. }
  6569. IHqlExpression * CExprFolderTransformer::replaceWithNullRowDs(IHqlExpression * expr)
  6570. {
  6571. assertex(!isGrouped(expr));
  6572. return createDatasetFromRow(createRow(no_null, LINK(expr->queryRecord())));
  6573. }
  6574. IHqlExpression * CExprFolderTransformer::transformExpanded(IHqlExpression * expr)
  6575. {
  6576. return transform(expr);
  6577. }
  6578. //---------------------------------------------------------------------------
  6579. IHqlExpression * foldHqlExpression(IHqlExpression * expr)
  6580. {
  6581. NullErrorReceiver errorProcessor;
  6582. return foldHqlExpression(errorProcessor, expr);
  6583. }
  6584. IHqlExpression * foldHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * expr, ITemplateContext *templateContext, unsigned foldOptions)
  6585. {
  6586. if (!expr)
  6587. return NULL;
  6588. if (foldOptions & HFOloseannotations)
  6589. expr = expr->queryBody();
  6590. switch (expr->getOperator())
  6591. {
  6592. case no_constant:
  6593. case no_param:
  6594. case no_variable:
  6595. case no_attr:
  6596. return LINK(expr);
  6597. case no_select:
  6598. if (!isNewSelector(expr))
  6599. return LINK(expr);
  6600. break;
  6601. }
  6602. CExprFolderTransformer folder(errorProcessor, templateContext, foldOptions);
  6603. #if 0
  6604. dbglogExpr(expr);
  6605. #endif
  6606. IHqlExpression * ret = folder.transformRoot(expr);
  6607. #if 0
  6608. dbglogExpr(ret);
  6609. #endif
  6610. return ret;
  6611. }
  6612. IHqlExpression * foldScopedHqlExpression(IErrorReceiver & errorProcessor, IHqlExpression * dataset, IHqlExpression * expr, unsigned foldOptions)
  6613. {
  6614. if (!expr)
  6615. return NULL;
  6616. CExprFolderTransformer folder(errorProcessor, NULL, foldOptions);
  6617. if (dataset)
  6618. folder.setScope(dataset);
  6619. IHqlExpression * ret = folder.transformRoot(expr);
  6620. return ret;
  6621. }
  6622. void foldHqlExpression(IErrorReceiver & errorProcessor, HqlExprArray & tgt, HqlExprArray & src, unsigned foldOptions)
  6623. {
  6624. CExprFolderTransformer folder(errorProcessor, NULL, foldOptions);
  6625. folder.transformRoot(src, tgt);
  6626. }
  6627. //Fold it to a constant if it is easy to otherwise return anything.
  6628. IHqlExpression * foldExprIfConstant(IHqlExpression * expr)
  6629. {
  6630. if (expr->isConstant())
  6631. return quickFoldExpression(expr);
  6632. node_operator op = expr->getOperator();
  6633. switch (op)
  6634. {
  6635. case no_and:
  6636. // case no_or:
  6637. {
  6638. ForEachChild(i, expr)
  6639. {
  6640. IHqlExpression * cur = expr->queryChild(i);
  6641. OwnedHqlExpr folded = foldExprIfConstant(cur);
  6642. IValue * foldedValue = folded->queryValue();
  6643. if (foldedValue)
  6644. {
  6645. bool ok = foldedValue->getBoolValue();
  6646. if (op == no_and ? !ok : ok)
  6647. return folded.getClear();
  6648. }
  6649. else
  6650. return LINK(expr);
  6651. }
  6652. return createConstant(op == no_and);
  6653. }
  6654. case no_not:
  6655. {
  6656. OwnedHqlExpr folded = foldExprIfConstant(expr->queryChild(0));
  6657. if (folded->queryValue())
  6658. return getInverse(folded);
  6659. break;
  6660. }
  6661. }
  6662. return LINK(expr);
  6663. }
  6664. //---------------------------------------------------------------------------
  6665. static HqlTransformerInfo normalizeFilenameTransformerInfo("NormalizeFilenameTransformer");
  6666. class NormalizeFilenameTransformer : public NewHqlTransformer
  6667. {
  6668. public:
  6669. NormalizeFilenameTransformer() : NewHqlTransformer(normalizeFilenameTransformerInfo) {}
  6670. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  6671. {
  6672. node_operator op = expr->getOperator();
  6673. switch (op)
  6674. {
  6675. case no_constant:
  6676. return getLowerCaseConstant(expr);
  6677. case no_cast:
  6678. case no_implicitcast:
  6679. case no_concat:
  6680. case no_nofold:
  6681. case no_nocombine:
  6682. case no_nohoist:
  6683. case no_alias:
  6684. case no_globalscope:
  6685. case no_map:
  6686. case no_trim:
  6687. return NewHqlTransformer::createTransformed(expr);
  6688. case no_if:
  6689. case no_mapto:
  6690. case no_case:
  6691. break;
  6692. default:
  6693. return LINK(expr);
  6694. }
  6695. HqlExprArray args;
  6696. args.append(*LINK(expr->queryChild(0)));
  6697. return completeTransform(expr, args);
  6698. }
  6699. };
  6700. /*
  6701. * The purpose of this function is to normalize a filename as much as possible, so that differences in case for
  6702. * string constants do not prevent a write to a file, and a subsequent read from the same file to be treated as
  6703. * the same filenames. It doesn't aim to be perfect, but to avoid the most common problems.
  6704. */
  6705. IHqlExpression * normalizeFilenameExpr(IHqlExpression * expr)
  6706. {
  6707. if (expr->getOperator() == no_constant)
  6708. return getLowerCaseConstant(expr);
  6709. NormalizeFilenameTransformer transformer;
  6710. return transformer.transformRoot(expr);
  6711. }
  6712. static HqlTransformerInfo quickConstantTransformerInfo("QuickConstantTransformer");
  6713. class QuickConstantTransformer : public QuickHqlTransformer
  6714. {
  6715. public:
  6716. QuickConstantTransformer(ITemplateContext * _templateContext, unsigned _foldOptions) :
  6717. QuickHqlTransformer(quickConstantTransformerInfo, NULL), templateContext(_templateContext), foldOptions(_foldOptions) {}
  6718. virtual IHqlExpression * createTransformedBody(IHqlExpression * expr)
  6719. {
  6720. node_operator op = expr->getOperator();
  6721. switch (op)
  6722. {
  6723. case no_if:
  6724. {
  6725. OwnedHqlExpr cond = transform(expr->queryChild(0));
  6726. IValue * condValue = cond->queryValue();
  6727. if (condValue)
  6728. {
  6729. unsigned idx = condValue->getBoolValue() ? 1 : 2;
  6730. IHqlExpression * branch = expr->queryChild(idx);
  6731. if (branch)
  6732. return transform(branch);
  6733. assertex(expr->isAction());
  6734. return createValue(no_null, makeVoidType());
  6735. }
  6736. break;
  6737. }
  6738. case no_and:
  6739. {
  6740. OwnedHqlExpr left = transform(expr->queryChild(0));
  6741. IValue * leftValue = left->queryValue();
  6742. if (leftValue)
  6743. {
  6744. if (!leftValue->getBoolValue())
  6745. return LINK(left);
  6746. return transform(expr->queryChild(1));
  6747. }
  6748. break;
  6749. }
  6750. case no_or:
  6751. {
  6752. OwnedHqlExpr left = transform(expr->queryChild(0));
  6753. IValue * leftValue = left->queryValue();
  6754. if (leftValue)
  6755. {
  6756. if (leftValue->getBoolValue())
  6757. return LINK(left);
  6758. return transform(expr->queryChild(1));
  6759. }
  6760. break;
  6761. }
  6762. case no_attr:
  6763. if (expr->queryName() == _original_Atom)
  6764. return LINK(expr);
  6765. break;
  6766. }
  6767. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  6768. return foldConstantOperator(transformed, foldOptions, templateContext);
  6769. }
  6770. protected:
  6771. ITemplateContext *templateContext;
  6772. unsigned foldOptions;
  6773. };
  6774. extern HQLFOLD_API IHqlExpression * quickFoldExpression(IHqlExpression * expr, ITemplateContext *context, unsigned options)
  6775. {
  6776. QuickConstantTransformer transformer(context, options);
  6777. return transformer.transform(expr);
  6778. }
  6779. extern HQLFOLD_API void quickFoldExpressions(HqlExprArray & target, const HqlExprArray & source, ITemplateContext *context, unsigned options)
  6780. {
  6781. QuickConstantTransformer transformer(context, options);
  6782. ForEachItemIn(i, source)
  6783. target.append(*transformer.transform(&source.item(i)));
  6784. }
  6785. //--------------------------------------------------------------------------------------------------------------------
  6786. static bool valueInList(IHqlExpression * search, IHqlExpression * list)
  6787. {
  6788. if (list->getOperator() != no_list)
  6789. return false;
  6790. ForEachChild(i, list)
  6791. {
  6792. if (search == list->queryChild(i))
  6793. return true;
  6794. }
  6795. return false;
  6796. }
  6797. static bool valueNotInList(IHqlExpression * search, IHqlExpression * list)
  6798. {
  6799. if (list->getOperator() != no_list)
  6800. return false;
  6801. IValue * value = search->queryValue();
  6802. if (!value)
  6803. return false; // can't tell
  6804. ForEachChild(i, list)
  6805. {
  6806. IHqlExpression * cur = list->queryChild(i);
  6807. IValue * curValue = cur->queryValue();
  6808. if (!curValue || value == curValue)
  6809. return false;
  6810. }
  6811. return true;
  6812. }
  6813. //Is it guaranteed that both conditions cannot be true at the same time. Avoid false positivies.
  6814. //Don't try and catch all examples, just the most common possibilities.
  6815. //This could be improved over time....
  6816. extern HQLFOLD_API bool areExclusiveConditions(IHqlExpression * left, IHqlExpression * right)
  6817. {
  6818. node_operator leftOp = left->getOperator();
  6819. node_operator rightOp = right->getOperator();
  6820. // Check for x = constant1, x = constant2, constant1 != constant2
  6821. if ((leftOp == no_eq) && (rightOp == no_eq))
  6822. {
  6823. if (left->queryChild(0) == right->queryChild(0))
  6824. {
  6825. //Can only really be sure if comparing against constants.
  6826. IValue * leftValue = left->queryChild(1)->queryValue();
  6827. IValue * rightValue = right->queryChild(1)->queryValue();
  6828. return (leftValue && rightValue && leftValue != rightValue);
  6829. }
  6830. return false;
  6831. }
  6832. // Check for NOT x, x
  6833. if ((leftOp == no_not) && (left->queryChild(0) == right))
  6834. return true;
  6835. // Check for x, NOT x
  6836. if ((rightOp == no_not) && (right->queryChild(0) == left))
  6837. return true;
  6838. // two tests against the same condition (could also pass in here if both NULL..)
  6839. if (left->queryChild(0) == right->queryChild(0))
  6840. {
  6841. // Check for x <op> y, x !<op> y - no need for y to be a constant.
  6842. if (leftOp == getInverseOp(rightOp))
  6843. {
  6844. return left->queryChild(1) == right->queryChild(1);
  6845. }
  6846. // Unusual, but occured in the main example I was trying to improve
  6847. // x = c1, x not in [c1, ....]
  6848. // x = c1, x in [c2, c3, c4, c5]
  6849. if ((leftOp == no_eq) && (rightOp == no_notin))
  6850. return valueInList(left->queryChild(1), right->queryChild(1));
  6851. if ((leftOp == no_eq) && (rightOp == no_in))
  6852. return valueNotInList(left->queryChild(1), right->queryChild(1));
  6853. if ((rightOp == no_eq) && (leftOp == no_notin))
  6854. return valueInList(right->queryChild(1), left->queryChild(1));
  6855. if ((rightOp == no_eq) && (leftOp == no_in))
  6856. return valueNotInList(right->queryChild(1), left->queryChild(1));
  6857. }
  6858. return false;
  6859. }
  6860. bool queryCompareConstantValues(int & result, IHqlExpression * left, IHqlExpression * right)
  6861. {
  6862. IValue * leftValue = left->queryValue();
  6863. IValue * rightValue = right->queryValue();
  6864. if (!leftValue || !rightValue)
  6865. return false;
  6866. ITypeInfo * leftType = left->queryType();
  6867. ITypeInfo * rightType = right->queryType();
  6868. if (leftType != rightType)
  6869. {
  6870. Owned<ITypeInfo> type = ::getPromotedECLCompareType(leftType, rightType);
  6871. OwnedHqlExpr castLeft = ensureExprType(left, type);
  6872. OwnedHqlExpr castRight = ensureExprType(right, type);
  6873. IValue * castLeftValue = castLeft->queryValue();
  6874. IValue * castRightValue = castRight->queryValue();
  6875. if (!castLeftValue || !castRightValue)
  6876. return false;
  6877. result = castLeftValue->compare(castRightValue);
  6878. return true;
  6879. }
  6880. else
  6881. {
  6882. result = leftValue->compare(rightValue);
  6883. return true;
  6884. }
  6885. }
  6886. IHqlExpression * foldConstantCaseExpr(IHqlExpression * expr)
  6887. {
  6888. IHqlExpression * search = expr->queryChild(0);
  6889. if (!search->isConstant())
  6890. return LINK(expr);
  6891. OwnedHqlExpr foldedSearch = foldHqlExpression(search);
  6892. ForEachChildFrom(i, expr, 1)
  6893. {
  6894. IHqlExpression * cur = expr->queryChild(i);
  6895. if (cur->getOperator() == no_mapto)
  6896. {
  6897. IHqlExpression * mapValue = cur->queryChild(0);
  6898. if (!mapValue->isConstant())
  6899. return LINK(expr);
  6900. OwnedHqlExpr foldedValue = foldHqlExpression(mapValue);
  6901. int result;
  6902. if (!queryCompareConstantValues(result, foldedSearch, foldedValue))
  6903. return LINK(expr);
  6904. if (result == 0)
  6905. return LINK(cur->queryChild(1));
  6906. }
  6907. else if (!cur->isAttribute())
  6908. return LINK(cur);
  6909. }
  6910. return LINK(expr);
  6911. }
  6912. IHqlExpression * foldConstantMapExpr(IHqlExpression * expr)
  6913. {
  6914. ForEachChild(i, expr)
  6915. {
  6916. IHqlExpression * cur = expr->queryChild(i);
  6917. if (cur->getOperator() == no_mapto)
  6918. {
  6919. IHqlExpression * mapValue = cur->queryChild(0);
  6920. if (!mapValue->isConstant())
  6921. return LINK(expr);
  6922. OwnedHqlExpr foldedValue = foldHqlExpression(mapValue);
  6923. IValue * value = foldedValue->queryValue();
  6924. if (!value)
  6925. return LINK(expr);
  6926. if (value->getBoolValue())
  6927. return LINK(cur->queryChild(1));
  6928. }
  6929. else if (!cur->isAttribute())
  6930. return LINK(cur);
  6931. }
  6932. return LINK(expr);
  6933. }