hqlfold.cpp 270 KB

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