hqlfold.cpp 225 KB

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