hqlttcpp.cpp 445 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691
  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 "jmisc.hpp"
  16. #include "jstream.ipp"
  17. #include "eclrtl.hpp"
  18. #include "hql.hpp"
  19. #include "hqlttcpp.ipp"
  20. #include "hqlmeta.hpp"
  21. #include "hqlutil.hpp"
  22. #include "hqlcpputil.hpp"
  23. #include "hqlthql.hpp"
  24. #include "hqlhtcpp.ipp"
  25. #include "hqltcppc.ipp"
  26. #include "hqlcatom.hpp"
  27. #include "hqlfold.hpp"
  28. #include "hqlgraph.ipp"
  29. #include "hqllib.ipp"
  30. #include "hqlpmap.hpp"
  31. #include "hqlopt.hpp"
  32. #include "hqlcerrors.hpp"
  33. #include "hqlscope.hpp"
  34. #include "hqlsource.ipp"
  35. #include "hqlvalid.hpp"
  36. #include "hqlerror.hpp"
  37. #include "hqlalias.hpp"
  38. #include "hqlir.hpp"
  39. #define TraceExprPrintLog(x, expr) TOSTRLOG(MCdebugInfo(300), unknownJob, x, (expr)->toString);
  40. //Following are for code that currently cause problems, but are probably a good idea
  41. //#define MAP_PROJECT_TO_USERTABLE
  42. //#define REMOVE_NAMED_SCALARS
  43. //#define OPTIMIZE_IMPLICIT_CAST
  44. #define REMOVE_GLOBAL_ANNOTATION // This should improve cse. It currently does for some, but not others...
  45. #define DEFAULT_FOLD_OPTIONS HFOfoldfilterproject
  46. //#define PICK_ENGINE_EARLY
  47. //===========================================================================
  48. static bool isWorthHoisting(IHqlExpression * expr, bool asSubQuery)
  49. {
  50. bool isFiltered = false;
  51. loop
  52. {
  53. switch (expr->getOperator())
  54. {
  55. case no_newkeyindex:
  56. case no_table:
  57. case no_temptable:
  58. case no_inlinetable:
  59. case no_globalscope:
  60. case no_global:
  61. case no_independent:
  62. case no_field:
  63. case no_datasetfromrow:
  64. case no_datasetfromdictionary:
  65. case no_null:
  66. case no_workunit_dataset:
  67. case no_colon:
  68. //compound activities not in list because not created at this point.
  69. return (isFiltered && asSubQuery);
  70. case no_select:
  71. return !isTargetSelector(expr);
  72. case no_filter:
  73. expr = expr->queryChild(0);
  74. isFiltered = true;
  75. break;
  76. case no_compound_diskread:
  77. case no_compound_indexread:
  78. case no_hqlproject:
  79. case no_newusertable:
  80. case no_limit:
  81. case no_catchds:
  82. case no_keyedlimit:
  83. case no_sorted:
  84. case no_grouped:
  85. case no_stepped:
  86. case no_distributed:
  87. case no_preservemeta:
  88. case no_nofold:
  89. case no_nohoist:
  90. case no_section:
  91. case no_sectioninput:
  92. case no_dataset_alias:
  93. case no_forcegraph:
  94. expr = expr->queryChild(0);
  95. break;
  96. case no_fail:
  97. return false;
  98. default:
  99. return true;
  100. }
  101. }
  102. }
  103. IHqlExpression * getDebugValueExpr(IConstWorkUnit * wu, IHqlExpression * expr)
  104. {
  105. StringBuffer name;
  106. getStringValue(name, expr->queryChild(0));
  107. SCMStringBuffer value;
  108. wu->getDebugValue(name, value);
  109. ITypeInfo * exprType = expr->queryType();
  110. if (exprType->getTypeCode() == type_boolean)
  111. return createConstant(clipStrToBool(value.length(), value.str()));
  112. return createConstant(exprType->castFrom(value.length(), value.str()));
  113. }
  114. //===========================================================================
  115. struct GlobalAttributeInfo
  116. {
  117. public:
  118. GlobalAttributeInfo(const char * _filePrefix, const char * _storedPrefix, IHqlExpression * _value) : value(_value)
  119. { setOp = no_none; persistOp = no_none; few = false; filePrefix = _filePrefix; storedPrefix = _storedPrefix; }
  120. void extractGlobal(IHqlExpression * global, ClusterType platform);
  121. void extractStoredInfo(IHqlExpression * expr, IHqlExpression * originalValue, bool isRoxie);
  122. void checkFew(HqlCppTranslator & translator);
  123. void splitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie);
  124. IHqlExpression * getStoredKey();
  125. void preventDiskSpill() { few = true; }
  126. IHqlExpression * queryCluster() const { return cluster; }
  127. protected:
  128. void doSplitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie);
  129. IHqlExpression * createSetValue(IHqlExpression * value, IHqlExpression * aliasName);
  130. void createSmallOutput(IHqlExpression * value, SharedHqlExpr & setOutput);
  131. IHqlExpression * queryAlias(IHqlExpression * value);
  132. IHqlExpression * queryFilename(IHqlExpression * value, IConstWorkUnit * wu, bool isRoxie);
  133. void splitSmallDataset(IHqlExpression * value, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput);
  134. void setCluster(IHqlExpression * expr);
  135. public:
  136. LinkedHqlExpr value;
  137. OwnedHqlExpr storedName;
  138. OwnedHqlExpr sequence;
  139. node_operator setOp;
  140. node_operator persistOp;
  141. protected:
  142. OwnedHqlExpr aliasName;
  143. OwnedHqlExpr cachedFilename;
  144. OwnedHqlExpr cluster;
  145. OwnedHqlExpr extraSetAttr;
  146. OwnedHqlExpr extraOutputAttr;
  147. const char * filePrefix;
  148. const char * storedPrefix;
  149. bool few;
  150. };
  151. static bool isTrivialInlineOutput(IHqlExpression * expr)
  152. {
  153. if (queryRealChild(expr, 1))
  154. return false;
  155. IHqlExpression * ds = expr->queryChild(0);
  156. if ((ds->getOperator() != no_null) || !ds->isDataset())
  157. return false;
  158. IHqlExpression * seq = querySequence(expr);
  159. if (getIntValue(seq, -1) >= 0)
  160. return false;
  161. return true;
  162. }
  163. //---------------------------------------------------------------------------
  164. IHqlExpression * createNextStringValue(IHqlExpression * value, const char * prefix = NULL)
  165. {
  166. StringBuffer valueText;
  167. valueText.append(prefix ? prefix : "a");
  168. getUniqueId(valueText);
  169. #if 0
  170. if (value)
  171. {
  172. const char * nameText = value->queryName()->str();
  173. if (nameText)
  174. valueText.append("__").appendLower(strlen(nameText), nameText);
  175. //otherwise append the operator?
  176. }
  177. #endif
  178. #if 0
  179. #ifdef _DEBUG
  180. //Following lines are here to add a break point when debugging
  181. if (stricmp(valueText.str(), "aQ") == 0)
  182. valueText.length();
  183. if (stricmp(valueText.str(), "aDR1") == 0)
  184. valueText.length();
  185. #endif
  186. #endif
  187. return createConstant(valueText.str());
  188. }
  189. IHqlExpression * createSetResult(IHqlExpression * value)
  190. {
  191. HqlExprArray args;
  192. args.append(*LINK(value));
  193. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  194. args.append(*createAttribute(namedAtom, createNextStringValue(value)));
  195. return createSetResult(args);
  196. }
  197. static IHqlExpression * addAttrOwnToDataset(IHqlExpression * dataset, IHqlExpression * attr)
  198. {
  199. HqlExprArray args;
  200. unwindChildren(args, dataset);
  201. args.append(*attr);
  202. return dataset->clone(args);
  203. }
  204. static IHqlExpression * mergeLimitIntoDataset(IHqlExpression * dataset, IHqlExpression * limit)
  205. {
  206. return addAttrOwnToDataset(dataset, createAttribute(limitAtom, LINK(limit->queryChild(1)), LINK(limit->queryChild(2))));
  207. }
  208. //---------------------------------------------------------------------------
  209. static bool isOptionTooLate(const char * name)
  210. {
  211. if (stricmp(name, "gatherDependencies") == 0) return true;
  212. if (stricmp(name, "gatherDependenciesSelection") == 0) return true;
  213. if (stricmp(name, "archiveToCpp") == 0) return true;
  214. if (stricmp(name, "importAllModules") == 0) return true;
  215. if (stricmp(name, "importImplicitModules") == 0) return true;
  216. if (stricmp(name, "noCache") == 0) return true;
  217. return false;
  218. }
  219. static HqlTransformerInfo newThorStoredReplacerInfo("NewThorStoredReplacer");
  220. NewThorStoredReplacer::NewThorStoredReplacer(HqlCppTranslator & _translator, IWorkUnit * _wu, ICodegenContextCallback * _ctxCallback)
  221. : QuickHqlTransformer(newThorStoredReplacerInfo, NULL), translator(_translator)
  222. {
  223. wu = _wu;
  224. ctxCallback = _ctxCallback;
  225. foldStored = false;
  226. seenMeta = false;
  227. }
  228. void NewThorStoredReplacer::doAnalyseBody(IHqlExpression * expr)
  229. {
  230. //NOTE: This is called very early before no_assertconstant has been processed, so we need to explicitly
  231. //constant fold, and check it is constant (bug 26963)
  232. node_operator op = expr->getOperator();
  233. if (op == no_setmeta)
  234. {
  235. StringBuffer errorTemp;
  236. seenMeta = true;
  237. _ATOM kind = expr->queryChild(0)->queryName();
  238. if (kind == debugAtom)
  239. {
  240. OwnedHqlExpr foldedName = foldHqlExpression(expr->queryChild(1));
  241. OwnedHqlExpr foldedValue = foldHqlExpression(expr->queryChild(2));
  242. IValue * name = foldedName->queryValue();
  243. IValue * value = foldedValue->queryValue();
  244. if (!name)
  245. throwError1(HQLERR_ExpectedConstantDebug, getExprECL(foldedName, errorTemp).str());
  246. if (!value)
  247. throwError1(HQLERR_ExpectedConstantDebug, getExprECL(foldedValue, errorTemp).str());
  248. StringBuffer nameText,valueText;
  249. name->getStringValue(nameText);
  250. if (isOptionTooLate(nameText.str()))
  251. translator.reportWarning(HQLWRN_OptionSetToLate, HQLWRN_OptionSetToLate_Text, nameText.str());
  252. if (value->queryType()->getTypeCode() == type_boolean)
  253. valueText.append(value->getBoolValue() ? 1 : 0);
  254. else
  255. value->getStringValue(valueText);
  256. wu->setDebugValue(nameText.str(), valueText, true);
  257. }
  258. else if (kind == workunitAtom)
  259. {
  260. OwnedHqlExpr foldedName = foldHqlExpression(expr->queryChild(1));
  261. OwnedHqlExpr foldedValue = foldHqlExpression(expr->queryChild(2));
  262. IValue * name = foldedName->queryValue();
  263. IValue * value = foldedValue->queryValue();
  264. if (!name)
  265. throwError1(HQLERR_ExpectedConstantWorkunit, getExprECL(foldedName, errorTemp).str());
  266. if (!value)
  267. throwError1(HQLERR_ExpectedConstantWorkunit, getExprECL(foldedValue, errorTemp).str());
  268. StringBuffer nameText,valueText;
  269. name->getStringValue(nameText);
  270. value->getStringValue(valueText);
  271. if (stricmp(nameText.str(), "name") == 0)
  272. wu->setJobName(valueText.str());
  273. else if (stricmp(nameText.str(), "priority") == 0)
  274. {
  275. if (isStringType(value->queryType()))
  276. {
  277. WUPriorityClass prio = PriorityClassUnknown;
  278. if (stricmp(valueText.str(), "low") == 0)
  279. prio = PriorityClassLow;
  280. else if (stricmp(valueText.str(), "normal") == 0)
  281. prio = PriorityClassNormal;
  282. else if (stricmp(valueText.str(), "high") == 0)
  283. prio = PriorityClassHigh;
  284. wu->setPriority(prio);
  285. }
  286. else
  287. wu->setPriorityLevel((int)value->getIntValue());
  288. }
  289. else if (stricmp(nameText.str(), "cluster") == 0)
  290. {
  291. ctxCallback->noteCluster(valueText.str());
  292. wu->setClusterName(valueText.str());
  293. }
  294. else if (stricmp(nameText.str(), "protect") == 0)
  295. {
  296. wu->protect(value->getBoolValue());
  297. }
  298. else if (stricmp(nameText.str(), "scope") == 0)
  299. {
  300. wu->setWuScope(valueText.str());
  301. }
  302. else
  303. throwError1(HQLERR_UnsupportedHashWorkunit, nameText.str());
  304. }
  305. else if (kind == linkAtom)
  306. {
  307. OwnedHqlExpr foldedName = foldHqlExpression(expr->queryChild(1));
  308. StringBuffer libraryText;
  309. if (getStringValue(libraryText, foldedName).length())
  310. translator.useLibrary(libraryText);
  311. }
  312. else if ((kind == constAtom) || (kind == storedAtom))
  313. {
  314. //assume there won't be many of these... otherwise we should use a hash table
  315. OwnedHqlExpr lowerName = lowerCaseHqlExpr(expr->queryChild(1));
  316. //Use lowerName->queryBody() to remove named symbols/location annotations etc.
  317. storedNames.append(*LINK(lowerName->queryBody()));
  318. storedValues.append(*LINK(expr->queryChild(2)));
  319. storedIsConstant.append(kind == constAtom);
  320. }
  321. else if (kind == onWarningAtom)
  322. translator.addGlobalOnWarning(expr);
  323. }
  324. else if (op == no_colon)
  325. {
  326. if (queryPropertyInList(labeledAtom, expr->queryChild(1)))
  327. seenMeta = true;
  328. }
  329. QuickHqlTransformer::doAnalyseBody(expr);
  330. }
  331. bool NewThorStoredReplacer::needToTransform()
  332. {
  333. //foldStored = translator.queryOptions().foldStored; // NB: options isn't initialised correctly at this point.
  334. foldStored = wu->getDebugValueBool("foldStored", false);
  335. return (foldStored || seenMeta);
  336. }
  337. // This works on unnormalized trees, so based on QuickHqlTransformer
  338. IHqlExpression * NewThorStoredReplacer::createTransformed(IHqlExpression * expr)
  339. {
  340. switch (expr->getOperator())
  341. {
  342. case no_colon:
  343. {
  344. HqlExprArray actions;
  345. expr->queryChild(1)->unwindList(actions, no_comma);
  346. OwnedHqlExpr replacement;
  347. OwnedHqlExpr matchedName;
  348. bool onlyStored = true;
  349. bool forceConstant = foldStored;
  350. ForEachItemIn(idx, actions)
  351. {
  352. IHqlExpression & cur = actions.item(idx);
  353. switch (cur.getOperator())
  354. {
  355. case no_stored:
  356. {
  357. OwnedHqlExpr storedName = lowerCaseHqlExpr(cur.queryChild(0));
  358. IHqlExpression * searchName = storedName->queryBody();
  359. unsigned match = storedNames.find(*searchName);
  360. if (match != NotFound)
  361. {
  362. if (storedIsConstant.item(match))
  363. forceConstant = true;
  364. matchedName.set(searchName);
  365. replacement.set(&storedValues.item(match));
  366. }
  367. break;
  368. }
  369. case no_attr:
  370. case no_attr_expr:
  371. if (cur.queryName() == labeledAtom)
  372. {
  373. OwnedHqlExpr storedName = lowerCaseHqlExpr(cur.queryChild(0));
  374. IHqlExpression * searchName = storedName->queryBody();
  375. unsigned match = storedNames.find(*searchName);
  376. if (match != NotFound)
  377. {
  378. matchedName.set(searchName);
  379. replacement.set(&storedValues.item(match));
  380. }
  381. else
  382. replacement.set(expr->queryChild(0));
  383. forceConstant = true;
  384. break;
  385. }
  386. default:
  387. onlyStored = false;
  388. break;
  389. }
  390. }
  391. if (matchedName)
  392. {
  393. unsigned activeMatch = activeReplacements.find(*matchedName);
  394. if (activeMatch != NotFound)
  395. {
  396. StringBuffer nameText;
  397. getExprECL(matchedName, nameText);
  398. if (activeMatch+1 != activeReplacements.ordinality())
  399. {
  400. StringBuffer othersText;
  401. for (unsigned i=activeMatch+1; i < activeReplacements.ordinality(); i++)
  402. {
  403. othersText.append(",");
  404. getExprECL(&activeReplacements.item(i), othersText);
  405. }
  406. throwError3(HQLERR_RecursiveStoredOther, forceConstant ? "CONSTANT" : "STORED", nameText.str(), othersText.str()+1);
  407. }
  408. else
  409. throwError2(HQLERR_RecursiveStored, forceConstant ? "CONSTANT" : "STORED", nameText.str());
  410. }
  411. ITypeInfo * exprType = expr->queryType();
  412. ITypeInfo * replacementType = replacement->queryType();
  413. type_t etc = exprType->getTypeCode();
  414. type_t rtc = replacementType->getTypeCode();
  415. StringBuffer nameText, exprTypeText, replacementTypeText;
  416. switch (etc)
  417. {
  418. case type_groupedtable:
  419. case type_table:
  420. case type_row:
  421. case type_record:
  422. case type_transform:
  423. case type_void:
  424. {
  425. if (etc != rtc)
  426. {
  427. getExprECL(matchedName, nameText);
  428. getFriendlyTypeStr(exprType, exprTypeText);
  429. getFriendlyTypeStr(replacementType, replacementTypeText);
  430. throwError3(HQLERR_HashStoredTypeMismatch, nameText.str(), exprTypeText.str(), replacementTypeText.str());
  431. }
  432. else if (expr->queryRecord() != replacement->queryRecord())
  433. {
  434. StringBuffer s;
  435. throwError1(HQLERR_HashStoredRecordMismatch, getExprECL(matchedName, s).str());
  436. }
  437. }
  438. break;
  439. case type_set:
  440. case type_array:
  441. {
  442. if ((rtc != type_set) && (rtc != type_array))
  443. {
  444. getExprECL(matchedName, nameText);
  445. getFriendlyTypeStr(exprType, exprTypeText);
  446. getFriendlyTypeStr(replacementType, replacementTypeText);
  447. throwError3(HQLERR_HashStoredTypeMismatch, nameText.str(), exprTypeText.str(), replacementTypeText.str());
  448. }
  449. replacement.setown(ensureExprType(replacement, exprType));
  450. break;
  451. }
  452. default:
  453. {
  454. switch (rtc)
  455. {
  456. case type_groupedtable:
  457. case type_table:
  458. case type_row:
  459. case type_record:
  460. case type_transform:
  461. case type_void:
  462. {
  463. getExprECL(matchedName, nameText);
  464. getFriendlyTypeStr(exprType, exprTypeText);
  465. getFriendlyTypeStr(replacementType, replacementTypeText);
  466. throwError3(HQLERR_HashStoredTypeMismatch, nameText.str(), exprTypeText.str(), replacementTypeText.str());
  467. }
  468. default:
  469. replacement.setown(ensureExprType(replacement, exprType));
  470. }
  471. }
  472. break;
  473. }
  474. }
  475. LinkedHqlExpr result;
  476. if (matchedName)
  477. activeReplacements.append(*matchedName);
  478. if (onlyStored)
  479. {
  480. if (forceConstant && replacement)
  481. result.setown(transform(replacement));
  482. else if (foldStored)
  483. result.setown(transform(expr->queryChild(0)));
  484. }
  485. if (replacement && !result)
  486. {
  487. HqlExprArray args;
  488. args.append(*transform(replacement));
  489. result.setown(completeTransform(expr, args));
  490. }
  491. if (matchedName)
  492. activeReplacements.pop();
  493. if (result)
  494. return result.getClear();
  495. break;
  496. }
  497. case no_comma:
  498. case no_compound:
  499. if (expr->queryChild(0)->getOperator() == no_setmeta)
  500. return transform(expr->queryChild(1));
  501. if (expr->queryChild(1)->getOperator() == no_setmeta)
  502. return transform(expr->queryChild(0));
  503. break;
  504. case no_actionlist:
  505. {
  506. HqlExprArray actions;
  507. ForEachChild(i, expr)
  508. {
  509. IHqlExpression * cur = expr->queryChild(i);
  510. if (cur->getOperator() != no_setmeta)
  511. actions.append(*transform(cur));
  512. }
  513. if (actions.ordinality() != 0)
  514. return expr->clone(actions);
  515. return transform(expr->queryChild(0));
  516. }
  517. }
  518. return QuickHqlTransformer::createTransformed(expr);
  519. }
  520. //---------------------------------------------------------------------------
  521. // NB: This is called after no_setresults are added, but before any normalization.
  522. static HqlTransformerInfo hqlThorBoundaryTransformerInfo("HqlThorBoundaryTransformer");
  523. HqlThorBoundaryTransformer::HqlThorBoundaryTransformer(IConstWorkUnit * _wu, bool _isRoxie, unsigned _maxRootMaybes, bool _resourceConditionalActions, bool _resourceSequential)
  524. : NewHqlTransformer(hqlThorBoundaryTransformerInfo)
  525. {
  526. wu = _wu;
  527. isRoxie = _isRoxie;
  528. maxRootMaybes = _maxRootMaybes;
  529. resourceConditionalActions = _resourceConditionalActions;
  530. resourceSequential = _resourceSequential;
  531. }
  532. void HqlThorBoundaryTransformer::transformCompound(HqlExprArray & result, node_operator compoundOp, const HqlExprArray & args, unsigned MaxMaybes)
  533. {
  534. UnsignedArray normalizeOptions;
  535. ForEachItemIn(i, args)
  536. {
  537. IHqlExpression & cur = args.item(i);
  538. normalizeOptions.append(normalizeThor(&cur));
  539. }
  540. //If any "yes" or "some" values are separated by maybes then convert the maybes (and "somes") into yes
  541. unsigned lastYes = NotFound;
  542. unsigned numMaybes = 0;
  543. ForEachItemIn(i2, args)
  544. {
  545. switch (normalizeOptions.item(i2))
  546. {
  547. case OptionYes:
  548. case OptionSome:
  549. if (lastYes != NotFound)
  550. {
  551. if (numMaybes <= MaxMaybes)
  552. {
  553. for (unsigned j = lastYes; j <= i2; j++)
  554. normalizeOptions.replace(OptionYes, j);
  555. }
  556. }
  557. numMaybes = 0;
  558. lastYes = i2;
  559. break;
  560. case OptionMaybe:
  561. numMaybes++;
  562. break;
  563. case OptionNo:
  564. lastYes = NotFound;
  565. break;
  566. }
  567. }
  568. //Do thor and non-thor parallel actions independently
  569. HqlExprArray thor;
  570. ForEachItemIn(idx, args)
  571. {
  572. IHqlExpression * cur = &args.item(idx);
  573. if (normalizeOptions.item(idx) == OptionYes)
  574. thor.append(*LINK(cur));
  575. else
  576. {
  577. if (thor.ordinality())
  578. {
  579. result.append(*createWrapper(no_thor, createCompound(compoundOp, thor)));
  580. thor.kill();
  581. }
  582. result.append(*createTransformed(cur));
  583. }
  584. }
  585. if (thor.ordinality())
  586. result.append(*createWrapper(no_thor, createCompound(compoundOp, thor)));
  587. }
  588. IHqlExpression * HqlThorBoundaryTransformer::createTransformed(IHqlExpression * expr)
  589. {
  590. node_operator op = expr->getOperator();
  591. switch (op)
  592. {
  593. case no_field:
  594. case no_constant:
  595. case no_attr:
  596. case no_attr_link:
  597. case no_getresult:
  598. case no_left:
  599. case no_right:
  600. return LINK(expr);
  601. case no_sizeof:
  602. case no_offsetof:
  603. return getTransformedChildren(expr);
  604. }
  605. //Unusually, wrap the expression in a thor node before processing annotations.
  606. //This ensures that the location/named symbol stays with the action.
  607. //MORE: If this is a dataset then it needs to turn it into a setResult()/getResult() pair.
  608. if (normalizeThor(expr) == OptionYes)
  609. {
  610. if (!expr->isTransform())
  611. return createWrapper(no_thor, LINK(expr));
  612. }
  613. IHqlExpression * ret = queryTransformAnnotation(expr);
  614. if (ret)
  615. return ret;
  616. switch (op)
  617. {
  618. case no_actionlist:
  619. {
  620. HqlExprArray nonThor, args;
  621. expr->unwindList(args, op);
  622. transformCompound(nonThor, op, args, (unsigned)-1);
  623. return createCompound(op, nonThor);
  624. }
  625. case no_parallel:
  626. {
  627. HqlExprArray expanded;
  628. expr->unwindList(expanded, no_parallel);
  629. //Similar to compound, but possible to reorder branches...
  630. unsigned numThor = 0;
  631. UnsignedArray normalizeOptions;
  632. ForEachItemIn(idx, expanded)
  633. {
  634. YesNoOption option = normalizeThor(&expanded.item(idx));
  635. normalizeOptions.append(option);
  636. if ((option == OptionYes) || (option == OptionSome))
  637. numThor++;
  638. }
  639. if (numThor > 1)
  640. {
  641. HqlExprArray thor, nonThor;
  642. ForEachItemIn(idx, expanded)
  643. {
  644. IHqlExpression * cur = &expanded.item(idx);
  645. switch (normalizeOptions.item(idx))
  646. {
  647. case OptionYes:
  648. case OptionSome:
  649. thor.append(*LINK(cur));
  650. break;
  651. default:
  652. nonThor.append(*createTransformed(cur));
  653. break;
  654. }
  655. }
  656. if (nonThor.ordinality() == 0)
  657. {
  658. //can happen if inputs are a mixture of yes and some.
  659. return createWrapper(no_thor, LINK(expr));
  660. }
  661. nonThor.append(*createWrapper(no_thor, createValue(no_parallel, makeVoidType(), thor)));
  662. return expr->clone(nonThor);
  663. }
  664. break;
  665. }
  666. case no_nothor:
  667. return LINK(expr);
  668. }
  669. return NewHqlTransformer::createTransformed(expr);
  670. }
  671. static YesNoOption combine(YesNoOption left, YesNoOption right, bool isUnion)
  672. {
  673. if ((left == OptionNo) || (right == OptionNo))
  674. return OptionNo;
  675. if (left == OptionUnknown)
  676. return right;
  677. if (right == OptionUnknown)
  678. return left;
  679. //Yes,Some,Maybe
  680. if (isUnion)
  681. {
  682. //return definite if both branches may benefit.
  683. switch (left)
  684. {
  685. case OptionYes:
  686. return (right != OptionMaybe) ? OptionYes : OptionSome;
  687. case OptionSome:
  688. return (right != OptionMaybe) ? OptionYes : OptionSome;
  689. case OptionMaybe:
  690. return (right != OptionMaybe) ? OptionSome : OptionMaybe;
  691. }
  692. }
  693. else
  694. {
  695. //Intersection, return definite
  696. switch (left)
  697. {
  698. case OptionYes:
  699. return (right == OptionYes) ? OptionYes : OptionSome;
  700. case OptionSome:
  701. return OptionSome;
  702. case OptionMaybe:
  703. return (right == OptionMaybe) ? OptionMaybe : OptionSome;
  704. }
  705. }
  706. throwUnexpected();
  707. }
  708. //MORE: Needs to be yes, no, possibly.
  709. YesNoOption HqlThorBoundaryTransformer::normalizeThor(IHqlExpression * expr)
  710. {
  711. HqlThorBoundaryInfo * extra = queryBodyExtra(expr);
  712. if (extra->normalize == OptionUnknown)
  713. extra->normalize = calcNormalizeThor(expr);
  714. return extra->normalize;
  715. }
  716. YesNoOption HqlThorBoundaryTransformer::calcNormalizeThor(IHqlExpression * expr)
  717. {
  718. //MORE: This should probably be cached in the extra info & recursed more correctly
  719. node_operator op = expr->getOperator();
  720. ITypeInfo * type = expr->queryType();
  721. switch (op)
  722. {
  723. case no_constant:
  724. case no_field:
  725. case no_record:
  726. case no_attr:
  727. case no_attr_expr:
  728. case no_attr_link:
  729. case no_getresult:
  730. case no_left:
  731. case no_right:
  732. case no_sizeof:
  733. case no_all:
  734. case no_self:
  735. case no_activerow:
  736. return OptionMaybe;
  737. case no_evaluate:
  738. throwUnexpected();
  739. case no_select:
  740. {
  741. bool isNew;
  742. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  743. switch (ds->getOperator())
  744. {
  745. case no_getresult:
  746. case no_call:
  747. case no_externalcall:
  748. return normalizeThor(ds);
  749. case no_self:
  750. return OptionMaybe;
  751. }
  752. return isNew ? OptionYes : OptionMaybe;
  753. }
  754. case NO_AGGREGATE:
  755. case no_executewhen:
  756. return OptionYes;
  757. case NO_ACTION_REQUIRES_GRAPH:
  758. {
  759. if ((op == no_output) && isTrivialInlineOutput(expr))
  760. return OptionMaybe;
  761. return OptionYes;
  762. }
  763. case no_sequential: // do not do inside thor - stops graphs being merged.
  764. if (!resourceSequential)
  765. return OptionNo;
  766. // fallthrough
  767. case no_actionlist:
  768. case no_parallel:
  769. {
  770. YesNoOption option = OptionUnknown;
  771. ForEachChild(idx, expr)
  772. {
  773. YesNoOption childOption = normalizeThor(expr->queryChild(idx));
  774. if (childOption == OptionNo)
  775. return OptionNo;
  776. option = combine(option, childOption, (op == no_sequential)); // can reorder parallel - so intersection is better
  777. }
  778. return option;
  779. }
  780. case no_cluster:
  781. case no_nothor:
  782. return OptionNo;
  783. case no_if:
  784. if (type && (type->getTypeCode() == type_void))
  785. {
  786. if (resourceConditionalActions)
  787. {
  788. IHqlExpression * falseExpr = expr->queryChild(2);
  789. YesNoOption leftOption = normalizeThor(expr->queryChild(1));
  790. YesNoOption rightOption = falseExpr ? normalizeThor(falseExpr) : OptionMaybe;
  791. YesNoOption branchOption = combine(leftOption, rightOption, true);
  792. YesNoOption condOption = normalizeThor(expr->queryChild(0));
  793. if ((branchOption == OptionYes) && (condOption != OptionNo))
  794. return OptionYes;
  795. // if ((condOption == OptionYes) && (branchOption != OptionNo))
  796. // return OptionYes;
  797. return combine(condOption, branchOption, true);
  798. }
  799. return OptionNo; // not supported
  800. }
  801. // default action. Not completely convinced it is correct....
  802. break;
  803. case no_choose:
  804. if (type && (type->getTypeCode() == type_void))
  805. {
  806. if (resourceConditionalActions)
  807. {
  808. UNIMPLEMENTED;
  809. }
  810. }
  811. break;
  812. case no_setresult:
  813. {
  814. IHqlExpression * value = expr->queryChild(0);
  815. YesNoOption valueOption = normalizeThor(value);
  816. //Probably worth doing the whole thing in thor if some part if it needs to be - will improve commoning up if nothing else.
  817. if (valueOption == OptionSome)
  818. return OptionYes;
  819. return valueOption;
  820. }
  821. case no_extractresult:
  822. {
  823. IHqlExpression * ds = expr->queryChild(0);
  824. OwnedHqlExpr transformedDs = transform(ds);
  825. if (transformedDs != ds)
  826. return OptionYes;
  827. //Probably worth doing the whole thing in thor if some part if it needs to be - will improve commoning up if nothing else.
  828. return normalizeThor(expr->queryChild(1));
  829. }
  830. case no_compound:
  831. {
  832. YesNoOption leftOption = normalizeThor(expr->queryChild(0));
  833. YesNoOption rightOption = normalizeThor(expr->queryChild(1));
  834. return combine(leftOption, rightOption, true);
  835. }
  836. case no_call:
  837. {
  838. YesNoOption bodyOption = normalizeThor(expr->queryBody()->queryFunctionDefinition());
  839. //do Something with it
  840. break;
  841. }
  842. case no_externalcall:
  843. {
  844. IHqlExpression * func = expr->queryExternalDefinition();
  845. IHqlExpression * funcDef = func->queryChild(0);
  846. if (funcDef->hasProperty(gctxmethodAtom) || funcDef->hasProperty(globalContextAtom))
  847. return OptionNo;
  848. // if (funcDef->hasProperty(graphAtom))
  849. // return OptionYes;
  850. if (!resourceConditionalActions && expr->isAction())
  851. return OptionNo;
  852. //depends on the results of the arguments..
  853. type = NULL; // don't check the return type
  854. break;
  855. }
  856. case no_setworkflow_cond:
  857. case no_ensureresult:
  858. return OptionNo;
  859. case no_null:
  860. return OptionMaybe;
  861. }
  862. //NB: things like NOT EXISTS we want evaluated as NOT THOR(EXISTS()), or as part of a larger context
  863. //otherwise things like klogermann14.xhql don't get EXISTS() csed between graphs.
  864. YesNoOption option = OptionMaybe;
  865. ForEachChild(idx, expr)
  866. {
  867. YesNoOption childOption = normalizeThor(expr->queryChild(idx));
  868. if (childOption == OptionNo)
  869. return OptionNo;
  870. option = combine(option, childOption, true);
  871. }
  872. if (type)
  873. {
  874. switch (type->getTypeCode())
  875. {
  876. case type_row:
  877. switch (op)
  878. {
  879. case no_fromxml:
  880. return option;
  881. case no_createrow:
  882. //MORE: There are more cases that could be evaluated outside of thor, but playing safe.
  883. if (expr->queryChild(0)->isConstant())
  884. return option;
  885. break;
  886. }
  887. return OptionYes;
  888. case type_groupedtable:
  889. case type_table:
  890. //must be a dataset parameter to a call, or an argument to a comparison
  891. //Need to know whether it can be evaluate inline or not.
  892. //if it does require thor, then we will need to generate a setresult/get result pair to do it.
  893. return !canProcessInline(NULL, expr) ? OptionYes : OptionMaybe;
  894. }
  895. }
  896. return option;
  897. }
  898. void HqlThorBoundaryTransformer::transformRoot(const HqlExprArray & in, HqlExprArray & out)
  899. {
  900. //NewHqlTransformer::transformArray(in, out);
  901. //following theoretically might improve things, but generally just causes code to become worse,
  902. //because all the global set results are done in activities, and there isn't cse between them
  903. transformCompound(out, no_actionlist, in, maxRootMaybes);
  904. }
  905. void HqlCppTranslator::markThorBoundaries(WorkflowArray & array)
  906. {
  907. HqlThorBoundaryTransformer thorTransformer(wu(), targetRoxie(), options.maxRootMaybeThorActions, options.resourceConditionalActions, options.resourceSequential);
  908. ForEachItemIn(idx, array)
  909. {
  910. WorkflowItem & cur = array.item(idx);
  911. HqlExprArray & exprs = cur.queryExprs();
  912. HqlExprArray bounded;
  913. thorTransformer.transformRoot(exprs, bounded);
  914. replaceArray(exprs, bounded);
  915. }
  916. }
  917. //---------------------------------------------------------------------------
  918. // NB: This is called after no_setresults are added, but before any normalization.
  919. IHqlExpression * ThorScalarTransformer::queryAlreadyTransformed(IHqlExpression * expr)
  920. {
  921. bool conditional = isConditional();
  922. if (conditional)
  923. {
  924. IHqlExpression * ret = queryExtra(expr)->transformed[false];
  925. if (ret)
  926. return ret;
  927. }
  928. return queryExtra(expr)->transformed[isConditional()];
  929. }
  930. IHqlExpression * ThorScalarTransformer::queryAlreadyTransformedSelector(IHqlExpression * expr)
  931. {
  932. return queryExtra(expr)->transformedSelector[isConditional()];
  933. }
  934. void ThorScalarTransformer::setTransformed(IHqlExpression * expr, IHqlExpression * transformed)
  935. {
  936. queryExtra(expr)->transformed[isConditional()].set(transformed);
  937. }
  938. void ThorScalarTransformer::setTransformedSelector(IHqlExpression * expr, IHqlExpression * transformed)
  939. {
  940. queryExtra(expr)->transformedSelector[isConditional()].set(transformed);
  941. }
  942. static HqlTransformerInfo ThorScalarTransformerInfo("ThorScalarTransformer");
  943. ThorScalarTransformer::ThorScalarTransformer(const HqlCppOptions & _options) : HoistingHqlTransformer(ThorScalarTransformerInfo, CTFnoteifactions), options(_options)
  944. {
  945. isConditionalDepth = 0;
  946. seenCandidate = false;
  947. }
  948. void ThorScalarTransformer::doAnalyseExpr(IHqlExpression * expr)
  949. {
  950. switch (expr->getOperator())
  951. {
  952. case no_thor:
  953. {
  954. ITypeInfo * type = expr->queryType();
  955. if (type && (type->isScalar() || type->getTypeCode() == type_row))
  956. seenCandidate = true;
  957. //No point looking further than a no_thor they don't (currently) get nested within each other.
  958. return;
  959. }
  960. }
  961. HoistingHqlTransformer::doAnalyseExpr(expr);
  962. }
  963. void ThorScalarTransformer::createHoisted(IHqlExpression * expr, SharedHqlExpr & setResultStmt, SharedHqlExpr & getResult, bool addWrapper)
  964. {
  965. IHqlExpression * value = expr;
  966. HqlExprArray actions;
  967. while (value->getOperator() == no_compound)
  968. {
  969. unwindCommaCompound(actions, value->queryChild(0));
  970. value = value->queryChild(1);
  971. }
  972. IHqlExpression * setResult = createSetResult(value);
  973. getResult.setown(createGetResultFromSetResult(setResult));
  974. actions.append(*setResult);
  975. setResultStmt.setown(createActionList(actions));
  976. if (addWrapper)
  977. setResultStmt.setown(createValue(no_thor, makeVoidType(), setResultStmt.getClear()));
  978. }
  979. IHqlExpression * ThorScalarTransformer::createTransformed(IHqlExpression * expr)
  980. {
  981. if (expr->isConstant())
  982. {
  983. //THOR(NULL) is marked as constant (probably incorrectly), but still needs hoisting.
  984. // if ((expr->getOperator() != no_thor) || (expr->numChildren() == 0))
  985. return LINK(expr);
  986. }
  987. IHqlExpression * ret = queryTransformAnnotation(expr);
  988. if (ret)
  989. return ret;
  990. node_operator op = expr->getOperator();
  991. switch (op)
  992. {
  993. case no_if:
  994. case no_chooseds:
  995. {
  996. bool isGuard = isFailureGuard(expr);
  997. HqlExprArray children;
  998. children.append(*transform(expr->queryChild(0)));
  999. if (!isGuard)
  1000. isConditionalDepth++;
  1001. transformChildren(expr, children);
  1002. if (!isGuard)
  1003. isConditionalDepth--;
  1004. return cloneOrLink(expr, children);
  1005. }
  1006. case no_thor:
  1007. {
  1008. ITypeInfo * type = expr->queryType();
  1009. // if (isUsedUnconditionally(expr) && type && (type->isScalar() || type->getTypeCode() == type_row))
  1010. if ((type->isScalar() || type->getTypeCode() == type_row))
  1011. {
  1012. //only other solution is to have some kind of graph result which is returned.
  1013. assertex(options.workunitTemporaries);
  1014. OwnedHqlExpr getResult, setResult;
  1015. OwnedHqlExpr transformedChild = transform(expr->queryChild(0));
  1016. createHoisted(transformedChild, setResult, getResult, true);
  1017. //Note sure if this condition is needed any more - I suspect better without.
  1018. if (isConditional())
  1019. return createCompound(setResult.getClear(), getResult.getClear());
  1020. else
  1021. {
  1022. appendToTarget(*setResult.getClear());
  1023. return getResult.getClear();
  1024. }
  1025. }
  1026. return LINK(expr);
  1027. }
  1028. break;
  1029. case no_mapto:
  1030. if (isConditional())
  1031. {
  1032. HqlExprArray children;
  1033. isConditionalDepth--;
  1034. children.append(*transform(expr->queryChild(0)));
  1035. isConditionalDepth++;
  1036. children.append(*transform(expr->queryChild(1)));
  1037. return cloneOrLink(expr, children);
  1038. }
  1039. break;
  1040. case no_case:
  1041. case no_map:
  1042. {
  1043. HqlExprArray children;
  1044. unsigned firstArg = 0;
  1045. unsigned numChildren = expr->numChildren();
  1046. children.ensure(numChildren);
  1047. if (op != no_map)
  1048. {
  1049. firstArg = 1;
  1050. children.append(*transform(expr->queryChild(0)));
  1051. }
  1052. isConditionalDepth++;
  1053. for (unsigned idx=firstArg; idx < numChildren; idx++)
  1054. children.append(*transform(expr->queryChild(idx)));
  1055. isConditionalDepth--;
  1056. return cloneOrLink(expr, children);
  1057. }
  1058. case no_table:
  1059. //Don't look at the default values for fields in the table's record
  1060. return LINK(expr);
  1061. }
  1062. return HoistingHqlTransformer::createTransformed(expr);
  1063. }
  1064. //---------------------------------------------------------------------------
  1065. /*
  1066. Look for expressions like count(x) and abc[1].x inside a condition and convert to
  1067. setresult(<complicated>, 'x')
  1068. getresult('x')
  1069. Problems:
  1070. o it tries to keep get/set results within the conditional branches that need them,
  1071. but that means if it occurs in more than one then it will only get added once.
  1072. o It (and all transformers) should possibly always generate a setresult,getresult locally,
  1073. and then have another pass that moves all the setresults to the optimal place. E.g. to the highest shared location.
  1074. [Alternatively can a global, but conditional, root graph be generated for it?]
  1075. Also converts
  1076. setresult(thor(x)) to thor(setresult(x))
  1077. thor(scalar) to setresult(scalar,'x'),getresult('x')
  1078. */
  1079. static void normalizeResultFormat(WorkflowArray & workflow, const HqlCppOptions & options)
  1080. {
  1081. ForEachItemIn(idx, workflow)
  1082. {
  1083. WorkflowItem & cur = workflow.item(idx);
  1084. HqlExprArray & exprs = cur.queryExprs();
  1085. //Until thor has a way of calling a graph and returning a result we need to call this transformer, so that
  1086. //scalars that need to be evaluated in thor are correctly hoisted.
  1087. {
  1088. ThorScalarTransformer transformer(options);
  1089. transformer.analyseArray(exprs, 0);
  1090. if (transformer.needToTransform())
  1091. {
  1092. HqlExprArray transformed;
  1093. transformer.transformRoot(exprs, transformed);
  1094. replaceArray(exprs, transformed);
  1095. }
  1096. }
  1097. }
  1098. }
  1099. //---------------------------------------------------------------------------
  1100. //Try and get the HOLe queries at the start and the Thor queries at the end.
  1101. //Keep track of the dependencies of the statements, so that they don't get reordered
  1102. //too aggressively.
  1103. //---------------------------------------------------------------------------
  1104. static HqlTransformerInfo sequenceNumberAllocatorInfo("SequenceNumberAllocator");
  1105. SequenceNumberAllocator::SequenceNumberAllocator(HqlCppTranslator & _translator) : NewHqlTransformer(sequenceNumberAllocatorInfo), translator(_translator)
  1106. {
  1107. applyDepth = 0;
  1108. sequence = 0;
  1109. }
  1110. void SequenceNumberAllocator::nextSequence(HqlExprArray & args, IHqlExpression * name, _ATOM overwriteAction, IHqlExpression * value, bool needAttr, bool * duplicate)
  1111. {
  1112. IHqlExpression * seq = NULL;
  1113. if (duplicate)
  1114. *duplicate = false;
  1115. if (name)
  1116. {
  1117. SharedHqlExpr * matched = namedMap.getValue(name);
  1118. if (matched)
  1119. {
  1120. StringBuffer nameText;
  1121. name->toString(nameText);
  1122. IHqlExpression * prev = matched->get();
  1123. if (prev->isAttribute())
  1124. {
  1125. _ATOM prevName = prev->queryName();
  1126. if (!overwriteAction)
  1127. {
  1128. if (prevName == extendAtom)
  1129. throwError1(HQLERR_ExtendMismatch, nameText.str());
  1130. else
  1131. throwError1(HQLERR_OverwriteMismatch, nameText.str());
  1132. }
  1133. else if (prevName != overwriteAction)
  1134. throwError1(HQLERR_ExtendOverwriteMismatch, nameText.str());
  1135. IHqlExpression * prevValue = prev->queryChild(1);
  1136. if (!recordTypesMatch(prevValue->queryType(), value->queryType()))
  1137. throwError1(HQLERR_ExtendTypeMismatch, nameText.str());
  1138. seq = LINK(prev->queryChild(0));
  1139. assertex(duplicate);
  1140. *duplicate = true;
  1141. }
  1142. else
  1143. {
  1144. if (overwriteAction)
  1145. {
  1146. if (overwriteAction == extendAtom)
  1147. throwError1(HQLERR_ExtendMismatch, nameText.str());
  1148. else
  1149. throwError1(HQLERR_OverwriteMismatch, nameText.str());
  1150. }
  1151. else
  1152. throwError1(HQLERR_DuplicateNameOutput, nameText.str());
  1153. }
  1154. }
  1155. if (!seq)
  1156. {
  1157. seq = createConstant(signedType->castFrom(true, (__int64)sequence++));
  1158. OwnedHqlExpr saveValue = overwriteAction ? createAttribute(overwriteAction, LINK(seq), LINK(value)) : LINK(seq);
  1159. namedMap.setValue(name, saveValue);
  1160. }
  1161. }
  1162. else
  1163. seq = createConstant(signedType->castFrom(true, (__int64)sequence++));
  1164. if (needAttr)
  1165. args.append(*createAttribute(sequenceAtom, seq));
  1166. else
  1167. args.append(*seq);
  1168. }
  1169. IHqlExpression * SequenceNumberAllocator::doTransformRootExpr(IHqlExpression * expr)
  1170. {
  1171. node_operator op = expr->getOperator();
  1172. switch(op)
  1173. {
  1174. case no_compound:
  1175. case no_comma:
  1176. case no_parallel:
  1177. case no_sequential:
  1178. case no_actionlist:
  1179. {
  1180. HqlExprArray args;
  1181. ForEachChild(idx, expr)
  1182. args.append(*doTransformRootExpr(expr->queryChild(idx)));
  1183. return cloneOrLink(expr, args);
  1184. }
  1185. case no_buildindex:
  1186. case no_output:
  1187. case no_apply:
  1188. case no_distribution:
  1189. case no_keydiff:
  1190. case no_keypatch:
  1191. case no_outputscalar:
  1192. return createTransformed(expr); //NB: Do not common up!!!
  1193. case no_setmeta:
  1194. return LINK(expr);
  1195. default:
  1196. {
  1197. OwnedHqlExpr transformed = transform(expr);
  1198. ITypeInfo * type = transformed->queryType();
  1199. if (type && type->getTypeCode() != type_void)
  1200. {
  1201. HqlExprArray args;
  1202. bool isOuterWorkflow = (op == no_colon) && workflowContainsSchedule(transformed);
  1203. assertex(!isOuterWorkflow || !workflowContainsNonSchedule(transformed));
  1204. if (isOuterWorkflow)
  1205. args.append(*LINK(transformed->queryChild(0)));
  1206. else
  1207. args.append(*LINK(transformed));
  1208. nextSequence(args, NULL, NULL, NULL, true, NULL);
  1209. IHqlExpression * ret = createSetResult(args);
  1210. if (isOuterWorkflow)
  1211. {
  1212. args.kill();
  1213. args.append(*ret);
  1214. unwindChildren(args, transformed, 1);
  1215. ret = transformed->clone(args);
  1216. }
  1217. return ret;
  1218. }
  1219. return LINK(transformed);
  1220. }
  1221. }
  1222. }
  1223. IHqlExpression * SequenceNumberAllocator::createTransformed(IHqlExpression * expr)
  1224. {
  1225. switch (expr->getOperator())
  1226. {
  1227. case no_actionlist:
  1228. return doTransformRootExpr(expr);
  1229. case no_apply:
  1230. {
  1231. HqlExprArray args;
  1232. args.append(*transform(expr->queryChild(0)));
  1233. applyDepth++;
  1234. args.append(*transform(expr->queryChild(1)));
  1235. applyDepth--;
  1236. OwnedHqlExpr ret = completeTransform(expr, args);
  1237. return attachSequenceNumber(ret);
  1238. }
  1239. case no_outputscalar:
  1240. if (applyDepth)
  1241. {
  1242. translator.WARNINGAT(expr, HQLERR_ScalarOutputWithinApply);
  1243. }
  1244. break;
  1245. }
  1246. Owned<IHqlExpression> transformed = NewHqlTransformer::createTransformed(expr);
  1247. return attachSequenceNumber(transformed.get());
  1248. }
  1249. static _ATOM queryOverwriteAction(IHqlExpression * expr)
  1250. {
  1251. if (expr->hasProperty(extendAtom))
  1252. return extendAtom;
  1253. if (expr->hasProperty(overwriteAtom))
  1254. return overwriteAtom;
  1255. if (expr->hasProperty(noOverwriteAtom))
  1256. return noOverwriteAtom;
  1257. return NULL;
  1258. }
  1259. IHqlExpression * SequenceNumberAllocator::attachSequenceNumber(IHqlExpression * expr)
  1260. {
  1261. switch (expr->getOperator())
  1262. {
  1263. case no_buildindex:
  1264. case no_output:
  1265. case no_apply:
  1266. case no_distribution:
  1267. case no_keydiff:
  1268. case no_keypatch:
  1269. {
  1270. queryExtra(expr)->setGetsSequence();
  1271. HqlExprArray args;
  1272. unwindChildren(args, expr);
  1273. bool duplicate = false;
  1274. nextSequence(args, queryResultName(expr), queryOverwriteAction(expr), expr->queryChild(0), true, &duplicate);
  1275. args.append(*createUniqueId());
  1276. return expr->clone(args);
  1277. }
  1278. break;
  1279. case no_outputscalar:
  1280. {
  1281. IHqlExpression * name = queryResultName(expr);
  1282. queryExtra(expr)->setGetsSequence();
  1283. HqlExprArray args;
  1284. args.append(*LINK(expr->queryChild(0)));
  1285. bool duplicate = false;
  1286. nextSequence(args, name, queryOverwriteAction(expr), expr->queryChild(0), true, &duplicate);
  1287. if (name)
  1288. args.append(*createAttribute(namedAtom, LINK(name)));
  1289. args.append(*createAttribute(outputAtom));
  1290. args.append(*createUniqueId());
  1291. return createSetResult(args);
  1292. }
  1293. default:
  1294. return LINK(expr);
  1295. }
  1296. }
  1297. void HqlCppTranslator::allocateSequenceNumbers(HqlExprArray & exprs)
  1298. {
  1299. HqlExprArray sequenced;
  1300. SequenceNumberAllocator transformer(*this);
  1301. transformer.transformRoot(exprs, sequenced);
  1302. replaceArray(exprs, sequenced);
  1303. maxSequence = transformer.getMaxSequence();
  1304. }
  1305. //---------------------------------------------------------------------------
  1306. static void replaceAssignSelector(HqlExprArray & assigns, IHqlExpression * newSelector)
  1307. {
  1308. ForEachItemIn(idx, assigns)
  1309. {
  1310. IHqlExpression & cur = assigns.item(idx);
  1311. IHqlExpression * lhs = cur.queryChild(0);
  1312. IHqlExpression * rhs = cur.queryChild(1);
  1313. assigns.replace(*createAssign(replaceSelector(lhs, queryActiveTableSelector(), newSelector), replaceSelector(rhs, queryActiveTableSelector(), newSelector)), idx);
  1314. }
  1315. }
  1316. static IHqlExpression * createArith(node_operator op, ITypeInfo * type, IHqlExpression * numerator, IHqlExpression * denominator)
  1317. {
  1318. return createValue(op, LINK(type), ensureExprType(numerator, type), ensureExprType(denominator, type));
  1319. }
  1320. //MORE: This might be better as a class, it would reduce the number of parameters
  1321. IHqlExpression * doNormalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts);
  1322. IHqlExpression * evalNormalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts)
  1323. {
  1324. switch (expr->getOperator())
  1325. {
  1326. case no_avegroup:
  1327. //Map this to sum(x)/count(x)
  1328. {
  1329. IHqlExpression * arg = expr->queryChild(0);
  1330. IHqlExpression * cond = expr->queryChild(1);
  1331. Owned<ITypeInfo> sumType = getSumAggType(arg);
  1332. ITypeInfo * exprType = expr->queryType();
  1333. OwnedHqlExpr sum = createValue(no_sumgroup, LINK(sumType), LINK(arg), LINK(cond));
  1334. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1335. //average should be done as a real operation I think, possibly decimal, if argument is decimal
  1336. OwnedHqlExpr avg = createArith(no_div, exprType, sum, count);
  1337. return doNormalizeAggregateExpr(selector, avg, fields, assigns, extraSelectNeeded, false);
  1338. }
  1339. case no_vargroup:
  1340. //Map this to (sum(x^2)-sum(x)^2/count())/count()
  1341. {
  1342. IHqlExpression * arg = expr->queryChild(0);
  1343. IHqlExpression * cond = expr->queryChild(1);
  1344. ITypeInfo * exprType = expr->queryType();
  1345. OwnedHqlExpr xx = createArith(no_mul, exprType, arg, arg);
  1346. OwnedHqlExpr sumxx = createValue(no_sumgroup, LINK(exprType), LINK(xx), LINK(cond));
  1347. OwnedHqlExpr sumx = createValue(no_sumgroup, LINK(exprType), LINK(arg), LINK(cond));
  1348. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1349. //average should be done as a real operation I think, possibly decimal, if argument is decimal
  1350. OwnedHqlExpr n1 = createArith(no_mul, exprType, sumx, sumx);
  1351. OwnedHqlExpr n2 = createArith(no_div, exprType, n1, count);
  1352. OwnedHqlExpr n3 = createArith(no_sub, exprType, sumxx, n2);
  1353. OwnedHqlExpr n4 = createArith(no_div, exprType, n3, count);
  1354. return doNormalizeAggregateExpr(selector, n4, fields, assigns, extraSelectNeeded, false);
  1355. }
  1356. case no_covargroup:
  1357. //Map this to (sum(x.y)-sum(x).sum(y)/count())/count()
  1358. {
  1359. IHqlExpression * argX = expr->queryChild(0);
  1360. IHqlExpression * argY = expr->queryChild(1);
  1361. IHqlExpression * cond = expr->queryChild(2);
  1362. ITypeInfo * exprType = expr->queryType();
  1363. OwnedHqlExpr xy = createArith(no_mul, exprType, argX, argY);
  1364. OwnedHqlExpr sumxy = createValue(no_sumgroup, LINK(exprType), LINK(xy), LINK(cond));
  1365. OwnedHqlExpr sumx = createValue(no_sumgroup, LINK(exprType), LINK(argX), LINK(cond));
  1366. OwnedHqlExpr sumy = createValue(no_sumgroup, LINK(exprType), LINK(argY), LINK(cond));
  1367. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1368. //average should be done as a real operation I think, possibly decimal, if argument is decimal
  1369. OwnedHqlExpr n1 = createArith(no_mul, exprType, sumx, sumy);
  1370. OwnedHqlExpr n2 = createArith(no_div, exprType, n1, count);
  1371. OwnedHqlExpr n3 = createArith(no_sub, exprType, sumxy, n2);
  1372. OwnedHqlExpr n4 = createArith(no_div, exprType, n3, count);
  1373. return doNormalizeAggregateExpr(selector, n4, fields, assigns, extraSelectNeeded, false);
  1374. }
  1375. case no_corrgroup:
  1376. //Map this to (covar(x,y)/(var(x).var(y)))
  1377. //== (sum(x.y)*count() - sum(x).sum(y))/sqrt((sum(x.x)*count()-sum(x)^2) * (sum(y.y)*count()-sum(y)^2))
  1378. {
  1379. IHqlExpression * argX = expr->queryChild(0);
  1380. IHqlExpression * argY = expr->queryChild(1);
  1381. IHqlExpression * cond = expr->queryChild(2);
  1382. ITypeInfo * exprType = expr->queryType();
  1383. OwnedHqlExpr xx = createArith(no_mul, exprType, argX, argX);
  1384. OwnedHqlExpr sumxx = createValue(no_sumgroup, LINK(exprType), LINK(xx), LINK(cond));
  1385. OwnedHqlExpr xy = createArith(no_mul, exprType, argX, argY);
  1386. OwnedHqlExpr sumxy = createValue(no_sumgroup, LINK(exprType), LINK(xy), LINK(cond));
  1387. OwnedHqlExpr yy = createArith(no_mul, exprType, argY, argY);
  1388. OwnedHqlExpr sumyy = createValue(no_sumgroup, LINK(exprType), LINK(yy), LINK(cond));
  1389. OwnedHqlExpr sumx = createValue(no_sumgroup, LINK(exprType), LINK(argX), LINK(cond));
  1390. OwnedHqlExpr sumy = createValue(no_sumgroup, LINK(exprType), LINK(argY), LINK(cond));
  1391. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1392. OwnedHqlExpr n1 = createArith(no_mul, exprType, sumxy, count);
  1393. OwnedHqlExpr n2 = createArith(no_mul, exprType, sumx, sumy);
  1394. OwnedHqlExpr n3 = createArith(no_sub, exprType, n1, n2);
  1395. OwnedHqlExpr n4 = createArith(no_mul, exprType, sumxx, count);
  1396. OwnedHqlExpr n5 = createArith(no_mul, exprType, sumx, sumx);
  1397. OwnedHqlExpr n6 = createArith(no_sub, exprType, n4, n5);
  1398. OwnedHqlExpr n7 = createArith(no_mul, exprType, sumyy, count);
  1399. OwnedHqlExpr n8 = createArith(no_mul, exprType, sumy, sumy);
  1400. OwnedHqlExpr n9 = createArith(no_sub, exprType, n7, n8);
  1401. OwnedHqlExpr n10 = createArith(no_mul, exprType, n6, n9);
  1402. OwnedHqlExpr n11 = createValue(no_sqrt, LINK(exprType), LINK(n10));
  1403. OwnedHqlExpr n12 = createArith(no_div, exprType, n3, n11);
  1404. return doNormalizeAggregateExpr(selector, n12, fields, assigns, extraSelectNeeded, false);
  1405. }
  1406. throwUnexpected();
  1407. case no_variance:
  1408. case no_covariance:
  1409. case no_correlation:
  1410. throwUnexpectedOp(expr->getOperator());
  1411. case no_count:
  1412. case no_sum:
  1413. case no_max:
  1414. case no_min:
  1415. case no_ave:
  1416. case no_select:
  1417. case no_exists:
  1418. case no_field:
  1419. // a count on a child dataset or something else - add it as it is...
  1420. //goes wrong for count(group)*
  1421. return LINK(expr);
  1422. case no_countgroup:
  1423. case no_sumgroup:
  1424. case no_maxgroup:
  1425. case no_mingroup:
  1426. case no_existsgroup:
  1427. {
  1428. ForEachItemIn(idx, assigns)
  1429. {
  1430. IHqlExpression & cur = assigns.item(idx);
  1431. if (cur.queryChild(1) == expr)
  1432. {
  1433. extraSelectNeeded = true;
  1434. return LINK(cur.queryChild(0)); //replaceSelector(cur.queryChild(0), querySelf(), queryActiveTableSelector());
  1435. }
  1436. }
  1437. IHqlExpression * targetField;
  1438. if (selector)
  1439. {
  1440. targetField = LINK(selector->queryChild(1));
  1441. }
  1442. else
  1443. {
  1444. StringBuffer temp;
  1445. temp.append("_agg_").append(assigns.ordinality());
  1446. targetField = createField(createIdentifierAtom(temp.str()), expr->getType(), NULL);
  1447. extraSelectNeeded = true;
  1448. }
  1449. fields.append(*targetField);
  1450. assigns.append(*createAssign(createSelectExpr(getActiveTableSelector(), LINK(targetField)), LINK(expr)));
  1451. return createSelectExpr(getActiveTableSelector(), LINK(targetField));
  1452. }
  1453. case no_cast:
  1454. case no_implicitcast:
  1455. if (selector && canOptimizeCasts)
  1456. {
  1457. IHqlExpression * child = expr->queryChild(0);
  1458. if (expr->queryType()->getTypeCode() == child->queryType()->getTypeCode())
  1459. {
  1460. IHqlExpression * ret = doNormalizeAggregateExpr(selector, child, fields, assigns, extraSelectNeeded, false);
  1461. //This should be ret==child
  1462. if (ret == selector)
  1463. return ret;
  1464. HqlExprArray args;
  1465. args.append(*ret);
  1466. return expr->clone(args);
  1467. }
  1468. }
  1469. //fallthrough...
  1470. default:
  1471. {
  1472. HqlExprArray args;
  1473. unsigned max = expr->numChildren();
  1474. unsigned idx;
  1475. bool diff = false;
  1476. args.ensure(max);
  1477. for (idx = 0; idx < max; idx++)
  1478. {
  1479. IHqlExpression * child = expr->queryChild(idx);
  1480. IHqlExpression * changed = doNormalizeAggregateExpr(NULL, child, fields, assigns, extraSelectNeeded, false);
  1481. args.append(*changed);
  1482. if (child != changed)
  1483. diff = true;
  1484. }
  1485. if (diff)
  1486. return expr->clone(args);
  1487. return LINK(expr);
  1488. }
  1489. }
  1490. }
  1491. IHqlExpression * doNormalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts)
  1492. {
  1493. IHqlExpression * match = static_cast<IHqlExpression *>(expr->queryTransformExtra());
  1494. if (match)
  1495. return LINK(match);
  1496. IHqlExpression * ret = evalNormalizeAggregateExpr(selector, expr, fields, assigns, extraSelectNeeded, canOptimizeCasts);
  1497. expr->setTransformExtra(ret);
  1498. return ret;
  1499. }
  1500. IHqlExpression * normalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts)
  1501. {
  1502. TransformMutexBlock block;
  1503. return doNormalizeAggregateExpr(selector, expr, fields, assigns, extraSelectNeeded, canOptimizeCasts);
  1504. }
  1505. //---------------------------------------------------------------------------
  1506. static void appendComponent(HqlExprArray & cpts, bool invert, IHqlExpression * expr)
  1507. {
  1508. if (invert)
  1509. cpts.append(*createValue(no_negate, expr->getType(), LINK(expr)));
  1510. else
  1511. cpts.append(*LINK(expr));
  1512. }
  1513. static void expandRowComponents(HqlExprArray & cpts, bool invert, IHqlExpression * select, IHqlExpression * record)
  1514. {
  1515. ForEachChild(i, record)
  1516. {
  1517. IHqlExpression * cur = record->queryChild(i);
  1518. switch (cur->getOperator())
  1519. {
  1520. case no_record:
  1521. expandRowComponents(cpts, invert, select, cur);
  1522. break;
  1523. case no_ifblock:
  1524. expandRowComponents(cpts, invert, select, cur->queryChild(1));
  1525. break;
  1526. case no_field:
  1527. {
  1528. OwnedHqlExpr childSelect = createSelectExpr(LINK(select), LINK(cur));
  1529. if (!childSelect->isDatarow())
  1530. appendComponent(cpts, invert, childSelect);
  1531. else
  1532. expandRowComponents(cpts, invert, childSelect, childSelect->queryRecord());
  1533. break;
  1534. }
  1535. }
  1536. }
  1537. }
  1538. static IHqlExpression * simplifySortlistComplexity(IHqlExpression * sortlist)
  1539. {
  1540. if (!sortlist)
  1541. return NULL;
  1542. //convert concat on fixed width strings to a list of fields.
  1543. bool same = true;
  1544. HqlExprArray cpts;
  1545. ForEachChild(idx, sortlist)
  1546. {
  1547. IHqlExpression * cpt = sortlist->queryChild(idx);
  1548. IHqlExpression * cur = cpt;
  1549. bool expand = false;
  1550. bool invert = false;
  1551. if (cpt->getOperator() == no_negate)
  1552. {
  1553. invert = true;
  1554. cur = cur->queryChild(0);
  1555. }
  1556. if (cur->getOperator() == no_concat)
  1557. {
  1558. HqlExprArray concats;
  1559. cur->unwindList(concats, no_concat);
  1560. expand = true;
  1561. ForEachItemIn(idxc, concats)
  1562. {
  1563. ITypeInfo * type = concats.item(idxc).queryType();
  1564. unsigned tc = type->getTypeCode();
  1565. if (!((tc == type_string || tc == type_data) && (type->getSize() != UNKNOWN_LENGTH)))
  1566. expand = false;
  1567. }
  1568. if (expand)
  1569. {
  1570. ForEachItemIn(idxc, concats)
  1571. appendComponent(cpts, invert, &concats.item(idxc));
  1572. }
  1573. }
  1574. else
  1575. {
  1576. #if 0
  1577. if (cur->getOperator() == no_select && cur->isDatarow() && !cur->hasProperty(newAtom))
  1578. {
  1579. expand = true;
  1580. expandRowComponents(cpts, invert, cur, cur->queryRecord());
  1581. }
  1582. #endif
  1583. }
  1584. if (!expand)
  1585. cpts.append(*LINK(cpt));
  1586. else
  1587. same = false;
  1588. }
  1589. if (!same)
  1590. return createSortList(cpts);
  1591. return NULL;
  1592. }
  1593. static IHqlExpression * normalizeIndexBuild(IHqlExpression * expr, bool sortIndexPayload, bool alwaysLocal, bool allowImplicitSubSort)
  1594. {
  1595. LinkedHqlExpr dataset = expr->queryChild(0);
  1596. IHqlExpression * normalizedDs = dataset->queryNormalizedSelector();
  1597. IHqlExpression * buildRecord = dataset->queryRecord();
  1598. // If any field types collate differently before and after translation to their hozed
  1599. // format, then we need to do the translation here, otherwise this
  1600. // sort may not be in the correct order. (ebcdic->ascii? integers are ok; unicode isn't!)
  1601. // First build the sort order we need....
  1602. HqlExprArray sorts;
  1603. gatherIndexBuildSortOrder(sorts, expr, sortIndexPayload);
  1604. OwnedHqlExpr sortOrder = createSortList(sorts);
  1605. OwnedHqlExpr newsort = simplifySortlistComplexity(sortOrder);
  1606. if (!newsort)
  1607. newsort.set(sortOrder);
  1608. ForEachChild(i1, expr)
  1609. {
  1610. IHqlExpression * cur = expr->queryChild(i1);
  1611. if (cur->getOperator() == no_distributer)
  1612. {
  1613. LinkedHqlExpr ds = dataset;
  1614. IHqlExpression * index = cur->queryChild(0);
  1615. if (!expr->hasProperty(sortedAtom))
  1616. {
  1617. if (!expr->hasProperty(localAtom))
  1618. {
  1619. HqlExprArray joinCondition;
  1620. IHqlExpression * indexRecord = index->queryChild(1);
  1621. assertex(indexRecord->numChildren() == buildRecord->numChildren());
  1622. unsigned numFields = firstPayloadField(index);
  1623. OwnedHqlExpr seq = createSelectorSequence();
  1624. OwnedHqlExpr left = createSelector(no_left, dataset, seq);
  1625. OwnedHqlExpr right = createSelector(no_right, index, seq);
  1626. OwnedHqlExpr cond;
  1627. unsigned idxLhs = 0;
  1628. unsigned idxRhs = 0;
  1629. for (unsigned i2=0; i2 < numFields; i2++)
  1630. {
  1631. IHqlExpression * lhs = createSelectExpr(LINK(left), LINK(queryNextRecordField(buildRecord, idxLhs)));
  1632. IHqlExpression * rhs = createSelectExpr(LINK(right), LINK(queryNextRecordField(indexRecord, idxRhs)));
  1633. IHqlExpression * test = createBoolExpr(no_eq, lhs, rhs);
  1634. extendConditionOwn(cond, no_and, test);
  1635. }
  1636. HqlExprArray args;
  1637. args.append(*ds.getClear());
  1638. args.append(*LINK(index));
  1639. args.append(*cond.getClear());
  1640. args.append(*LINK(seq));
  1641. ds.setown(createDataset(no_keyeddistribute, args));
  1642. ds.setown(cloneInheritedAnnotations(expr, ds));
  1643. }
  1644. ds.setown(createDataset(no_sort, ds.getClear(), createComma(LINK(newsort), createLocalAttribute())));
  1645. ds.setown(cloneInheritedAnnotations(expr, ds));
  1646. }
  1647. if (expr->hasProperty(mergeAtom))
  1648. {
  1649. LinkedHqlExpr sortedIndex = index;
  1650. if (!index->hasProperty(sortedAtom))
  1651. {
  1652. HqlExprArray args;
  1653. unwindChildren(args, index);
  1654. args.append(*createAttribute(sortedAtom));
  1655. sortedIndex.setown(index->clone(args));
  1656. }
  1657. HqlExprArray sorts;
  1658. unwindChildren(sorts, newsort);
  1659. OwnedHqlExpr sortAttr = createExprAttribute(sortedAtom, sorts);
  1660. HqlExprArray args;
  1661. args.append(*LINK(ds));
  1662. args.append(*sortedIndex.getClear());
  1663. args.append(*createLocalAttribute());
  1664. args.append(*replaceSelector(sortAttr, ds->queryNormalizedSelector(), queryActiveTableSelector()));
  1665. ds.setown(createDataset(no_merge, args));
  1666. ds.setown(cloneInheritedAnnotations(expr, ds));
  1667. }
  1668. HqlExprArray args;
  1669. unwindChildren(args, expr);
  1670. args.replace(*ds.getClear(), 0);
  1671. args.remove(i1);
  1672. args.append(*createAttribute(sortedAtom));
  1673. args.append(*createLocalAttribute());
  1674. args.append(*createAttribute(indexAtom, LINK(index->queryChild(3))));
  1675. return expr->clone(args);
  1676. }
  1677. }
  1678. IHqlExpression * distributed = expr->queryProperty(distributedAtom);
  1679. if (distributed && distributed->queryChild(0))
  1680. {
  1681. OwnedHqlExpr distribute = createDataset(no_distribute, LINK(dataset), LINK(distributed->queryChild(0)));
  1682. distribute.setown(cloneInheritedAnnotations(expr, distribute));
  1683. HqlExprArray args;
  1684. args.append(*distribute.getClear());
  1685. unwindChildren(args, expr, 1);
  1686. args.zap(*distributed);
  1687. return expr->clone(args);
  1688. }
  1689. if (!expr->hasProperty(sortedAtom))
  1690. {
  1691. if (dataset->queryType()->getTypeCode() == type_groupedtable)
  1692. {
  1693. while (dataset->getOperator() == no_group)
  1694. dataset.set(dataset->queryChild(0));
  1695. if (dataset->queryType()->getTypeCode() == type_groupedtable)
  1696. {
  1697. dataset.setown(createDataset(no_group, LINK(dataset), NULL));
  1698. dataset.setown(cloneInheritedAnnotations(expr, dataset));
  1699. }
  1700. }
  1701. OwnedHqlExpr sorted = ensureSorted(dataset, newsort, expr->hasProperty(localAtom), true, alwaysLocal, allowImplicitSubSort);
  1702. if (sorted == dataset)
  1703. return NULL;
  1704. sorted.setown(inheritAttribute(sorted, expr, skewAtom));
  1705. sorted.setown(inheritAttribute(sorted, expr, thresholdAtom));
  1706. HqlExprArray args;
  1707. args.append(*LINK(sorted));
  1708. unwindChildren(args, expr, 1);
  1709. args.append(*createAttribute(sortedAtom));
  1710. return expr->clone(args);
  1711. }
  1712. if (expr->hasProperty(dedupAtom))
  1713. {
  1714. IHqlExpression * ds = expr->queryChild(0);
  1715. OwnedHqlExpr seq = createSelectorSequence();
  1716. OwnedHqlExpr mappedSortList = replaceSelector(newsort, queryActiveTableSelector(), ds);
  1717. HqlExprArray dedupArgs;
  1718. dedupArgs.append(*LINK(expr->queryChild(0)));
  1719. unwindChildren(dedupArgs, mappedSortList);
  1720. dedupArgs.append(*createLocalAttribute());
  1721. dedupArgs.append(*LINK(seq));
  1722. OwnedHqlExpr dedup = createDataset(no_dedup, dedupArgs);
  1723. HqlExprArray buildArgs;
  1724. buildArgs.append(*cloneInheritedAnnotations(expr, dedup));
  1725. unwindChildren(buildArgs, expr, 1);
  1726. removeProperty(buildArgs, dedupAtom);
  1727. return expr->clone(buildArgs);
  1728. }
  1729. return NULL;
  1730. }
  1731. static HqlTransformerInfo thorHqlTransformerInfo("ThorHqlTransformer");
  1732. ThorHqlTransformer::ThorHqlTransformer(HqlCppTranslator & _translator, ClusterType _targetClusterType, IConstWorkUnit * wu)
  1733. : NewHqlTransformer(thorHqlTransformerInfo), translator(_translator), options(_translator.queryOptions())
  1734. {
  1735. targetClusterType = _targetClusterType;
  1736. topNlimit = options.topnLimit;
  1737. groupAllDistribute = isThorCluster(targetClusterType) && options.groupAllDistribute;
  1738. }
  1739. IHqlExpression * ThorHqlTransformer::createTransformed(IHqlExpression * expr)
  1740. {
  1741. OwnedHqlExpr transformed = PARENT::createTransformed(expr);
  1742. updateOrphanedSelectors(transformed, expr);
  1743. IHqlExpression * normalized = NULL;
  1744. switch (transformed->getOperator())
  1745. {
  1746. case no_group:
  1747. normalized = normalizeGroup(transformed);
  1748. break;
  1749. case no_join:
  1750. case no_selfjoin:
  1751. case no_denormalize:
  1752. case no_denormalizegroup:
  1753. normalized = normalizeJoinOrDenormalize(transformed);
  1754. break;
  1755. case no_cosort:
  1756. case no_sort:
  1757. case no_sorted:
  1758. case no_assertsorted:
  1759. normalized = normalizeSort(transformed);
  1760. break;
  1761. case no_subsort:
  1762. normalized = normalizeSubSort(transformed);
  1763. break;
  1764. case no_cogroup:
  1765. normalized = normalizeCoGroup(transformed);
  1766. break;
  1767. case no_choosen:
  1768. normalized = normalizeChooseN(transformed);
  1769. break;
  1770. case no_aggregate:
  1771. normalized = normalizeTableGrouping(transformed);
  1772. break;
  1773. case no_newusertable:
  1774. normalized = normalizeTableGrouping(transformed);
  1775. if (!normalized)
  1776. normalized = normalizeTableToAggregate(expr, true);
  1777. break;
  1778. case no_newaggregate:
  1779. normalized = normalizePrefetchAggregate(transformed);
  1780. break;
  1781. case no_dedup:
  1782. normalized = normalizeDedup(transformed);
  1783. break;
  1784. case no_rollup:
  1785. normalized = normalizeRollup(transformed);
  1786. break;
  1787. case no_select:
  1788. normalized = normalizeSelect(transformed);
  1789. break;
  1790. case no_temptable:
  1791. normalized = normalizeTempTable(transformed);
  1792. break;
  1793. //MORE should do whole aggregate expression e.g., max(x)-min(x)
  1794. case NO_AGGREGATE:
  1795. normalized = normalizeScalarAggregate(transformed);
  1796. break;
  1797. case no_setresult:
  1798. normalized = convertSetResultToExtract(transformed);
  1799. break;
  1800. case no_projectrow:
  1801. {
  1802. IHqlExpression * ds = transformed->queryChild(0);
  1803. if (isAlwaysActiveRow(ds))
  1804. {
  1805. //Transform PROJECT(row, transform) to a ROW(transform') since more efficient
  1806. OwnedHqlExpr myLeft = createSelector(no_left, ds, querySelSeq(transformed));
  1807. OwnedHqlExpr replaced = replaceSelector(transformed->queryChild(1), myLeft, ds);
  1808. normalized = createRow(no_createrow, LINK(replaced));
  1809. }
  1810. break;
  1811. }
  1812. case no_debug_option_value:
  1813. //pick best engine etc. definitely done by now, so substitute any options that haven't been processed already
  1814. return getDebugValueExpr(translator.wu(), expr);
  1815. }
  1816. if (normalized)
  1817. {
  1818. transformed.setown(transform(normalized));
  1819. normalized->Release();
  1820. }
  1821. /*
  1822. //Has a minor impact on unnecessary local attributes
  1823. if (!translator.targetThor() && transformed->hasProperty(localAtom) && localChangesActivityAction(transformed))
  1824. return removeProperty(transformed, localAtom);
  1825. */
  1826. return transformed.getClear();
  1827. }
  1828. static IHqlExpression * convertDedupToGroupedDedup(IHqlExpression * expr, IHqlExpression * grouping, bool compareAll)
  1829. {
  1830. IHqlExpression * localAttr = expr->queryProperty(localAtom);
  1831. HqlExprArray groupArgs;
  1832. groupArgs.append(*LINK(expr->queryChild(0)));
  1833. groupArgs.append(*LINK(grouping));
  1834. if (compareAll)
  1835. groupArgs.append(*createAttribute(allAtom));
  1836. if (localAttr)
  1837. groupArgs.append(*LINK(localAttr));
  1838. //Ideally this would remove the equality conditions from the dedup, but ok since they are ignored later when generating
  1839. OwnedHqlExpr group = createDataset(no_group, groupArgs);
  1840. group.setown(cloneInheritedAnnotations(expr, group));
  1841. HqlExprArray dedupArgs;
  1842. dedupArgs.append(*LINK(group));
  1843. unwindChildren(dedupArgs, expr, 1);
  1844. removeProperty(dedupArgs, localAtom); //(since now a grouped dedup)
  1845. OwnedHqlExpr ungroup = createDataset(no_group, expr->clone(dedupArgs), NULL);
  1846. return cloneInheritedAnnotations(expr, ungroup);
  1847. }
  1848. IHqlExpression * ThorHqlTransformer::normalizeDedup(IHqlExpression * expr)
  1849. {
  1850. if (isGroupedActivity(expr))
  1851. {
  1852. //MORE: It should be possible to remove ,ALL if no conditions and
  1853. //the equalities (ignoring any grouping conditions) match the group sort order
  1854. return NULL;
  1855. }
  1856. // DEDUP, ALL, local: - pre sort the data, group, dedup and ungroup
  1857. // DEDUP, ALL, global - if just had a sort by any of the criteria then do it local
  1858. // DEDUP, not all, not grouped, group by criteria, dedup, degroup
  1859. DedupInfoExtractor info(expr);
  1860. if (info.equalities.ordinality() == 0)
  1861. return NULL;
  1862. IHqlExpression * dataset = expr->queryChild(0);
  1863. bool hasLocal = isLocalActivity(expr);
  1864. bool isLocal = hasLocal || !translator.targetThor();
  1865. bool isHashDedup = expr->hasProperty(hashAtom);
  1866. if (info.compareAllRows)
  1867. {
  1868. IHqlExpression * manyProp = expr->queryProperty(manyAtom);
  1869. if (!isLocal && manyProp)
  1870. {
  1871. //If lots of duplicates, then dedup all locally and then dedup all globally.
  1872. HqlExprArray localArgs;
  1873. unwindChildren(localArgs, expr);
  1874. localArgs.zap(*manyProp);
  1875. localArgs.append(*createLocalAttribute());
  1876. OwnedHqlExpr localDedup = expr->clone(localArgs);
  1877. HqlExprArray globalArgs;
  1878. globalArgs.append(*localDedup.getClear());
  1879. unwindChildren(globalArgs, expr, 1);
  1880. globalArgs.zap(*manyProp);
  1881. return expr->clone(globalArgs);
  1882. }
  1883. }
  1884. //If a dedup can be done locally then force it to be local
  1885. if (!isLocal)
  1886. {
  1887. OwnedHqlExpr newSort = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  1888. if (isPartitionedForGroup(dataset, newSort, info.compareAllRows))
  1889. {
  1890. OwnedHqlExpr ret = appendOwnedOperand(expr, createLocalAttribute());
  1891. //A global all join implies hash (historically) so preserve that semantic
  1892. if (info.compareAllRows && !isHashDedup)
  1893. return appendOwnedOperand(ret, createAttribute(hashAtom));
  1894. return ret.getClear();
  1895. }
  1896. }
  1897. //DEDUP,ALL
  1898. if (info.compareAllRows)
  1899. {
  1900. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  1901. bool checkLocal = isLocal || (options.supportsMergeDistribute && !isHashDedup);
  1902. //If the dataset is already sorted for deduping, (and no extra tests) then
  1903. //if local can just remove the ALL attribute, since the records are already adjacent.
  1904. //if global remove the all, but enclose the dedup in a group to avoid serial processing
  1905. //Ignore HASH if specified since this has to be more efficient.
  1906. if (info.conds.ordinality() == 0)
  1907. {
  1908. bool alreadySorted = isSortedForGroup(dataset, groupOrder, checkLocal);
  1909. if (alreadySorted)
  1910. {
  1911. OwnedHqlExpr noHash = removeProperty(expr, hashAtom);
  1912. OwnedHqlExpr noAll = removeProperty(noHash, allAtom);
  1913. if (isLocal)
  1914. return noAll.getClear();
  1915. return convertDedupToGroupedDedup(noAll, groupOrder, checkLocal && !isLocal);
  1916. }
  1917. }
  1918. if (!isHashDedup)
  1919. {
  1920. //If has post non equality condition, change it to a group all->dedup->ungroup
  1921. if (info.conds.ordinality())
  1922. return convertDedupToGroupedDedup(expr, groupOrder, true);
  1923. //If local and thor (since hash dedup may overflow) convert to sort, dedup(not all)
  1924. //Otherwise a hashdedup is likely to be more efficient - since it will be linear cf O(NlnN) for the sort
  1925. if (hasLocal && translator.targetThor())
  1926. {
  1927. HqlExprArray dedupArgs;
  1928. dedupArgs.append(*ensureSortedForGroup(dataset, groupOrder, true, false, options.implicitGroupSubSort));
  1929. unwindChildren(dedupArgs, expr, 1);
  1930. removeProperty(dedupArgs, allAtom);
  1931. return expr->clone(dedupArgs);
  1932. }
  1933. else
  1934. {
  1935. if (matchesConstantValue(info.numToKeep, 1) && !info.keepLeft)
  1936. return appendOwnedOperand(expr, createAttribute(hashAtom));
  1937. }
  1938. }
  1939. }
  1940. else
  1941. {
  1942. //Convert dedup(ds, exprs) to group(dedup(group(ds, exprs), exprs))
  1943. //To ensure that the activity isn't executed serially.
  1944. if (!isLocal && !areConstant(info.equalities))
  1945. {
  1946. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  1947. return convertDedupToGroupedDedup(expr, groupOrder, false);
  1948. }
  1949. }
  1950. return NULL;
  1951. }
  1952. IHqlExpression * ThorHqlTransformer::normalizeRollup(IHqlExpression * expr)
  1953. {
  1954. if (isGroupedActivity(expr))
  1955. return NULL;
  1956. IHqlExpression * dataset = expr->queryChild(0);
  1957. IHqlExpression * cond = expr->queryChild(1);
  1958. if (isThorCluster(targetClusterType) && !expr->queryProperty(localAtom) && isIndependentOfScope(expr))
  1959. {
  1960. HqlExprArray equalities;
  1961. OwnedHqlExpr extra;
  1962. if (cond->getOperator() == no_sortlist)
  1963. cond->unwindList(equalities, no_sortlist);
  1964. else if (!cond->isBoolean())
  1965. equalities.append(*LINK(cond));
  1966. else
  1967. {
  1968. HqlExprArray terms;
  1969. cond->unwindList(terms, no_and);
  1970. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(expr));
  1971. OwnedHqlExpr right = createSelector(no_right, dataset, querySelSeq(expr));
  1972. ForEachItemIn(i, terms)
  1973. {
  1974. IHqlExpression & cur = terms.item(i);
  1975. bool matched = false;
  1976. if (cur.getOperator() == no_eq)
  1977. {
  1978. OwnedHqlExpr mappedLeft = replaceSelector(cur.queryChild(0), left, dataset);
  1979. OwnedHqlExpr mappedRight = replaceSelector(cur.queryChild(1), right, dataset);
  1980. if (mappedLeft == mappedRight)
  1981. {
  1982. equalities.append(*LINK(mappedLeft));
  1983. matched = true;
  1984. }
  1985. }
  1986. if (!matched)
  1987. extendConditionOwn(extra, no_and, LINK(&cur));
  1988. }
  1989. }
  1990. //Don't create a group by constant - it will kill thor!
  1991. ForEachItemInRev(ie, equalities)
  1992. if (equalities.item(ie).isConstant())
  1993. equalities.remove(ie);
  1994. if (equalities.ordinality())
  1995. {
  1996. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(expr));
  1997. //If anything in the join condition references LEFT then the whole condition is currently passed the modified row
  1998. //so remove any fields that are modified in the transform
  1999. HqlExprArray ambiguousSelects;
  2000. if (cond->usesSelector(left))
  2001. filterAmbiguousRollupCondition(ambiguousSelects, equalities, expr);
  2002. if (equalities.ordinality() == 0)
  2003. {
  2004. translator.reportWarning(queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupNoGroup));
  2005. }
  2006. else
  2007. {
  2008. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), equalities);
  2009. if (isPartitionedForGroup(dataset, groupOrder, false))
  2010. return appendOwnedOperand(expr, createLocalAttribute());
  2011. //This list can only contain items if the filter is using left/right => expand to an equality
  2012. IHqlExpression * selector = dataset->queryNormalizedSelector();
  2013. OwnedHqlExpr right = createSelector(no_right, dataset, querySelSeq(expr));
  2014. ForEachItemIn(i, ambiguousSelects)
  2015. {
  2016. IHqlExpression * select = &ambiguousSelects.item(i);
  2017. OwnedHqlExpr leftSelect = replaceSelector(select, selector, left);
  2018. OwnedHqlExpr rightSelect = replaceSelector(select, selector, right);
  2019. IHqlExpression * eq = createBoolExpr(no_eq, leftSelect.getClear(), rightSelect.getClear());
  2020. extendConditionOwn(extra, no_and, eq);
  2021. }
  2022. HqlExprArray groupArgs, rollupArgs;
  2023. groupArgs.append(*LINK(dataset));
  2024. groupArgs.append(*LINK(groupOrder));
  2025. OwnedHqlExpr group = createDataset(no_group, groupArgs);
  2026. group.setown(cloneInheritedAnnotations(expr, group));
  2027. rollupArgs.append(*LINK(group));
  2028. if (extra)
  2029. rollupArgs.append(*extra.getClear());
  2030. else
  2031. rollupArgs.append(*createConstant(true));
  2032. unwindChildren(rollupArgs, expr, 2);
  2033. OwnedHqlExpr ungroup = createDataset(no_group, expr->clone(rollupArgs), NULL);
  2034. return cloneInheritedAnnotations(expr, ungroup);
  2035. }
  2036. }
  2037. }
  2038. return NULL;
  2039. }
  2040. IHqlExpression * ThorHqlTransformer::skipOverGroups(IHqlExpression * dataset, bool isLocal)
  2041. {
  2042. //if grouping a group, remove the initial group.
  2043. //Not completely sure about this - it may potentially cause extra splitters.
  2044. IHqlExpression * newDataset = dataset;
  2045. while (newDataset->getOperator() == no_group)
  2046. {
  2047. if (newDataset->hasProperty(allAtom))
  2048. break;
  2049. if (isLocal && queryRealChild(newDataset, 1))
  2050. {
  2051. //NOTE: local groups should not remove preceding non-local groups.
  2052. if (translator.targetThor() && !newDataset->hasProperty(localAtom))
  2053. break;
  2054. }
  2055. newDataset = newDataset->queryChild(0);
  2056. }
  2057. return newDataset;
  2058. }
  2059. IHqlExpression * ThorHqlTransformer::skipGroupsWithinGroup(IHqlExpression * expr, bool isLocal)
  2060. {
  2061. //if grouping a group, remove the initial group.
  2062. //Not completely sure about this - it may potentially cause extra splitters.
  2063. IHqlExpression * dataset = expr->queryChild(0);
  2064. if (dataset->getOperator() == no_group)
  2065. {
  2066. IHqlExpression * newDataset = skipOverGroups(dataset, isLocal);
  2067. if (newDataset == dataset)
  2068. return NULL;
  2069. //if we end up with the original grouping then probably have ungroup(group(x,y))
  2070. //so no need to do this group either
  2071. if (queryGrouping(newDataset) == queryGrouping(expr))
  2072. return LINK(newDataset);
  2073. return replaceChild(expr, 0, newDataset);
  2074. }
  2075. return NULL;
  2076. }
  2077. IHqlExpression * ThorHqlTransformer::normalizeGroup(IHqlExpression * expr)
  2078. {
  2079. assertex(expr->getOperator() == no_group);
  2080. IHqlExpression * sortlist = queryRealChild(expr, 1);
  2081. IHqlExpression * dataset = expr->queryChild(0);
  2082. if (!sortlist)
  2083. return skipGroupsWithinGroup(expr, false);
  2084. OwnedHqlExpr newsort = simplifySortlistComplexity(sortlist);
  2085. if (newsort)
  2086. return replaceChild(expr, 1, newsort);
  2087. bool hasLocal = expr->hasProperty(localAtom);
  2088. bool isLocal = hasLocal || !translator.targetThor();
  2089. bool wantSorted = expr->hasProperty(sortedAtom);
  2090. bool hasAll = expr->hasProperty(allAtom);
  2091. // First check if a global group can be done locally - applicable to all and non-all versions.
  2092. if (!isLocal)
  2093. {
  2094. if (!wantSorted && isPartitionedForGroup(dataset, sortlist, hasAll))
  2095. return appendLocalAttribute(expr);
  2096. }
  2097. if (!hasAll)
  2098. {
  2099. //if grouping a group, remove the initial group.
  2100. //Not completely sure about this - it may potentially cause extra splitters.
  2101. return skipGroupsWithinGroup(expr, isLocal);
  2102. }
  2103. //First check to see if the dataset is already sorted by the group criteria, or more.
  2104. //The the data could be globally sorted, but not distributed, and this is likely to be more efficient than redistributing...
  2105. OwnedHqlExpr sorted = ensureSortedForGroup(dataset, sortlist, hasLocal, !translator.targetThor(), options.implicitGroupSubSort);
  2106. if (sorted == dataset)
  2107. return removeProperty(expr, allAtom);
  2108. sorted.setown(cloneInheritedAnnotations(expr, sorted));
  2109. sorted.setown(inheritAttribute(sorted, expr, skewAtom));
  2110. sorted.setown(inheritAttribute(sorted, expr, thresholdAtom));
  2111. if (!isLocal)
  2112. {
  2113. //Options for ensuring distributed and locally sorted (in order)
  2114. // DISTRIBUTE,MERGE - since lightweight and streaming.
  2115. // DISTRIBUTE,LOCAL SORT
  2116. // SORT
  2117. if (!wantSorted)
  2118. {
  2119. //is it best to hash on all the grouping fields, or just some of them? Do all for the moment.
  2120. OwnedHqlExpr hashed = createValue(no_hash32, LINK(unsignedType), LINK(sortlist), createAttribute(internalAtom));
  2121. if (options.supportsMergeDistribute && isSortedForGroup(dataset, sortlist, true))
  2122. {
  2123. //Dataset is locally sorted, so can use the merge distribute to remove the subsequent local sort.
  2124. //changing a heavyweight global sort into a lightweight distribute,merge
  2125. OwnedHqlExpr sortOrder = getExistingSortOrder(dataset, true, true);
  2126. OwnedHqlExpr mergeAttr = createExprAttribute(mergeAtom, replaceSelector(sortOrder, queryActiveTableSelector(), dataset));
  2127. sorted.setown(createDatasetF(no_distribute, LINK(dataset), LINK(hashed), mergeAttr.getClear(), NULL));
  2128. sorted.setown(cloneInheritedAnnotations(expr, sorted));
  2129. }
  2130. else
  2131. {
  2132. if (groupAllDistribute || expr->hasProperty(unsortedAtom))
  2133. {
  2134. OwnedHqlExpr distributed = createDataset(no_distribute, LINK(dataset), LINK(hashed));
  2135. distributed.setown(cloneInheritedAnnotations(expr, distributed));
  2136. sorted.setown(createDataset(no_sort, LINK(distributed), createComma(LINK(sortlist), createLocalAttribute())));
  2137. sorted.setown(cloneInheritedAnnotations(expr, sorted));
  2138. }
  2139. }
  2140. }
  2141. #ifdef _DEBUG
  2142. assertex(!sortlist->isPure() || isPartitionedForGroup(sorted, sortlist, true)); // sanity check
  2143. #endif
  2144. }
  2145. //Do a local group after the sort because we know they can't overlap...
  2146. OwnedHqlExpr ret = createDatasetF(no_group, sorted.getClear(), LINK(sortlist), createLocalAttribute(), NULL);
  2147. return expr->cloneAllAnnotations(ret);
  2148. }
  2149. IHqlExpression * ThorHqlTransformer::normalizeCoGroup(IHqlExpression * expr)
  2150. {
  2151. IHqlExpression * grouping = queryPropertyChild(expr, groupAtom, 0);
  2152. OwnedHqlExpr newsort = simplifySortlistComplexity(grouping);
  2153. if (newsort)
  2154. {
  2155. OwnedHqlExpr newGroup = createExprAttribute(groupAtom, newsort.getClear());
  2156. return replaceOwnedProperty(expr, newGroup.getClear());
  2157. }
  2158. HqlExprArray inputs;
  2159. //Gather the inputs and ensure they aren't grouped.
  2160. ForEachChild(i, expr)
  2161. {
  2162. IHqlExpression * cur = expr->queryChild(i);
  2163. if (!cur->isAttribute())
  2164. {
  2165. if (isGrouped(cur))
  2166. {
  2167. OwnedHqlExpr ungroup = createDataset(no_group, LINK(cur));
  2168. inputs.append(*cloneInheritedAnnotations(expr, ungroup));
  2169. }
  2170. else
  2171. inputs.append(*LINK(cur));
  2172. }
  2173. }
  2174. bool hasLocal = expr->hasProperty(localAtom);
  2175. bool alwaysLocal = !translator.targetThor();
  2176. bool isLocal = hasLocal || alwaysLocal;
  2177. OwnedHqlExpr localFlag = !alwaysLocal ? createLocalAttribute() : NULL;
  2178. OwnedHqlExpr bestSortOrder;
  2179. //Choose the best existing sort order (for the moment assume the shortest - although
  2180. //even better would be to pick the shortest most frequent
  2181. ForEachItemIn(iBest, inputs)
  2182. {
  2183. if (isSortedForGroup(&inputs.item(iBest), grouping, true))
  2184. {
  2185. OwnedHqlExpr localOrder = getExistingSortOrder(&inputs.item(iBest), true, true);
  2186. if (!bestSortOrder || (localOrder->numChildren() < bestSortOrder->numChildren()))
  2187. bestSortOrder.set(localOrder);
  2188. }
  2189. }
  2190. if (!isLocal)
  2191. {
  2192. //Ensure all the inputs are co-distributed (use an existing distribution if possible)
  2193. //Even better would be to pick the most frequent
  2194. OwnedHqlExpr distribution;
  2195. ForEachItemIn(i, inputs)
  2196. {
  2197. IHqlExpression & cur = inputs.item(i);
  2198. if (isPartitionedForGroup(&cur, grouping, true))
  2199. {
  2200. IHqlExpression * curDistribution = queryDistribution(&cur);
  2201. if (!isSortDistribution(curDistribution))
  2202. {
  2203. distribution.set(curDistribution);
  2204. break;
  2205. }
  2206. }
  2207. }
  2208. if (!distribution)
  2209. distribution.setown(createValue(no_hash32, LINK(unsignedType), LINK(grouping), createAttribute(internalAtom)));
  2210. ForEachItemIn(iReplace, inputs)
  2211. {
  2212. IHqlExpression & cur = inputs.item(iReplace);
  2213. if (queryDistribution(&cur) != distribution)
  2214. {
  2215. OwnedHqlExpr mappedDistribution = replaceSelector(distribution, queryActiveTableSelector(), &cur);
  2216. OwnedHqlExpr mergeAttr;
  2217. if (bestSortOrder && isAlreadySorted(&cur, bestSortOrder, true, true))
  2218. mergeAttr.setown(createExprAttribute(mergeAtom, replaceSelector(bestSortOrder, queryActiveTableSelector(), &cur)));
  2219. OwnedHqlExpr distributedInput = createDatasetF(no_distribute, LINK(&cur), LINK(mappedDistribution), mergeAttr.getClear(), NULL);
  2220. distributedInput.setown(cloneInheritedAnnotations(expr, distributedInput));
  2221. inputs.replace(*distributedInput.getClear(), iReplace);
  2222. }
  2223. }
  2224. }
  2225. OwnedHqlExpr merged;
  2226. if (bestSortOrder)
  2227. {
  2228. //If some of the datasets are sorted then sort the remaining inputs by the same order and merge
  2229. HqlExprArray sortedInputs;
  2230. ForEachItemIn(i, inputs)
  2231. {
  2232. IHqlExpression & cur = inputs.item(i);
  2233. OwnedHqlExpr mappedOrder = replaceSelector(bestSortOrder, queryActiveTableSelector(), &cur);
  2234. sortedInputs.append(*ensureSorted(&cur, mappedOrder, true, true, alwaysLocal, options.implicitSubSort));
  2235. }
  2236. HqlExprArray sortedArgs;
  2237. unwindChildren(sortedArgs, bestSortOrder);
  2238. sortedInputs.append(*createExprAttribute(sortedAtom, sortedArgs));
  2239. if (localFlag)
  2240. sortedInputs.append(*LINK(localFlag));
  2241. merged.setown(createDataset(no_merge, sortedInputs));
  2242. }
  2243. else
  2244. {
  2245. //otherwise append the datasets and then sort them all
  2246. OwnedHqlExpr appended = createDataset(no_addfiles, inputs);
  2247. appended.setown(cloneInheritedAnnotations(expr, appended));
  2248. OwnedHqlExpr mappedOrder = replaceSelector(grouping, queryActiveTableSelector(), appended);
  2249. merged.setown(createDatasetF(no_sort, LINK(appended), mappedOrder.getClear(), LINK(localFlag), NULL));
  2250. }
  2251. //Now group by the grouping condition
  2252. merged.setown(cloneInheritedAnnotations(expr, merged));
  2253. OwnedHqlExpr mappedGrouping = replaceSelector(grouping, queryActiveTableSelector(), merged);
  2254. OwnedHqlExpr grouped = createDataset(no_group, LINK(merged), mappedGrouping.getClear());
  2255. return expr->cloneAllAnnotations(grouped);
  2256. }
  2257. static IHqlExpression * getNonThorSortedJoinInput(IHqlExpression * joinExpr, IHqlExpression * dataset, HqlExprArray & sorts, bool implicitSubSort)
  2258. {
  2259. if (!sorts.length())
  2260. return LINK(dataset);
  2261. LinkedHqlExpr expr = dataset;
  2262. if (isGrouped(expr))
  2263. {
  2264. expr.setown(createDataset(no_group, LINK(expr), NULL));
  2265. expr.setown(cloneInheritedAnnotations(joinExpr, expr));
  2266. }
  2267. // if already sorted or grouped, use it!
  2268. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  2269. groupOrder.setown(replaceSelector(groupOrder, queryActiveTableSelector(), expr->queryNormalizedSelector()));
  2270. //not used for thor, so sort can be local
  2271. OwnedHqlExpr table = ensureSorted(expr, groupOrder, false, true, true, implicitSubSort);
  2272. if (table != expr)
  2273. table.setown(cloneInheritedAnnotations(joinExpr, table));
  2274. OwnedHqlExpr group = createDatasetF(no_group, table.getClear(), LINK(groupOrder), NULL);
  2275. return cloneInheritedAnnotations(joinExpr, group);
  2276. }
  2277. static bool sameOrGrouped(IHqlExpression * newLeft, IHqlExpression * oldLeft)
  2278. {
  2279. if (newLeft->queryBody() == oldLeft->queryBody())
  2280. return true;
  2281. if (newLeft->getOperator() != no_group)
  2282. return false;
  2283. newLeft = newLeft->queryChild(0);
  2284. return (newLeft->queryBody() == oldLeft->queryBody());
  2285. }
  2286. bool canReorderMatchExistingLocalSort(HqlExprArray & newElements1, HqlExprArray & newElements2, IHqlExpression * ds1, Shared<IHqlExpression> & ds2, const HqlExprArray & elements1, HqlExprArray & elements2, bool canSubSort, bool isLocal, bool alwaysLocal)
  2287. {
  2288. newElements1.kill();
  2289. newElements2.kill();
  2290. if (reorderMatchExistingLocalSort(newElements1, newElements2, ds1, elements1, elements2))
  2291. {
  2292. if (isAlreadySorted(ds2, newElements2, isLocal||alwaysLocal, true))
  2293. return true;
  2294. if (canSubSort && isWorthShuffling(ds2, newElements2, isLocal||alwaysLocal, true))
  2295. {
  2296. OwnedHqlExpr subsorted = getSubSort(ds2, newElements2, isLocal, true, alwaysLocal);
  2297. if (subsorted)
  2298. {
  2299. ds2.swap(subsorted);
  2300. return true;
  2301. }
  2302. }
  2303. }
  2304. return false;
  2305. }
  2306. bool ThorHqlTransformer::isLightweightJoinCandidate(IHqlExpression * expr, bool isLocal, bool isLimitedSubstringJoin)
  2307. {
  2308. //This is equally applicable to hthor and roxie. However non lookup joins currently generate group activities on
  2309. //the inputs which look less efficient. It may still be better to enable it though.
  2310. if (!translator.targetThor())
  2311. return false;
  2312. if (!options.spotLocalMerge || isLimitedSubstringJoin || !isLocal)
  2313. return false;
  2314. if (expr->hasProperty(_lightweight_Atom))
  2315. return false;
  2316. switch (expr->getOperator())
  2317. {
  2318. case no_join:
  2319. case no_selfjoin:
  2320. case no_denormalizegroup:
  2321. case no_denormalize:
  2322. return true;
  2323. }
  2324. return false;
  2325. }
  2326. IHqlExpression * ThorHqlTransformer::normalizeJoinOrDenormalize(IHqlExpression * expr)
  2327. {
  2328. IHqlExpression * leftDs = expr->queryChild(0);
  2329. IHqlExpression * rightDs = queryJoinRhs(expr);
  2330. IHqlExpression * seq = querySelSeq(expr);
  2331. node_operator op = expr->getOperator();
  2332. if (op == no_join)
  2333. {
  2334. if (isSelfJoin(expr))
  2335. {
  2336. HqlExprArray children;
  2337. unwindChildren(children, expr);
  2338. children.replace(*createAttribute(_selfJoinPlaceholder_Atom), 1); // replace the 1st dataset with an attribute so parameters are still in the same place.
  2339. OwnedHqlExpr ret = createDataset(no_selfjoin, children);
  2340. return expr->cloneAllAnnotations(ret);
  2341. }
  2342. }
  2343. bool hasLocal = isLocalActivity(expr);
  2344. bool alwaysLocal = !translator.targetThor();
  2345. bool isLocal = hasLocal || alwaysLocal;
  2346. //hash,local doesn't make sense (hash is only used for distribution) => remove hash
  2347. //but also prevent it being converted to a lookup join??
  2348. if (isLocal && expr->hasProperty(hashAtom))
  2349. {
  2350. HqlExprArray args;
  2351. unwindChildren(args, expr);
  2352. removeProperty(args, hashAtom);
  2353. // args.append(*createAttribute(_normalized_Atom));
  2354. return expr->clone(args);
  2355. }
  2356. //Check to see if this join should be done as a keyed join...
  2357. if (!expr->hasProperty(lookupAtom) && !expr->hasProperty(allAtom))
  2358. {
  2359. if (rightDs->getOperator() == no_filter)
  2360. {
  2361. bool moveRhsFilter = false;
  2362. if (expr->hasProperty(keyedAtom) && queryPropertyChild(expr, keyedAtom, 0))
  2363. {
  2364. //Full keyed join - ensure the filter is moved from the rhs to the condition.
  2365. moveRhsFilter = true;
  2366. }
  2367. else if (options.spotPotentialKeyedJoins && (rightDs != leftDs))
  2368. {
  2369. //This can turn some non keyed joins into keyed joins
  2370. IHqlExpression * cur = rightDs;
  2371. while (cur->getOperator() == no_filter)
  2372. cur = cur->queryChild(0);
  2373. if (cur->getOperator() == no_newkeyindex)
  2374. moveRhsFilter = true;
  2375. }
  2376. if (moveRhsFilter)
  2377. {
  2378. //Transform join(a, b(x), c) to join(a, b, c and evaluate(right, x))
  2379. HqlExprAttr extraFilter;
  2380. OwnedHqlExpr right = createSelector(no_right, rightDs, seq);
  2381. IHqlExpression * cur = rightDs;
  2382. while (cur->getOperator() == no_filter)
  2383. {
  2384. unsigned max = cur->numChildren();
  2385. for (unsigned i = 1; i < max; i++)
  2386. {
  2387. IHqlExpression * filter = cur->queryChild(i);
  2388. if (!filter->isAttribute())
  2389. {
  2390. IHqlExpression * newFilter = replaceSelector(filter, rightDs, right);
  2391. extendConditionOwn(extraFilter, no_and, newFilter);
  2392. }
  2393. }
  2394. cur = cur->queryChild(0);
  2395. }
  2396. HqlExprArray args;
  2397. unwindChildren(args, expr);
  2398. args.replace(*LINK(cur), 1);
  2399. args.replace(*createValue(no_and, makeBoolType(), LINK(expr->queryChild(2)), extraFilter.getClear()), 2);
  2400. return expr->clone(args);
  2401. }
  2402. }
  2403. }
  2404. //Tag a keyed join as ordered in the platforms that ensure it does remain ordered. Extend if the others do.
  2405. if (isKeyedJoin(expr))
  2406. {
  2407. if (translator.targetRoxie() && !expr->hasProperty(_ordered_Atom))
  2408. return appendOwnedOperand(expr, createAttribute(_ordered_Atom));
  2409. return NULL;
  2410. }
  2411. HqlExprArray leftSorts, rightSorts, slidingMatches;
  2412. bool isLimitedSubstringJoin;
  2413. OwnedHqlExpr fuzzyMatch = findJoinSortOrders(expr, leftSorts, rightSorts, isLimitedSubstringJoin, canBeSlidingJoin(expr) ? &slidingMatches : NULL);
  2414. //If the data is already distributed so the data is on the correct machines then perform the join locally.
  2415. //Should be equally applicable to lookup, hash, all and normal joins.
  2416. if (!isLocal && !isLimitedSubstringJoin && leftSorts.ordinality())
  2417. {
  2418. if (isDistributedCoLocally(leftDs, rightDs, leftSorts, rightSorts))
  2419. return appendOwnedOperand(expr, createLocalAttribute());
  2420. //MORE: If left side (assumed to be the largest) is already distributed, it would be more efficient
  2421. //to redistribute the rhs by a matching hash function (or use cosort), and then join locally.
  2422. //Be careful about the persist scaling factors though.
  2423. if (!isPersistDistribution(queryDistribution(leftDs)) && isPartitionedForGroup(leftDs, leftSorts, true))
  2424. {
  2425. DBGLOG("MORE: Potential for distributed join optimization");
  2426. //MORE: May need a flag to stop this - to prevent issues with skew.
  2427. }
  2428. }
  2429. if (expr->hasProperty(allAtom))
  2430. return NULL;
  2431. if (expr->hasProperty(lookupAtom))
  2432. return NULL;
  2433. //Try and convert local joins to a lightweight join that doesn't require any sorting of the inputs.
  2434. //Improves resourcing for thor, and prevents lookup conversion for hthor/roxie
  2435. //Worthwhile even for lookup joins
  2436. if (isLightweightJoinCandidate(expr, isLocal, isLimitedSubstringJoin))
  2437. {
  2438. if (isAlreadySorted(leftDs, leftSorts, true, true) &&
  2439. isAlreadySorted(rightDs, rightSorts, true, true))
  2440. {
  2441. //If this is a lookup join without a many then we need to make sure only the first match is retained.
  2442. return appendOwnedOperand(expr, createAttribute(_lightweight_Atom));
  2443. }
  2444. //Check for a local join where we can reorder the condition so both sides match the existing sort orders.
  2445. //could special case self-join to do less work, but probably not worth the effort.
  2446. HqlExprArray sortedLeft, sortedRight;
  2447. if (!isLimitedSubstringJoin)
  2448. {
  2449. //Since the distribution and order of global joins is not defined this could probably be used for non-local as well.
  2450. LinkedHqlExpr newLeftDs = leftDs;
  2451. LinkedHqlExpr newRightDs = rightDs;
  2452. bool canSubSort = options.subsortLocalJoinConditions;
  2453. bool reordered = canReorderMatchExistingLocalSort(sortedLeft, sortedRight, newLeftDs, newRightDs,
  2454. leftSorts, rightSorts, canSubSort, isLocal, alwaysLocal);
  2455. //If allowed to subsort then try the otherway around
  2456. if (!reordered && canSubSort)
  2457. reordered = canReorderMatchExistingLocalSort(sortedRight, sortedLeft, newRightDs, newLeftDs,
  2458. rightSorts, leftSorts, canSubSort, isLocal, alwaysLocal);
  2459. if (reordered)
  2460. {
  2461. //Recreate the join condition in the correct order to match the existing sorts...
  2462. HqlExprAttr newcond;
  2463. OwnedHqlExpr leftSelector = createSelector(no_left, newLeftDs, seq);
  2464. OwnedHqlExpr rightSelector = createSelector(no_right, newRightDs, seq);
  2465. ForEachItemIn(i, sortedLeft)
  2466. {
  2467. OwnedHqlExpr lc = replaceSelector(&sortedLeft.item(i), queryActiveTableSelector(), leftSelector);
  2468. OwnedHqlExpr rc = replaceSelector(&sortedRight.item(i), queryActiveTableSelector(), rightSelector);
  2469. extendConditionOwn(newcond, no_and, createValue(no_eq, makeBoolType(), lc.getClear(), rc.getClear()));
  2470. }
  2471. extendConditionOwn(newcond, no_and, fuzzyMatch.getClear());
  2472. HqlExprArray args;
  2473. args.append(*newLeftDs.getClear());
  2474. args.append(*newRightDs.getClear());
  2475. args.append(*newcond.getClear());
  2476. unwindChildren(args, expr, 3);
  2477. args.append(*createAttribute(_lightweight_Atom));
  2478. return expr->clone(args);
  2479. }
  2480. }
  2481. }
  2482. //Sort,Sort->join is O(NlnN) lookup join using a hash table is O(N) =>convert for hthor/roxie
  2483. if (!isThorCluster(targetClusterType) && !expr->hasProperty(_normalized_Atom))
  2484. {
  2485. bool createLookup = false;
  2486. if ((op == no_join) && options.convertJoinToLookup)
  2487. {
  2488. if ((targetClusterType == RoxieCluster) || hasFewRows(rightDs))
  2489. if (!isFullJoin(expr) && !isRightJoin(expr) && !expr->hasProperty(partitionRightAtom))
  2490. createLookup = !expr->hasProperty(_lightweight_Atom);
  2491. }
  2492. if (isLimitedSubstringJoin)
  2493. createLookup = false; //doesn't support it yet
  2494. else if (createLookup && leftSorts.ordinality() && rightSorts.ordinality())
  2495. {
  2496. //Check this isn't going to generate a between join - if it is that takes precedence.
  2497. if ((slidingMatches.ordinality() != 0) && (leftSorts.ordinality() == slidingMatches.ordinality()))
  2498. createLookup = false;
  2499. }
  2500. if (createLookup)
  2501. {
  2502. IHqlExpression * lhs = expr->queryChild(0);
  2503. HqlExprArray args;
  2504. if (isGrouped(lhs))
  2505. {
  2506. OwnedHqlExpr ungroup = createDataset(no_group, LINK(lhs));
  2507. args.append(*cloneInheritedAnnotations(expr, ungroup));
  2508. }
  2509. else
  2510. args.append(*LINK(lhs));
  2511. unwindChildren(args, expr, 1);
  2512. args.append(*createAttribute(manyAtom));
  2513. args.append(*createAttribute(lookupAtom));
  2514. return expr->clone(args);
  2515. }
  2516. OwnedHqlExpr newLeft = getNonThorSortedJoinInput(expr, leftDs, leftSorts, options.implicitSubSort);
  2517. OwnedHqlExpr newRight = getNonThorSortedJoinInput(expr, rightDs, rightSorts, options.implicitSubSort);
  2518. try
  2519. {
  2520. if ((leftDs != newLeft) || (rightDs != newRight))
  2521. {
  2522. HqlExprArray args;
  2523. args.append(*newLeft.getClear());
  2524. args.append(*newRight.getClear());
  2525. unwindChildren(args, expr, 2);
  2526. args.append(*createAttribute(_normalized_Atom));
  2527. return expr->clone(args);
  2528. }
  2529. }
  2530. catch (IException * e)
  2531. {
  2532. //Couldn't work out the sort orders - shouldn't be fatal because may constant fold later.
  2533. EXCLOG(e, "Transform");
  2534. e->Release();
  2535. }
  2536. }
  2537. //Convert hash selfjoin to self-join(distribute)
  2538. if ((op == no_selfjoin) && expr->hasProperty(hashAtom))
  2539. {
  2540. assertex(!isLocal);
  2541. if (isLimitedSubstringJoin)
  2542. {
  2543. leftSorts.pop();
  2544. rightSorts.pop();
  2545. }
  2546. if (leftSorts.ordinality())
  2547. {
  2548. OwnedHqlExpr sortlist = createValueSafe(no_sortlist, makeSortListType(NULL), leftSorts);
  2549. OwnedHqlExpr distribute;
  2550. //Only likely to catch this partition test if isLimitedSubstringJoin true, otherwise caught above
  2551. if (!isPartitionedForGroup(leftDs, sortlist, true))
  2552. {
  2553. //could use a more optimal hash function since comparing against self, so fields are same type
  2554. OwnedHqlExpr activeDist = createValue(no_hash32, LINK(unsignedType), LINK(sortlist), createAttribute(internalAtom));
  2555. //OwnedHqlExpr activeDist = createValue(no_hash, LINK(unsignedType), LINK(sortlist));
  2556. OwnedHqlExpr dist = replaceSelector(activeDist, queryActiveTableSelector(), leftDs);
  2557. distribute.setown(createDataset(no_distribute, LINK(leftDs), LINK(dist)));
  2558. distribute.setown(cloneInheritedAnnotations(expr, distribute));
  2559. }
  2560. else
  2561. distribute.set(leftDs);
  2562. HqlExprArray args;
  2563. args.append(*LINK(distribute));
  2564. unwindChildren(args, expr, 1);
  2565. removeProperty(args, hashAtom);
  2566. args.append(*createLocalAttribute());
  2567. return expr->clone(args);
  2568. }
  2569. }
  2570. if (isThorCluster(targetClusterType) && isLocal && options.implicitJoinSubSort)
  2571. {
  2572. IHqlExpression * noSortAttr = expr->queryProperty(noSortAtom);
  2573. OwnedHqlExpr newLeft;
  2574. OwnedHqlExpr newRight;
  2575. if (!userPreventsSort(noSortAttr, no_left))
  2576. newLeft.setown(getSubSort(leftDs, leftSorts, isLocal, true, alwaysLocal));
  2577. if (!userPreventsSort(noSortAttr, no_right))
  2578. newRight.setown(getSubSort(rightDs, rightSorts, isLocal, true, alwaysLocal));
  2579. if (newLeft || newRight)
  2580. {
  2581. HqlExprArray args;
  2582. if (newLeft)
  2583. args.append(*newLeft.getClear());
  2584. else
  2585. args.append(*LINK(leftDs));
  2586. if (newRight)
  2587. args.append(*newRight.getClear());
  2588. else
  2589. args.append(*LINK(rightDs));
  2590. unwindChildren(args, expr, 2);
  2591. return expr->clone(args);
  2592. }
  2593. }
  2594. return NULL;
  2595. }
  2596. IHqlExpression * ThorHqlTransformer::normalizeScalarAggregate(IHqlExpression * expr)
  2597. {
  2598. OwnedHqlExpr project = convertScalarAggregateToDataset(expr);
  2599. if (!project)
  2600. throwUnexpected();
  2601. IHqlExpression * field = project->queryRecord()->queryChild(0);
  2602. OwnedHqlExpr ret = createNewSelectExpr(project.getClear(), LINK(field));
  2603. return expr->cloneAllAnnotations(ret);
  2604. }
  2605. IHqlExpression * ThorHqlTransformer::normalizeSelect(IHqlExpression * expr)
  2606. {
  2607. return NULL;
  2608. /*
  2609. The idea of this code is to convert a.b.c into normalize(a.b, a.b.c) if a.b is an out-of scope dataset
  2610. However the following isn't good enough since the fields from a.b also need to be accessible. We would
  2611. need to introduce a field in the result $parent$, and also assign that across. Subsequent references to
  2612. a.b.xyz would need to be converted to in.parent.xyz. It will generate very inefficient code, so not going
  2613. to go this way at the moment.
  2614. */
  2615. if (!isNewSelector(expr) || !expr->isDataset())
  2616. return NULL;
  2617. IHqlExpression * ds = expr->queryChild(0);
  2618. if (!ds->isDataset())
  2619. return NULL;
  2620. //If we are a no_select of a no_select that is also new, insert an implicit denormalized
  2621. HqlExprArray args;
  2622. args.append(*LINK(ds));
  2623. OwnedHqlExpr selSeq = createSelectorSequence();
  2624. HqlExprArray selectArgs;
  2625. unwindChildren(selectArgs, expr);
  2626. selectArgs.replace(*createSelector(no_left, ds, selSeq), 0);
  2627. removeProperty(selectArgs, newAtom);
  2628. args.append(*expr->clone(selectArgs));
  2629. //Create a transform self := right;
  2630. OwnedHqlExpr right = createSelector(no_right, expr, selSeq);
  2631. OwnedHqlExpr assign = createAssign(getSelf(expr), LINK(right));
  2632. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(LINK(expr->queryRecordType())), LINK(assign));
  2633. args.append(*LINK(transform));
  2634. args.append(*LINK(selSeq));
  2635. args.append(*createAttribute(_internal_Atom));
  2636. return createDataset(no_normalize, args);
  2637. }
  2638. IHqlExpression * ThorHqlTransformer::normalizeSort(IHqlExpression * expr)
  2639. {
  2640. IHqlExpression * dataset = expr->queryChild(0);
  2641. IHqlExpression * sortlist = expr->queryChild(1);
  2642. OwnedHqlExpr newsort = simplifySortlistComplexity(sortlist);
  2643. if (newsort)
  2644. {
  2645. if (newsort == sortlist)
  2646. {
  2647. dbglogExpr(sortlist);
  2648. throwUnexpected();
  2649. }
  2650. HqlExprArray args;
  2651. unwindChildren(args, expr);
  2652. args.replace(*newsort.getClear(), 1);
  2653. return expr->clone(args);
  2654. }
  2655. node_operator op = expr->getOperator();
  2656. if (translator.targetThor())
  2657. {
  2658. if ((op == no_sort) && !isGrouped(expr) && !expr->hasProperty(localAtom))
  2659. {
  2660. //sort(ds, a,b,c) - check so see if there is a previous sort distribution of sort(ds,a,b,c) if so, this sort can be done locally
  2661. if (queryDistribution(expr) == queryDistribution(dataset))
  2662. return appendLocalAttribute(expr);
  2663. }
  2664. }
  2665. if (op == no_sorted)
  2666. {
  2667. IHqlExpression * normalized = normalizeSortSteppedIndex(expr, sortedAtom);
  2668. if (normalized)
  2669. return normalized;
  2670. }
  2671. bool isLocal = expr->hasProperty(localAtom);
  2672. bool alwaysLocal = !translator.targetThor();
  2673. if ((op != no_assertsorted) && isAlreadySorted(dataset, sortlist, isLocal||alwaysLocal, false))
  2674. return LINK(dataset);
  2675. if (op == no_sorted)
  2676. return normalizeSortSteppedIndex(expr, sortedAtom);
  2677. //NOTE: We can't convert a global sort to a subsort because that will change the distribution
  2678. if (options.implicitSubSort && (isLocal || alwaysLocal) && (op != no_assertsorted))
  2679. {
  2680. OwnedHqlExpr subsorted = getSubSort(dataset, sortlist, isLocal, false, alwaysLocal);
  2681. if (subsorted)
  2682. return dataset->cloneAllAnnotations(subsorted);
  2683. }
  2684. return NULL;
  2685. }
  2686. IHqlExpression * ThorHqlTransformer::normalizeSubSort(IHqlExpression * expr)
  2687. {
  2688. IHqlExpression * dataset = expr->queryChild(0);
  2689. IHqlExpression * sortlist = expr->queryChild(1);
  2690. IHqlExpression * grouping = expr->queryChild(2);
  2691. OwnedHqlExpr newsort = simplifySortlistComplexity(sortlist);
  2692. OwnedHqlExpr newgrouping = simplifySortlistComplexity(grouping);
  2693. if (newsort || newgrouping)
  2694. {
  2695. HqlExprArray args;
  2696. unwindChildren(args, expr);
  2697. if (newsort)
  2698. args.replace(*newsort.getClear(), 1);
  2699. if (newgrouping)
  2700. args.replace(*newgrouping.getClear(), 2);
  2701. return expr->clone(args);
  2702. }
  2703. if (translator.targetThor() && !expr->hasProperty(localAtom))
  2704. return convertSubSortToGroupedSort(expr);
  2705. return NULL;
  2706. }
  2707. IHqlExpression * ThorHqlTransformer::normalizeSortSteppedIndex(IHqlExpression * expr, _ATOM attrName)
  2708. {
  2709. node_operator op = expr->getOperator();
  2710. if (op == no_assertsorted)
  2711. return NULL;
  2712. IHqlExpression * dataset = expr->queryChild(0);
  2713. node_operator datasetOp = dataset->getOperator();
  2714. if ((datasetOp == no_keyindex) || (datasetOp == no_newkeyindex))
  2715. {
  2716. IHqlExpression * indexRecord = dataset->queryRecord();
  2717. if (!dataset->hasProperty(attrName))
  2718. {
  2719. HqlExprArray selects;
  2720. IHqlExpression * sortList = expr->queryChild(1);
  2721. if (sortList)
  2722. {
  2723. OwnedHqlExpr mapped = replaceSelector(sortList, dataset->queryNormalizedSelector(), queryActiveTableSelector());
  2724. unwindChildren(selects, mapped);
  2725. }
  2726. HqlExprArray args;
  2727. unwindChildren(args, dataset);
  2728. args.append(*createExprAttribute(attrName, selects));
  2729. return dataset->clone(args);
  2730. }
  2731. }
  2732. return NULL;
  2733. }
  2734. IHqlExpression * ThorHqlTransformer::normalizeTempTable(IHqlExpression * expr)
  2735. {
  2736. #if 0
  2737. //This would be a great improvement to the generated code, but the xml storage formats are different + it doesn't cope with ALL.
  2738. IHqlExpression * values = expr->queryChild(0);
  2739. ITypeInfo * valuesType = values->queryType();
  2740. if ((values->getOperator() == no_getresult) && (valuesType->getTypeCode() == type_set))
  2741. {
  2742. IHqlExpression * record = expr->queryChild(1);
  2743. if ((record->numChildren() == 1) && (valuesType->queryChildType() == record->queryChild(0)->queryType()))
  2744. {
  2745. HqlExprArray args;
  2746. args.append(*LINK(record));
  2747. args.append(*createAttribute(sequenceAtom, LINK(values->queryChild(0))));
  2748. if (values->queryChild(1))
  2749. args.append(*createAttribute(nameAtom, LINK(values->queryChild(1))));
  2750. return createDataset(no_workunit_dataset, args);
  2751. }
  2752. }
  2753. #endif
  2754. return NULL;
  2755. }
  2756. IHqlExpression * ThorHqlTransformer::normalizeChooseN(IHqlExpression * expr)
  2757. {
  2758. OwnedHqlExpr first = foldHqlExpression(queryRealChild(expr, 2));
  2759. if (first)
  2760. {
  2761. if (matchesConstantValue(first, 1))
  2762. {
  2763. HqlExprArray args;
  2764. unwindChildren(args, expr);
  2765. args.remove(2);
  2766. return expr->clone(args);
  2767. }
  2768. }
  2769. if (!options.spotTopN) return NULL;
  2770. return queryConvertChoosenNSort(expr, topNlimit);
  2771. }
  2772. static IHqlExpression * extractPrefetchFields(HqlExprArray & fields, HqlExprArray & values, IHqlExpression * ds, IHqlExpression * expr)
  2773. {
  2774. switch (expr->getOperator())
  2775. {
  2776. case no_newtransform:
  2777. case no_transform:
  2778. case no_assignall:
  2779. case NO_AGGREGATEGROUP:
  2780. case no_sortlist:
  2781. {
  2782. HqlExprArray args;
  2783. ForEachChild(i, expr)
  2784. args.append(*extractPrefetchFields(fields, values, ds, expr->queryChild(i)));
  2785. return expr->clone(args);
  2786. }
  2787. case no_assign:
  2788. {
  2789. HqlExprArray args;
  2790. args.append(*LINK(expr->queryChild(0)));
  2791. args.append(*extractPrefetchFields(fields, values, ds, expr->queryChild(1)));
  2792. return expr->clone(args);
  2793. }
  2794. case no_attr:
  2795. case no_attr_expr:
  2796. case no_attr_link:
  2797. case no_record:
  2798. case no_field:
  2799. return LINK(expr);
  2800. }
  2801. unsigned match = values.find(*expr);
  2802. if (match == NotFound)
  2803. {
  2804. //What about preserving link counting on datasets?
  2805. match = fields.ordinality();
  2806. StringBuffer name;
  2807. name.append("_f").append(match).append("_");
  2808. IHqlExpression * field = createField(createIdentifierAtom(name.str()), expr->getType(), NULL);
  2809. fields.append(*field);
  2810. values.append(*LINK(expr));
  2811. }
  2812. return createSelectExpr(getActiveTableSelector(), LINK(&fields.item(match)));
  2813. }
  2814. IHqlExpression * ThorHqlTransformer::normalizePrefetchAggregate(IHqlExpression * expr)
  2815. {
  2816. //This optimization may be worth doing even if there is no prefetch attribute if the value being summed is very complicated!
  2817. IHqlExpression * prefetch = expr->queryProperty(prefetchAtom);
  2818. if (!prefetch)
  2819. return NULL;
  2820. //Create a prefetch project for all parameters to count/sum/grouping expressions
  2821. //and then aggregate those values.
  2822. IHqlExpression * ds = expr->queryChild(0);
  2823. HqlExprArray tempArgs, fields, values;
  2824. ForEachChildFrom(i, expr, 2)
  2825. {
  2826. IHqlExpression * cur = expr->queryChild(i);
  2827. if (cur != prefetch)
  2828. tempArgs.append(*extractPrefetchFields(fields, values, ds, cur));
  2829. }
  2830. OwnedHqlExpr newRecord = createRecord(fields);
  2831. OwnedHqlExpr self = createSelector(no_self, newRecord, NULL);
  2832. HqlExprArray assigns;
  2833. ForEachItemIn(iv, fields)
  2834. {
  2835. IHqlExpression * tgt = createSelectExpr(LINK(self), &OLINK(fields.item(iv)));
  2836. assigns.append(*createAssign(tgt, &OLINK(values.item(iv))));
  2837. }
  2838. HqlExprArray args;
  2839. args.append(*LINK(ds));
  2840. args.append(*LINK(newRecord));
  2841. args.append(*createValue(no_newtransform, makeTransformType(newRecord->getType()), assigns));
  2842. args.append(*LINK(prefetch));
  2843. OwnedHqlExpr project = createDataset(no_newusertable, args);
  2844. project.setown(cloneInheritedAnnotations(expr, project));
  2845. args.kill();
  2846. args.append(*LINK(project));
  2847. args.append(*LINK(expr->queryChild(1)));
  2848. ForEachItemIn(i2, tempArgs)
  2849. args.append(*replaceSelector(&tempArgs.item(i2), queryActiveTableSelector(), project->queryNormalizedSelector()));
  2850. return expr->clone(args);
  2851. }
  2852. static IHqlExpression * convertAggregateGroupingToGroupedAggregate(IHqlExpression * expr, IHqlExpression* groupBy)
  2853. {
  2854. IHqlExpression * dataset = expr->queryChild(0);
  2855. HqlExprArray groupArgs;
  2856. groupArgs.append(*LINK(dataset));
  2857. groupArgs.append(*LINK(groupBy));
  2858. groupArgs.append(*createAttribute(allAtom));
  2859. unwindChildren(groupArgs, expr, 4);
  2860. OwnedHqlExpr result = createDataset(no_group, groupArgs);
  2861. result.setown(cloneInheritedAnnotations(expr, result));
  2862. HqlExprArray args;
  2863. unwindChildren(args, expr);
  2864. args.replace(*result.getClear(), 0);
  2865. args.remove(3); // no longer grouped.
  2866. args.append(*createAttribute(aggregateAtom));
  2867. return expr->clone(args);
  2868. }
  2869. IHqlExpression * ThorHqlTransformer::getMergeTransform(IHqlExpression * dataset, IHqlExpression * transform)
  2870. {
  2871. HqlExprArray args;
  2872. ForEachChild(i, transform)
  2873. {
  2874. IHqlExpression * cur = transform->queryChild(i);
  2875. switch (cur->getOperator())
  2876. {
  2877. case no_assignall:
  2878. args.append(*getMergeTransform(dataset, cur));
  2879. break;
  2880. case no_assign:
  2881. {
  2882. IHqlExpression * lhs = cur->queryChild(0);
  2883. IHqlExpression * lhsField = lhs->queryChild(1);
  2884. IHqlExpression * rhs = cur->queryChild(1);
  2885. OwnedHqlExpr selected = createSelectExpr(LINK(dataset), LINK(lhsField));
  2886. OwnedHqlExpr newRhs;
  2887. node_operator rhsOp = rhs->getOperator();
  2888. switch (rhsOp)
  2889. {
  2890. case no_countgroup:
  2891. case no_sumgroup:
  2892. newRhs.setown(createValue(no_sumgroup, selected->getType(), LINK(selected)));
  2893. break;
  2894. case no_maxgroup:
  2895. case no_mingroup:
  2896. newRhs.setown(createValue(rhsOp, selected->getType(), LINK(selected)));
  2897. break;
  2898. case no_existsgroup:
  2899. newRhs.setown(createValue(no_existsgroup, selected->getType(), LINK(selected)));
  2900. break;
  2901. case no_vargroup:
  2902. case no_covargroup:
  2903. case no_corrgroup:
  2904. case no_avegroup:
  2905. throwUnexpected();
  2906. default:
  2907. newRhs.set(selected);
  2908. break;
  2909. }
  2910. args.append(*createAssign(LINK(lhs), newRhs.getClear()));
  2911. break;
  2912. }
  2913. default:
  2914. args.append(*LINK(cur));
  2915. break;
  2916. }
  2917. }
  2918. return transform->clone(args);
  2919. }
  2920. //Convert table(x { count(group), sum(group, x) }, gr) to
  2921. //sort(x, gr, local) -> group(gr) -> aggregate -> distribute(merge) -> group(local) -> aggregate'
  2922. IHqlExpression * ThorHqlTransformer::normalizeMergeAggregate(IHqlExpression * expr)
  2923. {
  2924. IHqlExpression * dataset = expr->queryChild(0);
  2925. IHqlExpression * groupBy = expr->queryChild(3);
  2926. //If locally distributed then don't do anything
  2927. OwnedHqlExpr noMerge = removeProperty(expr, mergeAtom);
  2928. if (!translator.targetThor() || expr->hasProperty(localAtom) || isPartitionedForGroup(dataset, groupBy, true))
  2929. return noMerge.getClear();
  2930. //Convert the aggregation (so no covariance/ave and other computed fields)
  2931. OwnedHqlExpr normalized = normalizeTableToAggregate(noMerge, true);
  2932. IHqlExpression * aggregate = normalized;
  2933. if (aggregate->getOperator() != no_newaggregate)
  2934. aggregate = aggregate->queryChild(0);
  2935. assertex(aggregate->getOperator() == no_newaggregate);
  2936. HqlExprArray localAggregateArgs;
  2937. unwindChildren(localAggregateArgs, aggregate);
  2938. removeProperty(localAggregateArgs, hashAtom);
  2939. removeProperty(localAggregateArgs, mergeAtom);
  2940. localAggregateArgs.append(*createLocalAttribute());
  2941. localAggregateArgs.append(*createAttribute(sortedAtom));
  2942. //Local aggregate and force a local sort order to be used
  2943. OwnedHqlExpr localAggregate = aggregate->clone(localAggregateArgs);
  2944. OwnedHqlExpr localGroupedAggregate = convertAggregateGroupingToGroupedAggregate(localAggregate, groupBy);
  2945. //Ensure the group,all is transformed to a local sort, local group
  2946. OwnedHqlExpr transformedFirstAggregate = transform(localGroupedAggregate);
  2947. //Use distribute(,MERGE) to move rows globally, and remain sorted
  2948. //Note grouping fields need to be mapped using the fields projected by the aggregate
  2949. TableProjectMapper mapper(transformedFirstAggregate);
  2950. bool groupCanBeMapped = false;
  2951. OwnedHqlExpr mappedGrouping = mapper.collapseFields(groupBy, dataset, transformedFirstAggregate, &groupCanBeMapped);
  2952. assertex(groupCanBeMapped);
  2953. OwnedHqlExpr sortOrder = getExistingSortOrder(transformedFirstAggregate, true, true);
  2954. OwnedHqlExpr mergeAttr = createExprAttribute(mergeAtom, replaceSelector(sortOrder, queryActiveTableSelector(), transformedFirstAggregate));
  2955. OwnedHqlExpr hashed = createValue(no_hash32, LINK(unsignedType), LINK(mappedGrouping), createAttribute(internalAtom));
  2956. OwnedHqlExpr redistributed = createDatasetF(no_distribute, LINK(transformedFirstAggregate), LINK(hashed), mergeAttr.getClear(), NULL);
  2957. redistributed.setown(cloneInheritedAnnotations(expr, redistributed));
  2958. OwnedHqlExpr grouped = createDatasetF(no_group, LINK(redistributed), LINK(mappedGrouping), createLocalAttribute(), NULL);
  2959. grouped.setown(cloneInheritedAnnotations(expr, grouped));
  2960. HqlExprArray args;
  2961. args.append(*LINK(grouped));
  2962. args.append(*LINK(localAggregate->queryChild(1)));
  2963. args.append(*getMergeTransform(grouped->queryNormalizedSelector(), localAggregate->queryChild(2)));
  2964. unwindChildren(args, localAggregate, 4);
  2965. OwnedHqlExpr newAggregate = localAggregate->clone(args);
  2966. if (aggregate == normalized)
  2967. return newAggregate.getClear();
  2968. return replaceChildDataset(normalized, newAggregate, 0);
  2969. }
  2970. IHqlExpression * ThorHqlTransformer::normalizeTableToAggregate(IHqlExpression * expr, bool canOptimizeCasts)
  2971. {
  2972. IHqlExpression * dataset = expr->queryChild(0);
  2973. IHqlExpression * record = expr->queryChild(1);
  2974. IHqlExpression * transform = expr->queryChild(2);
  2975. IHqlExpression * groupBy = expr->queryChild(3);
  2976. if (!isAggregateDataset(expr))
  2977. return NULL;
  2978. //MORE: Should fail if asked to group by variable length field, or do max/min on variable length field.
  2979. HqlExprArray aggregateFields;
  2980. HqlExprArray aggregateAssigns;
  2981. HqlExprArray extraAssigns;
  2982. bool extraSelectNeeded = false;
  2983. OwnedHqlExpr self = getSelf(expr);
  2984. ForEachChild(idx, transform)
  2985. {
  2986. IHqlExpression * assign=transform->queryChild(idx);
  2987. IHqlExpression * cur = assign->queryChild(0);
  2988. IHqlExpression * src = assign->queryChild(1);
  2989. IHqlExpression * mapped = normalizeAggregateExpr(cur, src, aggregateFields, aggregateAssigns, extraSelectNeeded, canOptimizeCasts);
  2990. if (mapped == src)
  2991. {
  2992. mapped->Release();
  2993. mapped = replaceSelector(cur, self, queryActiveTableSelector());
  2994. // Not an aggregate - must be an expression that is used in the grouping
  2995. aggregateFields.append(*LINK(cur->queryChild(1)));
  2996. aggregateAssigns.append(*createAssign(LINK(mapped), LINK(src)));
  2997. }
  2998. // Add expression to calculate the fields to the second projection
  2999. extraAssigns.append(*createAssign(LINK(cur), mapped));
  3000. }
  3001. //Now add any grouping fields.......
  3002. IHqlExpression * newGroupBy = NULL;
  3003. if (groupBy && !groupBy->isAttribute())
  3004. {
  3005. unsigned numGroupBy = groupBy->numChildren();
  3006. HqlExprArray newGroupElement;
  3007. for (unsigned idx = 0; idx < numGroupBy; idx++)
  3008. {
  3009. IHqlExpression * curGroup = groupBy->queryChild(idx);
  3010. bool matched = false;
  3011. ForEachItemIn(idxa, aggregateAssigns)
  3012. {
  3013. IHqlExpression * rhs = aggregateAssigns.item(idxa).queryChild(1);
  3014. if (rhs->getOperator() == no_activerow)
  3015. rhs = rhs->queryChild(0);
  3016. if (rhs == curGroup)
  3017. {
  3018. matched = true;
  3019. break;
  3020. }
  3021. }
  3022. if (!matched)
  3023. {
  3024. StringBuffer temp;
  3025. temp.append("_agg_").append(aggregateAssigns.ordinality());
  3026. IHqlExpression * targetField = createField(createIdentifierAtom(temp.str()), curGroup->getType(), NULL);
  3027. aggregateFields.append(*targetField);
  3028. aggregateAssigns.append(*createAssign(createSelectExpr(getActiveTableSelector(), LINK(targetField)), LINK(curGroup)));
  3029. extraSelectNeeded = true;
  3030. }
  3031. newGroupElement.append(*LINK(curGroup));
  3032. }
  3033. newGroupBy = createSortList(newGroupElement);
  3034. }
  3035. IHqlExpression * aggregateRecord = extraSelectNeeded ? createRecord(aggregateFields) : LINK(record);
  3036. OwnedHqlExpr aggregateSelf = getSelf(aggregateRecord);
  3037. replaceAssignSelector(aggregateAssigns, aggregateSelf);
  3038. IHqlExpression * aggregateTransform = createValue(no_newtransform, makeTransformType(aggregateRecord->getType()), aggregateAssigns);
  3039. HqlExprArray aggregateAttrs;
  3040. unwindAttributes(aggregateAttrs, expr);
  3041. removeProperty(aggregateAttrs, aggregateAtom);
  3042. removeProperty(aggregateAttrs, fewAtom);
  3043. if (!expr->hasProperty(localAtom) && newGroupBy && !isGrouped(dataset) && isPartitionedForGroup(dataset, newGroupBy, true))
  3044. aggregateAttrs.append(*createLocalAttribute());
  3045. OwnedHqlExpr ret = createDataset(no_newaggregate, LINK(dataset), createComma(aggregateRecord, aggregateTransform, newGroupBy, createComma(aggregateAttrs)));
  3046. if (extraSelectNeeded)
  3047. ret.setown(cloneInheritedAnnotations(expr, ret));
  3048. else
  3049. ret.setown(expr->cloneAllAnnotations(ret));
  3050. if (expr->hasProperty(mergeAtom))
  3051. ret.setown(normalizeMergeAggregate(ret));
  3052. if (extraSelectNeeded)
  3053. {
  3054. replaceAssignSelector(extraAssigns, ret);
  3055. IHqlExpression * projectTransform = createValue(no_newtransform, makeTransformType(record->getType()), extraAssigns);
  3056. ret.setown(createDataset(no_newusertable, ret.getClear(), createComma(LINK(record), projectTransform)));
  3057. ret.setown(expr->cloneAllAnnotations(ret));
  3058. }
  3059. return ret.getClear();
  3060. }
  3061. IHqlExpression * ThorHqlTransformer::normalizeTableGrouping(IHqlExpression * expr)
  3062. {
  3063. //Transform table(x,y,z) to table(group(x,z),y)
  3064. IHqlExpression * dataset = expr->queryChild(0);
  3065. LinkedHqlExpr group = queryRealChild(expr, 3);
  3066. if (group)
  3067. {
  3068. if (expr->hasProperty(mergeAtom))
  3069. return normalizeMergeAggregate(expr);
  3070. bool useHashAggregate = expr->hasProperty(fewAtom);
  3071. if (expr->getOperator() == no_aggregate)
  3072. {
  3073. OwnedHqlExpr selector = createSelector(no_left, dataset->queryRecord(), querySelSeq(expr));
  3074. group.setown(replaceSelector(group, selector, dataset));
  3075. //Cannot use a hash aggregate if we don't know the mapping from input to output fields...
  3076. if (!isKnownTransform(expr->queryChild(2)))
  3077. useHashAggregate = false;
  3078. }
  3079. if (useHashAggregate && group->isConstant() && !translator.targetThor())
  3080. return removeProperty(expr, fewAtom);
  3081. if (!expr->hasProperty(manyAtom) && !expr->hasProperty(sortedAtom))
  3082. {
  3083. if (isSmallGrouping(group))
  3084. {
  3085. OwnedHqlExpr newsort = simplifySortlistComplexity(group);
  3086. if (!newsort)
  3087. newsort.set(group);
  3088. LinkedHqlExpr ds = dataset;
  3089. if (ds->queryType()->queryGroupInfo())
  3090. {
  3091. ds.setown(createDataset(no_group, ds.getClear(), NULL));
  3092. ds.setown(cloneInheritedAnnotations(expr, ds));
  3093. }
  3094. OwnedHqlExpr sorted = ensureSortedForGroup(ds, newsort, expr->hasProperty(localAtom), !translator.targetThor(), options.implicitGroupSubSort);
  3095. //For thor a global grouped aggregate would transfer elements between nodes so it is still likely to
  3096. //be more efficient to do a hash aggregate. Even better would be to check the distribution
  3097. if ((sorted != ds) ||
  3098. (translator.targetThor() && !expr->hasProperty(localAtom) && !isPartitionedForGroup(ds, newsort, true)))
  3099. useHashAggregate = true;
  3100. }
  3101. //Default to a hash aggregate for child queries/normalized sources
  3102. IHqlExpression * rootDs = queryExpression(dataset->queryDataset()->queryRootTable());
  3103. if (rootDs && rootDs->getOperator() == no_select)
  3104. useHashAggregate = true;
  3105. }
  3106. if (!expr->hasProperty(aggregateAtom) && !useHashAggregate && !expr->hasProperty(groupedAtom))
  3107. return convertAggregateGroupingToGroupedAggregate(expr, group);
  3108. }
  3109. return NULL;
  3110. }
  3111. void HqlCppTranslator::convertLogicalToActivities(WorkflowArray & workflow)
  3112. {
  3113. {
  3114. unsigned time = msTick();
  3115. ThorHqlTransformer transformer(*this, targetClusterType, wu());
  3116. ForEachItemIn(idx, workflow)
  3117. {
  3118. HqlExprArray & exprs = workflow.item(idx).queryExprs();
  3119. HqlExprArray transformed;
  3120. transformer.transformRoot(exprs, transformed);
  3121. replaceArray(exprs, transformed);
  3122. }
  3123. DEBUG_TIMER("EclServer: tree transform: convert logical", msTick()-time);
  3124. }
  3125. if (queryOptions().normalizeLocations)
  3126. normalizeAnnotations(*this, workflow);
  3127. }
  3128. //------------------------------------------------------------------------
  3129. CompoundSourceInfo::CompoundSourceInfo(IHqlExpression * _original) : NewTransformInfo(_original)
  3130. {
  3131. sourceOp = no_none;
  3132. mode = no_none;
  3133. splitCount = 0;
  3134. reset();
  3135. }
  3136. void CompoundSourceInfo::reset()
  3137. {
  3138. forceCompound = false;
  3139. isBoundary = false;
  3140. isPreloaded = false;
  3141. isLimited = false;
  3142. hasChoosen = false;
  3143. hasSkipLimit = false;
  3144. isCloned = false;
  3145. isFiltered = false;
  3146. isPostFiltered = false;
  3147. isCreateRowLimited = false;
  3148. }
  3149. bool CompoundSourceInfo::canMergeLimit(IHqlExpression * expr, ClusterType targetClusterType) const
  3150. {
  3151. if (isAggregate() || isChooseNAllLimit(expr->queryChild(1)) || !isBinary())
  3152. return false;
  3153. node_operator op = expr->getOperator();
  3154. switch (op)
  3155. {
  3156. case no_limit:
  3157. //Can't merge a limit into a choosen() because the limit will be applied first
  3158. if (isLimited || hasChoosen)
  3159. return false;
  3160. //Don't merge skip and onfail limits into activities that can't implement them completely
  3161. if (targetClusterType != RoxieCluster)
  3162. {
  3163. if (expr->hasProperty(skipAtom) || expr->hasProperty(onFailAtom))
  3164. return false;
  3165. }
  3166. else
  3167. {
  3168. //Can always limit a count/aggregate with a skip limit - just resets count to 0
  3169. if (expr->hasProperty(skipAtom))
  3170. return true;
  3171. }
  3172. break;
  3173. case no_choosen:
  3174. if (hasChoosen)
  3175. return false;
  3176. break;
  3177. }
  3178. switch (sourceOp)
  3179. {
  3180. case no_compound_diskread:
  3181. case no_compound_disknormalize:
  3182. case no_compound_indexread:
  3183. case no_compound_indexnormalize:
  3184. return true;
  3185. }
  3186. return false;
  3187. }
  3188. void CompoundSourceInfo::ensureCompound()
  3189. {
  3190. if (sourceOp != no_none)
  3191. {
  3192. forceCompound = true;
  3193. #if 0
  3194. //MORE: We should really remove the sharing for entries that are going to become compound activities.
  3195. //However, that isn't just for this case - should be iterative
  3196. //e.g. while (spotMoreCompoundActivities())....
  3197. IHqlExpression * search = original;
  3198. loop
  3199. {
  3200. CompoundSourceInfo * extra = queryExtra(search);
  3201. if (extra->sharedCount-- > 1)
  3202. break;
  3203. search = search->queryChild(0);
  3204. }
  3205. #endif
  3206. }
  3207. }
  3208. bool CompoundSourceInfo::inherit(const CompoundSourceInfo & other, node_operator newSourceOp)
  3209. {
  3210. isLimited = other.isLimited;
  3211. hasSkipLimit = other.hasSkipLimit;
  3212. hasChoosen = other.hasChoosen;
  3213. isFiltered = other.isFiltered;
  3214. isPostFiltered = other.isPostFiltered;
  3215. isPreloaded = other.isPreloaded;
  3216. isCreateRowLimited = other.isCreateRowLimited;
  3217. mode = other.mode;
  3218. uid.set(other.uid);
  3219. if (other.sourceOp == no_none)
  3220. return false;
  3221. if (newSourceOp == no_none)
  3222. {
  3223. if (other.isCloned)
  3224. return false;
  3225. newSourceOp = other.sourceOp;
  3226. }
  3227. sourceOp = newSourceOp;
  3228. return true;
  3229. }
  3230. bool CompoundSourceInfo::isAggregate() const
  3231. {
  3232. switch (sourceOp)
  3233. {
  3234. case no_compound_diskaggregate:
  3235. case no_compound_diskcount:
  3236. case no_compound_diskgroupaggregate:
  3237. case no_compound_indexaggregate:
  3238. case no_compound_indexcount:
  3239. case no_compound_indexgroupaggregate:
  3240. case no_compound_childaggregate:
  3241. case no_compound_childcount:
  3242. case no_compound_childgroupaggregate:
  3243. return true;
  3244. }
  3245. return false;
  3246. }
  3247. //This doesn't try to restrict creating the compound nodes to the inner level, but will also create them for nested children.
  3248. //This shouldn't cause any problems, since compound operators within compounds are ignored, and it means that this transformer
  3249. //doesn't have to cope with being scope dependent.
  3250. //Calling the transformer again later on child queries should extend the compound activities if appropriate.
  3251. static HqlTransformerInfo compoundSourceTransformerInfo("CompoundSourceTransformer");
  3252. CompoundSourceTransformer::CompoundSourceTransformer(HqlCppTranslator & _translator, unsigned _flags)
  3253. : NewHqlTransformer(compoundSourceTransformerInfo), translator(_translator)
  3254. {
  3255. targetClusterType = translator.getTargetClusterType();
  3256. flags = _flags;
  3257. insideCompound = false;
  3258. candidate = false;
  3259. }
  3260. void CompoundSourceTransformer::analyseGatherInfo(IHqlExpression * expr)
  3261. {
  3262. CompoundSourceInfo * extra = queryBodyExtra(expr);
  3263. node_operator op = expr->getOperator();
  3264. bool wasInsideCompound = insideCompound;
  3265. if (!insideCompound)
  3266. extra->noteUsage();
  3267. if (!expr->isDataset())
  3268. insideCompound = false;
  3269. switch (op)
  3270. {
  3271. case no_fetch:
  3272. {
  3273. unsigned max = expr->numChildren();
  3274. for (unsigned i =1; i < max; i++)
  3275. analyseExpr(expr->queryChild(i));
  3276. break;
  3277. }
  3278. case no_keyed:
  3279. case no_record:
  3280. case no_attr:
  3281. case no_attr_expr:
  3282. break;
  3283. case no_keyedlimit:
  3284. case no_compound_diskread:
  3285. case no_compound_disknormalize:
  3286. case no_compound_diskaggregate:
  3287. case no_compound_diskcount:
  3288. case no_compound_diskgroupaggregate:
  3289. case no_compound_indexread:
  3290. case no_compound_indexnormalize:
  3291. case no_compound_indexaggregate:
  3292. case no_compound_indexcount:
  3293. case no_compound_indexgroupaggregate:
  3294. case no_compound_childread:
  3295. case no_compound_childnormalize:
  3296. case no_compound_childaggregate:
  3297. case no_compound_childcount:
  3298. case no_compound_childgroupaggregate:
  3299. case no_compound_selectnew:
  3300. case no_compound_inline:
  3301. case no_preload:
  3302. insideCompound = true;
  3303. NewHqlTransformer::analyseExpr(expr);
  3304. break;
  3305. case no_filter:
  3306. if (filterIsKeyed(expr))
  3307. insideCompound = true;
  3308. NewHqlTransformer::analyseExpr(expr);
  3309. break;
  3310. case no_hqlproject:
  3311. case no_newusertable:
  3312. case no_aggregate:
  3313. case no_newaggregate:
  3314. if (expr->hasProperty(keyedAtom))
  3315. insideCompound = true;
  3316. NewHqlTransformer::analyseExpr(expr);
  3317. break;
  3318. case no_join:
  3319. if (isKeyedJoin(expr) && !expr->hasProperty(_complexKeyed_Atom))
  3320. {
  3321. analyseExpr(expr->queryChild(0));
  3322. doAnalyseChildren(expr, 2);
  3323. }
  3324. else
  3325. NewHqlTransformer::analyseExpr(expr);
  3326. break;
  3327. default:
  3328. NewHqlTransformer::analyseExpr(expr);
  3329. break;
  3330. }
  3331. switch (op)
  3332. {
  3333. case no_newkeyindex:
  3334. extra->sourceOp = no_compound_indexread;
  3335. extra->uid.set(expr->queryProperty(_uid_Atom));
  3336. extra->mode = no_thor;
  3337. break;
  3338. case no_table:
  3339. {
  3340. IHqlExpression * mode = expr->queryChild(2);
  3341. if (!mode)
  3342. break;
  3343. switch (mode->getOperator())
  3344. {
  3345. case no_thor:
  3346. case no_flat:
  3347. if ((flags & CSFcompoundSpill) || !expr->hasProperty(_spill_Atom))
  3348. {
  3349. extra->sourceOp = no_compound_diskread;
  3350. extra->isPreloaded = expr->hasProperty(preloadAtom);
  3351. extra->uid.set(expr->queryProperty(_uid_Atom));
  3352. extra->mode = no_thor;
  3353. }
  3354. break;
  3355. case no_csv:
  3356. if (translator.queryOptions().enableCompoundCsvRead)
  3357. {
  3358. extra->sourceOp = no_compound_diskread;
  3359. extra->isPreloaded = expr->hasProperty(preloadAtom);
  3360. extra->uid.set(expr->queryProperty(_uid_Atom));
  3361. extra->mode = mode->getOperator();
  3362. }
  3363. break;
  3364. }
  3365. break;
  3366. }
  3367. case no_hqlproject:
  3368. {
  3369. if (!expr->hasProperty(prefetchAtom))
  3370. {
  3371. IHqlExpression * transform = expr->queryChild(1);
  3372. IHqlExpression * counter = queryPropertyChild(expr, _countProject_Atom, 0);
  3373. if (!counter || !transformContainsCounter(transform, counter))
  3374. {
  3375. IHqlExpression * dataset = expr->queryChild(0);
  3376. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3377. //Skips in datasets don't work very well at the moment - pure() is a bit strict really.
  3378. if ((dataset->isPure() || expr->hasProperty(keyedAtom)) && !parentExtra->isAggregate())
  3379. {
  3380. extra->inherit(*parentExtra);
  3381. if (expr->hasProperty(keyedAtom))
  3382. extra->ensureCompound();
  3383. if (!isPureActivity(expr))
  3384. {
  3385. extra->isFiltered = true;
  3386. extra->isPostFiltered = true;
  3387. }
  3388. }
  3389. }
  3390. }
  3391. break;
  3392. }
  3393. case no_keyedlimit:
  3394. {
  3395. IHqlExpression * dataset = expr->queryChild(0);
  3396. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3397. if (!parentExtra->isAggregate() && parentExtra->isBinary())
  3398. {
  3399. extra->inherit(*parentExtra);
  3400. extra->ensureCompound();
  3401. }
  3402. break;
  3403. }
  3404. case no_inlinetable:
  3405. case no_temptable:
  3406. case no_datasetfromrow:
  3407. extra->sourceOp = no_compound_inline;
  3408. extra->mode = no_inlinetable;
  3409. break;
  3410. case no_workunit_dataset:
  3411. // extra->sourceOp = no_compound_childread;
  3412. break;
  3413. case no_getgraphresult:
  3414. case no_externalcall:
  3415. // if (expr->isDataset())
  3416. // extra->sourceOp = no_compound_childread;
  3417. break;
  3418. case no_compound_diskread:
  3419. case no_compound_disknormalize:
  3420. case no_compound_diskaggregate:
  3421. case no_compound_diskcount:
  3422. case no_compound_diskgroupaggregate:
  3423. case no_compound_indexread:
  3424. case no_compound_indexnormalize:
  3425. case no_compound_indexaggregate:
  3426. case no_compound_indexcount:
  3427. case no_compound_indexgroupaggregate:
  3428. case no_compound_childread:
  3429. case no_compound_childnormalize:
  3430. case no_compound_childaggregate:
  3431. case no_compound_childcount:
  3432. case no_compound_childgroupaggregate:
  3433. case no_compound_selectnew:
  3434. case no_compound_inline:
  3435. {
  3436. IHqlExpression * dataset = expr->queryChild(0);
  3437. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3438. extra->inherit(*parentExtra, op);
  3439. extra->uid.set(expr->queryProperty(_uid_Atom));
  3440. break;
  3441. }
  3442. case no_select:
  3443. if (expr->isDataset())
  3444. {
  3445. if (expr->hasProperty(newAtom))
  3446. {
  3447. IHqlExpression * dataset = expr->queryChild(0);
  3448. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3449. if (!parentExtra->isAggregate() && !parentExtra->hasAnyLimit() && parentExtra->isBinary())
  3450. {
  3451. node_operator newOp = no_none;
  3452. switch (parentExtra->sourceOp)
  3453. {
  3454. case no_compound_diskread:
  3455. case no_compound_disknormalize:
  3456. if (flags & CSFnewdisk)
  3457. newOp = no_compound_disknormalize;
  3458. break;
  3459. case no_compound_indexread:
  3460. case no_compound_indexnormalize:
  3461. if (flags & CSFnewindex)
  3462. newOp = no_compound_indexnormalize;
  3463. break;
  3464. case no_compound_childread:
  3465. case no_compound_childnormalize:
  3466. if (flags & CSFnewchild)
  3467. newOp = no_compound_childnormalize;
  3468. break;
  3469. }
  3470. if (newOp)
  3471. {
  3472. if (extra->inherit(*parentExtra))
  3473. {
  3474. extra->sourceOp = newOp;
  3475. extra->ensureCompound();
  3476. }
  3477. }
  3478. }
  3479. if ((flags & CSFnewchild) && (extra->sourceOp == no_none))
  3480. {
  3481. extra->reset();
  3482. extra->sourceOp = no_compound_selectnew;
  3483. extra->ensureCompound();
  3484. }
  3485. }
  3486. else
  3487. {
  3488. if ((flags & CSFnewchild) && !isTargetSelector(expr)) // latter is optimization - still works without this
  3489. {
  3490. extra->sourceOp = no_compound_childread;
  3491. }
  3492. }
  3493. }
  3494. break;
  3495. case no_choosen:
  3496. {
  3497. IHqlExpression * arg2 = expr->queryChild(2);
  3498. if (arg2 && !arg2->isPure())
  3499. break;
  3500. //fall through
  3501. }
  3502. case no_limit:
  3503. {
  3504. IHqlExpression * dataset = expr->queryChild(0);
  3505. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3506. bool cloneRequired = needToCloneLimit(expr, parentExtra->sourceOp);
  3507. if (cloneRequired && !expr->queryChild(1)->isPure())
  3508. break;
  3509. if (parentExtra->canMergeLimit(expr, targetClusterType) && !isGrouped(expr) && parentExtra->isBinary())
  3510. {
  3511. if (extra->inherit(*parentExtra))
  3512. {
  3513. if (op == no_choosen)
  3514. {
  3515. extra->hasChoosen = true;
  3516. }
  3517. else
  3518. {
  3519. extra->isLimited = true;
  3520. if (expr->hasProperty(skipAtom))
  3521. extra->hasSkipLimit = true;
  3522. }
  3523. if (expr->hasProperty(onFailAtom))
  3524. extra->isCreateRowLimited = true;
  3525. extra->isCloned = cloneRequired;
  3526. }
  3527. }
  3528. break;
  3529. }
  3530. case no_aggregate:
  3531. case no_newusertable:
  3532. case no_newaggregate:
  3533. {
  3534. IHqlExpression * dataset = expr->queryChild(0);
  3535. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3536. if (isAggregateDataset(expr))
  3537. {
  3538. //Don't yet have csv/xml variants!
  3539. if (!parentExtra->isBinary())
  3540. break;
  3541. IHqlExpression * root = queryRoot(dataset);
  3542. if (!root || isGrouped(root) || expr->hasProperty(localAtom))
  3543. break;
  3544. bool isSimpleCountExists = isSimpleCountExistsAggregate(expr, true, false);
  3545. if (parentExtra->isCreateRowLimited)
  3546. break;
  3547. if (parentExtra->hasAnyLimit() && !isSimpleCountExists)
  3548. break;
  3549. node_operator newOp = no_none;
  3550. node_operator parentOp = parentExtra->sourceOp;
  3551. if (queryRealChild(expr, 3))
  3552. {
  3553. //Grouped aggregate
  3554. switch (parentOp)
  3555. {
  3556. case no_compound_diskread:
  3557. case no_compound_disknormalize:
  3558. if (flags & CSFnewdisk)
  3559. newOp = no_compound_diskgroupaggregate;
  3560. break;
  3561. case no_compound_indexread:
  3562. case no_compound_indexnormalize:
  3563. if (flags & CSFnewindex)
  3564. newOp = no_compound_indexgroupaggregate;
  3565. break;
  3566. case no_compound_childread:
  3567. case no_compound_childnormalize:
  3568. if (flags & CSFnewchild)
  3569. newOp = no_compound_childgroupaggregate;
  3570. break;
  3571. }
  3572. }
  3573. else
  3574. {
  3575. switch (parentOp)
  3576. {
  3577. case no_compound_diskread:
  3578. case no_compound_disknormalize:
  3579. if (flags & CSFnewdisk)
  3580. {
  3581. newOp = no_compound_diskaggregate;
  3582. if (isSimpleCountExists && !parentExtra->isFiltered && (parentOp == no_compound_diskread))
  3583. {
  3584. IHqlExpression * root = queryRoot(expr);
  3585. if (root)
  3586. {
  3587. ColumnToOffsetMap * map = translator.queryRecordOffsetMap(root->queryRecord());
  3588. if (map->isFixedWidth())
  3589. extra->forceCompound = true;
  3590. }
  3591. }
  3592. }
  3593. break;
  3594. case no_compound_indexread:
  3595. case no_compound_indexnormalize:
  3596. //Don't create counts for (non-keyed) skip limits - little benefit, and could cause problems
  3597. //correctly returning the counts - e.g. especially for exists()
  3598. if ((flags & CSFnewindex) && !parentExtra->hasSkipLimit)
  3599. {
  3600. newOp = no_compound_indexaggregate;
  3601. //Force counts on indexes to become a new compound activity
  3602. //otherwise if(count(x) > n, f(x), g()) will always cause x to be read and spilt.
  3603. //The commented out test would do a better job, but not all keyed filters have an explicit keyed() so it is insufficient
  3604. //
  3605. //Really this should become a count if there are no index reads with the same level of conditionality, or if all accesses
  3606. //are counts.
  3607. //That can be logged as a future enhancement.....
  3608. // if (isSimpleCountExists && !parentExtra->isPostFiltered && (parentOp == no_compound_indexread))
  3609. if (isSimpleCountExists && (parentOp == no_compound_indexread))
  3610. {
  3611. //A skip limit will require everything to be read anyway - so no point splitting in two
  3612. if (!parentExtra->hasSkipLimit)
  3613. extra->forceCompound = true;
  3614. }
  3615. }
  3616. break;
  3617. case no_compound_childread:
  3618. case no_compound_childnormalize:
  3619. if (flags & CSFnewchild)
  3620. newOp = no_compound_childaggregate;
  3621. break;
  3622. case no_compound_inline:
  3623. if (flags & CSFnewinline)
  3624. newOp = no_compound_inline;
  3625. break;
  3626. }
  3627. }
  3628. if (newOp)
  3629. {
  3630. //NB: When creating a limited aggregate, it is ok if the input indicates it is cloned
  3631. //because the new compound count operation will take it into account.
  3632. extra->inherit(*parentExtra, newOp);
  3633. }
  3634. }
  3635. else
  3636. {
  3637. if (!parentExtra->isAggregate())
  3638. extra->inherit(*queryBodyExtra(dataset));
  3639. }
  3640. if (expr->hasProperty(keyedAtom))
  3641. extra->ensureCompound();
  3642. }
  3643. break;
  3644. case no_filter:
  3645. {
  3646. IHqlExpression * dataset = expr->queryChild(0);
  3647. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3648. if (!parentExtra->hasAnyLimit() && !parentExtra->isAggregate())
  3649. {
  3650. if (extra->inherit(*parentExtra))
  3651. {
  3652. extra->isFiltered = true;
  3653. if (filterIsKeyed(expr))
  3654. extra->ensureCompound();
  3655. if (filterIsUnkeyed(expr))
  3656. extra->isPostFiltered = true;
  3657. }
  3658. }
  3659. }
  3660. break;
  3661. case no_preload:
  3662. {
  3663. IHqlExpression * dataset = expr->queryChild(0);
  3664. extra->inherit(*queryBodyExtra(dataset));
  3665. extra->isPreloaded = true;
  3666. break;
  3667. }
  3668. case no_sorted:
  3669. case no_preservemeta:
  3670. case no_distributed:
  3671. case no_grouped:
  3672. case no_stepped:
  3673. case no_section:
  3674. case no_sectioninput:
  3675. case no_dataset_alias:
  3676. {
  3677. IHqlExpression * dataset = expr->queryChild(0);
  3678. extra->inherit(*queryBodyExtra(dataset));
  3679. break;
  3680. }
  3681. case no_usertable:
  3682. case no_selectfields:
  3683. UNIMPLEMENTED;
  3684. break;
  3685. case no_addfiles:
  3686. if (canProcessInline(NULL, expr) && (flags & CSFnewinline))
  3687. extra->sourceOp = no_compound_inline;
  3688. break;
  3689. }
  3690. insideCompound = wasInsideCompound;
  3691. }
  3692. void CompoundSourceTransformer::analyseMarkBoundaries(IHqlExpression * expr)
  3693. {
  3694. //This code means that child-query compounds inside a compound aren't yet spotted, they are spotted later.
  3695. if (createCompoundSource(expr))
  3696. {
  3697. queryBodyExtra(expr)->isBoundary = true;
  3698. candidate = true;
  3699. return;
  3700. }
  3701. else if (isCompoundSource(expr))
  3702. return;
  3703. //Might cause problems if Some items are references (e.g., keyed, fetch(0), keyedjoin(1) and don't want translating.
  3704. NewHqlTransformer::analyseExpr(expr);
  3705. }
  3706. void CompoundSourceTransformer::analyseExpr(IHqlExpression * expr)
  3707. {
  3708. if (alreadyVisited(expr->queryBody()))
  3709. {
  3710. if ((pass == 0) && !insideCompound)
  3711. {
  3712. if (!queryBodyExtra(expr)->isNoteUsageFirst())
  3713. return;
  3714. }
  3715. else
  3716. return;
  3717. }
  3718. if (expr->isConstant())
  3719. return;
  3720. switch (pass)
  3721. {
  3722. case 0:
  3723. analyseGatherInfo(expr);
  3724. break;
  3725. case 1:
  3726. analyseMarkBoundaries(expr);
  3727. break;
  3728. default:
  3729. throwUnexpected();
  3730. break;
  3731. }
  3732. }
  3733. bool CompoundSourceTransformer::childrenAreShared(IHqlExpression * expr)
  3734. {
  3735. if (isCompoundSource(expr))
  3736. return false;
  3737. unsigned numChildren = getNumChildTables(expr);
  3738. for (unsigned i=0; i < numChildren; i++)
  3739. {
  3740. IHqlExpression * cur = expr->queryChild(i);
  3741. if (queryBodyExtra(cur)->isShared() || childrenAreShared(cur))
  3742. return true;
  3743. }
  3744. return false;
  3745. }
  3746. bool CompoundSourceTransformer::createCompoundSource(IHqlExpression * expr)
  3747. {
  3748. CompoundSourceInfo * extra = queryBodyExtra(expr);
  3749. if (extra->sourceOp == no_none)
  3750. return false;
  3751. if (extra->forceCompound)
  3752. return true;
  3753. if (isSourceActivity(expr))
  3754. return false;
  3755. if (expr->getOperator() == no_preservemeta)
  3756. return false;
  3757. if (extra->isPreloaded)
  3758. return (flags & CSFpreload) != 0;
  3759. switch (extra->sourceOp)
  3760. {
  3761. case no_compound_diskread:
  3762. case no_compound_diskaggregate:
  3763. case no_compound_diskcount:
  3764. case no_compound_diskgroupaggregate:
  3765. return ((flags & CSFignoreShared) || !childrenAreShared(expr));
  3766. case no_compound_disknormalize:
  3767. return true;
  3768. case no_compound_indexaggregate:
  3769. case no_compound_indexcount:
  3770. case no_compound_indexgroupaggregate:
  3771. case no_compound_indexread:
  3772. //MORE: Should stop at sufficiently shared children - e.g.,
  3773. //* if the children are aggregates, when we get that far.
  3774. //* if child actions don't change the filter significantly (e.g, just projects, or no seg monitors)
  3775. {
  3776. if (!(flags & CSFindex))
  3777. return false;
  3778. CompoundSourceInfo * parentExtra = queryBodyExtra(expr->queryChild(0));
  3779. return ((flags & CSFignoreShared) || !childrenAreShared(expr) || !parentExtra->isFiltered);
  3780. }
  3781. case no_compound_indexnormalize:
  3782. return ((flags & CSFindex) != 0);
  3783. case no_compound_inline:
  3784. if (!(flags & CSFnewinline))
  3785. return false;
  3786. return !childrenAreShared(expr);
  3787. case no_compound_childread:
  3788. case no_compound_childnormalize:
  3789. case no_compound_childaggregate:
  3790. case no_compound_childcount:
  3791. case no_compound_childgroupaggregate:
  3792. case no_compound_selectnew:
  3793. return true;
  3794. }
  3795. UNIMPLEMENTED;
  3796. return false;
  3797. }
  3798. IHqlExpression * CompoundSourceTransformer::createTransformed(IHqlExpression * expr)
  3799. {
  3800. if (expr->isConstant())
  3801. return LINK(expr);
  3802. OwnedHqlExpr ret = queryTransformAnnotation(expr);
  3803. if (ret)
  3804. return ret.getClear();
  3805. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  3806. CompoundSourceInfo * extra = queryBodyExtra(expr);
  3807. if (extra->isBoundary)
  3808. {
  3809. HqlExprAttr def = transformed;
  3810. if (extra->isCloned)
  3811. transformed.setown(appendLocalAttribute(transformed));
  3812. transformed.setown(createDataset(extra->sourceOp, LINK(transformed), LINK(extra->uid)));
  3813. if (extra->isCloned)
  3814. {
  3815. HqlExprArray args;
  3816. unwindChildren(args, def);
  3817. args.replace(*transformed.getClear(), 0);
  3818. transformed.setown(def->clone(args));
  3819. }
  3820. }
  3821. return transformed.getClear();
  3822. }
  3823. ANewTransformInfo * CompoundSourceTransformer::createTransformInfo(IHqlExpression * expr)
  3824. {
  3825. return CREATE_NEWTRANSFORMINFO(CompoundSourceInfo, expr);
  3826. }
  3827. bool CompoundSourceTransformer::needToCloneLimit(IHqlExpression * expr, node_operator sourceOp)
  3828. {
  3829. node_operator op = expr->getOperator();
  3830. switch (op)
  3831. {
  3832. case no_choosen:
  3833. if (queryRealChild(expr, 2))
  3834. return true;
  3835. break;
  3836. case no_limit:
  3837. if (expr->hasProperty(skipAtom) && (targetClusterType != RoxieCluster))
  3838. return true;
  3839. break;
  3840. }
  3841. switch (targetClusterType)
  3842. {
  3843. case RoxieCluster:
  3844. return false;
  3845. case HThorCluster:
  3846. return (sourceOp != no_compound_indexread) || (op != no_limit);
  3847. case ThorLCRCluster:
  3848. return true;
  3849. default:
  3850. UNIMPLEMENTED;
  3851. }
  3852. }
  3853. IHqlExpression * CompoundSourceTransformer::process(IHqlExpression * expr)
  3854. {
  3855. analyse(expr, 0);
  3856. analyse(expr, 1);
  3857. if (candidate)
  3858. return transformRoot(expr);
  3859. return LINK(expr);
  3860. }
  3861. //---------------------------------------------------------------------------
  3862. IHqlExpression * getMergedFetch(IHqlExpression * expr)
  3863. {
  3864. IHqlExpression * child = expr->queryChild(0);
  3865. if (isLimitedDataset(child))
  3866. return LINK(expr);
  3867. HqlExprArray args;
  3868. if (child->getOperator() == no_compound_fetch)
  3869. return swapDatasets(expr);
  3870. if (child->getOperator() != no_fetch)
  3871. return LINK(expr);
  3872. args.append(*LINK(expr));
  3873. return createDataset(no_compound_fetch, args);
  3874. }
  3875. static HqlTransformerInfo compoundActivityTransformerInfo("CompoundActivityTransformer");
  3876. CompoundActivityTransformer::CompoundActivityTransformer(ClusterType _targetClusterType) : NewHqlTransformer(compoundActivityTransformerInfo)
  3877. {
  3878. targetClusterType = _targetClusterType;
  3879. }
  3880. IHqlExpression * CompoundActivityTransformer::createTransformed(IHqlExpression * expr)
  3881. {
  3882. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  3883. updateOrphanedSelectors(transformed, expr);
  3884. switch (transformed->getOperator())
  3885. {
  3886. case no_filter:
  3887. return getMergedFetch(transformed);
  3888. case no_limit:
  3889. {
  3890. if (transformed->hasProperty(onFailAtom))
  3891. break;
  3892. LinkedHqlExpr dataset = transformed->queryChild(0);
  3893. if (dataset->hasProperty(limitAtom) || transformed->hasProperty(skipAtom))
  3894. break;
  3895. switch (dataset->getOperator())
  3896. {
  3897. case no_join:
  3898. case no_denormalize:
  3899. case no_denormalizegroup:
  3900. if (isKeyedJoin(dataset))
  3901. break;
  3902. return transformed.getClear();
  3903. default:
  3904. return transformed.getClear();
  3905. }
  3906. if (!isThorCluster(targetClusterType))
  3907. return mergeLimitIntoDataset(dataset, transformed);
  3908. HqlExprArray args;
  3909. unwindChildren(args, transformed);
  3910. args.replace(*mergeLimitIntoDataset(dataset, transformed), 0);
  3911. return transformed->clone(args);
  3912. }
  3913. }
  3914. return transformed.getClear();
  3915. }
  3916. //------------------------------------------------------------------------
  3917. static HqlTransformerInfo optimizeActivityTransformerInfo("OptimizeActivityTransformer");
  3918. OptimizeActivityTransformer::OptimizeActivityTransformer(bool _optimizeCountCompare, bool _optimizeNonEmpty)
  3919. : NewHqlTransformer(optimizeActivityTransformerInfo)
  3920. {
  3921. optimizeCountCompare = _optimizeCountCompare; optimizeNonEmpty = _optimizeNonEmpty;
  3922. }
  3923. void OptimizeActivityTransformer::analyseExpr(IHqlExpression * expr)
  3924. {
  3925. expr = expr->queryBody();
  3926. queryBodyExtra(expr)->noteUsed();
  3927. if (alreadyVisited(expr))
  3928. return;
  3929. NewHqlTransformer::analyseExpr(expr);
  3930. }
  3931. //either a simple count, or isCountAggregate is guaranteed to be true - so structure is well defined
  3932. IHqlExpression * OptimizeActivityTransformer::insertChoosen(IHqlExpression * lhs, IHqlExpression * limit, __int64 limitDelta)
  3933. {
  3934. if (isShared(lhs))
  3935. return NULL;
  3936. IHqlExpression * ds = lhs->queryChild(0);
  3937. HqlExprArray args;
  3938. switch (lhs->getOperator())
  3939. {
  3940. case no_choosen:
  3941. return NULL;
  3942. case no_count:
  3943. case no_newaggregate:
  3944. {
  3945. //count on a child dataset is better if not limited...
  3946. node_operator dsOp = ds->getOperator();
  3947. if ((dsOp == no_select) || (dsOp == no_choosen) || (dsOp == no_rows))
  3948. return NULL;
  3949. args.append(*createDataset(no_choosen, LINK(ds), adjustValue(limit, limitDelta)));
  3950. break;
  3951. }
  3952. case no_implicitcast:
  3953. case no_cast:
  3954. case no_compound_childaggregate:
  3955. case no_compound_diskaggregate:
  3956. case no_compound_indexaggregate:
  3957. case no_select:
  3958. {
  3959. IHqlExpression * newDs = insertChoosen(ds, limit, limitDelta);
  3960. if (!newDs)
  3961. return NULL;
  3962. args.append(*newDs);
  3963. break;
  3964. }
  3965. default:
  3966. throwUnexpectedOp(lhs->getOperator());
  3967. }
  3968. unwindChildren(args, lhs, 1);
  3969. return lhs->clone(args);
  3970. }
  3971. static bool looksLikeSimpleCount(IHqlExpression * expr)
  3972. {
  3973. if ((expr->getOperator() == no_select) && expr->hasProperty(newAtom))
  3974. {
  3975. IHqlExpression * ds = expr->queryChild(0);
  3976. return isSimpleCountAggregate(ds, false);
  3977. }
  3978. return (expr->getOperator() == no_count);
  3979. }
  3980. IHqlExpression * OptimizeActivityTransformer::optimizeCompare(IHqlExpression * lhs, IHqlExpression * rhs, node_operator op)
  3981. {
  3982. if (isShared(lhs))
  3983. return NULL;
  3984. if (!isIndependentOfScope(rhs))
  3985. return NULL;
  3986. if (!looksLikeSimpleCount(lhs))
  3987. return NULL;
  3988. // count(x) op count(y) - not clear if a choosen should be added to either, so assume neither for the moment,
  3989. // (we definitely don't want it added to both, which happens without the second test.)
  3990. if (looksLikeSimpleCount(rhs))
  3991. return NULL;
  3992. //Convert count(x) >= 1 to exists(x) (and other varients)
  3993. node_operator existOp = no_none;
  3994. switch (op)
  3995. {
  3996. case no_ne:
  3997. case no_gt:
  3998. if (matchesConstantValue(rhs, 0))
  3999. existOp = no_exists;
  4000. break;
  4001. case no_eq:
  4002. case no_le:
  4003. if (matchesConstantValue(rhs, 0))
  4004. existOp = no_not;
  4005. break;
  4006. case no_lt:
  4007. if (matchesConstantValue(rhs, 1))
  4008. existOp = no_not;
  4009. break;
  4010. case no_ge:
  4011. if (matchesConstantValue(rhs, 1))
  4012. existOp = no_exists;
  4013. break;
  4014. }
  4015. if (existOp != no_none)
  4016. {
  4017. if (lhs->getOperator() == no_count)
  4018. {
  4019. IHqlExpression * ds = lhs->queryChild(0);
  4020. OwnedHqlExpr ret = createValue(no_exists, makeBoolType(), LINK(ds));
  4021. if (existOp == no_not)
  4022. return createValue(no_not, makeBoolType(), ret.getClear());
  4023. return ret.getClear();
  4024. }
  4025. }
  4026. unsigned choosenDelta =0;
  4027. switch (op)
  4028. {
  4029. case no_eq:
  4030. //count(x) == n -> count(choosen(x,n+1)) == n
  4031. choosenDelta = 1;
  4032. break;
  4033. case no_ne:
  4034. //count(x) != 0 -> count(choosen(x,n+1)) != n
  4035. choosenDelta = 1;
  4036. break;
  4037. case no_lt:
  4038. //count(x) < n -> count(choosen(x,n)) < n
  4039. break;
  4040. case no_le:
  4041. //count(x) <= n -> count(choosen(x,n+1)) <= n
  4042. choosenDelta = 1;
  4043. break;
  4044. case no_gt:
  4045. //count(x) > n -> count(choosen(x,n+1)) > n
  4046. choosenDelta = 1;
  4047. break;
  4048. case no_ge:
  4049. //count(x) >= n -> count(choosen(x,n)) >= n
  4050. break;
  4051. }
  4052. IHqlExpression * newLhs = insertChoosen(lhs, rhs, choosenDelta);
  4053. if (!newLhs)
  4054. return NULL;
  4055. return createValue(op, makeBoolType(), newLhs, LINK(rhs));
  4056. }
  4057. static IHqlExpression * queryNormalizedAggregateParameter(IHqlExpression * expr)
  4058. {
  4059. loop
  4060. {
  4061. switch (expr->getOperator())
  4062. {
  4063. case no_choosen:
  4064. if (queryRealChild(expr, 2))
  4065. return expr;
  4066. break;
  4067. case no_sort:
  4068. case no_subsort:
  4069. case no_distribute:
  4070. break;
  4071. default:
  4072. return expr;
  4073. }
  4074. expr = expr->queryChild(0);
  4075. }
  4076. }
  4077. static bool aggregateMatchesDataset(IHqlExpression * agg, IHqlExpression * ds)
  4078. {
  4079. return queryNormalizedAggregateParameter(agg)->queryBody() == queryNormalizedAggregateParameter(ds)->queryBody();
  4080. }
  4081. static bool isCheckExistsAtleast(IHqlExpression * cond, IHqlExpression * ds, __int64 minMinElements, __int64 maxMinElements)
  4082. {
  4083. if (maxMinElements <= 0)
  4084. return false;
  4085. switch (cond->getOperator())
  4086. {
  4087. case no_exists:
  4088. if (aggregateMatchesDataset(cond->queryChild(0), ds))
  4089. return true;
  4090. break;
  4091. case no_ne:
  4092. {
  4093. IHqlExpression * condLhs = cond->queryChild(0);
  4094. if ((condLhs->getOperator() == no_count) && isZero(cond->queryChild(1)))
  4095. {
  4096. if (aggregateMatchesDataset(condLhs->queryChild(0), ds))
  4097. return true;
  4098. }
  4099. break;
  4100. }
  4101. case no_gt:
  4102. minMinElements--;
  4103. maxMinElements--;
  4104. //fallthrough
  4105. case no_ge:
  4106. {
  4107. IHqlExpression * condLhs = cond->queryChild(0);
  4108. if (condLhs->getOperator() == no_count)
  4109. {
  4110. IHqlExpression * limit = cond->queryChild(1);
  4111. if (limit->queryValue())
  4112. {
  4113. __int64 limitVal = limit->queryValue()->getIntValue();
  4114. if ((limitVal <= maxMinElements) && (limitVal >= minMinElements))
  4115. {
  4116. if (aggregateMatchesDataset(condLhs->queryChild(0), ds))
  4117. return true;
  4118. }
  4119. }
  4120. }
  4121. }
  4122. break;
  4123. }
  4124. return false;
  4125. }
  4126. //is "value" of the form ds[n].x and other the same as the null expression for that field?
  4127. //if so we may be able to remove a condition
  4128. IHqlExpression * queryNullDsSelect(__int64 & selectIndex, IHqlExpression * value, IHqlExpression * other)
  4129. {
  4130. if (isCast(value))
  4131. value = value->queryChild(0);
  4132. if (value->getOperator() != no_select)
  4133. return NULL;
  4134. bool isNew;
  4135. IHqlExpression * ds = querySelectorDataset(value, isNew);
  4136. if (!isNew || ds->getOperator() != no_selectnth)
  4137. return NULL;
  4138. IValue * index = ds->queryChild(1)->queryValue();
  4139. if (!index)
  4140. return NULL;
  4141. if (!isNullExpr(other, value))
  4142. return NULL;
  4143. selectIndex = index->getIntValue();
  4144. return ds->queryChild(0);
  4145. }
  4146. IHqlExpression * OptimizeActivityTransformer::createTransformed(IHqlExpression * expr)
  4147. {
  4148. OwnedHqlExpr transformed = doCreateTransformed(expr);
  4149. if (transformed)
  4150. {
  4151. assertex(transformed != expr);
  4152. queryBodyExtra(transformed)->inherit(queryBodyExtra(expr));
  4153. return transform(transformed);
  4154. }
  4155. transformed.setown(NewHqlTransformer::createTransformed(expr));
  4156. if (transformed != expr)
  4157. queryBodyExtra(transformed)->inherit(queryBodyExtra(expr));
  4158. return transformed.getClear();
  4159. }
  4160. IHqlExpression * OptimizeActivityTransformer::doCreateTransformed(IHqlExpression * expr)
  4161. {
  4162. node_operator op = expr->getOperator();
  4163. switch (op)
  4164. {
  4165. case no_if:
  4166. {
  4167. IHqlExpression * cond = expr->queryChild(0);
  4168. IHqlExpression * lhs = expr->queryChild(1);
  4169. //convert if(exists(x)|count(x)>0, x, y) to nonempty(x, y);
  4170. //must happen before the count(x)>n optimization below....
  4171. if (optimizeNonEmpty && expr->isDataset() && !canProcessInline(NULL, expr))
  4172. {
  4173. if (isCheckExistsAtleast(cond, lhs, 1, 1))
  4174. {
  4175. HqlExprArray args;
  4176. args.append(*transform(lhs));
  4177. args.append(*transform(expr->queryChild(2)));
  4178. OwnedHqlExpr ret = createDataset(no_nonempty, args);
  4179. return expr->cloneAllAnnotations(ret);
  4180. }
  4181. }
  4182. __int64 selectIndex = 0;
  4183. IHqlExpression * ds = queryNullDsSelect(selectIndex, expr->queryChild(1), expr->queryChild(2));
  4184. if (ds)
  4185. {
  4186. if (isCheckExistsAtleast(cond, ds, 1, selectIndex))
  4187. return LINK(lhs);
  4188. }
  4189. break;
  4190. }
  4191. case no_selectnth:
  4192. {
  4193. IHqlExpression * ds = expr->queryChild(0);
  4194. if ((ds->getOperator() != no_sort) || isShared(ds))
  4195. break;
  4196. IHqlExpression * index = expr->queryChild(1);
  4197. if (getIntValue(index, 99999) > 100)
  4198. break;
  4199. OwnedHqlExpr transformedDs = transform(ds);
  4200. OwnedHqlExpr transformedIndex = transform(index);
  4201. HqlExprArray args;
  4202. unwindChildren(args, transformedDs);
  4203. args.add(*LINK(transformedIndex), 2);
  4204. OwnedHqlExpr topn = createDataset(no_topn, args);
  4205. args.kill();
  4206. args.append(*ds->cloneAllAnnotations(topn));
  4207. args.append(*LINK(transformedIndex));
  4208. unwindChildren(args, expr, 2);
  4209. return expr->clone(args);
  4210. }
  4211. case no_eq:
  4212. case no_ne:
  4213. case no_le:
  4214. case no_lt:
  4215. case no_ge:
  4216. case no_gt:
  4217. //MORE Would still be worth doing for thor i) if a no_select non-new, ii) if the lhs was an aggregate on
  4218. //a compound_disk_aggregate iii) possibly others.
  4219. if (optimizeCountCompare)
  4220. {
  4221. IHqlExpression * lhs = expr->queryChild(0);
  4222. IHqlExpression * rhs = expr->queryChild(1);
  4223. OwnedHqlExpr ret = optimizeCompare(lhs, rhs, op);
  4224. if (!ret)
  4225. ret.setown(optimizeCompare(rhs, lhs, getReverseOp(op)));
  4226. if (ret)
  4227. return ret.getClear();
  4228. }
  4229. break;
  4230. }
  4231. return NULL;
  4232. }
  4233. void optimizeActivities(HqlExprArray & exprs, bool optimizeCountCompare, bool optimizeNonEmpty)
  4234. {
  4235. OptimizeActivityTransformer transformer(optimizeCountCompare, optimizeNonEmpty);
  4236. HqlExprArray results;
  4237. transformer.analyseArray(exprs, 0);
  4238. transformer.transformRoot(exprs, results);
  4239. replaceArray(exprs, results);
  4240. }
  4241. IHqlExpression * optimizeActivities(IHqlExpression * expr, bool optimizeCountCompare, bool optimizeNonEmpty)
  4242. {
  4243. OptimizeActivityTransformer transformer(optimizeCountCompare, optimizeNonEmpty);
  4244. HqlExprArray results;
  4245. transformer.analyse(expr, 0);
  4246. return transformer.transformRoot(expr);
  4247. }
  4248. void optimizeActivities(WorkflowArray & array, bool optimizeCountCompare, bool optimizeNonEmpty)
  4249. {
  4250. ForEachItemIn(idx, array)
  4251. optimizeActivities(array.item(idx).queryExprs(), optimizeCountCompare, optimizeNonEmpty);
  4252. }
  4253. IHqlExpression * GlobalAttributeInfo::queryAlias(IHqlExpression * value)
  4254. {
  4255. if (!aliasName)
  4256. {
  4257. if (storedName)
  4258. aliasName.set(storedName);
  4259. else
  4260. aliasName.setown(createNextStringValue(value, storedPrefix));
  4261. }
  4262. return aliasName;
  4263. }
  4264. IHqlExpression * GlobalAttributeInfo::queryFilename(IHqlExpression * value, IConstWorkUnit * wu, bool isRoxie)
  4265. {
  4266. if (!cachedFilename)
  4267. {
  4268. if (storedName)
  4269. cachedFilename.set(storedName);
  4270. else
  4271. cachedFilename.setown(createNextStringValue(value, filePrefix));
  4272. if (persistOp != no_persist)
  4273. {
  4274. StringBuffer prefix("~");
  4275. if (storedName)
  4276. {
  4277. if (persistOp == no_stored)
  4278. prefix.append("spill::stored");
  4279. else if (persistOp == no_checkpoint)
  4280. prefix.append("spill::checkpoint");
  4281. }
  4282. if (persistOp == no_once)
  4283. prefix.append("once::");
  4284. bool wuidIsConstant = isRoxie || !wu->getCloneable();
  4285. if (wuidIsConstant)
  4286. {
  4287. StringBuffer s;
  4288. cachedFilename->queryValue()->getStringValue(s.append(prefix));
  4289. cachedFilename.setown(createConstant(s.str()));
  4290. }
  4291. else
  4292. {
  4293. ITypeInfo * type = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  4294. OwnedHqlExpr filename = createValue(no_concat, type, createConstant(prefix), cachedFilename.getClear());
  4295. cachedFilename.setown(foldHqlExpression(filename));
  4296. }
  4297. }
  4298. }
  4299. return cachedFilename;
  4300. }
  4301. IHqlExpression * GlobalAttributeInfo::createSetValue(IHqlExpression * value, IHqlExpression * name)
  4302. {
  4303. HqlExprArray args;
  4304. args.append(*LINK(value));
  4305. args.append(*createAttribute(sequenceAtom, LINK(sequence)));
  4306. args.append(*createAttribute(namedAtom, LINK(name)));
  4307. if (extraSetAttr)
  4308. extraSetAttr->unwindList(args, no_comma);
  4309. if (cluster)
  4310. args.append(*createAttribute(clusterAtom, LINK(cluster)));
  4311. if (setOp == no_setresult)
  4312. return createSetResult(args);
  4313. return createValue(setOp, makeVoidType(), args);
  4314. }
  4315. IHqlExpression * GlobalAttributeInfo::getStoredKey()
  4316. {
  4317. return createAttribute(nameAtom, LINK(sequence), lowerCaseHqlExpr(storedName));
  4318. }
  4319. void GlobalAttributeInfo::setCluster(IHqlExpression * expr)
  4320. {
  4321. if (expr && !isBlankString(expr))
  4322. cluster.set(expr);
  4323. }
  4324. void GlobalAttributeInfo::extractGlobal(IHqlExpression * global, ClusterType platform)
  4325. {
  4326. few = spillToWorkunitNotFile(value, platform) || value->isDictionary();
  4327. if (global)
  4328. {
  4329. if (global->hasProperty(fewAtom))
  4330. few = true;
  4331. else if (global->hasProperty(manyAtom) && (platform != RoxieCluster))
  4332. few = false;
  4333. }
  4334. setOp = no_setresult;
  4335. sequence.setown(getLocalSequenceNumber());
  4336. persistOp = no_global;
  4337. }
  4338. void GlobalAttributeInfo::extractStoredInfo(IHqlExpression * expr, IHqlExpression * originalValue, bool isRoxie)
  4339. {
  4340. node_operator op = expr->getOperator();
  4341. few = expr->hasProperty(fewAtom) || (isRoxie) || (value->isDictionary() && !expr->hasProperty(manyAtom));
  4342. switch (op)
  4343. {
  4344. case no_stored:
  4345. setOp = no_ensureresult;
  4346. storedName.set(expr->queryChild(0));
  4347. sequence.setown(getStoredSequenceNumber());
  4348. few = true;
  4349. break;
  4350. case no_checkpoint:
  4351. setOp = no_ensureresult;
  4352. storedName.set(expr->queryChild(0));
  4353. sequence.setown(getLocalSequenceNumber());
  4354. extraSetAttr.setown(createAttribute(checkpointAtom));
  4355. break;
  4356. case no_persist:
  4357. setOp = no_ensureresult;
  4358. storedName.set(expr->queryChild(0));
  4359. sequence.setown(getGlobalSequenceNumber());
  4360. extraSetAttr.setown(createAttribute(_workflowPersist_Atom, LINK(originalValue)));
  4361. setCluster(queryRealChild(expr, 1));
  4362. few = expr->hasProperty(fewAtom); // PERSISTs need a consistent format.
  4363. extraOutputAttr.setown(createComma(LINK(expr->queryProperty(expireAtom)), LINK(expr->queryProperty(clusterAtom))));
  4364. break;
  4365. case no_global:
  4366. throwUnexpected();
  4367. case no_independent:
  4368. setOp = no_setresult;
  4369. storedName.clear();
  4370. sequence.setown(getLocalSequenceNumber());
  4371. extraSetAttr.setown(createAttribute(_workflow_Atom));
  4372. setCluster(queryRealChild(expr, 0));
  4373. op = no_global;
  4374. break;
  4375. case no_once:
  4376. setOp = no_setresult;
  4377. storedName.clear();
  4378. sequence.setown(getOnceSequenceNumber());
  4379. extraSetAttr.setown(createAttribute(_workflow_Atom));
  4380. break;
  4381. case no_success:
  4382. case no_failure:
  4383. case no_recovery:
  4384. if(setOp == no_none)
  4385. {
  4386. storedName.clear();
  4387. setOp = no_setresult;
  4388. sequence.setown(getLocalSequenceNumber());
  4389. }
  4390. break;
  4391. default:
  4392. return;
  4393. }
  4394. persistOp = op;
  4395. }
  4396. void GlobalAttributeInfo::splitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie)
  4397. {
  4398. doSplitGlobalDefinition(type, value, wu, setOutput, getOutput, isRoxie);
  4399. }
  4400. void GlobalAttributeInfo::doSplitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie)
  4401. {
  4402. OwnedHqlExpr targetName;
  4403. if (storedName)
  4404. targetName.set(storedName);
  4405. else
  4406. targetName.setown(createNextStringValue(value));
  4407. ITypeInfo * valueType = value->queryType();
  4408. if (value->isDataset() || value->isDictionary())
  4409. {
  4410. IHqlExpression * groupOrder = (IHqlExpression *)valueType->queryGroupInfo();
  4411. if (few)
  4412. {
  4413. splitSmallDataset(value, setOutput, getOutput);
  4414. return;
  4415. }
  4416. LinkedHqlExpr filename = queryFilename(value, wu, isRoxie);
  4417. HqlExprArray args;
  4418. if (value->isDictionary())
  4419. args.append(*createDataset(no_datasetfromdictionary, LINK(value)));
  4420. else
  4421. args.append(*LINK(value));
  4422. args.append(*LINK(filename));
  4423. //NB: Also update the dataset node at the end...
  4424. if (valueType->getTypeCode() == type_groupedtable)
  4425. args.append(*createAttribute(groupedAtom));
  4426. else
  4427. assertex(groupOrder == NULL);
  4428. bool compressFile = true;
  4429. switch (persistOp)
  4430. {
  4431. case no_persist:
  4432. {
  4433. args.append(*createAttribute(_workflowPersist_Atom));
  4434. args.append(*createAttribute(sequenceAtom, getGlobalSequenceNumber()));
  4435. //add a flag to help get the resourcing right - may need to hash distribute on different size thor
  4436. IHqlExpression * distribution = queryDistribution(valueType);
  4437. if (distribution && !distribution->isAttribute())
  4438. args.append(*createAttribute(distributedAtom));
  4439. break;
  4440. }
  4441. case no_stored:
  4442. args.append(*createAttribute(ownedAtom));
  4443. args.append(*createAttribute(sequenceAtom, getStoredSequenceNumber()));
  4444. break;
  4445. case no_checkpoint:
  4446. args.append(*createAttribute(ownedAtom));
  4447. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  4448. break;
  4449. case no_once:
  4450. args.append(*createAttribute(ownedAtom));
  4451. args.append(*createAttribute(sequenceAtom, getOnceSequenceNumber()));
  4452. break;
  4453. case no_global:
  4454. //May extend over several different graphs
  4455. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  4456. args.append(*createAttribute(ownedAtom));
  4457. args.append(*createAttribute(jobTempAtom));
  4458. break;
  4459. default:
  4460. //global, independent, success, failure, etc. etc.
  4461. args.append(*createAttribute(ownedAtom));
  4462. args.append(*createAttribute(jobTempAtom));
  4463. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  4464. break;
  4465. }
  4466. if (compressFile)
  4467. args.append(*createAttribute(__compressed__Atom));
  4468. args.append(*createAttribute(overwriteAtom));
  4469. if (extraOutputAttr)
  4470. extraOutputAttr->unwindList(args, no_comma);
  4471. OwnedHqlExpr output = createValue(no_output, makeVoidType(), args);
  4472. // if (persistOp == no_independent)
  4473. if (setOp == no_setresult)
  4474. setOutput.set(output);
  4475. else
  4476. setOutput.setown(createSetValue(output, queryAlias(value)));
  4477. if(getOutput)
  4478. {
  4479. IHqlExpression * record = value->queryRecord();
  4480. args.kill();
  4481. args.append(*LINK(filename));
  4482. args.append(*LINK(record));
  4483. args.append(*createValue(no_thor));
  4484. args.append(*createAttribute(_noVirtual_Atom)); // don't interpret virtual fields in spilled output
  4485. if (persistOp == no_persist)
  4486. args.append(*createAttribute(_workflowPersist_Atom));
  4487. if (groupOrder)
  4488. args.append(*createAttribute(groupedAtom));
  4489. if (compressFile)
  4490. args.append(*createAttribute(__compressed__Atom));
  4491. if (hasSingleRow(value))
  4492. args.append(*createAttribute(rowAtom));
  4493. if (output->hasProperty(jobTempAtom))
  4494. args.append(*createAttribute(jobTempAtom));
  4495. if (persistOp != no_stored)
  4496. {
  4497. IHqlExpression * recordCountAttr = queryRecordCountInfo(value);
  4498. if (recordCountAttr)
  4499. args.append(*LINK(recordCountAttr));
  4500. }
  4501. OwnedHqlExpr getValue = createDataset(no_table, args);
  4502. //getValue.setown(cloneInheritedAnnotations(value, getValue));
  4503. if (persistOp != no_stored)
  4504. getValue.setown(preserveTableInfo(getValue, value, false, (persistOp == no_persist) ? filename : NULL));
  4505. //Note: getValue->queryType() != valueType because the dataset used for field resolution has changed...
  4506. if (value->isDictionary())
  4507. getValue.setown(createDictionary(no_createdictionary, getValue.getClear()));
  4508. getOutput->setown(getValue.getClear());
  4509. }
  4510. }
  4511. else if (type->getTypeCode() == type_void)
  4512. {
  4513. switch (persistOp)
  4514. {
  4515. case no_stored:
  4516. case no_checkpoint:
  4517. case no_once:
  4518. case no_persist:
  4519. setOutput.setown(createSetValue(value, queryAlias(value)));
  4520. break;
  4521. default:
  4522. setOutput.set(value);
  4523. break;
  4524. }
  4525. if(getOutput) getOutput->setown(createValue(no_null, makeVoidType(), createAttribute(_internal_Atom, LINK(sequence), LINK(queryAlias(value)))));
  4526. }
  4527. else
  4528. {
  4529. ITypeInfo * ct = type->queryChildType();
  4530. if (type->getTypeCode() == type_set)
  4531. extraSetAttr.setown(createComma(extraSetAttr.getClear(), createAttribute(_original_Atom, createValue(no_implicitcast, LINK(type), LINK(value)))));
  4532. setOutput.setown(createSetValue(value, queryAlias(value)));
  4533. if(getOutput) getOutput->setown(createGetResultFromSetResult(setOutput, type));
  4534. }
  4535. }
  4536. void GlobalAttributeInfo::createSmallOutput(IHqlExpression * value, SharedHqlExpr & setOutput)
  4537. {
  4538. if (value->getOperator() == no_temptable)
  4539. {
  4540. IHqlExpression * values = value->queryChild(0);
  4541. if ((values->getOperator() == no_null) ||
  4542. ((values->getOperator() == no_list) && (values->numChildren() == 0)))
  4543. {
  4544. OwnedHqlExpr newNull = createDataset(no_null, LINK(value->queryRecord()));
  4545. setOutput.setown(createSetValue(newNull, queryAlias(value)));
  4546. return;
  4547. }
  4548. else if (values->getOperator() == no_all)
  4549. {
  4550. OwnedHqlExpr newAll = createDataset(no_all, LINK(value->queryRecord()));
  4551. setOutput.setown(createSetValue(newAll, queryAlias(value)));
  4552. return;
  4553. }
  4554. }
  4555. // else if (value->getOperator() == no_null)
  4556. // {
  4557. // setOutput.setown(createSetValue(value, queryAlias()));
  4558. // return;
  4559. // }
  4560. HqlExprArray args;
  4561. args.append(*LINK(value));
  4562. args.append(*createAttribute(sequenceAtom, LINK(sequence)));
  4563. args.append(*createAttribute(namedAtom, LINK(queryAlias(value))));
  4564. if (isGrouped(value))
  4565. args.append(*createAttribute(groupedAtom));
  4566. setOutput.setown(createValue(no_output, makeVoidType(), args));
  4567. if (setOp != no_setresult)
  4568. {
  4569. extraSetAttr.setown(createComma(LINK(extraSetAttr), createAttribute(noSetAtom)));
  4570. setOutput.setown(createSetValue(setOutput, queryAlias(value)));
  4571. }
  4572. }
  4573. void GlobalAttributeInfo::checkFew(HqlCppTranslator & translator)
  4574. {
  4575. // if (few && isGrouped(value))
  4576. // translator.WARNINGAT(queryLocation(value), HQLWRN_GroupedGlobalFew);
  4577. }
  4578. void GlobalAttributeInfo::splitSmallDataset(IHqlExpression * value, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput)
  4579. {
  4580. createSmallOutput(value, setOutput);
  4581. if(getOutput)
  4582. {
  4583. IHqlExpression * record = value->queryRecord();
  4584. HqlExprArray args;
  4585. args.append(*LINK(record));
  4586. args.append(*createAttribute(nameAtom, LINK(queryAlias(value))));
  4587. args.append(*createAttribute(sequenceAtom, LINK(sequence)));
  4588. if (isGrouped(value))
  4589. args.append(*createAttribute(groupedAtom));
  4590. if (persistOp != no_stored)
  4591. {
  4592. IHqlExpression * recordCountAttr = queryRecordCountInfo(value);
  4593. if (recordCountAttr)
  4594. args.append(*LINK(recordCountAttr));
  4595. }
  4596. OwnedHqlExpr wuRead = value->isDictionary() ? createDictionary(no_workunit_dataset, args) : createDataset(no_workunit_dataset, args);
  4597. //wuRead.setown(cloneInheritedAnnotations(value, wuRead));
  4598. if (persistOp != no_stored)
  4599. getOutput->setown(preserveTableInfo(wuRead, value, true, NULL));
  4600. else
  4601. getOutput->set(wuRead);
  4602. }
  4603. }
  4604. //------------------------------------------------------------------------
  4605. static bool isStored(IHqlExpression * set)
  4606. {
  4607. switch (set->getOperator())
  4608. {
  4609. case no_setresult:
  4610. case no_ensureresult:
  4611. case no_output:
  4612. return matchesConstantValue(queryPropertyChild(set, sequenceAtom, 0), ResultSequenceStored);
  4613. }
  4614. return false;
  4615. }
  4616. static bool isTrivialStored(IHqlExpression * set)
  4617. {
  4618. switch (set->getOperator())
  4619. {
  4620. case no_setresult:
  4621. case no_ensureresult:
  4622. if (matchesConstantValue(queryPropertyChild(set, sequenceAtom, 0), ResultSequenceStored))
  4623. {
  4624. IHqlExpression * value = set->queryChild(0);
  4625. loop
  4626. {
  4627. switch (value->getOperator())
  4628. {
  4629. case no_constant:
  4630. case no_all:
  4631. case no_null:
  4632. return true;
  4633. case no_list:
  4634. return (value->numChildren() == 0);
  4635. case no_cast:
  4636. case no_implicitcast:
  4637. value = value->queryChild(0);
  4638. break;
  4639. case no_output:
  4640. return isTrivialInlineOutput(value);
  4641. default:
  4642. return false;
  4643. }
  4644. }
  4645. }
  4646. break;
  4647. case no_output:
  4648. return isTrivialInlineOutput(set);
  4649. }
  4650. return false;
  4651. }
  4652. inline bool isWorkflowAction(IHqlExpression * expr)
  4653. {
  4654. return expr && (expr->getOperator() == no_workflow_action);
  4655. }
  4656. void cloneDependencies(UnsignedArray & tgt, const UnsignedArray & src)
  4657. {
  4658. ForEachItemIn(i, src)
  4659. tgt.append(src.item(i));
  4660. }
  4661. inline bool addDependency(UnsignedArray & tgt, unsigned wfid)
  4662. {
  4663. if (!tgt.contains(wfid))
  4664. {
  4665. tgt.append(wfid);
  4666. return true;
  4667. }
  4668. return false;
  4669. }
  4670. void inheritDependencies(UnsignedArray & tgt, const UnsignedArray & src)
  4671. {
  4672. ForEachItemIn(i, src)
  4673. addDependency(tgt, src.item(i));
  4674. }
  4675. bool hasSameDependencies(UnsignedArray const & d1, UnsignedArray const & d2)
  4676. {
  4677. if (d1.ordinality() != d2.ordinality())
  4678. return false;
  4679. ForEachItemIn(i, d2)
  4680. {
  4681. if (d1.find(d2.item(i)) == NotFound)
  4682. return false;
  4683. }
  4684. return true;
  4685. }
  4686. bool hasExtraDependencies(UnsignedArray const & p, UnsignedArray const & n, UnsignedArray const & ignore)
  4687. {
  4688. if (n.ordinality() > p.ordinality() + ignore.ordinality())
  4689. return true;
  4690. ForEachItemIn(i, n)
  4691. {
  4692. unsigned cur = n.item(i);
  4693. if (!p.contains(cur) && !ignore.contains(cur))
  4694. return true;
  4695. }
  4696. return false;
  4697. }
  4698. void diffDependencies(UnsignedArray & target, UnsignedArray const & d1, UnsignedArray const & d2)
  4699. {
  4700. ForEachItemIn(i, d1)
  4701. {
  4702. unsigned cur = d1.item(i);
  4703. if (d2.find(cur) == NotFound)
  4704. addDependency(target, cur);
  4705. }
  4706. ForEachItemIn(j, d2)
  4707. {
  4708. unsigned cur = d2.item(j);
  4709. if (d1.find(cur) == NotFound)
  4710. addDependency(target, cur);
  4711. }
  4712. }
  4713. void intersectDependencies(UnsignedArray & target, UnsignedArray const & d1, UnsignedArray const & d2)
  4714. {
  4715. ForEachItemIn(i, d1)
  4716. {
  4717. unsigned cur = d1.item(i);
  4718. if (d2.find(cur) != NotFound)
  4719. addDependency(target, cur);
  4720. }
  4721. }
  4722. //------------------------------------------------------------------------
  4723. static HqlTransformerInfo workflowTransformerInfo("WorkflowTransformer");
  4724. WorkflowTransformer::WorkflowTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  4725. : NewHqlTransformer(workflowTransformerInfo), wu(_wu), translator(_translator), wfidCount(0)
  4726. {
  4727. trivialStoredWfid = 0;
  4728. nextInternalFunctionId = 0;
  4729. onceWfid = 0;
  4730. combineAllStored = translator.queryOptions().combineAllStored;
  4731. combineTrivialStored = translator.queryOptions().combineTrivialStored;
  4732. isRootAction = true;
  4733. isRoxie = (translator.getTargetClusterType() == RoxieCluster);
  4734. workflowOut = NULL;
  4735. isConditional = false;
  4736. insideStored = false;
  4737. }
  4738. //-- Helper routines --
  4739. IWorkflowItem * WorkflowTransformer::addWorkflowToWorkunit(unsigned wfid, WFType type, WFMode mode, UnsignedArray const & dependencies, ContingencyData const & conts, IHqlExpression * cluster)
  4740. {
  4741. Owned<IWorkflowItem> wf(wu->addWorkflowItem(wfid, type, mode, conts.success, conts.failure, conts.recovery, conts.retries, conts.contingencyFor));
  4742. if (cluster)
  4743. {
  4744. StringBuffer clusterText;
  4745. getStringValue(clusterText, cluster);
  4746. wf->setCluster(clusterText);
  4747. }
  4748. ForEachItemIn(idx, dependencies)
  4749. wf->addDependency(dependencies.item(idx));
  4750. return wf.getClear();
  4751. }
  4752. void WorkflowTransformer::setWorkflowSchedule(IWorkflowItem * wf, const ScheduleData & sched)
  4753. {
  4754. if(sched.now)
  4755. {
  4756. wf->setScheduledNow();
  4757. }
  4758. else
  4759. {
  4760. wu->incEventScheduledCount();
  4761. wf->setScheduledOn(sched.eventName.str(), sched.eventText.str());
  4762. if(sched.counting)
  4763. {
  4764. wf->setScheduleCount(sched.count);
  4765. if (sched.count == 0)
  4766. wf->setState(WFStateDone);
  4767. }
  4768. }
  4769. int priority = sched.priority;
  4770. if(priority > 100) priority = 100;
  4771. if(priority < 0) priority = 0;
  4772. wf->setSchedulePriority(priority);
  4773. }
  4774. void WorkflowTransformer::setWorkflowPersist(IWorkflowItem * wf, char const * persistName, unsigned persistWfid)
  4775. {
  4776. wf->setPersistInfo(persistName, persistWfid);
  4777. }
  4778. WorkflowItem * WorkflowTransformer::createWorkflowItem(IHqlExpression * expr, unsigned wfid, unsigned persistWfid)
  4779. {
  4780. WorkflowItem * item = new WorkflowItem(wfid);
  4781. expr->unwindList(item->queryExprs(), no_comma);
  4782. gatherIndirectDependencies(item->dependencies, expr);
  4783. return item;
  4784. }
  4785. IWorkflowItem * WorkflowTransformer::lookupWorkflowItem(unsigned wfid)
  4786. {
  4787. Owned<IWorkflowItemIterator> iter = wu->updateWorkflowItems();
  4788. ForEach(*iter)
  4789. {
  4790. Owned<IWorkflowItem> cur = iter->get();
  4791. if (cur->queryWfid() == wfid)
  4792. return cur.getClear();
  4793. }
  4794. return NULL;
  4795. }
  4796. bool WorkflowTransformer::hasStoredDependencies(IHqlExpression * expr)
  4797. {
  4798. return false;
  4799. }
  4800. void WorkflowTransformer::inheritDependencies(IHqlExpression * expr)
  4801. {
  4802. ForEachChild(i, expr)
  4803. copyDependencies(queryBodyExtra(expr->queryChild(i)), queryBodyExtra(expr));
  4804. }
  4805. void WorkflowTransformer::copyDependencies(WorkflowTransformInfo * source, WorkflowTransformInfo * dest)
  4806. {
  4807. if(!source) return;
  4808. UnsignedArray const & dependencies = source->queryDependencies();
  4809. ForEachItemIn(idx, dependencies)
  4810. dest->addDependency(dependencies.item(idx));
  4811. }
  4812. void WorkflowTransformer::copySetValueDependencies(WorkflowTransformInfo * source, IHqlExpression * expr)
  4813. {
  4814. node_operator op = expr->getOperator();
  4815. if (op == no_compound || op==no_actionlist)
  4816. {
  4817. copySetValueDependencies(source, expr->queryChild(expr->numChildren()-1));
  4818. inheritDependencies(expr);
  4819. }
  4820. else
  4821. copyDependencies(source, queryBodyExtra(expr));
  4822. }
  4823. unsigned WorkflowTransformer::ensureWorkflowAction(IHqlExpression * expr)
  4824. {
  4825. if (isWorkflowAction(expr))
  4826. return (unsigned)getIntValue(expr->queryChild(0));
  4827. unsigned wfid = ++wfidCount;
  4828. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(expr), rootCluster);
  4829. workflowOut->append(*createWorkflowItem(expr, wfid));
  4830. return wfid;
  4831. }
  4832. //-- first pass - extracting workflow
  4833. unsigned WorkflowTransformer::splitValue(IHqlExpression * value)
  4834. {
  4835. GlobalAttributeInfo info("spill::wf", "wf", value);
  4836. info.sequence.setown(getLocalSequenceNumber());
  4837. info.setOp = no_setresult;
  4838. info.persistOp = no_global;
  4839. OwnedHqlExpr setValue;
  4840. info.checkFew(translator);
  4841. info.splitGlobalDefinition(value->queryType(), value, wu, setValue, 0, (translator.getTargetClusterType() == RoxieCluster));
  4842. inheritDependencies(setValue);
  4843. unsigned wfid = ++wfidCount;
  4844. workflowOut->append(*createWorkflowItem(setValue, wfid));
  4845. return wfid;
  4846. }
  4847. IHqlExpression * WorkflowTransformer::extractWorkflow(IHqlExpression * untransformed, IHqlExpression * expr)
  4848. {
  4849. IHqlExpression * value = expr->queryChild(0);
  4850. GlobalAttributeInfo info("spill::wf", "wf", value);
  4851. info.sequence.setown(getLocalSequenceNumber());
  4852. OwnedHqlExpr scheduleActions;
  4853. HqlExprArray actions;
  4854. unwindChildren(actions, expr, 1);
  4855. IHqlExpression * original = queryProperty(_original_Atom, actions);
  4856. if (original) original = original->queryChild(0);
  4857. //First check for duplicate expressions, and cope with the weird case where they are identical except for the annotations.
  4858. //Do it before wfid is allocated to make life simpler
  4859. ForEachItemIn(iCheck, actions)
  4860. {
  4861. IHqlExpression & cur = actions.item(iCheck);
  4862. node_operator curOp = cur.getOperator();
  4863. switch (curOp)
  4864. {
  4865. case no_persist:
  4866. case no_checkpoint:
  4867. case no_stored:
  4868. info.extractStoredInfo(&cur, original, isRoxie);
  4869. OwnedHqlExpr id = info.getStoredKey();
  4870. unsigned match = alreadyProcessed.find(*id);
  4871. if (match == NotFound)
  4872. break;
  4873. //Compare the definitions - not the expressions, otherwise the original attribute can create false negatives
  4874. IHqlExpression * prevValue = alreadyProcessedExpr.item(match).queryChild(0);
  4875. if(prevValue->queryBody() != value->queryBody())
  4876. {
  4877. StringBuffer s;
  4878. getStoredDescription(s, info.sequence, info.storedName, true);
  4879. if(prevValue->queryType() != value->queryBody()->queryType())
  4880. {
  4881. #ifdef _DEBUG
  4882. debugFindFirstDifference(alreadyProcessedExpr.item(match).queryBody(), expr->queryBody());
  4883. #endif
  4884. if (curOp == no_stored)
  4885. throwError1(HQLERR_DuplicateStoredDiffType, s.str());
  4886. else
  4887. throwError1(HQLERR_DuplicateDefinitionDiffType, s.str());
  4888. }
  4889. else if (translator.queryOptions().allowStoredDuplicate) // only here as a temporary workaround
  4890. translator.reportWarning(queryActiveLocation(expr), HQLERR_DuplicateDefinition, HQLERR_DuplicateDefinition_Text, s.str());
  4891. else
  4892. {
  4893. if (queryLocationIndependent(prevValue) != queryLocationIndependent(value))
  4894. {
  4895. EclIR::dbglogIR(2, queryLocationIndependent(prevValue), queryLocationIndependent(value));
  4896. if (curOp == no_stored)
  4897. throwError1(HQLERR_DuplicateStoredDefinition, s.str());
  4898. else
  4899. throwError1(HQLERR_DuplicateDefinition, s.str());
  4900. }
  4901. }
  4902. }
  4903. //If the body was essentially the same, call transform on the previous value - so
  4904. return transform(&alreadyProcessedUntransformed.item(match));
  4905. }
  4906. }
  4907. ContingencyData conts;
  4908. ScheduleData sched;
  4909. unsigned wfid = ++wfidCount;
  4910. unsigned schedWfid = 0;
  4911. ForEachItemIn(idx, actions)
  4912. {
  4913. IHqlExpression & cur = actions.item(idx);
  4914. node_operator curOp = cur.getOperator();
  4915. switch (curOp)
  4916. {
  4917. case no_persist:
  4918. if (isRoxie && translator.getCheckRoxieRestrictions())
  4919. {
  4920. StringBuffer s;
  4921. IHqlExpression * name = cur.queryChild(0);
  4922. OwnedHqlExpr seq = getGlobalSequenceNumber();
  4923. getStoredDescription(s, seq, name, true);
  4924. throwError1(HQLERR_NotSupportInRoxie, s.str());
  4925. }
  4926. //fall through
  4927. case no_checkpoint:
  4928. case no_stored:
  4929. {
  4930. info.extractStoredInfo(&cur, original, isRoxie);
  4931. OwnedHqlExpr id = info.getStoredKey();
  4932. alreadyProcessed.append(*id.getClear());
  4933. alreadyProcessedExpr.append(*LINK(expr));
  4934. alreadyProcessedUntransformed.append(*LINK(untransformed));
  4935. }
  4936. break;
  4937. case no_independent:
  4938. case no_once:
  4939. info.extractStoredInfo(&cur, original, isRoxie);
  4940. break;
  4941. case no_success:
  4942. {
  4943. OwnedHqlExpr successExpr = transformSequentialEtc(cur.queryChild(0));
  4944. conts.success = splitValue(successExpr);
  4945. Owned<IWorkflowItem> wf = addWorkflowContingencyToWorkunit(conts.success, WFTypeSuccess, WFModeNormal, queryDirectDependencies(successExpr), NULL, wfid);
  4946. info.extractStoredInfo(&cur, original, isRoxie);
  4947. break;
  4948. }
  4949. case no_failure:
  4950. {
  4951. OwnedHqlExpr failureExpr = transformSequentialEtc(cur.queryChild(0));
  4952. conts.failure = splitValue(failureExpr);
  4953. Owned<IWorkflowItem> wf = addWorkflowContingencyToWorkunit(conts.failure, WFTypeFailure, WFModeNormal, queryDirectDependencies(failureExpr), NULL, wfid);
  4954. info.extractStoredInfo(&cur, original, isRoxie);
  4955. break;
  4956. }
  4957. case no_recovery:
  4958. {
  4959. conts.recovery = splitValue(cur.queryChild(0));
  4960. conts.retries = (unsigned)getIntValue(cur.queryChild(1), 0);
  4961. Owned<IWorkflowItem> wf = addWorkflowContingencyToWorkunit(conts.recovery, WFTypeRecovery, WFModeNormal, queryDirectDependencies(cur.queryChild(0)), NULL, wfid);
  4962. info.extractStoredInfo(&cur, original, isRoxie);
  4963. break;
  4964. }
  4965. case no_attr:
  4966. assertex(cur.queryName() == _original_Atom);
  4967. break;
  4968. case no_when:
  4969. {
  4970. OwnedHqlExpr folded = foldHqlExpression(&cur);
  4971. IHqlExpression * event = folded->queryChild(0);
  4972. IHqlExpression * eventFilter = event->queryChild(1);
  4973. sched.now = false;
  4974. event->queryChild(0)->queryValue()->getStringValue(sched.eventName);
  4975. if (eventFilter)
  4976. eventFilter->queryValue()->getStringValue(sched.eventText);
  4977. else
  4978. sched.eventText.append("*");
  4979. if(cur.numChildren()>1)
  4980. {
  4981. sched.counting = true;
  4982. sched.count = (unsigned)getIntValue(folded->queryChild(1));
  4983. }
  4984. sched.independent = true;
  4985. }
  4986. break;
  4987. case no_priority:
  4988. {
  4989. sched.priority = (int)getIntValue(cur.queryChild(0));
  4990. sched.independent = true;
  4991. break;
  4992. }
  4993. default:
  4994. throwUnexpectedOp(curOp);
  4995. }
  4996. }
  4997. OwnedHqlExpr setValue;
  4998. OwnedHqlExpr getValue;
  4999. bool done = false;
  5000. if (info.setOp != no_none)
  5001. {
  5002. assertex(!sched.independent); // should have been enforced by the tree normalization
  5003. ITypeInfo * type = expr->queryType();
  5004. info.checkFew(translator);
  5005. info.splitGlobalDefinition(type, value, wu, setValue, &getValue, isRoxie);
  5006. copySetValueDependencies(queryBodyExtra(value), setValue);
  5007. }
  5008. else
  5009. {
  5010. assertex(sched.independent);
  5011. getValue.set(value);
  5012. done = true;
  5013. schedWfid = wfid;
  5014. }
  5015. if(!sched.independent && !conts.success && !conts.failure && !conts.recovery)
  5016. {
  5017. bool combine = false;
  5018. if (combineAllStored && !hasNonTrivialDependencies(setValue))
  5019. {
  5020. switch (getResultSequenceValue(setValue))
  5021. {
  5022. case ResultSequenceStored:
  5023. combine = true;
  5024. break;
  5025. case ResultSequenceInternal:
  5026. combine = insideStored;
  5027. break;
  5028. }
  5029. }
  5030. if (info.persistOp == no_once)
  5031. {
  5032. //MORE: Error if refers to stored or persist
  5033. if (queryDirectDependencies(setValue).ordinality())
  5034. translator.ERRORAT(queryLocation(untransformed), HQLERR_OnceCannotAccessStored);
  5035. if (onceWfid == 0)
  5036. {
  5037. onceWfid = wfid;
  5038. }
  5039. else
  5040. {
  5041. wfid = onceWfid;
  5042. wfidCount--;
  5043. }
  5044. if (!onceExprs.contains(*setValue))
  5045. onceExprs.append(*LINK(setValue));
  5046. done = true;
  5047. }
  5048. if (combineTrivialStored && isTrivialStored(setValue))
  5049. combine = true;
  5050. if (combine)
  5051. {
  5052. if (trivialStoredWfid == 0)
  5053. {
  5054. trivialStoredWfid = wfid;
  5055. storedWfids.append(wfid);
  5056. }
  5057. else
  5058. {
  5059. wfid = trivialStoredWfid;
  5060. wfidCount--;
  5061. }
  5062. if (trivialStoredExprs.find(*setValue) == NotFound)
  5063. trivialStoredExprs.append(*LINK(setValue));
  5064. done = true;
  5065. }
  5066. }
  5067. if (!done)
  5068. {
  5069. if (info.persistOp == no_stored)
  5070. storedWfids.append(wfid);
  5071. //If you really want side effects within a no_persist to be processed in the correct sequence
  5072. //you need to use persist(failure(independent, f(independent))
  5073. //It generally makes worse code (and incorrect in jbellow.xhql) if they are expanded.
  5074. //because there is no ensure result in the expected wfid.
  5075. if ((info.persistOp != no_persist) && expr->isAction())
  5076. setValue.setown(transformSequentialEtc(setValue));
  5077. if(info.persistOp == no_persist)
  5078. {
  5079. StringBuffer persistName;
  5080. info.storedName->queryValue()->getStringValue(persistName);
  5081. unsigned persistWfid = ++wfidCount;
  5082. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModePersist, queryDirectDependencies(setValue), conts, info.queryCluster());
  5083. setWorkflowPersist(wf, persistName.str(), persistWfid);
  5084. Owned<IWorkflowItem> wfPersist = addWorkflowToWorkunit(persistWfid, WFTypeNormal, WFModeNormal, NULL);
  5085. DependenciesUsed dependencies(false);
  5086. gatherDependencies(setValue, dependencies, GatherAll);
  5087. dependencies.removeInternalReads();
  5088. HqlExprArray checkArgs;
  5089. checkArgs.append(*createExprAttribute(_files_Atom, dependencies.tablesRead));
  5090. if (dependencies.resultsRead.ordinality())
  5091. checkArgs.append(*createExprAttribute(_results_Atom, dependencies.resultsRead));
  5092. checkArgs.append(*createAttribute(_original_Atom, LINK(original)));
  5093. checkArgs.append(*createAttribute(namedAtom, LINK(info.storedName)));
  5094. if (expr->isDataset())
  5095. checkArgs.append(*createAttribute(fileAtom));
  5096. OwnedHqlExpr check = createValue(no_persist_check, makeVoidType(), checkArgs);
  5097. workflowOut->append(*createWorkflowItem(check, persistWfid));
  5098. workflowOut->append(*createWorkflowItem(setValue, wfid, persistWfid));
  5099. }
  5100. else
  5101. {
  5102. if (info.queryCluster())
  5103. {
  5104. OwnedHqlExpr cluster = createValue(no_cluster, makeVoidType(), LINK(setValue), LINK(info.queryCluster()));
  5105. inheritDependencies(cluster);
  5106. setValue.set(cluster);
  5107. }
  5108. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(setValue), conts, info.queryCluster());
  5109. workflowOut->append(*createWorkflowItem(setValue, wfid));
  5110. }
  5111. }
  5112. if(sched.independent)
  5113. {
  5114. if (schedWfid == 0)
  5115. schedWfid = ++wfidCount;
  5116. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(schedWfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(getValue), info.queryCluster());
  5117. setWorkflowSchedule(wf, sched);
  5118. workflowOut->append(*createWorkflowItem(getValue, schedWfid));
  5119. getValue.setown(createValue(no_null, makeVoidType()));
  5120. }
  5121. else
  5122. queryBodyExtra(getValue.get())->addDependency(wfid);
  5123. return getValue.getClear();
  5124. }
  5125. IHqlExpression * WorkflowTransformer::extractCommonWorkflow(IHqlExpression * expr, IHqlExpression * transformed)
  5126. {
  5127. if (!transformed->queryDataset())
  5128. return LINK(transformed);
  5129. WorkflowTransformInfo * extra = queryBodyExtra(expr);
  5130. if (!extra->isCommonUpCandidate() || !isWorthHoisting(transformed, false))
  5131. return LINK(transformed);
  5132. if (isContextDependent(transformed) || !isIndependentOfScope(transformed))
  5133. return LINK(transformed);
  5134. StringBuffer s;
  5135. IHqlExpression * location = activeLocations.ordinality() ? &activeLocations.tos() : NULL;
  5136. if (!translator.queryOptions().performWorkflowCse)
  5137. {
  5138. s.appendf("AutoWorkflow: Try adding ': INDEPENDENT' to %s ", getOpString(expr->getOperator()));
  5139. if (expr->queryName())
  5140. s.append("[").append(expr->queryName()).append("] ");
  5141. s.append(" to common up code between workflow items");
  5142. DBGLOG("%s", s.str());
  5143. translator.addWorkunitException(ExceptionSeverityInformation, HQLWRN_TryAddingIndependent, s.str(), location);
  5144. if (!translator.queryOptions().performWorkflowCse)
  5145. return LINK(transformed);
  5146. }
  5147. //This code would need a lot more work for it to be enabled by default.
  5148. // e.g., ensure it really is worth commoning up, the expressions aren't to be evaluated on different clusters etc. etc.
  5149. unsigned wfid = ++wfidCount;
  5150. s.appendf("AutoWorkflow: Spotted %s ", getOpString(expr->getOperator()));
  5151. if (expr->queryName())
  5152. s.append("[").append(expr->queryName()).append("] ");
  5153. s.append(" to common up between workflow items [").append(wfid).append("]");
  5154. DBGLOG("%s", s.str());
  5155. translator.addWorkunitException(ExceptionSeverityInformation, 0, s.str(), location);
  5156. GlobalAttributeInfo info("spill::wfa", "wfa", transformed);
  5157. info.extractGlobal(NULL, translator.getTargetClusterType()); // should really be a slightly different function
  5158. OwnedHqlExpr setValue;
  5159. OwnedHqlExpr getValue;
  5160. ContingencyData conts;
  5161. WorkflowTransformInfo * transformedExtra = queryBodyExtra(transformed);
  5162. info.splitGlobalDefinition(transformed->queryType(), transformed, wu, setValue, &getValue, isRoxie);
  5163. copySetValueDependencies(transformedExtra, setValue);
  5164. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(setValue), conts, NULL);
  5165. workflowOut->append(*createWorkflowItem(setValue, wfid));
  5166. queryBodyExtra(getValue.get())->addDependency(wfid);
  5167. return getValue.getClear();
  5168. }
  5169. IHqlExpression * WorkflowTransformer::transformInternalFunction(IHqlExpression * newFuncDef)
  5170. {
  5171. IHqlExpression * body = newFuncDef->queryChild(0);
  5172. if (body->getOperator() != no_outofline)
  5173. return LINK(newFuncDef);
  5174. IHqlExpression * ecl = body->queryChild(0);
  5175. StringBuffer funcname;
  5176. funcname.append("user").append(++nextInternalFunctionId);
  5177. if (translator.queryOptions().debugGeneratedCpp)
  5178. funcname.append("_").append(newFuncDef->queryName()).toLowerCase();
  5179. OwnedHqlExpr funcNameExpr = createConstant(funcname);
  5180. IHqlExpression * formals = newFuncDef->queryChild(1);
  5181. OwnedHqlExpr newFormals = mapInternalFunctionParameters(formals);
  5182. HqlExprArray bodyArgs;
  5183. bodyArgs.append(*replaceParameters(ecl, formals, newFormals));
  5184. unwindChildren(bodyArgs, body, 1);
  5185. bodyArgs.append(*createLocalAttribute());
  5186. bodyArgs.append(*createExprAttribute(entrypointAtom, LINK(funcNameExpr)));
  5187. OwnedHqlExpr newBody = body->clone(bodyArgs);
  5188. inheritDependencies(newBody);
  5189. HqlExprArray funcdefArgs;
  5190. funcdefArgs.append(*LINK(newBody));
  5191. funcdefArgs.append(*LINK(newFormals));
  5192. unwindChildren(funcdefArgs, newFuncDef, 2);
  5193. OwnedHqlExpr namedFuncDef = newFuncDef->clone(funcdefArgs);
  5194. inheritDependencies(namedFuncDef);
  5195. if (ecl->getOperator() == no_embedbody)
  5196. return namedFuncDef.getClear();
  5197. WorkflowItem * item = new WorkflowItem(namedFuncDef);
  5198. workflowOut->append(*item);
  5199. return createExternalFuncdefFromInternal(namedFuncDef);
  5200. }
  5201. IHqlExpression * WorkflowTransformer::transformInternalCall(IHqlExpression * transformed)
  5202. {
  5203. IHqlExpression * funcDef = transformed->queryDefinition();
  5204. Owned<IHqlExpression> newFuncDef = transform(funcDef);
  5205. HqlExprArray paramters;
  5206. unwindChildren(paramters, transformed);
  5207. OwnedHqlExpr rebound = createReboundFunction(newFuncDef, paramters);
  5208. inheritDependencies(rebound);
  5209. return rebound.getClear();
  5210. }
  5211. IHqlExpression * WorkflowTransformer::createTransformed(IHqlExpression * expr)
  5212. {
  5213. //Could short-circuit if doesn't contain workflow, but it also modifies outputs/buildindex...
  5214. //Force record to be transformed - so any stored values in record (ifblock!!) are hoisted.
  5215. node_operator op = expr->getOperator();
  5216. if (op == no_param)
  5217. return LINK(expr);
  5218. if (op == no_transform || op == no_newtransform)
  5219. ::Release(transform(expr->queryRecord()));
  5220. IHqlExpression * body = expr->queryBody(true);
  5221. if (expr != body)
  5222. {
  5223. switch (expr->getAnnotationKind())
  5224. {
  5225. case annotate_location:
  5226. case annotate_symbol:
  5227. activeLocations.append(*expr);
  5228. break;
  5229. }
  5230. OwnedHqlExpr transformedBody = transform(body);
  5231. switch (expr->getAnnotationKind())
  5232. {
  5233. case annotate_location:
  5234. case annotate_symbol:
  5235. activeLocations.pop();
  5236. break;
  5237. }
  5238. OwnedHqlExpr transformed = (transformedBody == body) ? LINK(expr) : expr->cloneAnnotation(transformedBody);
  5239. //more: this really shouldn't be needed
  5240. inheritDependencies(transformed);
  5241. return transformed.getClear();
  5242. }
  5243. bool wasInsideStored = insideStored;
  5244. if ((op == no_colon) && queryOperatorInList(no_stored, expr->queryChild(1)))
  5245. insideStored = true;
  5246. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  5247. insideStored = wasInsideStored;
  5248. inheritDependencies(transformed);
  5249. switch (op)
  5250. {
  5251. #if 0
  5252. //MORE: Workflow in user functions doesn't work for roxie at the moment
  5253. case no_call:
  5254. transformed.setown(transformCall(transformed));
  5255. inheritDependencies(transformed);
  5256. copyDependencies(queryBodyExtra(transformed->queryExternalDefinition()), queryBodyExtra(transformed));
  5257. break;
  5258. case no_externalcall:
  5259. transformed.setown(transformExternalCall(transformed));
  5260. inheritDependencies(transformed);
  5261. copyDependencies(queryExtra(transformed->queryExternalDefinition()), queryExtra(transformed));
  5262. break;
  5263. #endif
  5264. case no_colon:
  5265. if (translator.insideLibrary())
  5266. {
  5267. SCMStringBuffer libraryName;
  5268. StringBuffer colonText(" (");
  5269. getOutputLibraryName(libraryName, wu);
  5270. getExprECL(expr, colonText);
  5271. colonText.append(")");
  5272. throwError2(HQLERR_LibraryCannotContainWorkflow, libraryName.str(), colonText.str());
  5273. }
  5274. transformed.setown(extractWorkflow(expr, transformed));
  5275. break;
  5276. case no_output:
  5277. case no_buildindex:
  5278. {
  5279. IHqlExpression * updateAttr = transformed->queryProperty(updateAtom);
  5280. if (updateAttr)
  5281. {
  5282. DependenciesUsed dependencies(false);
  5283. gatherDependencies(transformed->queryChild(0), dependencies, GatherAll);
  5284. dependencies.removeInternalReads();
  5285. bool canEvaluateFilenames = true;
  5286. HqlExprArray updateArgs;
  5287. unwindChildren(updateArgs, updateAttr);
  5288. if (dependencies.tablesRead.ordinality())
  5289. {
  5290. OwnedHqlExpr attr = createExprAttribute(_files_Atom, dependencies.tablesRead);
  5291. if (!isIndependentOfScope(attr) || isContextDependent(attr))
  5292. {
  5293. if (!updateAttr->hasProperty(alwaysAtom))
  5294. throwError(HQLERR_InputsAreTooComplexToUpdate);
  5295. canEvaluateFilenames = false;
  5296. }
  5297. else
  5298. updateArgs.append(*attr.getClear());
  5299. }
  5300. if (dependencies.resultsRead.ordinality())
  5301. updateArgs.append(*createExprAttribute(_results_Atom, dependencies.resultsRead));
  5302. HqlExprArray args;
  5303. unwindChildren(args, transformed);
  5304. args.zap(*updateAttr);
  5305. if (canEvaluateFilenames)
  5306. args.append(*createExprAttribute(updateAtom, updateArgs));
  5307. transformed.setown(transformed->clone(args));
  5308. inheritDependencies(transformed);
  5309. }
  5310. break;
  5311. }
  5312. case no_funcdef:
  5313. transformed.setown(transformInternalFunction(transformed));
  5314. break;
  5315. case no_call:
  5316. transformed.setown(transformInternalCall(transformed));
  5317. break;
  5318. }
  5319. return extractCommonWorkflow(expr, transformed);
  5320. }
  5321. //-- second pass - sort out sequential etc.
  5322. /*
  5323. This is very tricky... The problem is we only want to create workflow actions for sequential/parallel and conditions if they
  5324. are necessary. In particular.
  5325. o workflow items are only executed once per invocation
  5326. o create them for sequential if the dependencies haven't already been evaluated
  5327. o create them for conditions if the non-intersection of the dependencies for the branches haven't already been evaluated
  5328. o create if a workflow action has been created for a child action.
  5329. o can't rely on createTransform() updating the dependencies so-far because the transform() may be cached.
  5330. o Need to be careful that dependencies done so far are set up correctly before each call to transform()
  5331. */
  5332. UnsignedArray const & WorkflowTransformer::queryDependencies(unsigned wfid)
  5333. {
  5334. if (wfid == trivialStoredWfid)
  5335. return emptyDependencies;
  5336. ForEachItemIn(i, *workflowOut)
  5337. {
  5338. WorkflowItem & cur = workflowOut->item(i);
  5339. if (cur.wfid == wfid)
  5340. return cur.dependencies;
  5341. }
  5342. throwUnexpected();
  5343. }
  5344. void WorkflowTransformer::gatherIndirectDependencies(UnsignedArray & result, IHqlExpression * expr)
  5345. {
  5346. if (isWorkflowAction(expr))
  5347. {
  5348. unsigned wfid = (unsigned)getIntValue(expr->queryChild(0));
  5349. ::inheritDependencies(result, queryDependencies(wfid));
  5350. }
  5351. else
  5352. {
  5353. const UnsignedArray & direct = queryBodyExtra(expr)->queryDependencies();
  5354. ForEachItemIn(i, direct)
  5355. {
  5356. unsigned wfid = direct.item(i);
  5357. if (addDependency(result, wfid))
  5358. ::inheritDependencies(result, queryDependencies(wfid));
  5359. }
  5360. }
  5361. }
  5362. bool WorkflowTransformer::hasNonTrivialDependencies(IHqlExpression * expr)
  5363. {
  5364. UnsignedArray const & dependencies = queryDirectDependencies(expr);
  5365. ForEachItemIn(i, dependencies)
  5366. {
  5367. unsigned cur = dependencies.item(i);
  5368. if ((cur != trivialStoredWfid) && (cur != onceWfid))
  5369. return true;
  5370. }
  5371. return false;
  5372. }
  5373. UnsignedArray const & WorkflowTransformer::queryDirectDependencies(IHqlExpression * expr)
  5374. {
  5375. return queryBodyExtra(expr)->queryDependencies();
  5376. }
  5377. void WorkflowTransformer::cacheWorkflowDependencies(unsigned wfid, UnsignedArray & extra)
  5378. {
  5379. WorkflowItem * item = new WorkflowItem(wfid);
  5380. ForEachItemIn(i, extra)
  5381. {
  5382. unsigned wfid = extra.item(i);
  5383. item->dependencies.append(wfid);
  5384. ::inheritDependencies(item->dependencies, queryDependencies(wfid));
  5385. }
  5386. workflowOut->append(*item);
  5387. }
  5388. IHqlExpression * WorkflowTransformer::createWorkflowAction(unsigned wfid)
  5389. {
  5390. //NB: Needs to include wfid as an argument otherwise inherited dependencies get messed up
  5391. OwnedHqlExpr transformed = createValue(no_workflow_action, makeVoidType(), getSizetConstant(wfid));
  5392. queryBodyExtra(transformed)->addDependency(wfid);
  5393. return transformed.getClear();
  5394. }
  5395. void WorkflowTransformer::ensureWorkflowAction(UnsignedArray & dependencies, IHqlExpression * expr)
  5396. {
  5397. unsigned wfid = ensureWorkflowAction(expr);
  5398. addDependency(dependencies, wfid);
  5399. }
  5400. //Create a sequential workflow action if any of the branches contains a workflow action
  5401. IHqlExpression * WorkflowTransformer::createCompoundWorkflow(IHqlExpression * expr)
  5402. {
  5403. HqlExprArray pendingBranches;
  5404. UnsignedArray childWfid;
  5405. ForEachChild(i, expr)
  5406. {
  5407. IHqlExpression * cur = expr->queryChild(i);
  5408. unsigned mark = markDependencies();
  5409. OwnedHqlExpr transformed = transformRootAction(cur);
  5410. restoreDependencies(mark);
  5411. if (isWorkflowAction(transformed))
  5412. {
  5413. if (pendingBranches.ordinality())
  5414. {
  5415. OwnedHqlExpr branch = createActionList(pendingBranches);
  5416. inheritDependencies(branch);
  5417. ensureWorkflowAction(childWfid, branch);
  5418. pendingBranches.kill();
  5419. }
  5420. ensureWorkflowAction(childWfid, transformed);
  5421. }
  5422. else
  5423. {
  5424. pendingBranches.append(*LINK(transformed));
  5425. }
  5426. gatherIndirectDependencies(cumulativeDependencies, transformed);
  5427. }
  5428. if (childWfid.ordinality())
  5429. {
  5430. if (pendingBranches.ordinality())
  5431. {
  5432. OwnedHqlExpr branch = createActionList(pendingBranches);
  5433. inheritDependencies(branch);
  5434. ensureWorkflowAction(childWfid, branch);
  5435. }
  5436. unsigned wfid = ++wfidCount;
  5437. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeSequential, childWfid, rootCluster);
  5438. cacheWorkflowDependencies(wfid, childWfid);
  5439. return createWorkflowAction(wfid);
  5440. }
  5441. return LINK(expr);
  5442. }
  5443. //Create a sequential workflow action if any of the branches introduce new dependencies/or creates a workflow item (e.g., wait!)
  5444. IHqlExpression * WorkflowTransformer::createSequentialWorkflow(IHqlExpression * expr)
  5445. {
  5446. OwnedHqlExpr nextBranch;
  5447. UnsignedArray childWfid;
  5448. ForEachChild(i, expr)
  5449. {
  5450. IHqlExpression * cur = expr->queryChild(i);
  5451. unsigned mark = markDependencies();
  5452. OwnedHqlExpr transformed = transformRootAction(cur);
  5453. restoreDependencies(mark);
  5454. UnsignedArray dependencies;
  5455. gatherIndirectDependencies(dependencies, transformed);
  5456. if (hasExtraDependencies(cumulativeDependencies, dependencies, storedWfids) || isWorkflowAction(transformed))
  5457. {
  5458. if (nextBranch)
  5459. {
  5460. ensureWorkflowAction(childWfid, nextBranch);
  5461. nextBranch.clear();
  5462. }
  5463. ::inheritDependencies(cumulativeDependencies, dependencies);
  5464. if (isWorkflowAction(transformed))
  5465. ensureWorkflowAction(childWfid, transformed);
  5466. else
  5467. nextBranch.set(transformed);
  5468. }
  5469. else
  5470. {
  5471. if (nextBranch)
  5472. nextBranch.setown(createValue(expr->getOperator(), nextBranch.getClear(), LINK(transformed)));
  5473. else
  5474. nextBranch.set(transformed);
  5475. inheritDependencies(nextBranch);
  5476. }
  5477. }
  5478. if (childWfid.ordinality())
  5479. {
  5480. if (nextBranch)
  5481. ensureWorkflowAction(childWfid, nextBranch);
  5482. unsigned wfid = ++wfidCount;
  5483. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeSequential, childWfid, rootCluster);
  5484. cacheWorkflowDependencies(wfid, childWfid);
  5485. return createWorkflowAction(wfid);
  5486. }
  5487. return LINK(expr);
  5488. }
  5489. // Create a parallel workflow action if any of the child actions are workflow actions
  5490. IHqlExpression * WorkflowTransformer::createParallelWorkflow(IHqlExpression * expr)
  5491. {
  5492. HqlExprArray branches;
  5493. UnsignedArray childWfid;
  5494. unsigned mark = markDependencies();
  5495. ForEachChild(i, expr)
  5496. {
  5497. IHqlExpression * cur = expr->queryChild(i);
  5498. OwnedHqlExpr transformed = transformRootAction(cur);
  5499. if (isWorkflowAction(transformed))
  5500. ensureWorkflowAction(childWfid, transformed);
  5501. else
  5502. branches.append(*LINK(transformed));
  5503. restoreDependencies(mark);
  5504. }
  5505. if (childWfid.ordinality())
  5506. {
  5507. if (branches.ordinality())
  5508. {
  5509. OwnedHqlExpr branch = createActionList(branches);
  5510. inheritDependencies(branch);
  5511. ensureWorkflowAction(childWfid, branch);
  5512. }
  5513. unsigned wfid = ++wfidCount;
  5514. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeParallel, childWfid, rootCluster);
  5515. cacheWorkflowDependencies(wfid, childWfid);
  5516. return createWorkflowAction(wfid);
  5517. }
  5518. return LINK(expr);
  5519. }
  5520. IHqlExpression * WorkflowTransformer::createIfWorkflow(IHqlExpression * expr)
  5521. {
  5522. IHqlExpression * cond = expr->queryChild(0);
  5523. IHqlExpression * trueExpr = expr->queryChild(1);
  5524. IHqlExpression * falseExpr = expr->queryChild(2);
  5525. OwnedHqlExpr newCond = LINK(cond);
  5526. gatherIndirectDependencies(cumulativeDependencies, cond);
  5527. //more: inherit dependencies?
  5528. UnsignedArray trueDepends, falseDepends;
  5529. unsigned mark = markDependencies();
  5530. OwnedHqlExpr newTrueExpr = transformRootAction(trueExpr);
  5531. restoreDependencies(mark);
  5532. OwnedHqlExpr newFalseExpr = falseExpr ? transformRootAction(falseExpr) : NULL;
  5533. restoreDependencies(mark);
  5534. //Need to turn a conditional action into a conditional workflow item if
  5535. //i) it has a workflow action as a child.
  5536. //ii) the true/false branches are dependent on something that hasn't already been evaluated
  5537. // (and isn't shared between both branches)
  5538. bool needToCreateWorkflow = false;
  5539. if (hasDependencies(newTrueExpr) || (newFalseExpr && hasDependencies(newFalseExpr)))
  5540. {
  5541. needToCreateWorkflow = isWorkflowAction(newTrueExpr) || isWorkflowAction(newFalseExpr);
  5542. if (!needToCreateWorkflow)
  5543. {
  5544. //Failures are assumed to be exceptional, so don't worry about extra dependencies
  5545. if (!isFailAction(newTrueExpr) && !isFailAction(newFalseExpr))
  5546. {
  5547. UnsignedArray newTrueDepends;
  5548. gatherIndirectDependencies(newTrueDepends, newTrueExpr);
  5549. if (!falseExpr)
  5550. needToCreateWorkflow = hasExtraDependencies(cumulativeDependencies, newTrueDepends, storedWfids);
  5551. else
  5552. {
  5553. UnsignedArray newFalseDepends;
  5554. gatherIndirectDependencies(newFalseDepends, newFalseExpr);
  5555. UnsignedArray diff;
  5556. diffDependencies(diff, newTrueDepends, newFalseDepends);
  5557. needToCreateWorkflow = hasExtraDependencies(cumulativeDependencies, diff, storedWfids);
  5558. }
  5559. }
  5560. }
  5561. if (needToCreateWorkflow)
  5562. {
  5563. //Represent as wfid(cond-wfid, true-wfid, false-wfid)
  5564. UnsignedArray dependencies;
  5565. OwnedHqlExpr setCondExpr = createValue(no_setworkflow_cond, makeVoidType(), LINK(cond));
  5566. inheritDependencies(setCondExpr);
  5567. ensureWorkflowAction(dependencies, setCondExpr);
  5568. ensureWorkflowAction(dependencies, newTrueExpr);
  5569. if (newFalseExpr)
  5570. ensureWorkflowAction(dependencies, newFalseExpr);
  5571. unsigned wfid = ++wfidCount;
  5572. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeCondition, dependencies, rootCluster);
  5573. WorkflowItem * item = new WorkflowItem(wfid);
  5574. cloneDependencies(item->dependencies, dependencies);
  5575. if (falseExpr)
  5576. {
  5577. UnsignedArray newTrueDepends;
  5578. UnsignedArray newFalseDepends;
  5579. gatherIndirectDependencies(newTrueDepends, newTrueExpr);
  5580. gatherIndirectDependencies(newFalseDepends, newFalseExpr);
  5581. intersectDependencies(item->dependencies, newTrueDepends, newFalseDepends);
  5582. }
  5583. workflowOut->append(*item);
  5584. return createWorkflowAction(wfid);
  5585. }
  5586. }
  5587. return LINK(expr);
  5588. }
  5589. IHqlExpression * WorkflowTransformer::createWaitWorkflow(IHqlExpression * expr)
  5590. {
  5591. //First create a EndWait workflow item which has a when clause of the wait criteria
  5592. OwnedHqlExpr folded = foldHqlExpression(expr);
  5593. IHqlExpression * event = folded->queryChild(0);
  5594. IHqlExpression * eventFilter = event->queryChild(1);
  5595. ScheduleData sched;
  5596. sched.now = false;
  5597. getStringValue(sched.eventName, event->queryChild(0));
  5598. if (eventFilter)
  5599. getStringValue(sched.eventText, eventFilter);
  5600. else
  5601. sched.eventText.append("*");
  5602. sched.counting = true;
  5603. sched.count = 0;
  5604. sched.independent = true;
  5605. unsigned endWaitWfid = ++wfidCount;
  5606. UnsignedArray noDependencies;
  5607. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(endWaitWfid, WFTypeNormal, WFModeWait, noDependencies, rootCluster);
  5608. setWorkflowSchedule(wf, sched);
  5609. OwnedHqlExpr doNothing = createValue(no_null, makeVoidType());
  5610. workflowOut->append(*createWorkflowItem(doNothing, endWaitWfid));
  5611. //Now create a wait entry, with the EndWait as the dependency
  5612. UnsignedArray dependencies;
  5613. dependencies.append(endWaitWfid);
  5614. unsigned beginWaitWfid = ++wfidCount;
  5615. Owned<IWorkflowItem> wfWait = addWorkflowToWorkunit(beginWaitWfid, WFTypeNormal, WFModeBeginWait, dependencies, rootCluster);
  5616. cacheWorkflowDependencies(beginWaitWfid, dependencies);
  5617. return createWorkflowAction(beginWaitWfid);
  5618. }
  5619. IHqlExpression * WorkflowTransformer::transformRootAction(IHqlExpression * expr)
  5620. {
  5621. node_operator op = expr->getOperator();
  5622. switch (op)
  5623. {
  5624. case no_compound:
  5625. if (expr->isAction())
  5626. return createCompoundWorkflow(expr);
  5627. break;
  5628. case no_parallel:
  5629. return createParallelWorkflow(expr);
  5630. case no_sequential:
  5631. return createSequentialWorkflow(expr);
  5632. case no_actionlist:
  5633. return createCompoundWorkflow(expr);
  5634. case no_if:
  5635. if (expr->isAction())
  5636. return createIfWorkflow(expr);
  5637. break;
  5638. case no_wait:
  5639. return createWaitWorkflow(expr);
  5640. case no_ensureresult:
  5641. {
  5642. IHqlExpression * value = expr->queryChild(0);
  5643. if (!value->isAction())
  5644. break;
  5645. OwnedHqlExpr transformed = transformRootAction(value);
  5646. if (value == transformed)
  5647. break;
  5648. HqlExprArray args;
  5649. args.append(*transformed.getClear());
  5650. unwindChildren(args, expr, 1);
  5651. OwnedHqlExpr ret = expr->clone(args);
  5652. inheritDependencies(ret);
  5653. return ret.getClear();
  5654. }
  5655. }
  5656. return LINK(expr);
  5657. }
  5658. IHqlExpression * WorkflowTransformer::transformSequentialEtc(IHqlExpression * expr)
  5659. {
  5660. unsigned mark = markDependencies();
  5661. //Ignore differences in access to trivial stored variables.
  5662. if (trivialStoredWfid)
  5663. cumulativeDependencies.append(trivialStoredWfid);
  5664. if (onceWfid)
  5665. cumulativeDependencies.append(onceWfid);
  5666. OwnedHqlExpr ret = transformRootAction(expr);
  5667. restoreDependencies(mark);
  5668. return ret.getClear();
  5669. }
  5670. void WorkflowTransformer::percolateScheduledIds(WorkflowArray & workflow)
  5671. {
  5672. ForEachItemIn(i, workflow)
  5673. {
  5674. WorkflowItem & cur = workflow.item(i);
  5675. Owned<IWorkflowItem> wf = lookupWorkflowItem(cur.queryWfid());
  5676. if (wf && wf->isScheduledNow())
  5677. {
  5678. ForEachItemIn(i2, cur.dependencies)
  5679. {
  5680. Owned<IWorkflowItem> child = lookupWorkflowItem(cur.dependencies.item(i2));
  5681. if (child->queryMode() == WFModeWait)
  5682. child->setScheduledWfid(cur.queryWfid());
  5683. }
  5684. }
  5685. }
  5686. }
  5687. ///- workflow processing
  5688. void WorkflowTransformer::analyseExpr(IHqlExpression * expr)
  5689. {
  5690. WorkflowTransformInfo * extra = queryBodyExtra(expr);
  5691. if (extra->noteWorkflow(activeWfid, isConditional))
  5692. return;
  5693. switch (expr->getOperator())
  5694. {
  5695. case no_allnodes:
  5696. //MORE: Do I need to recurse and explicitly disable hoisting?
  5697. return;
  5698. case no_if:
  5699. {
  5700. bool wasConditional = isConditional;
  5701. analyseExpr(expr->queryChild(0));
  5702. isConditional = true;
  5703. analyseExpr(expr->queryChild(1));
  5704. if (expr->queryChild(2))
  5705. analyseExpr(expr->queryChild(2));
  5706. isConditional = wasConditional;
  5707. return;
  5708. }
  5709. case no_colon:
  5710. {
  5711. if (!isIndependentOfScope(expr->queryChild(0)))
  5712. {
  5713. StringBuffer s;
  5714. if (expr->queryName())
  5715. s.appendf(" '%s'", expr->queryName()->str());
  5716. //MORE: Better if we also kept nested track of locations
  5717. translator.WARNINGAT1(queryActiveLocation(expr), HQLWRN_WorkflowSeemsToBeDependent, s.str());
  5718. }
  5719. unsigned prevWfid = activeWfid;
  5720. activeWfid = ++wfidCount;
  5721. analyseExpr(expr->queryChild(0));
  5722. activeWfid = prevWfid;
  5723. return;
  5724. }
  5725. }
  5726. NewHqlTransformer::analyseExpr(expr);
  5727. }
  5728. void WorkflowTransformer::analyseAll(const HqlExprArray & in)
  5729. {
  5730. activeWfid = ++wfidCount;
  5731. analyseArray(in, 0);
  5732. wfidCount = 0;
  5733. }
  5734. void WorkflowTransformer::transformRoot(const HqlExprArray & in, WorkflowArray & out)
  5735. {
  5736. wfidCount = 0;
  5737. workflowOut = &out;
  5738. HqlExprArray transformed;
  5739. WorkflowTransformInfo globalInfo(NULL);
  5740. ForEachItemIn(idx, in)
  5741. {
  5742. OwnedHqlExpr ret = transform(&in.item(idx));
  5743. copyDependencies(queryBodyExtra(ret), &globalInfo);
  5744. //ignore results that do nothing, but still collect the dependencies...
  5745. if (ret->getOperator() != no_null)
  5746. transformed.append(*ret.getClear());
  5747. }
  5748. if (onceExprs.length())
  5749. {
  5750. //By definition they don't have any dependencies, so no need to call inheritDependencies.
  5751. OwnedHqlExpr onceExpr = createActionList(onceExprs);
  5752. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(onceWfid, WFTypeNormal, WFModeOnce, queryDirectDependencies(onceExpr), NULL);
  5753. wf->setScheduledNow();
  5754. out.append(*createWorkflowItem(onceExpr, onceWfid));
  5755. }
  5756. if (trivialStoredExprs.length())
  5757. {
  5758. //By definition they don't have any dependencies, so no need to call inheritDependencies.
  5759. OwnedHqlExpr trivialStoredExpr = createActionList(trivialStoredExprs);
  5760. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(trivialStoredWfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(trivialStoredExpr), NULL);
  5761. out.append(*createWorkflowItem(trivialStoredExpr, trivialStoredWfid));
  5762. }
  5763. if (transformed.ordinality())
  5764. {
  5765. //Handle sequential etc.
  5766. OwnedHqlExpr combined = createActionList(transformed);
  5767. OwnedHqlExpr result = transformSequentialEtc(combined);
  5768. transformed.kill();
  5769. transformed.append(*result.getClear());
  5770. }
  5771. UnsignedArray const & dependencies = globalInfo.queryDependencies();
  5772. if(transformed.ordinality() || dependencies.ordinality())
  5773. {
  5774. if ((transformed.ordinality() == 0) && (dependencies.ordinality() == 1))
  5775. {
  5776. Owned<IWorkflowItem> wf = lookupWorkflowItem(dependencies.item(0));
  5777. wf->setScheduledNow();
  5778. }
  5779. else
  5780. {
  5781. Owned<IHqlExpression> combinedItems = createComma(transformed);
  5782. if (!combinedItems)
  5783. combinedItems.setown(createValue(no_null, makeVoidType()));
  5784. unsigned wfid;
  5785. if (!isWorkflowAction(combinedItems))
  5786. {
  5787. wfid = ++wfidCount;
  5788. ScheduleData sched;
  5789. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, dependencies, NULL);
  5790. setWorkflowSchedule(wf, sched);
  5791. out.append(*createWorkflowItem(combinedItems, wfid));
  5792. }
  5793. else
  5794. wfid = ensureWorkflowAction(combinedItems);
  5795. Owned<IWorkflowItem> wf = lookupWorkflowItem(wfid);
  5796. wf->setScheduledNow();
  5797. }
  5798. }
  5799. workflowOut = NULL;
  5800. percolateScheduledIds(out);
  5801. }
  5802. void extractWorkflow(HqlCppTranslator & translator, HqlExprArray & exprs, WorkflowArray & out)
  5803. {
  5804. WorkflowTransformer transformer(translator.wu(), translator);
  5805. if (translator.queryOptions().performWorkflowCse || translator.queryOptions().notifyWorkflowCse)
  5806. transformer.analyseAll(exprs);
  5807. transformer.transformRoot(exprs, out);
  5808. }
  5809. //------------------------------------------------------------------------
  5810. enum { SIKnone, SIKhole, SIKagent, SIKthor };
  5811. class StatementInfo : public CInterface
  5812. {
  5813. public:
  5814. StatementInfo(IHqlExpression * _expr);
  5815. void calcDependencies();
  5816. bool canSwapOrder(StatementInfo & other)
  5817. {
  5818. return queryDependencies().canSwapOrder(other.queryDependencies());
  5819. }
  5820. inline bool isConditional() { return expr->getOperator() == no_if; }
  5821. inline bool isThorQuery() { return category == SIKthor; }
  5822. DependenciesUsed & queryDependencies()
  5823. {
  5824. if (!hasDependencies)
  5825. {
  5826. calcDependencies();
  5827. hasDependencies = true;
  5828. }
  5829. return dependencies;
  5830. }
  5831. public:
  5832. HqlExprAttr expr;
  5833. protected:
  5834. DependenciesUsed dependencies;
  5835. bool hasDependencies;
  5836. unsigned category;
  5837. };
  5838. StatementInfo::StatementInfo(IHqlExpression * _expr) : dependencies(true)
  5839. {
  5840. expr.set(_expr);
  5841. if (expr->getOperator() == no_thor)
  5842. category = SIKthor;
  5843. else
  5844. category = SIKagent;
  5845. hasDependencies = false;
  5846. }
  5847. void StatementInfo::calcDependencies()
  5848. {
  5849. gatherDependencies(expr, dependencies, GatherAll);
  5850. }
  5851. void groupThorGraphs(HqlExprArray & in)
  5852. {
  5853. //Gather information about the statements...
  5854. bool hadThor = false;
  5855. bool lastWasThor = false;
  5856. bool couldImprove = false;
  5857. CIArrayOf<StatementInfo> stmts;
  5858. ForEachItemIn(idx, in)
  5859. {
  5860. StatementInfo & cur = *new StatementInfo(&in.item(idx));
  5861. stmts.append(cur);
  5862. if (cur.isThorQuery())
  5863. {
  5864. if (hadThor && !lastWasThor)
  5865. couldImprove = true;
  5866. hadThor = true;
  5867. lastWasThor = true;
  5868. }
  5869. else
  5870. lastWasThor = false;
  5871. }
  5872. //If no thor queries are split by other queries, then may as well keep in the same order...
  5873. if (!couldImprove)
  5874. return;
  5875. //Need to work out the best order to generate the statements in. We want
  5876. //to move non thor queries to the front, so we do a insertion sort on them
  5877. CopyCIArrayOf<StatementInfo> sorted;
  5878. ForEachItemIn(idx1, stmts)
  5879. {
  5880. StatementInfo & cur = stmts.item(idx1);
  5881. bool curIsThor = cur.isThorQuery();
  5882. unsigned insertPos = sorted.ordinality();
  5883. ForEachItemInRev(idx2, sorted)
  5884. {
  5885. StatementInfo & compare = sorted.item(idx2);
  5886. if (compare.isThorQuery() == curIsThor)
  5887. {
  5888. insertPos = idx2+1;
  5889. break;
  5890. }
  5891. if (!compare.canSwapOrder(cur))
  5892. break;
  5893. }
  5894. sorted.add(cur, insertPos);
  5895. }
  5896. //Finally see if there is any merit in moving an initial block of thor queries down to
  5897. //merge with a subsequent one.
  5898. StatementInfo & first = sorted.item(0);
  5899. if (first.isThorQuery())
  5900. {
  5901. unsigned max = sorted.ordinality();
  5902. unsigned numToMove;
  5903. for (numToMove = 1; numToMove < max; numToMove++)
  5904. {
  5905. if (!(sorted.item(numToMove)).isThorQuery())
  5906. break;
  5907. }
  5908. for (unsigned i=numToMove; i < max; i++)
  5909. {
  5910. StatementInfo & compare = sorted.item(i);
  5911. if (compare.isThorQuery())
  5912. {
  5913. for (unsigned j=0; j < numToMove; j++)
  5914. sorted.rotateL(0, i-1);
  5915. break;
  5916. }
  5917. for (unsigned j=0; j < numToMove; j++)
  5918. {
  5919. if (!compare.canSwapOrder(sorted.item(j)))
  5920. {
  5921. i = max - 1;
  5922. break;
  5923. }
  5924. }
  5925. }
  5926. }
  5927. in.kill();
  5928. ForEachItemIn(idxSorted, sorted)
  5929. {
  5930. StatementInfo & cur = sorted.item(idxSorted);
  5931. in.append(*cur.expr.getLink());
  5932. }
  5933. }
  5934. //------------------------------------------------------------------------
  5935. //We will generate better code if conditional statements precede unconditional statements because globals can
  5936. //be commoned up better.
  5937. bool moveUnconditionalEarlier(HqlExprArray & in)
  5938. {
  5939. //Gather information about the statements...
  5940. unsigned numConditionals = 0;
  5941. unsigned firstConditional = NotFound;
  5942. bool couldImprove = false;
  5943. CIArrayOf<StatementInfo> stmts;
  5944. ForEachItemIn(idx, in)
  5945. {
  5946. StatementInfo & cur = *new StatementInfo(&in.item(idx));
  5947. stmts.append(cur);
  5948. if (cur.isConditional())
  5949. {
  5950. if (numConditionals == 0)
  5951. firstConditional = idx;
  5952. numConditionals++;
  5953. }
  5954. else if (numConditionals)
  5955. couldImprove = true;
  5956. }
  5957. //If no unconditionals follow a conditional, and no conditionals to be combined, then keep in the same order...
  5958. if (!couldImprove && numConditionals <= 1)
  5959. return false;
  5960. //For each block of unconditional statements which follow a conditional statement, see if they can be moved over the conditional statements.
  5961. //(copies with no overhead if couldImprove is false)
  5962. CopyCIArrayOf<StatementInfo> sorted;
  5963. unsigned max = stmts.ordinality();
  5964. for (unsigned idx1 = 0; idx1 < max;)
  5965. {
  5966. StatementInfo & cur = stmts.item(idx1);
  5967. bool isConditional = cur.isConditional();
  5968. unsigned cnt = 1;
  5969. if (isConditional || idx1 < firstConditional)
  5970. {
  5971. sorted.append(cur);
  5972. }
  5973. else
  5974. {
  5975. //calculate the number of contiguous unconditional statements
  5976. for (cnt=1; idx1+cnt < max; cnt++)
  5977. {
  5978. if (stmts.item(idx1+cnt).isConditional())
  5979. break;
  5980. }
  5981. unsigned movePosition = 0;
  5982. for (unsigned iBlock = 0; iBlock < cnt; iBlock++)
  5983. {
  5984. StatementInfo & curBlock = stmts.item(idx1+iBlock);
  5985. unsigned bestPosition = NotFound; // best position to add block.
  5986. unsigned prev = idx1;
  5987. while (prev-- > firstConditional)
  5988. {
  5989. StatementInfo & compare = sorted.item(prev);
  5990. if (!compare.canSwapOrder(curBlock))
  5991. break;
  5992. if (prev == firstConditional)
  5993. bestPosition = prev;
  5994. else if (compare.isConditional() && !sorted.item(prev-1).isConditional())
  5995. bestPosition = prev;
  5996. }
  5997. if (bestPosition == NotFound)
  5998. {
  5999. //can't move this element in the block => append the items to the list.
  6000. movePosition = sorted.ordinality();
  6001. break;
  6002. }
  6003. //Intersection of the best positions to provide earliest we can move the block
  6004. if (movePosition < bestPosition)
  6005. movePosition = bestPosition;
  6006. }
  6007. for (unsigned iBlock2 = 0; iBlock2 < cnt; iBlock2++)
  6008. sorted.add(stmts.item(idx1+iBlock2), movePosition+iBlock2);
  6009. }
  6010. idx1 += cnt;
  6011. }
  6012. //See if moving conditional statements could make some conditions next to each other
  6013. //Now see if any of the conditional statements can be combined.
  6014. //Finally replace the array
  6015. in.kill();
  6016. ForEachItemIn(idxSorted, sorted)
  6017. {
  6018. StatementInfo & cur = (StatementInfo &)sorted.item(idxSorted);
  6019. in.append(*cur.expr.getLink());
  6020. }
  6021. return true;
  6022. }
  6023. //------------------------------------------------------------------------
  6024. void mergeThorGraphs(HqlExprArray & exprs, bool resourceConditionalActions, bool resourceSequential);
  6025. IHqlExpression * mergeThorGraphs(IHqlExpression * expr, bool resourceConditionalActions, bool resourceSequential)
  6026. {
  6027. HqlExprArray args;
  6028. expr->unwindList(args, no_actionlist);
  6029. mergeThorGraphs(args, resourceConditionalActions, resourceSequential);
  6030. return createActionList(args);
  6031. }
  6032. void mergeThorGraphs(HqlExprArray & exprs, bool resourceConditionalActions, bool resourceSequential)
  6033. {
  6034. HqlExprArray thorActions;
  6035. HqlExprArray combined;
  6036. ForEachItemIn(idx, exprs)
  6037. {
  6038. IHqlExpression * original = &exprs.item(idx);
  6039. LinkedHqlExpr cur = original;
  6040. const node_operator op = cur->getOperator();
  6041. switch (op)
  6042. {
  6043. case no_compound:
  6044. {
  6045. OwnedHqlExpr replace = mergeThorGraphs(cur->queryChild(0), resourceConditionalActions, resourceSequential);
  6046. cur.setown(replaceChild(cur, 0, replace));
  6047. break;
  6048. }
  6049. case no_if:
  6050. if (cur->isAction())
  6051. {
  6052. IHqlExpression * left = cur->queryChild(1);
  6053. IHqlExpression * right = cur->queryChild(2);
  6054. OwnedHqlExpr newLeft = mergeThorGraphs(left, resourceConditionalActions, resourceSequential);
  6055. OwnedHqlExpr newRight = right ? mergeThorGraphs(right, resourceConditionalActions, resourceSequential) : NULL;
  6056. if (left != newLeft || right != newRight)
  6057. {
  6058. HqlExprArray args;
  6059. unwindChildren(args, cur);
  6060. //Not sure about this - the test condition may not be evaluatable inside thor
  6061. if (resourceConditionalActions && ((newLeft->getOperator() == no_thor) && (!newRight || newRight->getOperator() == no_thor)))
  6062. {
  6063. args.replace(*LINK(newLeft->queryChild(0)), 1);
  6064. if (newRight)
  6065. args.replace(*LINK(newRight->queryChild(0)), 2);
  6066. cur.setown(createValue(no_thor, makeVoidType(), cur->clone(args)));
  6067. }
  6068. else
  6069. {
  6070. args.replace(*LINK(newLeft), 1);
  6071. if (newRight)
  6072. args.replace(*LINK(newRight), 2);
  6073. cur.setown(cur->clone(args));
  6074. }
  6075. }
  6076. }
  6077. break;
  6078. case no_parallel:
  6079. if (false)
  6080. {
  6081. HqlExprArray args;
  6082. bool allThor = true;
  6083. ForEachChild(i, cur)
  6084. {
  6085. IHqlExpression * merged = mergeThorGraphs(cur->queryChild(i), resourceConditionalActions, resourceSequential);
  6086. args.append(*merged);
  6087. if (merged->getOperator() != no_thor)
  6088. allThor = false;
  6089. }
  6090. if (allThor)
  6091. {
  6092. ForEachItemIn(i, args)
  6093. args.replace(*LINK(args.item(i).queryChild(0)), i);
  6094. cur.setown(cur->clone(args));
  6095. cur.setown(createValue(no_thor, makeVoidType(), cur.getClear()));
  6096. }
  6097. else
  6098. cur.setown(cur->clone(args));
  6099. break;
  6100. }
  6101. //fall through
  6102. case no_actionlist:
  6103. {
  6104. HqlExprArray args;
  6105. cur->unwindList(args, op);
  6106. mergeThorGraphs(args, resourceConditionalActions, resourceSequential);
  6107. cur.setown(cur->clone(args));
  6108. break;
  6109. }
  6110. case no_sequential:
  6111. {
  6112. HqlExprArray args;
  6113. bool allThor = true;
  6114. ForEachChild(i, cur)
  6115. {
  6116. IHqlExpression * merged = mergeThorGraphs(cur->queryChild(i), resourceConditionalActions, resourceSequential);
  6117. args.append(*merged);
  6118. if (merged->getOperator() != no_thor)
  6119. allThor = false;
  6120. }
  6121. if (resourceSequential && allThor)
  6122. {
  6123. ForEachItemIn(i, args)
  6124. args.replace(*LINK(args.item(i).queryChild(0)), i);
  6125. cur.setown(cur->clone(args));
  6126. cur.setown(createValue(no_thor, makeVoidType(), cur.getClear()));
  6127. }
  6128. else
  6129. cur.setown(cur->clone(args));
  6130. break;
  6131. }
  6132. case no_ensureresult:
  6133. {
  6134. HqlExprArray args;
  6135. unwindChildren(args, cur);
  6136. args.replace(*mergeThorGraphs(cur->queryChild(0), resourceConditionalActions, resourceSequential), 0);
  6137. cur.setown(cloneOrLink(cur, args));
  6138. break;
  6139. }
  6140. }
  6141. if (cur->getOperator() == no_thor)
  6142. {
  6143. thorActions.append(*LINK(cur->queryChild(0)));
  6144. }
  6145. else
  6146. {
  6147. if (thorActions.ordinality())
  6148. {
  6149. combined.append(*createValue(no_thor, makeVoidType(), createActionList(thorActions)));
  6150. thorActions.kill();
  6151. }
  6152. combined.append(*cur.getClear());
  6153. }
  6154. }
  6155. if (thorActions.ordinality())
  6156. combined.append(*createValue(no_thor, makeVoidType(), createActionList(thorActions)));
  6157. replaceArray(exprs, combined);
  6158. }
  6159. void mergeThorGraphs(WorkflowArray & array, bool resourceConditionalActions, bool resourceSequential)
  6160. {
  6161. ForEachItemIn(idx4, array)
  6162. groupThorGraphs(array.item(idx4).queryExprs());
  6163. ForEachItemIn(idx2, array)
  6164. mergeThorGraphs(array.item(idx2).queryExprs(), resourceConditionalActions, resourceSequential);
  6165. }
  6166. //------------------------------------------------------------------------
  6167. //#define NEW_SCALAR_CODE
  6168. //I think NEW_SCALAR_CODE should be better - but in practice it seems to be worse.....
  6169. inline bool isTypeToHoist(ITypeInfo * type)
  6170. {
  6171. return isSingleValuedType(type);// || (type && type->getTypeCode() == type_set);
  6172. }
  6173. static HqlTransformerInfo scalarGlobalTransformerInfo("ScalarGlobalTransformer");
  6174. ScalarGlobalTransformer::ScalarGlobalTransformer(HqlCppTranslator & _translator)
  6175. : HoistingHqlTransformer(scalarGlobalTransformerInfo, CTFtraverseallnodes), translator(_translator)
  6176. {
  6177. okToHoist = true;
  6178. neverHoist = false;
  6179. }
  6180. void ScalarGlobalTransformer::analyseExpr(IHqlExpression * expr)
  6181. {
  6182. ScalarGlobalExtra * extra = queryBodyExtra(expr);
  6183. analyseThis(expr);
  6184. #ifdef NEW_SCALAR_CODE
  6185. if (++extra->numUses > 1)
  6186. {
  6187. if (!extra->candidate)
  6188. return;
  6189. if (extra->couldHoist || extra->alreadyGlobal)
  6190. return;
  6191. }
  6192. extra->candidate = !containsAnyDataset(expr) && !expr->isConstant() && !isContextDependent(expr);
  6193. extra->couldHoist = extra->candidate && isTypeToHoist(expr->queryType()) && canCreateTemporary(expr) && expr->isPure();
  6194. #else
  6195. if (++extra->numUses > 1)
  6196. {
  6197. if (!okToHoist)
  6198. {
  6199. if (!neverHoist || extra->neverHoist)
  6200. return;
  6201. }
  6202. if (extra->couldHoist)
  6203. {
  6204. if (extra->createGlobal)
  6205. return;
  6206. //Allow a global to be created inside a global marked from somewhere else.
  6207. if (containsAnyDataset(expr) || expr->isConstant() || isContextDependent(expr))
  6208. return;
  6209. }
  6210. }
  6211. extra->couldHoist = okToHoist;
  6212. if (!okToHoist && !neverHoist && !isTypeToHoist(expr->queryType()))
  6213. okToHoist = true;
  6214. #endif
  6215. extra->neverHoist = neverHoist;
  6216. doAnalyseExpr(expr);
  6217. okToHoist = extra->couldHoist;
  6218. neverHoist = extra->neverHoist;
  6219. }
  6220. void ScalarGlobalTransformer::doAnalyseExpr(IHqlExpression * expr)
  6221. {
  6222. switch (expr->getOperator())
  6223. {
  6224. case no_attr:
  6225. case no_constant:
  6226. case no_attr_link:
  6227. case no_null:
  6228. case no_all:
  6229. return;
  6230. case no_persist_check:
  6231. //No point spotting global within this since it will not create a subquery..
  6232. return;
  6233. case no_attr_expr:
  6234. {
  6235. _ATOM name = expr->queryName();
  6236. if ((name == _selectors_Atom) || (name == keyedAtom))
  6237. return;
  6238. analyseChildren(expr);
  6239. return;
  6240. }
  6241. case no_getresult:
  6242. case no_libraryinput:
  6243. queryBodyExtra(expr)->alreadyGlobal = true;
  6244. break;
  6245. case no_globalscope:
  6246. case no_setresult:
  6247. case no_ensureresult:
  6248. {
  6249. queryBodyExtra(expr)->alreadyGlobal = true; // don't tag again - even if opt flag is present
  6250. queryBodyExtra(expr->queryChild(0))->alreadyGlobal = true;
  6251. okToHoist = false;
  6252. break;
  6253. }
  6254. }
  6255. #ifndef NEW_SCALAR_CODE
  6256. // Commented line has problems with SELF used in HOLE definition, and explosion in thumphrey7 etc.
  6257. // if (okToHoist && isIndependentOfScope(expr) && !expr->isConstant() && !isContextDependent(expr) && expr->isPure())
  6258. if (okToHoist && !containsAnyDataset(expr) && !expr->isConstant() && !isContextDependent(expr) && expr->isPure())
  6259. {
  6260. ITypeInfo * type = expr->queryType();
  6261. if (isTypeToHoist(type))
  6262. {
  6263. if (canCreateTemporary(expr))
  6264. {
  6265. queryBodyExtra(expr)->createGlobal = true;
  6266. okToHoist = false;
  6267. }
  6268. }
  6269. }
  6270. #endif
  6271. HoistingHqlTransformer::doAnalyseExpr(expr);
  6272. }
  6273. /*
  6274. Try and decide what is trivial enough to serialise, and what should remain. It is more trial an error than particularly logical
  6275. o Better to store smaller objects because they will serialize smaller.
  6276. o If something is used more than once then probably worth serializing regardless - since calculation will be commoned up.
  6277. o Don't really want to serialize 'x' and 'x <> ''' to the same function - but much better to serialize 'x <> ''' rather than 'x' if only one used.
  6278. */
  6279. bool ScalarGlobalTransformer::isComplex(IHqlExpression * expr, bool checkGlobal)
  6280. {
  6281. ScalarGlobalExtra * extra = queryBodyExtra(expr);
  6282. if (checkGlobal)
  6283. {
  6284. //If something else has turned this into a global then no point.
  6285. if (extra->alreadyGlobal)
  6286. return false;
  6287. }
  6288. switch (expr->getOperator())
  6289. {
  6290. case no_constant:
  6291. case no_getresult:
  6292. case no_globalscope:
  6293. case no_workunit_dataset:
  6294. case no_libraryinput:
  6295. return false;
  6296. case no_cast:
  6297. case no_implicitcast:
  6298. //serialize if the cast reduces the size of the item, otherwise check argument.
  6299. if (expr->queryType()->getSize() <= expr->queryChild(0)->queryType()->getSize())
  6300. return true;
  6301. //If used a lot then save lots of duplicated work.
  6302. if (extra->numUses > 2)
  6303. return true;
  6304. break;
  6305. case no_eq:
  6306. case no_ne:
  6307. case no_lt:
  6308. case no_gt:
  6309. case no_le:
  6310. case no_ge:
  6311. //Accessed more than once-> probably worth commoning up
  6312. if (extra->numUses > 1)
  6313. return true;
  6314. break;
  6315. //f[1..length(trim(x))] = x is very common, and if the length(trim)) was serialized separately then
  6316. //the generated code would be worse.
  6317. case no_trim:
  6318. case no_charlen:
  6319. case no_sorted:
  6320. break;
  6321. case no_substring:
  6322. //single character substring - don't create separate items just for this, since likely to have many of them.
  6323. if (!expr->queryChild(1)->queryValue())
  6324. return true;
  6325. break;
  6326. default:
  6327. if (expr->isConstant())
  6328. return false;
  6329. return true;
  6330. }
  6331. ForEachChild(i, expr)
  6332. {
  6333. if (isComplex(expr->queryChild(i), true))
  6334. return true;
  6335. }
  6336. return false;
  6337. }
  6338. IHqlExpression * ScalarGlobalTransformer::createTransformed(IHqlExpression * expr)
  6339. {
  6340. IHqlExpression * ret = queryTransformAnnotation(expr);
  6341. if (ret)
  6342. return ret;
  6343. OwnedHqlExpr transformed = HoistingHqlTransformer::createTransformed(expr);
  6344. ScalarGlobalExtra * extra = queryBodyExtra(expr);
  6345. #ifdef NEW_SCALAR_CODE
  6346. if (extra->numUses > 1 && extra->couldHoist && !extra->alreadyGlobal && isComplex(expr, false))
  6347. #else
  6348. if (extra->createGlobal && !extra->alreadyGlobal && isComplex(expr, false))
  6349. #endif
  6350. {
  6351. #ifdef _DEBUG
  6352. translator.traceExpression("Mark as global", expr);
  6353. #endif
  6354. //mark as global, so isComplex() can take it into account.
  6355. extra->alreadyGlobal = true;
  6356. if (expr->getOperator() == no_createset)
  6357. transformed.setown(projectCreateSetDataset(transformed));
  6358. return createValue(no_globalscope, transformed->getType(), LINK(transformed));
  6359. }
  6360. return transformed.getClear();
  6361. }
  6362. //------------------------------------------------------------------------
  6363. static HqlTransformerInfo explicitGlobalTransformerInfo("ExplicitGlobalTransformer");
  6364. ExplicitGlobalTransformer::ExplicitGlobalTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  6365. : HoistingHqlTransformer(explicitGlobalTransformerInfo, CTFnoteifactions|CTFtraverseallnodes), translator(_translator)
  6366. {
  6367. wu = _wu;
  6368. isRoxie = (translator.getTargetClusterType() == RoxieCluster);
  6369. seenGlobalScope = false;
  6370. seenLocalGlobalScope = false;
  6371. }
  6372. void ExplicitGlobalTransformer::doAnalyseExpr(IHqlExpression * expr)
  6373. {
  6374. node_operator op = expr->getOperator();
  6375. switch (op)
  6376. {
  6377. case no_output:
  6378. if (!isIndependentOfScope(expr))
  6379. {
  6380. IHqlExpression * filename = queryRealChild(expr, 2);
  6381. if (!filename)
  6382. filename = expr->queryProperty(namedAtom);
  6383. StringBuffer s;
  6384. if (filename)
  6385. getExprECL(filename, s);
  6386. translator.WARNINGAT1(queryActiveLocation(expr), HQLWRN_OutputDependendOnScope, s.str());
  6387. #if 0
  6388. checkIndependentOfScope(expr);
  6389. #endif
  6390. }
  6391. break;
  6392. case no_nothor:
  6393. if (expr->isAction())
  6394. break;
  6395. //fall through
  6396. case no_globalscope:
  6397. //Try and avoid transforms (especially nested ones) as much as possible.
  6398. seenGlobalScope = true;
  6399. //If local attribute is present on a global, then an independent transform may cause an extra
  6400. //transformation because it may become unconditional, when previously conditional
  6401. if (expr->hasProperty(localAtom))
  6402. seenLocalGlobalScope = true;
  6403. break;
  6404. }
  6405. HoistingHqlTransformer::doAnalyseExpr(expr);
  6406. }
  6407. IHqlExpression * ExplicitGlobalTransformer::createTransformed(IHqlExpression * expr)
  6408. {
  6409. if (expr->isConstant())
  6410. return LINK(expr);
  6411. IHqlExpression * ret = queryTransformAnnotation(expr);
  6412. if (ret)
  6413. return ret;
  6414. OwnedHqlExpr transformed = HoistingHqlTransformer::createTransformed(expr);
  6415. node_operator op = expr->getOperator();
  6416. switch (op)
  6417. {
  6418. case no_nothor:
  6419. if (transformed->isAction())
  6420. break;
  6421. //fall through
  6422. case no_globalscope:
  6423. {
  6424. if (!expr->hasProperty(localAtom) || isUsedUnconditionally(expr))
  6425. {
  6426. IHqlExpression * value = transformed->queryChild(0);
  6427. if (!isIndependentOfScope(value))
  6428. {
  6429. if (expr->hasProperty(optAtom))
  6430. return LINK(transformed->queryChild(0));
  6431. IHqlExpression * symbol = queryActiveSymbol();
  6432. StringBuffer s;
  6433. if (symbol && symbol->queryBody() == expr)
  6434. s.appendf(" '%s'", symbol->queryName()->str());
  6435. else
  6436. {
  6437. s.append(" ").append(getOpString(value->getOperator()));
  6438. if (symbol)
  6439. s.append(" in ").append(symbol->queryName());
  6440. }
  6441. translator.reportWarning(queryActiveLocation(expr), ECODETEXT(HQLWRN_GlobalDoesntSeemToBe), s.str());
  6442. }
  6443. if (value->getOperator() == no_createset)
  6444. {
  6445. OwnedHqlExpr createset = projectCreateSetDataset(value);
  6446. IHqlExpression * ds = createset->queryChild(0);
  6447. HqlExprArray outArgs, setArgs;
  6448. outArgs.append(*LINK(ds));
  6449. outArgs.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  6450. outArgs.append(*createAttribute(namedAtom, createNextStringValue(value)));
  6451. IHqlExpression * setResult = createValue(no_output, makeVoidType(), outArgs);
  6452. appendToTarget(*setResult);
  6453. transformed.setown(createGetResultFromSetResult(setResult, expr->queryType()));
  6454. }
  6455. else
  6456. {
  6457. GlobalAttributeInfo info("spill::global","gl", transformed);
  6458. if (op == no_nothor)
  6459. info.extractGlobal(NULL, RoxieCluster);
  6460. else
  6461. info.extractGlobal(transformed, translator.getTargetClusterType());
  6462. OwnedHqlExpr getResult, setResult;
  6463. info.checkFew(translator);
  6464. info.splitGlobalDefinition(transformed->queryType(), value, wu, setResult, &getResult, isRoxie);
  6465. if (op == no_nothor)
  6466. setResult.setown(createValue(no_nothor, makeVoidType(), LINK(setResult)));
  6467. IHqlExpression * cluster = queryRealChild(transformed, 1);
  6468. if (cluster && !isBlankString(cluster))
  6469. setResult.setown(createValue(no_cluster, makeVoidType(), LINK(setResult), LINK(cluster)));
  6470. appendToTarget(*setResult.getClear());
  6471. transformed.setown(getResult.getClear());
  6472. }
  6473. break;
  6474. }
  6475. }
  6476. }
  6477. return transformed.getClear();
  6478. }
  6479. //------------------------------------------------------------------------
  6480. IHqlDataset * queryRootDataset(IHqlExpression * dataset)
  6481. {
  6482. return dataset->queryDataset()->queryRootTable();
  6483. }
  6484. //roxie only executes outputs to temporaries if they are required, or if not all references are from within the graph
  6485. //therefore, there is no need to special case if actions. Thor on the other hand will cause it to be executed unnecessarily.
  6486. static HqlTransformerInfo newScopeMigrateTransformerInfo("NewScopeMigrateTransformer");
  6487. NewScopeMigrateTransformer::NewScopeMigrateTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  6488. : HoistingHqlTransformer(newScopeMigrateTransformerInfo, 0), translator(_translator)
  6489. {
  6490. wu = _wu;
  6491. isRoxie = translator.targetRoxie();
  6492. if (!isRoxie && !_translator.queryOptions().resourceConditionalActions)
  6493. setFlags(CTFnoteifactions);
  6494. minimizeWorkunitTemporaries = translator.queryOptions().minimizeWorkunitTemporaries;
  6495. #ifdef REMOVE_GLOBAL_ANNOTATION
  6496. activityDepth = 0; // should be 0 to actually have any effect - but causes problems...
  6497. #else
  6498. activityDepth = 999; // should be 0 to actually have any effect - but causes problems...
  6499. #endif
  6500. }
  6501. void NewScopeMigrateTransformer::analyseExpr(IHqlExpression * expr)
  6502. {
  6503. ScopeMigrateInfo * extra = queryBodyExtra(expr);
  6504. if (activityDepth > extra->maxActivityDepth)
  6505. {
  6506. if (extra->maxActivityDepth == 0)
  6507. extra->setUnvisited(); // so we walk children again
  6508. extra->maxActivityDepth = activityDepth;
  6509. }
  6510. unsigned savedActivityDepth = activityDepth;
  6511. node_operator op = expr->getOperator();
  6512. switch (op)
  6513. {
  6514. case NO_AGGREGATE:
  6515. case no_createset:
  6516. case NO_ACTION_REQUIRES_GRAPH:
  6517. case no_extractresult:
  6518. case no_distributer:
  6519. case no_within:
  6520. case no_notwithin:
  6521. case no_soapaction_ds:
  6522. case no_returnresult:
  6523. activityDepth++;
  6524. break;
  6525. case no_setresult:
  6526. if (expr->queryChild(0)->isDataset())
  6527. activityDepth++;
  6528. break;
  6529. case no_select:
  6530. if (expr->hasProperty(newAtom))
  6531. activityDepth++;
  6532. break;
  6533. }
  6534. HoistingHqlTransformer::analyseExpr(expr);
  6535. activityDepth = savedActivityDepth;
  6536. }
  6537. IHqlExpression * NewScopeMigrateTransformer::hoist(IHqlExpression * expr, IHqlExpression * hoisted)
  6538. {
  6539. if (minimizeWorkunitTemporaries)
  6540. return createWrapper(no_globalscope, LINK(hoisted));
  6541. IHqlExpression * setResult = createSetResult(hoisted);
  6542. IHqlExpression * seqAttr = setResult->queryProperty(sequenceAtom);
  6543. IHqlExpression * aliasAttr = setResult->queryProperty(namedAtom);
  6544. appendToTarget(*setResult);
  6545. return createGetResultFromSetResult(setResult);
  6546. }
  6547. IHqlExpression * NewScopeMigrateTransformer::createTransformed(IHqlExpression * expr)
  6548. {
  6549. if (expr->isConstant())
  6550. return LINK(expr);
  6551. IHqlExpression * ret = queryTransformAnnotation(expr);
  6552. if (ret)
  6553. return ret;
  6554. OwnedHqlExpr transformed = HoistingHqlTransformer::createTransformed(expr);
  6555. ScopeMigrateInfo * extra = queryBodyExtra(expr);
  6556. node_operator op = expr->getOperator();
  6557. switch (op)
  6558. {
  6559. case no_createset:
  6560. {
  6561. if (isUsedUnconditionally(expr))
  6562. {
  6563. if (isIndependentOfScope(transformed) && !isContextDependent(expr))
  6564. {
  6565. OwnedHqlExpr createset = projectCreateSetDataset(transformed);
  6566. if (minimizeWorkunitTemporaries)
  6567. return createWrapper(no_globalscope, LINK(createset));
  6568. //MORE: This is only temporary until child datasets come into existence, then it will need improving
  6569. //Save it as a temporary dataset in the wu, and retrieve it as a getresult(set)
  6570. IHqlExpression * ds = createset->queryChild(0);
  6571. HqlExprArray outArgs, setArgs;
  6572. outArgs.append(*LINK(ds));
  6573. outArgs.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  6574. outArgs.append(*createAttribute(namedAtom, createNextStringValue(expr)));
  6575. IHqlExpression * setResult = createValue(no_output, makeVoidType(), outArgs);
  6576. appendToTarget(*setResult);
  6577. transformed.setown(createGetResultFromSetResult(setResult, expr->queryType()));
  6578. }
  6579. }
  6580. break;
  6581. }
  6582. case no_select:
  6583. {
  6584. IHqlExpression * newAttr = transformed->queryProperty(newAtom);
  6585. if (newAttr)
  6586. {
  6587. if (isUsedUnconditionally(expr))
  6588. {
  6589. if (extra->maxActivityDepth != 0)
  6590. {
  6591. IHqlExpression * row = transformed->queryChild(0);
  6592. node_operator rowOp = row->getOperator();
  6593. if (rowOp == no_selectnth)
  6594. {
  6595. node_operator dsOp = row->queryChild(0)->getOperator();
  6596. if ((dsOp == no_workunit_dataset) || (dsOp == no_inlinetable))
  6597. break;
  6598. }
  6599. if (rowOp == no_createrow)
  6600. break;
  6601. if (!isInlineTrivialDataset(row) && !isContextDependent(row) && !transformed->isDataset() && !transformed->isDictionary())
  6602. {
  6603. if (isIndependentOfScope(row))
  6604. return hoist(expr, transformed);
  6605. }
  6606. }
  6607. }
  6608. }
  6609. }
  6610. break;
  6611. case NO_AGGREGATE:
  6612. {
  6613. if (isUsedUnconditionally(expr))
  6614. {
  6615. if (extra->maxActivityDepth != 0)
  6616. {
  6617. IHqlExpression * datasetExpr = transformed->queryChild(0);
  6618. IHqlDataset * rootDataset = queryRootDataset(datasetExpr);
  6619. if (!rootDataset)
  6620. {
  6621. //Something like a+b+c
  6622. rootDataset = datasetExpr->queryDataset()->queryTable();
  6623. if (!rootDataset)
  6624. break;
  6625. }
  6626. //Don't do anything with child datasets....
  6627. IHqlExpression * rootDatasetExpr = queryExpression(rootDataset);
  6628. node_operator rootOp = rootDatasetExpr->getOperator();
  6629. if ((rootOp == no_select) || (rootOp == no_field))
  6630. break;
  6631. if (isIndependentOfScope(datasetExpr) && !isContextDependent(expr))
  6632. {
  6633. return hoist(expr, transformed);
  6634. }
  6635. }
  6636. }
  6637. break;
  6638. }
  6639. }
  6640. return transformed.getClear();
  6641. }
  6642. void migrateExprToNaturalLevel(WorkflowArray & array, IWorkUnit * wu, HqlCppTranslator & translator)
  6643. {
  6644. const HqlCppOptions & options = translator.queryOptions();
  6645. ForEachItemIn(idx, array)
  6646. {
  6647. WorkflowItem & cur = array.item(idx);
  6648. HqlExprArray & exprs = cur.queryExprs();
  6649. if (translator.queryOptions().moveUnconditionalActions)
  6650. moveUnconditionalEarlier(exprs);
  6651. translator.checkNormalized(exprs);
  6652. if (options.hoistSimpleGlobal)
  6653. {
  6654. ScalarGlobalTransformer transformer(translator);
  6655. HqlExprArray results;
  6656. transformer.analyseArray(exprs, 0);
  6657. transformer.transformRoot(exprs, results);
  6658. replaceArray(exprs, results);
  6659. translator.checkNormalized(exprs);
  6660. }
  6661. translator.traceExpressions("m0", exprs);
  6662. if (options.workunitTemporaries)
  6663. {
  6664. ExplicitGlobalTransformer transformer(wu, translator);
  6665. transformer.analyseArray(exprs, 0);
  6666. if (transformer.needToTransform())
  6667. {
  6668. HqlExprArray results;
  6669. transformer.transformRoot(exprs, results);
  6670. replaceArray(exprs, results);
  6671. }
  6672. translator.checkNormalized(exprs);
  6673. }
  6674. translator.traceExpressions("m1", exprs);
  6675. if (options.allowScopeMigrate) // && !options.minimizeWorkunitTemporaries)
  6676. {
  6677. NewScopeMigrateTransformer transformer(wu, translator);
  6678. HqlExprArray results;
  6679. transformer.analyseArray(exprs, 0);
  6680. transformer.transformRoot(exprs, results);
  6681. replaceArray(exprs, results);
  6682. translator.checkNormalized(exprs);
  6683. }
  6684. translator.traceExpressions("m2", exprs);
  6685. }
  6686. }
  6687. void expandGlobalDatasets(WorkflowArray & array, IWorkUnit * wu, HqlCppTranslator & translator)
  6688. {
  6689. }
  6690. //---------------------------------------------------------------------------
  6691. bool AutoScopeMigrateInfo::addGraph(unsigned graph)
  6692. {
  6693. if (graph == lastGraph)
  6694. return false;
  6695. if (lastGraph)
  6696. manyGraphs = true;
  6697. lastGraph = graph;
  6698. return true;
  6699. }
  6700. bool AutoScopeMigrateInfo::doAutoHoist(IHqlExpression * transformed, bool minimizeWorkunitTemporaries)
  6701. {
  6702. if (useCount == 0)
  6703. return false;
  6704. node_operator op = original->getOperator();
  6705. switch (op)
  6706. {
  6707. case no_fail:
  6708. return false;
  6709. }
  6710. if (firstUseIsConditional && firstUseIsSequential)
  6711. return false;
  6712. if (firstUseIsSequential && !manyGraphs)
  6713. return false;
  6714. // The following *should* generate better code, but there are currently a couple of exceptions (cmaroney29, jholt20) which need investigation
  6715. // if (!manyGraphs)
  6716. // return false;
  6717. if (globalInsideChild && !minimizeWorkunitTemporaries)// && !transformed->isDataset() && !transformed->isDatarow())
  6718. return true;
  6719. if (!manyGraphs)
  6720. return false;
  6721. if (!original->isDataset())
  6722. {
  6723. switch (op)
  6724. {
  6725. case NO_AGGREGATE:
  6726. break;
  6727. default:
  6728. return false;
  6729. }
  6730. }
  6731. if (!isWorthHoisting(transformed, false))
  6732. return false;
  6733. if (isContextDependent(transformed))
  6734. return false;
  6735. return isIndependentOfScope(original);
  6736. }
  6737. static HqlTransformerInfo autoScopeMigrateTransformerInfo("AutoScopeMigrateTransformer");
  6738. AutoScopeMigrateTransformer::AutoScopeMigrateTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  6739. : NewHqlTransformer(autoScopeMigrateTransformerInfo), translator(_translator)
  6740. {
  6741. wu = _wu;
  6742. isRoxie = (translator.getTargetClusterType() == RoxieCluster);
  6743. isConditional = false;
  6744. isSequential = false;
  6745. hasCandidate = false;
  6746. activityDepth = 0;
  6747. curGraph = 1;
  6748. }
  6749. void AutoScopeMigrateTransformer::analyseExpr(IHqlExpression * expr)
  6750. {
  6751. AutoScopeMigrateInfo * extra = queryBodyExtra(expr);
  6752. if (isConditional)
  6753. extra->condUseCount++;
  6754. else
  6755. extra->useCount++;
  6756. bool newGraph = extra->addGraph(curGraph);
  6757. if (!newGraph)
  6758. return;
  6759. if (extra->doAutoHoist(expr, translator.queryOptions().minimizeWorkunitTemporaries))
  6760. {
  6761. hasCandidate = true;
  6762. return;
  6763. }
  6764. unsigned savedDepth = activityDepth;
  6765. doAnalyseExpr(expr);
  6766. activityDepth = savedDepth;
  6767. }
  6768. void AutoScopeMigrateTransformer::doAnalyseExpr(IHqlExpression * expr)
  6769. {
  6770. AutoScopeMigrateInfo * extra = queryBodyExtra(expr);
  6771. if (activityDepth && expr->isDataset())
  6772. {
  6773. if (isWorthHoisting(expr, true) && isIndependentOfScope(expr) && !isContextDependent(expr))
  6774. {
  6775. #ifdef _DEBUG
  6776. isWorthHoisting(expr, true);
  6777. #endif
  6778. extra->globalInsideChild = true;
  6779. hasCandidate = true;
  6780. activityDepth = 0;
  6781. }
  6782. }
  6783. extra->firstUseIsConditional = isConditional;
  6784. extra->firstUseIsSequential = isSequential;
  6785. switch (expr->getOperator())
  6786. {
  6787. case no_allnodes:
  6788. case no_keyedlimit:
  6789. case no_nothor:
  6790. return;
  6791. case no_sequential:
  6792. return;
  6793. case no_if:
  6794. case no_choose:
  6795. {
  6796. if (expr->isAction())
  6797. {
  6798. bool wasConditional = isConditional;
  6799. analyseExpr(expr->queryChild(0));
  6800. isConditional = true;
  6801. ForEachChildFrom(i, expr, 1)
  6802. analyseExpr(expr->queryChild(i));
  6803. isConditional = wasConditional;
  6804. return;
  6805. }
  6806. break;
  6807. }
  6808. case no_newtransform:
  6809. case no_transform:
  6810. if (curGraph)
  6811. {
  6812. activityDepth++;
  6813. NewHqlTransformer::analyseExpr(expr);
  6814. activityDepth--;
  6815. return;
  6816. }
  6817. break;
  6818. case no_thor:
  6819. //ignore thor attribute on a dataset..
  6820. if (expr->queryType())
  6821. {
  6822. curGraph++;
  6823. NewHqlTransformer::analyseExpr(expr);
  6824. curGraph++; // don't restore - new pseudo graph to aid cse between global branches separated by graphs
  6825. return;
  6826. }
  6827. break;
  6828. }
  6829. NewHqlTransformer::analyseExpr(expr);
  6830. }
  6831. IHqlExpression * AutoScopeMigrateTransformer::createTransformed(IHqlExpression * expr)
  6832. {
  6833. switch (expr->getOperator())
  6834. {
  6835. case no_allnodes:
  6836. case no_keyedlimit:
  6837. case no_libraryscope:
  6838. case no_nothor:
  6839. case no_sequential:
  6840. return LINK(expr);
  6841. case no_thor:
  6842. {
  6843. IHqlExpression * actions = expr->queryChild(0);
  6844. if (actions)
  6845. {
  6846. //MORE: Simplify this???? or remove the special case all together?
  6847. //OwnedHqlExpr newActions = transform(actions);
  6848. HqlExprArray args;
  6849. unwindCommaCompound(args, actions);
  6850. ForEachItemIn(i, args)
  6851. graphActions.append(*transform(&args.item(i)));
  6852. OwnedHqlExpr newActions = createActionList(graphActions);
  6853. graphActions.kill();
  6854. if (actions == newActions)
  6855. return LINK(expr);
  6856. return createWrapper(no_thor, newActions.getClear());
  6857. }
  6858. break;
  6859. }
  6860. }
  6861. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  6862. updateOrphanedSelectors(transformed, expr);
  6863. AutoScopeMigrateInfo * extra = queryBodyExtra(expr);
  6864. if (extra->doAutoHoist(transformed, translator.queryOptions().minimizeWorkunitTemporaries))
  6865. {
  6866. StringBuffer s;
  6867. s.appendf("AutoGlobal: Spotted %s ", getOpString(expr->getOperator()));
  6868. if (expr->queryName())
  6869. s.append("[").append(expr->queryName()).append("] ");
  6870. s.append("as an item to hoist");
  6871. DBGLOG("%s", s.str());
  6872. GlobalAttributeInfo info("spill::auto","auto", transformed);
  6873. info.extractGlobal(NULL, translator.getTargetClusterType());
  6874. if (translator.targetThor() && extra->globalInsideChild)
  6875. info.preventDiskSpill();
  6876. OwnedHqlExpr getResult, setResult;
  6877. info.checkFew(translator);
  6878. info.splitGlobalDefinition(transformed->queryType(), transformed, wu, setResult, &getResult, isRoxie);
  6879. //If the first use is conditional, then hoist the expression globally (it can't have any dependents)
  6880. //else hoist it within the current graph, otherwise it can get hoisted before globals on datasets that
  6881. //it is dependent on.
  6882. if (extra->firstUseIsConditional)
  6883. globalTarget->append(*createWrapper(no_thor, setResult.getClear()));
  6884. else
  6885. graphActions.append(*setResult.getClear());
  6886. transformed.setown(getResult.getClear());
  6887. }
  6888. return transformed.getClear();
  6889. }
  6890. void AutoScopeMigrateTransformer::transformRoot(const HqlExprArray & in, HqlExprArray & out)
  6891. {
  6892. globalTarget = &out;
  6893. NewHqlTransformer::transformRoot(in, out);
  6894. globalTarget = NULL;
  6895. }
  6896. //---------------------------------------------------------------------------
  6897. static HqlTransformerInfo trivialGraphRemoverInfo("TrivialGraphRemover");
  6898. TrivialGraphRemover::TrivialGraphRemover() : NewHqlTransformer(trivialGraphRemoverInfo)
  6899. {
  6900. hasCandidate = false;
  6901. }
  6902. void TrivialGraphRemover::analyseExpr(IHqlExpression * expr)
  6903. {
  6904. if (hasCandidate || alreadyVisited(expr))
  6905. return;
  6906. if (expr->getOperator() == no_thor)
  6907. {
  6908. if (isTrivialGraph(expr->queryChild(0)))
  6909. hasCandidate = true;
  6910. return;
  6911. }
  6912. NewHqlTransformer::analyseExpr(expr);
  6913. }
  6914. IHqlExpression * TrivialGraphRemover::createTransformed(IHqlExpression * expr)
  6915. {
  6916. switch (expr->getOperator())
  6917. {
  6918. case no_thor:
  6919. {
  6920. IHqlExpression * child = expr->queryChild(0);
  6921. if (child && isTrivialGraph(child))
  6922. return LINK(child);
  6923. return LINK(expr);
  6924. }
  6925. }
  6926. return NewHqlTransformer::createTransformed(expr);
  6927. }
  6928. bool TrivialGraphRemover::isTrivialGraph(IHqlExpression * expr)
  6929. {
  6930. if (!expr)
  6931. return false;
  6932. if (expr->getOperator() == no_setresult)
  6933. {
  6934. IHqlExpression * value = expr->queryChild(0);
  6935. if (value->getOperator() != no_getresult)
  6936. return false;
  6937. return true;
  6938. }
  6939. else if (expr->getOperator() == no_output)
  6940. return isTrivialInlineOutput(expr);
  6941. else
  6942. return false;
  6943. }
  6944. void removeTrivialGraphs(WorkflowArray & workflow)
  6945. {
  6946. ForEachItemIn(idx, workflow)
  6947. {
  6948. WorkflowItem & cur = workflow.item(idx);
  6949. HqlExprArray & exprs = cur.queryExprs();
  6950. TrivialGraphRemover transformer;
  6951. transformer.analyseArray(exprs, 0);
  6952. if (transformer.worthTransforming())
  6953. {
  6954. HqlExprArray simplified;
  6955. transformer.transformRoot(exprs, simplified);
  6956. replaceArray(exprs, simplified);
  6957. }
  6958. }
  6959. }
  6960. //==============================================================================================================
  6961. class FilterCloner
  6962. {
  6963. public:
  6964. FilterCloner(IHqlExpression * _ds) { ds.set(_ds); matched = false; lockTransformMutex(); }
  6965. ~FilterCloner() { unlockTransformMutex(); }
  6966. void addMappings(IHqlExpression * expr, IHqlExpression * addDs);
  6967. IHqlExpression * inheritFilters(IHqlExpression * expr);
  6968. inline bool hasMappings() { return matched; }
  6969. protected:
  6970. void doAddMappings(IHqlExpression * expr);
  6971. bool isMatchingSelector(IHqlExpression * expr);
  6972. void setMapping(IHqlExpression * selector, IHqlExpression * value);
  6973. protected:
  6974. HqlExprAttr ds;
  6975. bool matched;
  6976. };
  6977. void FilterCloner::setMapping(IHqlExpression * selector, IHqlExpression * value)
  6978. {
  6979. selector->setTransformExtra(value);
  6980. matched = true;
  6981. }
  6982. void FilterCloner::doAddMappings(IHqlExpression * expr)
  6983. {
  6984. loop
  6985. {
  6986. switch (expr->getOperator())
  6987. {
  6988. case no_and:
  6989. doAddMappings(expr->queryChild(0));
  6990. expr = expr->queryChild(1);
  6991. continue;
  6992. case no_in:
  6993. case no_notin:
  6994. {
  6995. IHqlExpression * lhs = expr->queryChild(0);
  6996. IHqlExpression * rhs = expr->queryChild(1);
  6997. if (isMatchingSelector(lhs) && !containsActiveDataset(rhs))
  6998. setMapping(lhs, expr);
  6999. break;
  7000. }
  7001. case no_between:
  7002. case no_notbetween:
  7003. {
  7004. IHqlExpression * lhs = expr->queryChild(0);
  7005. if (isMatchingSelector(lhs) && !containsActiveDataset(expr->queryChild(1)) && !containsActiveDataset(expr->queryChild(2)))
  7006. setMapping(lhs, expr);
  7007. break;
  7008. }
  7009. case no_eq:
  7010. case no_ne:
  7011. case no_lt:
  7012. case no_gt:
  7013. case no_ge:
  7014. case no_le:
  7015. {
  7016. IHqlExpression * lhs = expr->queryChild(0);
  7017. IHqlExpression * rhs = expr->queryChild(1);
  7018. if (isMatchingSelector(lhs) && !containsActiveDataset(rhs))
  7019. setMapping(lhs, expr);
  7020. else if (isMatchingSelector(rhs) && !containsActiveDataset(lhs))
  7021. setMapping(rhs, expr);
  7022. break;
  7023. }
  7024. }
  7025. return;
  7026. }
  7027. }
  7028. void FilterCloner::addMappings(IHqlExpression * expr, IHqlExpression * addDs)
  7029. {
  7030. if (!expr) return;
  7031. OwnedHqlExpr replaced = replaceSelector(expr, addDs, ds);
  7032. doAddMappings(replaced);
  7033. }
  7034. bool FilterCloner::isMatchingSelector(IHqlExpression * expr)
  7035. {
  7036. return queryDatasetCursor(expr) == ds;
  7037. }
  7038. IHqlExpression * FilterCloner::inheritFilters(IHqlExpression * expr)
  7039. {
  7040. switch (expr->getOperator())
  7041. {
  7042. case no_and:
  7043. case no_assertkeyed:
  7044. case no_assertstepped:
  7045. {
  7046. HqlExprArray args;
  7047. ForEachChild(i, expr)
  7048. args.append(*inheritFilters(expr->queryChild(i)));
  7049. return cloneOrLink(expr, args);
  7050. }
  7051. case no_eq:
  7052. {
  7053. IHqlExpression * lhs = expr->queryChild(0);
  7054. IHqlExpression * rhs = expr->queryChild(1);
  7055. IHqlExpression * lhsExtra = (IHqlExpression *)lhs->queryTransformExtra();
  7056. if (lhsExtra)
  7057. {
  7058. DBGLOG("Inheriting filter condition");
  7059. IHqlExpression * cond = replaceExpression(lhsExtra, lhs, rhs);
  7060. return createValue(no_and, LINK(expr), cond);
  7061. }
  7062. IHqlExpression * rhsExtra = (IHqlExpression *)rhs->queryTransformExtra();
  7063. if (rhsExtra)
  7064. {
  7065. DBGLOG("Inheriting filter condition");
  7066. IHqlExpression * cond = replaceExpression(rhsExtra, rhs, lhs);
  7067. return createValue(no_and, LINK(expr), cond);
  7068. }
  7069. break;
  7070. }
  7071. case no_in:
  7072. case no_notin:
  7073. case no_between:
  7074. case no_notbetween:
  7075. {
  7076. IHqlExpression * lhs = expr->queryChild(0);
  7077. IHqlExpression * lhsExtra = (IHqlExpression *)lhs->queryTransformExtra();
  7078. if (lhsExtra)
  7079. {
  7080. DBGLOG("Inheriting filter condition");
  7081. return createValue(no_and, LINK(expr), LINK(lhsExtra));
  7082. }
  7083. break;
  7084. }
  7085. }
  7086. return LINK(expr);
  7087. }
  7088. static IHqlExpression * optimizeJoinFilter(IHqlExpression * expr)
  7089. {
  7090. //NB: Not a member function because we use a different transform mutex, and don't want to accidentally interfere with caller's use
  7091. IHqlExpression * index = expr->queryChild(1);
  7092. if (!index->hasProperty(filteredAtom) && !index->hasProperty(_filtered_Atom) && (index->getOperator() == no_newkeyindex))
  7093. return LINK(expr);
  7094. if (expr->hasProperty(keyedAtom))
  7095. return LINK(expr); //MORE!
  7096. OwnedHqlExpr rhs = createSelector(no_right, index, querySelSeq(expr));
  7097. FilterCloner processor(rhs);
  7098. while (index->getOperator() != no_newkeyindex)
  7099. {
  7100. switch (index->getOperator())
  7101. {
  7102. case no_filter:
  7103. //case no_filtered:
  7104. //MORE: This might be useful in the future
  7105. UNIMPLEMENTED;
  7106. }
  7107. index = index->queryChild(0);
  7108. }
  7109. processor.addMappings(queryPropertyChild(index, filteredAtom, 0), queryActiveTableSelector());
  7110. processor.addMappings(queryPropertyChild(index, _filtered_Atom, 0), queryActiveTableSelector());
  7111. if (!processor.hasMappings())
  7112. return LINK(expr);
  7113. HqlExprArray exprs;
  7114. expr->queryChild(2)->unwindList(exprs, no_and);
  7115. bool keyedExplicitly = false;
  7116. ForEachItemIn(i1, exprs)
  7117. {
  7118. IHqlExpression & cur = exprs.item(i1);
  7119. switch (cur.getOperator())
  7120. {
  7121. case no_assertkeyed:
  7122. case no_assertwild:
  7123. keyedExplicitly = true;
  7124. exprs.replace(*processor.inheritFilters(&cur), i1);
  7125. break;
  7126. }
  7127. }
  7128. if (!keyedExplicitly)
  7129. {
  7130. ForEachItemIn(i2, exprs)
  7131. {
  7132. IHqlExpression & cur = exprs.item(i2);
  7133. switch (cur.getOperator())
  7134. {
  7135. case no_assertkeyed:
  7136. case no_assertwild:
  7137. case no_attr:
  7138. case no_attr_link:
  7139. case no_attr_expr:
  7140. break;
  7141. default:
  7142. exprs.replace(*processor.inheritFilters(&cur), i2);
  7143. break;
  7144. }
  7145. }
  7146. }
  7147. HqlExprArray args;
  7148. unwindChildren(args, expr);
  7149. args.replace(*createBalanced(no_and, queryBoolType(), exprs), 2);
  7150. return expr->clone(args);
  7151. }
  7152. static HqlTransformerInfo filteredIndexOptimizerInfo("FilteredIndexOptimizer");
  7153. FilteredIndexOptimizer::FilteredIndexOptimizer(bool _processJoins, bool _processReads)
  7154. : NewHqlTransformer(filteredIndexOptimizerInfo)
  7155. {
  7156. processJoins = _processJoins;
  7157. processReads = _processReads;
  7158. }
  7159. IHqlExpression * FilteredIndexOptimizer::createTransformed(IHqlExpression * expr)
  7160. {
  7161. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  7162. if (processJoins && isKeyedJoin(transformed))
  7163. transformed.setown(optimizeJoinFilter(transformed));
  7164. if (processReads)
  7165. {
  7166. switch (transformed->getOperator())
  7167. {
  7168. case no_compound_indexread:
  7169. case no_compound_indexnormalize:
  7170. case no_compound_indexaggregate:
  7171. case no_compound_indexcount:
  7172. case no_compound_indexgroupaggregate:
  7173. //MORE:
  7174. break;
  7175. }
  7176. }
  7177. return transformed.getClear();
  7178. }
  7179. //==============================================================================================================
  7180. static HqlTransformerInfo localUploadTransformerInfo("LocalUploadTransformer");
  7181. LocalUploadTransformer::LocalUploadTransformer(IWorkUnit * _wu) : NewHqlTransformer(localUploadTransformerInfo)
  7182. {
  7183. wu = _wu;
  7184. }
  7185. IHqlExpression * LocalUploadTransformer::createTransformed(IHqlExpression * expr)
  7186. {
  7187. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  7188. if (transformed->hasProperty(localUploadAtom))
  7189. {
  7190. assertex(transformed->getOperator() == no_table);
  7191. IHqlExpression * filename = transformed->queryChild(0);
  7192. IHqlExpression * mode = transformed->queryChild(2);
  7193. assertex(filename->getOperator() == no_constant);
  7194. StringBuffer sourceName,localName;
  7195. filename->queryValue()->getStringValue(sourceName);
  7196. getUniqueId(localName.append("local"));
  7197. LocalFileUploadType uploadType = UploadTypeWUResult;
  7198. switch (mode->getOperator())
  7199. {
  7200. case no_csv:
  7201. uploadType = UploadTypeWUResultCsv;
  7202. break;
  7203. case no_xml:
  7204. uploadType = UploadTypeWUResultXml;
  7205. break;
  7206. }
  7207. wu->addLocalFileUpload(uploadType, sourceName, localName, NULL);
  7208. HqlExprArray args;
  7209. args.append(*LINK(expr->queryRecord()));
  7210. args.append(*createAttribute(nameAtom, createConstant(localName.str())));
  7211. args.append(*createAttribute(sequenceAtom, getStoredSequenceNumber()));
  7212. return createDataset(no_workunit_dataset, args);
  7213. }
  7214. return transformed.getClear();
  7215. }
  7216. //==============================================================================================================
  7217. /*
  7218. The following code converts expressions of the form a.b where a and b are datasets into a normalized form including
  7219. an explicit normalize activity. It follows the following rules:
  7220. 1) An filter/project/table on a.b logically has access to fields in a and a.b.
  7221. 2) An operation with a transform (or record defining the output) other than a PROJECT/TABLE, implicitly loses access to fields in a for all
  7222. subsequent operations.
  7223. 3) When a dataset is used in an output or outer outer context (e.g., call parameter) then only the fields in the child dataset are passed.
  7224. This is done by converting f(a.b) to normalize(a, f(LEFT.b)) at the appropriate place.
  7225. These rules mean we maintain the HOLe semantics which allow computed fields to be implemented by projecting fields from the parent dataset,
  7226. but also mean that we avoid problems with parent datasets e.g., join(a.b, c.d)
  7227. To make this efficient we also need to implement the following in the code generator:
  7228. 1) aggregate-normalize(x).
  7229. 2) normalize-source.
  7230. 3) aggregate-normalize-source
  7231. 4) inline processing of normalize.
  7232. After this transform there should be no existing datasets of the form <a.b>[new]. There is a new function to ensure this is correct.
  7233. For the first version, it only generates normalizes around datasets - and assumes that parent fields don't need to be mapped into the denormalize.
  7234. This makes it simpler, but means that parse statements that take a record which could theoretically access parent dataset
  7235. fields won't work. The fix would require a new kind of child normalize that took a no_newtransform, and would require
  7236. analysis of which parent fields are used in the child's no_newtransform.
  7237. */
  7238. inline void getDatasetRange(IHqlExpression * expr, unsigned & first, unsigned & max)
  7239. {
  7240. first = 0;
  7241. switch (getChildDatasetType(expr))
  7242. {
  7243. case childdataset_many_noscope:
  7244. case childdataset_many:
  7245. max = expr->numChildren();
  7246. break;
  7247. case childdataset_if:
  7248. first = 1;
  7249. max = expr->numChildren();
  7250. break;
  7251. default:
  7252. max = getNumChildTables(expr);
  7253. break;
  7254. }
  7255. }
  7256. static HqlTransformerInfo nestedSelectorNormalizerInfo("NestedSelectorNormalizer");
  7257. NestedSelectorNormalizer::NestedSelectorNormalizer() : NewHqlTransformer(nestedSelectorNormalizerInfo)
  7258. {
  7259. spottedCandidate = false;
  7260. }
  7261. void NestedSelectorNormalizer::analyseExpr(IHqlExpression * expr)
  7262. {
  7263. if (alreadyVisited(expr))
  7264. return;
  7265. NewHqlTransformer::analyseExpr(expr);
  7266. if (expr->isDataset())
  7267. {
  7268. bool childrenAreDenormalized = false;
  7269. unsigned first, max;
  7270. getDatasetRange(expr, first, max);
  7271. for (unsigned i=0; i < max; i++)
  7272. {
  7273. if (queryBodyExtra(expr->queryChild(i))->isDenormalized)
  7274. childrenAreDenormalized = true;
  7275. }
  7276. NestedSelectorInfo * extra = queryBodyExtra(expr);
  7277. switch (expr->getOperator())
  7278. {
  7279. case no_select:
  7280. if (isNewSelector(expr))
  7281. {
  7282. childrenAreDenormalized = true;
  7283. spottedCandidate = true;
  7284. }
  7285. break;
  7286. case no_hqlproject:
  7287. case no_usertable:
  7288. break;
  7289. default:
  7290. //Follow test effectively checks whether parent dataset is active beyond this point
  7291. if (expr->queryBody() == expr->queryNormalizedSelector())
  7292. {
  7293. if (childrenAreDenormalized)
  7294. {
  7295. extra->insertDenormalize = true;
  7296. childrenAreDenormalized = false;
  7297. }
  7298. }
  7299. break;
  7300. }
  7301. extra->isDenormalized = childrenAreDenormalized;
  7302. }
  7303. }
  7304. static IHqlExpression * splitSelector(IHqlExpression * expr, SharedHqlExpr & oldDataset)
  7305. {
  7306. assertex(expr->getOperator() == no_select);
  7307. IHqlExpression * ds = expr->queryChild(0);
  7308. if (expr->hasProperty(newAtom))
  7309. {
  7310. oldDataset.set(ds);
  7311. OwnedHqlExpr left = createSelector(no_left, ds, querySelSeq(expr));
  7312. return createSelectExpr(left.getClear(), LINK(expr->queryChild(1)));
  7313. }
  7314. HqlExprArray args;
  7315. args.append(*splitSelector(ds, oldDataset));
  7316. unwindChildren(args, expr, 1);
  7317. return expr->clone(args);
  7318. }
  7319. IHqlExpression * NestedSelectorNormalizer::createNormalized(IHqlExpression * expr)
  7320. {
  7321. IHqlExpression * root = queryRoot(expr);
  7322. assertex(root && root->getOperator() == no_select && isNewSelector(root));
  7323. OwnedHqlExpr selSeq = createSelectorSequence();
  7324. OwnedHqlExpr oldDataset;
  7325. OwnedHqlExpr newSelector = splitSelector(root, oldDataset);
  7326. OwnedHqlExpr right = createSelector(no_right, expr, selSeq);
  7327. HqlExprArray args;
  7328. args.append(*LINK(oldDataset));
  7329. args.append(*replaceExpression(expr, root, newSelector));
  7330. args.append(*createTransformFromRow(right));
  7331. args.append(*LINK(selSeq));
  7332. OwnedHqlExpr ret = createDataset(no_normalize, args);
  7333. return expr->cloneAllAnnotations(ret);
  7334. }
  7335. IHqlExpression * NestedSelectorNormalizer::createTransformed(IHqlExpression * expr)
  7336. {
  7337. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  7338. NestedSelectorInfo * extra = queryBodyExtra(expr);
  7339. bool denormalizeInputs = false;
  7340. if (extra->insertDenormalize)
  7341. {
  7342. denormalizeInputs = true;
  7343. }
  7344. else
  7345. {
  7346. switch (expr->getOperator())
  7347. {
  7348. case NO_AGGREGATE:
  7349. case no_joined:
  7350. case no_buildindex:
  7351. case no_apply:
  7352. case no_distribution:
  7353. case no_distributer:
  7354. case no_within:
  7355. case no_notwithin:
  7356. case no_output:
  7357. case no_createset:
  7358. case no_soapaction_ds:
  7359. case no_newsoapaction_ds:
  7360. case no_returnresult:
  7361. case no_setgraphresult:
  7362. case no_setgraphloopresult:
  7363. case no_keydiff:
  7364. case no_rowdiff:
  7365. case no_extractresult:
  7366. // case no_setresult:
  7367. case no_blob2id:
  7368. case no_selectnth:
  7369. case no_keypatch:
  7370. case no_assign:
  7371. case no_lt:
  7372. case no_le:
  7373. case no_gt:
  7374. case no_ge:
  7375. case no_ne:
  7376. case no_eq:
  7377. case no_order:
  7378. case no_keyed:
  7379. case no_loopbody:
  7380. case no_rowvalue:
  7381. case no_setmeta:
  7382. case no_typetransfer:
  7383. case no_subgraph:
  7384. denormalizeInputs = true;
  7385. break;
  7386. }
  7387. }
  7388. if (denormalizeInputs)
  7389. {
  7390. bool same = true;
  7391. HqlExprArray args;
  7392. unwindChildren(args, transformed);
  7393. unsigned first, max;
  7394. getDatasetRange(expr, first, max);
  7395. for (unsigned i = first; i < max; i++)
  7396. {
  7397. if (queryBodyExtra(expr->queryChild(i))->isDenormalized)
  7398. {
  7399. args.replace(*createNormalized(&args.item(i)), i);
  7400. same = false;
  7401. }
  7402. }
  7403. if (!same)
  7404. return transformed->clone(args);
  7405. }
  7406. return transformed.getClear();
  7407. }
  7408. //==============================================================================================================
  7409. /*
  7410. Code to spot ambiguous LEFT dataset references....
  7411. */
  7412. static HqlTransformerInfo leftRightSelectorNormalizerInfo("LeftRightSelectorNormalizer");
  7413. LeftRightSelectorNormalizer::LeftRightSelectorNormalizer(bool _allowAmbiguity) : NewHqlTransformer(leftRightSelectorNormalizerInfo)
  7414. {
  7415. allowAmbiguity = _allowAmbiguity;
  7416. isAmbiguous = false;
  7417. }
  7418. void LeftRightSelectorNormalizer::checkAmbiguity(const HqlExprCopyArray & inScope, IHqlExpression * selector)
  7419. {
  7420. node_operator selectOp = selector->getOperator();
  7421. ForEachItemIn(i, inScope)
  7422. {
  7423. IHqlExpression & cur = inScope.item(i);
  7424. if ((&cur != selector) && (cur.getOperator() == selectOp) && (cur.queryRecord() == selector->queryRecord()))
  7425. {
  7426. isAmbiguous = true;
  7427. if (!allowAmbiguity)
  7428. {
  7429. StringBuffer ecl;
  7430. getExprECL(selector, ecl);
  7431. throwError1(HQLERR_AmbiguousLeftRight, ecl.str());
  7432. }
  7433. }
  7434. }
  7435. }
  7436. void LeftRightSelectorNormalizer::analyseExpr(IHqlExpression * expr)
  7437. {
  7438. if (alreadyVisited(expr))
  7439. return;
  7440. IHqlExpression * selSeq = querySelSeq(expr);
  7441. if (selSeq)
  7442. {
  7443. HqlExprCopyArray inScope;
  7444. switch (getChildDatasetType(expr))
  7445. {
  7446. case childdataset_none:
  7447. case childdataset_many_noscope:
  7448. case childdataset_many:
  7449. case childdataset_map:
  7450. case childdataset_dataset_noscope:
  7451. case childdataset_if:
  7452. case childdataset_case:
  7453. case childdataset_dataset:
  7454. case childdataset_evaluate:
  7455. break;
  7456. case childdataset_datasetleft:
  7457. case childdataset_left:
  7458. {
  7459. IHqlExpression * dataset = expr->queryChild(0);
  7460. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  7461. gatherChildTablesUsed(NULL, &inScope, expr, 1);
  7462. checkAmbiguity(inScope, left);
  7463. break;
  7464. }
  7465. case childdataset_leftright:
  7466. {
  7467. OwnedHqlExpr left = createSelector(no_left, expr->queryChild(0), selSeq);
  7468. OwnedHqlExpr right = createSelector(no_right, expr->queryChild(1), selSeq);
  7469. gatherChildTablesUsed(NULL, &inScope, expr, 2);
  7470. checkAmbiguity(inScope, left);
  7471. checkAmbiguity(inScope, right);
  7472. break;
  7473. }
  7474. case childdataset_same_left_right:
  7475. case childdataset_top_left_right:
  7476. case childdataset_nway_left_right:
  7477. {
  7478. IHqlExpression * dataset = expr->queryChild(0);
  7479. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  7480. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  7481. gatherChildTablesUsed(NULL, &inScope, expr, 1);
  7482. checkAmbiguity(inScope, left);
  7483. checkAmbiguity(inScope, right);
  7484. break;
  7485. }
  7486. default:
  7487. UNIMPLEMENTED;
  7488. }
  7489. }
  7490. NewHqlTransformer::analyseExpr(expr);
  7491. }
  7492. IHqlExpression * LeftRightSelectorNormalizer::createTransformed(IHqlExpression * expr)
  7493. {
  7494. if (expr->isAttribute() && expr->queryName() == _selectorSequence_Atom)
  7495. return createDummySelectorSequence();
  7496. return NewHqlTransformer::createTransformed(expr);
  7497. }
  7498. IHqlExpression * LeftRightSelectorNormalizer::createTransformedSelector(IHqlExpression * expr)
  7499. {
  7500. node_operator op = expr->getOperator();
  7501. switch (op)
  7502. {
  7503. case no_left:
  7504. case no_right:
  7505. return transform(expr);
  7506. }
  7507. return NewHqlTransformer::createTransformedSelector(expr);
  7508. }
  7509. //==============================================================================================================
  7510. static HqlTransformerInfo forceLocalTransformerInfo("ForceLocalTransformer");
  7511. ForceLocalTransformer::ForceLocalTransformer(ClusterType _targetClusterType) : NewHqlTransformer(forceLocalTransformerInfo)
  7512. {
  7513. targetClusterType = _targetClusterType;
  7514. insideForceLocal = false;
  7515. allNodesDepth = 0;
  7516. }
  7517. IHqlExpression * ForceLocalTransformer::createTransformed(IHqlExpression * expr)
  7518. {
  7519. node_operator op = expr->getOperator();
  7520. switch (expr->getOperator())
  7521. {
  7522. case no_forcelocal:
  7523. case no_forcenolocal:
  7524. {
  7525. bool wasLocal = insideForceLocal;
  7526. insideForceLocal = (op == no_forcelocal) && (targetClusterType != HThorCluster);
  7527. IHqlExpression * ret = transform(expr->queryChild(0));
  7528. insideForceLocal = wasLocal;
  7529. return ret;
  7530. }
  7531. case no_thisnode:
  7532. if ((targetClusterType != HThorCluster) && (allNodesDepth == 0))
  7533. throwError(HQLERR_ThisNodeNotInsideAllNodes);
  7534. //fall through
  7535. case no_allnodes:
  7536. {
  7537. if (targetClusterType != HThorCluster)
  7538. {
  7539. unsigned oldDepth = allNodesDepth;
  7540. if (op == no_allnodes)
  7541. allNodesDepth++;
  7542. else
  7543. allNodesDepth--;
  7544. IHqlExpression * ret = NewHqlTransformer::createTransformed(expr);
  7545. allNodesDepth = oldDepth;
  7546. return ret;
  7547. }
  7548. else
  7549. return transform(expr->queryChild(0));
  7550. }
  7551. case no_globalscope:
  7552. case no_colon:
  7553. {
  7554. bool wasLocal = insideForceLocal;
  7555. unsigned oldDepth = allNodesDepth;
  7556. insideForceLocal = false;
  7557. allNodesDepth = 0;
  7558. IHqlExpression * ret = NewHqlTransformer::createTransformed(expr);
  7559. insideForceLocal = wasLocal;
  7560. allNodesDepth = oldDepth;
  7561. return ret;
  7562. }
  7563. }
  7564. OwnedHqlExpr ret = NewHqlTransformer::createTransformed(expr);
  7565. if (!insideForceLocal || !localChangesActivity(expr) || expr->hasProperty(noLocalAtom))
  7566. return ret.getClear();
  7567. return appendLocalAttribute(ret);
  7568. }
  7569. ANewTransformInfo * ForceLocalTransformer::createTransformInfo(IHqlExpression * expr)
  7570. {
  7571. return CREATE_NEWTRANSFORMINFO(ForceLocalTransformInfo, expr);
  7572. }
  7573. IHqlExpression * ForceLocalTransformer::queryAlreadyTransformed(IHqlExpression * expr)
  7574. {
  7575. ForceLocalTransformInfo * extra = queryExtra(expr);
  7576. return extra->localTransformed[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())];
  7577. }
  7578. void ForceLocalTransformer::setTransformed(IHqlExpression * expr, IHqlExpression * transformed)
  7579. {
  7580. ForceLocalTransformInfo * extra = queryExtra(expr);
  7581. extra->localTransformed[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())].set(transformed);
  7582. }
  7583. IHqlExpression * ForceLocalTransformer::queryAlreadyTransformedSelector(IHqlExpression * expr)
  7584. {
  7585. ForceLocalTransformInfo * extra = queryExtra(expr);
  7586. return extra->localTransformedSelector[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())];
  7587. }
  7588. void ForceLocalTransformer::setTransformedSelector(IHqlExpression * expr, IHqlExpression * transformed)
  7589. {
  7590. ForceLocalTransformInfo * extra = queryExtra(expr);
  7591. extra->localTransformedSelector[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())].set(transformed);
  7592. }
  7593. //---------------------------------------------------------------------------
  7594. /*
  7595. This transform is responsible for ensuring that all datasets get converted to link counted datasets. Because all records of the same type get converted it is necessary to
  7596. transform the index and table definitions - otherwise a single record would need to be transformed in multiple different ways, which would require a much more
  7597. complicated transformation. However there are some exceptions:
  7598. a) weird field dataset syntax which dates back to hole days is no transformed.
  7599. b) add a project before a build index to ensure the code is more efficient. (It will be later moved over any intervening sorts).
  7600. c) ensure input and out from a pipe is serialized (so that sizeof(inputrow) returns a sensible value)
  7601. */
  7602. static HqlTransformerInfo hqlLinkedChildRowTransformerInfo("HqlLinkedChildRowTransformer");
  7603. HqlLinkedChildRowTransformer::HqlLinkedChildRowTransformer(bool _implicitLinkedChildRows) : QuickHqlTransformer(hqlLinkedChildRowTransformerInfo, NULL)
  7604. {
  7605. implicitLinkedChildRows = _implicitLinkedChildRows;
  7606. }
  7607. IHqlExpression * HqlLinkedChildRowTransformer::ensureInputSerialized(IHqlExpression * expr)
  7608. {
  7609. LinkedHqlExpr dataset = expr->queryChild(0);
  7610. IHqlExpression * record = dataset->queryRecord();
  7611. OwnedHqlExpr serializedRecord = getSerializedForm(record, diskAtom);
  7612. //If the dataset requires serialization, it is much more efficient to serialize before the sort, than to serialize after.
  7613. if (record == serializedRecord)
  7614. return LINK(expr);
  7615. OwnedHqlExpr selSeq = createSelectorSequence();
  7616. //The expression/transform has references to the in-memory selector, but the selector provided to transform will be serialised.
  7617. //so create a mapping <unserialized> := f(serialized)
  7618. //and then use it to expand references to the unserialized format
  7619. IHqlExpression * selector = dataset->queryNormalizedSelector();
  7620. OwnedHqlExpr mapTransform = createRecordMappingTransform(no_transform, serializedRecord, selector);
  7621. OwnedHqlExpr newDataset = createDatasetF(no_newusertable, LINK(dataset), LINK(serializedRecord), LINK(mapTransform), LINK(selSeq), NULL);
  7622. NewProjectMapper2 mapper;
  7623. mapper.setMapping(mapTransform);
  7624. HqlExprArray oldArgs, expandedArgs, newArgs;
  7625. newArgs.append(*LINK(newDataset));
  7626. unwindChildren(oldArgs, expr, 1);
  7627. mapper.expandFields(expandedArgs, oldArgs, dataset, newDataset, selector);
  7628. //Finally replace any remaining selectors - so that sizeof(ds) gets mapped correctly. Obscure..... but could possibly be used in a pipe,repeat
  7629. ForEachItemIn(i, expandedArgs)
  7630. newArgs.append(*replaceSelector(&expandedArgs.item(i), selector, newDataset->queryNormalizedSelector()));
  7631. return expr->clone(newArgs);
  7632. }
  7633. IHqlExpression * HqlLinkedChildRowTransformer::transformBuildIndex(IHqlExpression * expr)
  7634. {
  7635. return ensureInputSerialized(expr);
  7636. }
  7637. IHqlExpression * HqlLinkedChildRowTransformer::transformPipeThrough(IHqlExpression * expr)
  7638. {
  7639. //serialize input to pipe through, so that if they happen to use sizeof(ds) on the input it will give the
  7640. //non serialized format. No major need to ensure output is not serialized.
  7641. return ensureInputSerialized(expr);
  7642. }
  7643. IHqlExpression * HqlLinkedChildRowTransformer::createTransformedBody(IHqlExpression * expr)
  7644. {
  7645. switch (expr->getOperator())
  7646. {
  7647. case no_field:
  7648. {
  7649. ITypeInfo * type = expr->queryType();
  7650. switch (type->getTypeCode())
  7651. {
  7652. case type_dictionary:
  7653. case type_table:
  7654. case type_groupedtable:
  7655. if (expr->hasProperty(embeddedAtom))
  7656. {
  7657. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  7658. return removeProperty(transformed, embeddedAtom);
  7659. }
  7660. if (implicitLinkedChildRows && !expr->hasProperty(_linkCounted_Atom))
  7661. {
  7662. //Don't use link counted rows for weird HOLe style dataset attributes
  7663. if (expr->hasProperty(countAtom) || expr->hasProperty(sizeofAtom))
  7664. break;
  7665. //add the attribute first so a no linked field doesn't contain a record that requires it
  7666. OwnedHqlExpr modified = appendOwnedOperand(expr, getLinkCountedAttr());
  7667. return transform(modified);
  7668. }
  7669. break;
  7670. }
  7671. break;
  7672. }
  7673. case no_buildindex:
  7674. {
  7675. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  7676. return transformBuildIndex(transformed);
  7677. }
  7678. case no_pipe:
  7679. if (expr->queryRecord())
  7680. {
  7681. return QuickHqlTransformer::createTransformedBody(expr);
  7682. }
  7683. case no_output:
  7684. //would this be a good idea for output to file? output to pipe?
  7685. if (false)
  7686. {
  7687. IHqlExpression * filename = queryRealChild(expr, 2);
  7688. if (filename)
  7689. {
  7690. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  7691. return ensureInputSerialized(transformed);
  7692. }
  7693. }
  7694. break;
  7695. }
  7696. return QuickHqlTransformer::createTransformedBody(expr);
  7697. }
  7698. //---------------------------------------------------------------------------
  7699. HqlScopeTaggerInfo::HqlScopeTaggerInfo(IHqlExpression * _expr) : MergingTransformInfo(_expr)
  7700. {
  7701. if (!onlyTransformOnce() && isIndependentOfScope(_expr))
  7702. {
  7703. //If the node doesn't have any active selectors then it isn't going to be context dependent
  7704. setOnlyTransformOnce(true);
  7705. }
  7706. }
  7707. ANewTransformInfo * HqlScopeTagger::createTransformInfo(IHqlExpression * expr)
  7708. {
  7709. return CREATE_NEWTRANSFORMINFO(HqlScopeTaggerInfo, expr);
  7710. }
  7711. /*
  7712. Details of the scope tagging.
  7713. no_select
  7714. if the lhs dataset is in scope then no flags are attached. if the lhs is not in scope, then a newAtom attribute is
  7715. attached to select node. That may contain the following attributes:
  7716. global - is an outer level activity
  7717. noTable - no other tables are active at this point e.g., global[1].field;
  7718. relatedTable - I think this could be deprecated in favour of the flag above.
  7719. Datasets
  7720. In other situations where a dataset/datarow is ambiguous whether it is new or in scope then a no_activerow
  7721. is inserted to indicate it is in scope.
  7722. Note:
  7723. new attributes aren't created for subfield e.g, myDataset.level1.level2.
  7724. This means that if (myDataset.level1) is expanded to some expression then a newAtom will be need to be created on the new select
  7725. */
  7726. static HqlTransformerInfo hqlScopeTaggerInfo("HqlScopeTagger");
  7727. HqlScopeTagger::HqlScopeTagger(IErrorReceiver * _errors)
  7728. : ScopedDependentTransformer(hqlScopeTaggerInfo), errors(_errors)
  7729. {
  7730. }
  7731. bool HqlScopeTagger::isValidNormalizeSelector(IHqlExpression * expr)
  7732. {
  7733. loop
  7734. {
  7735. switch (expr->getOperator())
  7736. {
  7737. case no_filter:
  7738. break;
  7739. case no_usertable:
  7740. if (isAggregateDataset(expr))
  7741. return false;
  7742. return true;
  7743. case no_hqlproject:
  7744. if (isCountProject(expr))
  7745. return false;
  7746. return true;
  7747. case no_select:
  7748. {
  7749. IHqlExpression * ds = expr->queryChild(0);
  7750. if (isDatasetActive(ds))
  7751. return true;
  7752. //Not really sure what the following should do. Avoid a.b.c[1].d.e
  7753. if (ds->isDatarow() && (ds->getOperator() != no_select))
  7754. return false;
  7755. break;
  7756. }
  7757. case no_table:
  7758. return (queryTableMode(expr) == no_flat);
  7759. case no_keyindex:
  7760. case no_newkeyindex:
  7761. case no_rows:
  7762. return true;
  7763. default:
  7764. return false;
  7765. }
  7766. expr = expr->queryChild(0);
  7767. }
  7768. }
  7769. static const char * getECL(IHqlExpression * expr, StringBuffer & s)
  7770. {
  7771. toUserECL(s, expr, false);
  7772. if (s.length() > 2)
  7773. s.setLength(s.length()-2);
  7774. return s.str();
  7775. }
  7776. void HqlScopeTagger::checkActiveRow(IHqlExpression * expr)
  7777. {
  7778. if (!isDatasetActive(expr))
  7779. {
  7780. StringBuffer exprText;
  7781. getECL(expr, exprText);
  7782. elideString(exprText, 20);
  7783. VStringBuffer msg("ROW(%s) - dataset argument is not in scope. Did you mean dataset[1]?", exprText.str());
  7784. reportError(msg);
  7785. }
  7786. }
  7787. void HqlScopeTagger::reportSelectorError(IHqlExpression * selector, IHqlExpression * expr)
  7788. {
  7789. ScopeInfo * scope = innerScope;
  7790. if (innerScope && innerScope->isEmpty() && scopeStack.ordinality() > 1)
  7791. scope = &scopeStack.item(scopeStack.ordinality()-2);
  7792. StringBuffer exprText, datasetName, scopeName;
  7793. StringBuffer msg;
  7794. if (scope && scope->dataset)
  7795. {
  7796. IHqlExpression * topScope = scope->dataset;
  7797. msg.appendf("%s - Table %s is not related to %s",
  7798. getECL(expr, exprText),
  7799. getExprIdentifier(datasetName, selector).str(), getExprIdentifier(scopeName, topScope).str());
  7800. }
  7801. else if (scope && scope->left)
  7802. {
  7803. msg.appendf("%s - no active row for Table %s inside transform (use LEFT?)",
  7804. getECL(expr, exprText),
  7805. getExprIdentifier(datasetName, selector).str());
  7806. }
  7807. else
  7808. {
  7809. msg.appendf("%s - no specified row for Table %s", getECL(expr, exprText),
  7810. getExprIdentifier(datasetName, selector).str());
  7811. }
  7812. reportError(msg);
  7813. }
  7814. IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
  7815. {
  7816. IHqlExpression * ds = expr->queryChild(0);
  7817. if (isDatasetActive(ds))
  7818. {
  7819. if (!innerScope && scopeStack.ordinality() == 0)
  7820. {
  7821. ds = queryDatasetCursor(ds);
  7822. switch (ds->getOperator())
  7823. {
  7824. case no_left:
  7825. case no_right:
  7826. StringBuffer exprText, datasetName;
  7827. VStringBuffer msg("%s - %s not in scope, possibly passed into a global/workflow definition", getECL(expr, exprText), getExprIdentifier(datasetName, ds).str());
  7828. reportError(msg);
  7829. break;
  7830. }
  7831. }
  7832. return Parent::createTransformed(expr); // this will call transformSelector() on lhs since new is not present
  7833. }
  7834. IHqlExpression * cursor = queryDatasetCursor(ds);
  7835. if (cursor->isDataset())
  7836. {
  7837. if (expr->isDictionary())
  7838. {
  7839. StringBuffer exprText;
  7840. VStringBuffer msg("dictionary %s must be explicitly NORMALIZED", getECL(expr, exprText));
  7841. reportError(msg, false);
  7842. }
  7843. else if (expr->isDataset())
  7844. {
  7845. if (!isValidNormalizeSelector(cursor))
  7846. {
  7847. StringBuffer exprText;
  7848. VStringBuffer msg("dataset %s may not be supported without using NORMALIZE", getECL(expr, exprText));
  7849. reportError(msg, true);
  7850. }
  7851. }
  7852. else
  7853. {
  7854. if (!isDatasetARow(ds))
  7855. reportSelectorError(ds, expr);
  7856. }
  7857. }
  7858. pushScope();
  7859. OwnedHqlExpr newDs = transformNewDataset(ds, false);
  7860. popScope();
  7861. IHqlExpression * field = expr->queryChild(1);
  7862. if (ds->isDataset())
  7863. {
  7864. if (!expr->isDataset() && !expr->isDatarow() && !expr->isDictionary())
  7865. {
  7866. //If the left is a dataset, and the right isn't a dataset or a datarow then this doesn't make sense - it is an illegal
  7867. return createSelectExpr(newDs.getClear(), LINK(field));
  7868. }
  7869. }
  7870. //MORE: What about child datasets - should really be tagged as
  7871. //if (!isNewDataset && field->isDataset() && !containsSelf(ds) && !isDatasetActive(ds)) isNew = true;
  7872. return createNewSelectExpr(newDs.getClear(), LINK(field));
  7873. }
  7874. IHqlExpression * HqlScopeTagger::transformSelectorsAttr(IHqlExpression * expr)
  7875. {
  7876. HqlExprArray args;
  7877. HqlExprArray transformedArgs;
  7878. unwindChildren(args, expr);
  7879. ForEachItemIn(i, args)
  7880. {
  7881. IHqlExpression & cur = args.item(i);
  7882. assertex(cur.getOperator() == no_select);
  7883. //Only retain selectors for datasets which are in scope.
  7884. if (isDatasetActive(cur.queryChild(0)))
  7885. transformedArgs.append(*transformSelector(&cur));
  7886. }
  7887. return expr->clone(transformedArgs);
  7888. }
  7889. IHqlExpression * HqlScopeTagger::transformNewDataset(IHqlExpression * expr, bool isActiveOk)
  7890. {
  7891. node_operator op = expr->getOperator();
  7892. switch (op)
  7893. {
  7894. case no_activerow:
  7895. {
  7896. IHqlExpression * arg0 = expr->queryChild(0);
  7897. checkActiveRow(arg0);
  7898. OwnedHqlExpr transformedArg = transformSelector(arg0);
  7899. return ensureActiveRow(transformedArg);
  7900. }
  7901. }
  7902. OwnedHqlExpr transformed = transform(expr);
  7903. switch (op)
  7904. {
  7905. //MORE: I'm still not quite sure the active tagging of rows is right to have these as exceptions...
  7906. case no_left:
  7907. case no_right:
  7908. case no_matchattr:
  7909. return transformed.getClear();
  7910. case no_select:
  7911. if (isDatasetActive(expr))
  7912. {
  7913. IHqlExpression * ds = expr->queryChild(0);
  7914. if (!isAlwaysActiveRow(ds))
  7915. {
  7916. StringBuffer exprText;
  7917. VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
  7918. reportError(msg, false);
  7919. }
  7920. }
  7921. return transformed.getClear();
  7922. }
  7923. if (isDatasetActive(expr))
  7924. {
  7925. if (!isActiveOk)
  7926. {
  7927. StringBuffer exprText;
  7928. VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
  7929. reportError(msg);
  7930. }
  7931. return ensureActiveRow(transformed->queryNormalizedSelector());
  7932. }
  7933. switch (op)
  7934. {
  7935. case no_if:
  7936. case no_chooseds:
  7937. {
  7938. HqlExprArray args;
  7939. args.append(*transform(expr->queryChild(0)));
  7940. args.append(*transformNewDataset(expr->queryChild(1), false));
  7941. ForEachChildFrom(i, expr, 2)
  7942. args.append(*transformNewDataset(expr->queryChild(i), false));
  7943. return expr->clone(args);
  7944. }
  7945. case no_addfiles:
  7946. case no_projectrow:
  7947. return transformAmbiguousChildren(expr);
  7948. case no_case:
  7949. case no_map:
  7950. throwUnexpected(); // should have been converted to no_if by now...
  7951. default:
  7952. return transformed.getClear();
  7953. }
  7954. }
  7955. IHqlExpression * HqlScopeTagger::transformAmbiguous(IHqlExpression * expr, bool isActiveOk)
  7956. {
  7957. ITypeInfo * type = expr->queryType();
  7958. type_t tc = type_void;
  7959. if (type)
  7960. tc = type->getTypeCode();
  7961. switch (tc)
  7962. {
  7963. case type_void:
  7964. return transformAmbiguousChildren(expr);
  7965. case type_table:
  7966. case type_groupedtable:
  7967. {
  7968. pushScope();
  7969. OwnedHqlExpr ret = transformNewDataset(expr, isActiveOk);
  7970. popScope();
  7971. return ret.getClear();
  7972. }
  7973. }
  7974. return transform(expr);
  7975. }
  7976. IHqlExpression * HqlScopeTagger::transformAmbiguousChildren(IHqlExpression * expr)
  7977. {
  7978. unsigned max = expr->numChildren();
  7979. if (max == 0)
  7980. return LINK(expr);
  7981. bool same = true;
  7982. HqlExprArray args;
  7983. args.ensure(max);
  7984. for(unsigned i=0; i < max; i++)
  7985. {
  7986. IHqlExpression * cur = expr->queryChild(i);
  7987. IHqlExpression * tr = transformAmbiguous(cur, false);
  7988. args.append(*tr);
  7989. if (cur != tr)
  7990. same = false;
  7991. }
  7992. if (same)
  7993. return LINK(expr);
  7994. return expr->clone(args);
  7995. }
  7996. IHqlExpression * HqlScopeTagger::transformSizeof(IHqlExpression * expr)
  7997. {
  7998. IHqlExpression * arg = expr->queryChild(0)->queryNormalizedSelector();
  7999. //Sizeof (dataset.somefield(<new>)) - convert to sizeof(record.somefield), so the argument doesn't get hoisted incorrectly, and don't get a scope error
  8000. OwnedHqlExpr newArg;
  8001. if (arg->getOperator() == no_select)
  8002. {
  8003. IHqlExpression * ds = arg->queryChild(0);
  8004. IHqlExpression * cursor = queryDatasetCursor(ds);
  8005. if (!isDatasetActive(cursor) && cursor->isDataset())
  8006. newArg.setown(createSelectExpr(LINK(ds->queryRecord()), LINK(arg->queryChild(1))));
  8007. }
  8008. if (!newArg)
  8009. newArg.setown(transformAmbiguous(arg, true));
  8010. HqlExprArray args;
  8011. args.append(*newArg.getClear());
  8012. return completeTransform(expr, args);
  8013. }
  8014. IHqlExpression * HqlScopeTagger::transformWithin(IHqlExpression * dataset, IHqlExpression * scope)
  8015. {
  8016. while (dataset->getOperator() == no_related)
  8017. dataset = dataset->queryChild(0);
  8018. if (dataset->getOperator() != no_select)
  8019. {
  8020. StringBuffer exprText;
  8021. VStringBuffer msg("%s - dataset filtered by WITHIN is too complex", getECL(dataset, exprText));
  8022. reportError(msg);
  8023. return transform(dataset);
  8024. }
  8025. IHqlExpression * ds = dataset->queryChild(0);
  8026. IHqlExpression * field = dataset->queryChild(1);
  8027. if (ds->queryNormalizedSelector() == scope)
  8028. {
  8029. OwnedHqlExpr newDs = transform(ds);
  8030. return createSelectExpr(newDs.getClear(), LINK(field));
  8031. }
  8032. OwnedHqlExpr newDs = transformWithin(ds, scope);
  8033. return createNewSelectExpr(newDs.getClear(), LINK(field));
  8034. }
  8035. IHqlExpression * HqlScopeTagger::transformRelated(IHqlExpression * expr)
  8036. {
  8037. IHqlExpression * ds = expr->queryChild(0);
  8038. IHqlExpression * scope = expr->queryChild(1);
  8039. if (!isDatasetActive(scope))
  8040. {
  8041. StringBuffer exprText;
  8042. VStringBuffer msg("dataset \"%s\" used in WITHIN is not in scope", getECL(scope, exprText));
  8043. reportError(msg);
  8044. }
  8045. //Check the ds is a table
  8046. IHqlDataset * scopeDs = scope->queryDataset();
  8047. if (scopeDs != scopeDs->queryTable())
  8048. {
  8049. StringBuffer exprText;
  8050. VStringBuffer msg("dataset \"%s\" used as parameter to WITHIN is too complex", getECL(expr, exprText));
  8051. reportError(msg);
  8052. }
  8053. return transformWithin(ds, scope->queryNormalizedSelector());
  8054. }
  8055. IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
  8056. {
  8057. IHqlExpression * body = expr->queryBody(true);
  8058. if (expr != body)
  8059. {
  8060. switch (expr->getAnnotationKind())
  8061. {
  8062. case annotate_meta:
  8063. collector.processMetaAnnotation(expr);
  8064. break;
  8065. case annotate_symbol:
  8066. {
  8067. WarningProcessor::OnWarningState saved;
  8068. collector.pushSymbol(saved, expr);
  8069. OwnedHqlExpr transformedBody = transform(body);
  8070. collector.popSymbol(saved);
  8071. if (body == transformedBody)
  8072. return LINK(expr);
  8073. return expr->cloneAnnotation(transformedBody);
  8074. }
  8075. break;
  8076. case annotate_location:
  8077. {
  8078. break;
  8079. }
  8080. }
  8081. OwnedHqlExpr transformedBody = transform(body);
  8082. if (body == transformedBody)
  8083. return LINK(expr);
  8084. return expr->cloneAnnotation(transformedBody);
  8085. }
  8086. collector.checkForGlobalOnWarning(expr);
  8087. switch (expr->getOperator())
  8088. {
  8089. case no_left:
  8090. case no_right:
  8091. case no_self:
  8092. case no_top:
  8093. return LINK(expr);
  8094. case no_activerow:
  8095. checkActiveRow(expr->queryChild(0));
  8096. break;
  8097. case no_select:
  8098. return transformSelect(expr);
  8099. case no_call:
  8100. case no_externalcall:
  8101. case no_rowvalue:
  8102. // case no_addfiles:
  8103. // case no_libraryscopeinstance:??
  8104. return transformAmbiguousChildren(expr);
  8105. case no_offsetof:
  8106. case no_sizeof:
  8107. return transformSizeof(expr);
  8108. case no_attr_expr:
  8109. if (expr->queryName() == _selectors_Atom)
  8110. return transformSelectorsAttr(expr);
  8111. return transformAmbiguousChildren(expr);
  8112. case no_datasetfromrow:
  8113. {
  8114. IHqlExpression * ds = expr->queryChild(0);
  8115. if (ds->isDataset() && !isDatasetActive(ds))
  8116. {
  8117. StringBuffer exprText;
  8118. VStringBuffer msg("dataset %s mistakenly interpreted as a datarow, possibly due to missing dataset() in parameter type", getECL(ds, exprText));
  8119. reportError(msg);
  8120. }
  8121. return transformAmbiguousChildren(expr);
  8122. }
  8123. case no_temptable:
  8124. if (expr->queryChild(0)->isDatarow())
  8125. return transformAmbiguousChildren(expr);
  8126. break;
  8127. case no_related:
  8128. return transformRelated(expr);
  8129. case no_eq:
  8130. case no_ne:
  8131. case no_lt:
  8132. case no_le:
  8133. case no_gt:
  8134. case no_ge:
  8135. case no_order:
  8136. //MORE: Should check this doesn't make the comparison invalid.
  8137. return transformAmbiguousChildren(expr);
  8138. case no_assign:
  8139. {
  8140. IHqlExpression * lhs = expr->queryChild(0);
  8141. IHqlExpression * rhs = expr->queryChild(1);
  8142. OwnedHqlExpr newRhs = transformAmbiguous(rhs, false);
  8143. if (lhs->isDatarow() && newRhs->isDataset())
  8144. {
  8145. StringBuffer exprText;
  8146. VStringBuffer msg("dataset expression (%s) assigned to field '%s' with type row", getECL(rhs, exprText), lhs->queryChild(1)->queryName()->str());
  8147. reportError(msg.str());
  8148. }
  8149. if (rhs == newRhs)
  8150. return LINK(expr);
  8151. HqlExprArray children;
  8152. children.append(*LINK(expr->queryChild(0)));
  8153. children.append(*newRhs.getClear());
  8154. return completeTransform(expr, children);
  8155. }
  8156. break;
  8157. case no_evaluate:
  8158. throwUnexpected();
  8159. case no_projectrow:
  8160. {
  8161. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  8162. if (transformed->queryChild(0)->isDataset())
  8163. reportError("PROJECT() row argument resolved to a dataset. Missing DATASET() from parameter type?");
  8164. return transformed.getClear();
  8165. }
  8166. case no_merge:
  8167. {
  8168. HqlExprArray children;
  8169. transformChildren(expr, children);
  8170. IHqlExpression * sorted = queryProperty(sortedAtom, children);
  8171. if (!sorted || queryProperty(_implicitSorted_Atom, children))
  8172. {
  8173. IHqlExpression * dataset = &children.item(0);
  8174. removeProperty(children, _implicitSorted_Atom);
  8175. if (sorted)
  8176. children.zap(*sorted);
  8177. HqlExprArray sorts;
  8178. OwnedHqlExpr order = getExistingSortOrder(dataset, expr->hasProperty(localAtom), true);
  8179. if (order)
  8180. unwindChildren(sorts, order);
  8181. ForEachItemInRev(i, sorts)
  8182. {
  8183. if (sorts.item(i).isAttribute())
  8184. {
  8185. reportError(HQLWRN_MergeBadSortOrder_Text, true);
  8186. sorts.remove(i);
  8187. }
  8188. }
  8189. children.append(*createExprAttribute(sortedAtom, sorts));
  8190. }
  8191. return expr->clone(children);
  8192. }
  8193. }
  8194. return Parent::createTransformed(expr);
  8195. }
  8196. void HqlScopeTagger::reportWarnings()
  8197. {
  8198. if (errors)
  8199. collector.report(*errors);
  8200. }
  8201. void HqlScopeTagger::reportError(const char * msg, bool warning)
  8202. {
  8203. IHqlExpression * location = collector.queryActiveSymbol();
  8204. //Make this an error when we are confident...
  8205. int startLine= location ? location->getStartLine() : 0;
  8206. int startColumn = location ? location->getStartColumn() : 0;
  8207. ISourcePath * sourcePath = location ? location->querySourcePath() : NULL;
  8208. Owned<IECLError> err = createECLError(!warning, ERR_ASSERT_WRONGSCOPING, msg, sourcePath->str(), startLine, startColumn, 0);
  8209. collector.report(NULL, errors, err); // will throw immediately if it is an error.
  8210. }
  8211. //---------------------------------------------------------------------------------------------------------------------
  8212. SharedTableInfo * ImplicitAliasTransformInfo::uses(IHqlExpression * tableBody) const
  8213. {
  8214. ForEachItemIn(i, sharedTables)
  8215. {
  8216. SharedTableInfo & cur = sharedTables.item(i);
  8217. if (cur.dataset == tableBody)
  8218. return &cur;
  8219. }
  8220. return NULL;
  8221. }
  8222. void ImplicitAliasTransformInfo::add(SharedTableInfo * table)
  8223. {
  8224. sharedTables.append(*LINK(table));
  8225. }
  8226. void ImplicitAliasTransformInfo::addAmbiguity(SharedTableInfo * table)
  8227. {
  8228. containsAmbiguity = true;
  8229. merge(table);
  8230. }
  8231. void ImplicitAliasTransformInfo::merge(SharedTableInfo * table)
  8232. {
  8233. ForEachItemIn(i, sharedTables)
  8234. {
  8235. SharedTableInfo & cur = sharedTables.item(i);
  8236. if (cur.dataset == table->dataset)
  8237. {
  8238. if (cur.depth < table->depth)
  8239. sharedTables.replace(*LINK(table), i);
  8240. return;
  8241. }
  8242. }
  8243. add(table);
  8244. }
  8245. void ImplicitAliasTransformInfo::inherit(const ImplicitAliasTransformInfo * other)
  8246. {
  8247. ForEachItemIn(i, other->sharedTables)
  8248. merge(&other->sharedTables.item(i));
  8249. }
  8250. static HqlTransformerInfo implicitAliasTransformerInfo("ImplicitAliasTransformer");
  8251. ImplicitAliasTransformer::ImplicitAliasTransformer() : NewHqlTransformer(implicitAliasTransformerInfo)
  8252. {
  8253. seenShared = true;
  8254. seenAmbiguity = false;
  8255. }
  8256. void ImplicitAliasTransformer::analyseExpr(IHqlExpression * _expr)
  8257. {
  8258. IHqlExpression * body = _expr->queryBody();
  8259. if (alreadyVisited(body))
  8260. {
  8261. if ((pass == 0) && body->isDataset())
  8262. {
  8263. switch (body->getOperator())
  8264. {
  8265. case no_rows:
  8266. break;
  8267. default:
  8268. seenShared = true;
  8269. queryExtra(body)->shared.setown(new SharedTableInfo(body, 0));
  8270. break;
  8271. }
  8272. }
  8273. return;
  8274. }
  8275. NewHqlTransformer::analyseExpr(body);
  8276. if (pass == 0)
  8277. return;
  8278. ImplicitAliasTransformInfo * extra = queryExtra(body);
  8279. if (extra->shared)
  8280. extra->add(extra->shared);
  8281. switch (body->getOperator())
  8282. {
  8283. case no_activerow:
  8284. case no_filepos:
  8285. case no_file_logicalname:
  8286. case no_offsetof:
  8287. case no_joined:
  8288. case no_colon:
  8289. case no_globalscope:
  8290. case no_attr:
  8291. return;
  8292. case no_select:
  8293. {
  8294. bool isNew;
  8295. IHqlExpression * ds = querySelectorDataset(body, isNew);
  8296. if (isNew)
  8297. {
  8298. ImplicitAliasTransformInfo * dsExtra = queryExtra(ds->queryBody());
  8299. extra->inherit(dsExtra);
  8300. }
  8301. return;
  8302. }
  8303. }
  8304. IHqlExpression * dataset = NULL;
  8305. switch (getChildDatasetType(body))
  8306. {
  8307. case childdataset_none:
  8308. case childdataset_many_noscope:
  8309. case childdataset_many:
  8310. case childdataset_map:
  8311. case childdataset_dataset_noscope:
  8312. case childdataset_if:
  8313. case childdataset_case:
  8314. case childdataset_evaluate:
  8315. case childdataset_left:
  8316. case childdataset_leftright:
  8317. case childdataset_same_left_right:
  8318. case childdataset_nway_left_right:
  8319. break;
  8320. case childdataset_dataset:
  8321. case childdataset_datasetleft:
  8322. case childdataset_top_left_right:
  8323. dataset = body->queryChild(0)->queryBody();
  8324. break;
  8325. default:
  8326. UNIMPLEMENTED;
  8327. }
  8328. ForEachChild(i, body)
  8329. {
  8330. IHqlExpression * cur = body->queryChild(i);
  8331. ImplicitAliasTransformInfo * childExtra = queryExtra(cur->queryBody());
  8332. //If this is one of the arguments to an operation which has an active top dataset,
  8333. //check to see if any of the contained expressions reference this item
  8334. if (dataset && (i != 0))
  8335. {
  8336. SharedTableInfo * match = childExtra->uses(dataset);
  8337. if (match)
  8338. {
  8339. seenAmbiguity = true;
  8340. SharedTableInfo * nested = createAmbiguityInfo(match->dataset, match->depth+1);
  8341. extra->addAmbiguity(nested);
  8342. }
  8343. // dbglogExpr(_expr);
  8344. // DBGLOG("Implicit nested table ambiguity spotted in expression");
  8345. }
  8346. extra->inherit(childExtra);
  8347. }
  8348. }
  8349. SharedTableInfo * ImplicitAliasTransformer::createAmbiguityInfo(IHqlExpression * dataset, unsigned depth)
  8350. {
  8351. ForEachItemIn(i, ambiguousTables)
  8352. {
  8353. SharedTableInfo & cur = ambiguousTables.item(i);
  8354. if ((cur.dataset == dataset) && (depth == cur.depth))
  8355. return &cur;
  8356. }
  8357. ambiguousTables.append(*new SharedTableInfo(dataset, depth));
  8358. return &ambiguousTables.tos();
  8359. }
  8360. ANewTransformInfo * ImplicitAliasTransformer::createTransformInfo(IHqlExpression * expr)
  8361. {
  8362. return CREATE_NEWTRANSFORMINFO(ImplicitAliasTransformInfo, expr);
  8363. }
  8364. IHqlExpression * ImplicitAliasTransformer::createTransformed(IHqlExpression * expr)
  8365. {
  8366. IHqlExpression * body = expr->queryBody();
  8367. if (expr != body)
  8368. {
  8369. OwnedHqlExpr newBody = transform(body);
  8370. return expr->cloneAllAnnotations(newBody);
  8371. }
  8372. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  8373. updateOrphanedSelectors(transformed, expr);
  8374. ImplicitAliasTransformInfo * extra = queryExtra(body);
  8375. if (!extra->containsAmbiguity)
  8376. return transformed.getClear();
  8377. SharedTableInfo * match = extra->uses(body->queryChild(0)->queryBody());
  8378. assertex(match && match->depth != 0);
  8379. if (!match->uid)
  8380. match->uid.setown(createUniqueId());
  8381. OwnedHqlExpr aliased;
  8382. IHqlExpression * dataset = transformed->queryChild(0)->queryBody();
  8383. IHqlExpression * uid = match->uid;
  8384. aliased.setown(createDataset(no_dataset_alias, LINK(dataset), LINK(uid)));
  8385. //Replace dataset with an aliased variety, and remap all the selectors
  8386. HqlExprArray args;
  8387. args.append(*LINK(aliased));
  8388. replaceSelectors(args, transformed, 1, dataset->queryNormalizedSelector(), aliased->queryNormalizedSelector());
  8389. return transformed->clone(args);
  8390. }
  8391. void ImplicitAliasTransformer::process(HqlExprArray & exprs)
  8392. {
  8393. analyseArray(exprs, 0);
  8394. if (!seenShared)
  8395. return;
  8396. analyseArray(exprs, 1);
  8397. if (hasAmbiguity())
  8398. {
  8399. // DBGLOG("Implicit nested dataset ambiguity spotted in expression");
  8400. HqlExprArray transformed;
  8401. transformRoot(exprs, transformed);
  8402. replaceArray(exprs, transformed);
  8403. }
  8404. }
  8405. //---------------------------------------------------------------------------------------------------------------------
  8406. SharedTableInfo * LeftRightTransformInfo::uses(IHqlExpression * tableBody) const
  8407. {
  8408. ForEachItemIn(i, sharedTables)
  8409. {
  8410. SharedTableInfo & cur = sharedTables.item(i);
  8411. if (cur.dataset == tableBody)
  8412. return &cur;
  8413. }
  8414. return NULL;
  8415. }
  8416. void LeftRightTransformInfo::add(SharedTableInfo * table)
  8417. {
  8418. sharedTables.append(*LINK(table));
  8419. }
  8420. bool LeftRightTransformInfo::noteUsed(IHqlExpression * seq)
  8421. {
  8422. if (!seqs.contains(*seq))
  8423. seqs.append(*seq);
  8424. if (seqs.ordinality() > 1)
  8425. {
  8426. shared.setown(new SharedTableInfo(original, 0));
  8427. return true;
  8428. }
  8429. return false;
  8430. }
  8431. void LeftRightTransformInfo::addAmbiguity(SharedTableInfo * table)
  8432. {
  8433. containsAmbiguity = true;
  8434. merge(table);
  8435. }
  8436. void LeftRightTransformInfo::merge(SharedTableInfo * table)
  8437. {
  8438. ForEachItemIn(i, sharedTables)
  8439. {
  8440. SharedTableInfo & cur = sharedTables.item(i);
  8441. if (cur.dataset == table->dataset)
  8442. {
  8443. if (cur.depth < table->depth)
  8444. sharedTables.replace(*LINK(table), i);
  8445. return;
  8446. }
  8447. }
  8448. add(table);
  8449. }
  8450. void LeftRightTransformInfo::inherit(const LeftRightTransformInfo * other)
  8451. {
  8452. ForEachItemIn(i, other->sharedTables)
  8453. merge(&other->sharedTables.item(i));
  8454. }
  8455. static HqlTransformerInfo LeftRightTransformerInfo("LeftRightTransformer");
  8456. LeftRightTransformer::LeftRightTransformer() : NewHqlTransformer(LeftRightTransformerInfo)
  8457. {
  8458. seenShared = true;
  8459. }
  8460. void LeftRightTransformer::analyseExpr(IHqlExpression * _expr)
  8461. {
  8462. IHqlExpression * body = _expr->queryBody();
  8463. if (alreadyVisited(body))
  8464. return;
  8465. NewHqlTransformer::analyseExpr(body);
  8466. if (pass == 0)
  8467. {
  8468. //First pass gathers a list of selectors that are potentially ambiguous if the sequence was removed
  8469. IHqlExpression * left = NULL;
  8470. IHqlExpression * right = NULL;
  8471. switch (getChildDatasetType(body))
  8472. {
  8473. case childdataset_left:
  8474. case childdataset_datasetleft:
  8475. left = body->queryChild(0);
  8476. break;
  8477. case childdataset_same_left_right:
  8478. case childdataset_nway_left_right:
  8479. case childdataset_top_left_right:
  8480. left = body->queryChild(0);
  8481. right = body->queryChild(0);
  8482. break;
  8483. case childdataset_leftright:
  8484. left = body->queryChild(0);
  8485. right = body->queryChild(1);
  8486. break;
  8487. }
  8488. if (left)
  8489. {
  8490. LeftRightTransformInfo * extra = queryExtra(body);
  8491. IHqlExpression * selSeq = querySelSeq(body);
  8492. OwnedHqlExpr seq = createDummySelectorSequence();
  8493. extra->rawLeft.setown(createSelector(no_left, left, seq));
  8494. incUsage(extra->rawLeft, selSeq);
  8495. if (right)
  8496. {
  8497. //no_left is used deliberately in the following to avoid complications where right matches
  8498. //but left doesn't, causing the depths to be messed up.
  8499. extra->rawRight.setown(createSelector(no_left, right, seq));
  8500. if (extra->rawLeft != extra->rawRight)
  8501. incUsage(extra->rawRight, selSeq);
  8502. else
  8503. extra->rawRight.clear();
  8504. }
  8505. }
  8506. }
  8507. else
  8508. {
  8509. //Second pass - for each expression, gather a list of selectors that would actually be ambiguous.
  8510. LeftRightTransformInfo * extra = queryExtra(body);
  8511. IHqlExpression * rawLeft = extra->rawLeft;
  8512. IHqlExpression * rawRight = extra->rawRight;
  8513. //If LEFT is potentially ambiguous, then add it to the list of selectors used by this expression
  8514. if (rawLeft)
  8515. {
  8516. LeftRightTransformInfo * leftExtra = queryExtra(rawLeft);
  8517. if (leftExtra->shared)
  8518. extra->add(leftExtra->shared);
  8519. }
  8520. //Ditto for right
  8521. if (rawRight)
  8522. {
  8523. LeftRightTransformInfo * rightExtra = queryExtra(rawRight);
  8524. if (rightExtra->shared)
  8525. extra->add(rightExtra->shared);
  8526. }
  8527. switch (body->getOperator())
  8528. {
  8529. case no_activerow:
  8530. case no_filepos:
  8531. case no_file_logicalname:
  8532. case no_offsetof:
  8533. case no_joined:
  8534. case no_colon:
  8535. case no_globalscope:
  8536. case no_attr:
  8537. return;
  8538. case no_select:
  8539. {
  8540. bool isNew;
  8541. IHqlExpression * ds = querySelectorDataset(body, isNew);
  8542. if (isNew)
  8543. {
  8544. LeftRightTransformInfo * dsExtra = queryExtra(ds->queryBody());
  8545. extra->inherit(dsExtra);
  8546. }
  8547. return;
  8548. }
  8549. }
  8550. ForEachChild(i, body)
  8551. {
  8552. IHqlExpression * cur = body->queryChild(i);
  8553. LeftRightTransformInfo * childExtra = queryExtra(cur->queryBody());
  8554. //If this is one of the arguments to an operation which has an active top dataset,
  8555. //check to see if any of the contained expressions reference this item
  8556. if ((i != 0) && rawLeft)
  8557. {
  8558. SharedTableInfo * matchLeft = childExtra->uses(rawLeft);
  8559. SharedTableInfo * matchRight = rawRight ? childExtra->uses(rawRight) : NULL;
  8560. if (matchLeft || matchRight)
  8561. {
  8562. unsigned leftDepth = matchLeft ? matchLeft->depth : 0;
  8563. unsigned rightDepth = matchRight ? matchRight->depth : 0;
  8564. unsigned depth = leftDepth > rightDepth ? leftDepth : rightDepth;
  8565. SharedTableInfo * nested = createAmbiguityInfo(rawLeft, depth+1);
  8566. extra->addAmbiguity(nested);
  8567. if (rawRight)
  8568. {
  8569. SharedTableInfo * nested = createAmbiguityInfo(rawRight, depth+1);
  8570. extra->addAmbiguity(nested);
  8571. }
  8572. }
  8573. }
  8574. extra->inherit(childExtra);
  8575. }
  8576. }
  8577. }
  8578. void LeftRightTransformer::incUsage(IHqlExpression * expr, IHqlExpression * seq)
  8579. {
  8580. //MORE: Needs to keep track of the sequences that were used with it, so know if needs disambiguating.
  8581. LeftRightTransformInfo * extra = queryExtra(expr);
  8582. if (extra->noteUsed(seq))
  8583. seenShared = true;
  8584. }
  8585. SharedTableInfo * LeftRightTransformer::createAmbiguityInfo(IHqlExpression * dataset, unsigned depth)
  8586. {
  8587. ForEachItemIn(i, ambiguousTables)
  8588. {
  8589. SharedTableInfo & cur = ambiguousTables.item(i);
  8590. if ((cur.dataset == dataset) && (depth == cur.depth))
  8591. return &cur;
  8592. }
  8593. ambiguousTables.append(*new SharedTableInfo(dataset, depth));
  8594. return &ambiguousTables.tos();
  8595. }
  8596. ANewTransformInfo * LeftRightTransformer::createTransformInfo(IHqlExpression * expr)
  8597. {
  8598. return CREATE_NEWTRANSFORMINFO(LeftRightTransformInfo, expr);
  8599. }
  8600. IHqlExpression * LeftRightTransformer::createTransformed(IHqlExpression * expr)
  8601. {
  8602. IHqlExpression * body = expr->queryBody();
  8603. if (expr != body)
  8604. {
  8605. OwnedHqlExpr newBody = transform(body);
  8606. return expr->cloneAllAnnotations(newBody);
  8607. }
  8608. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  8609. updateOrphanedSelectors(transformed, expr);
  8610. LeftRightTransformInfo * extra = queryExtra(body);
  8611. SharedTableInfo * matchLeft = extra->rawLeft ? extra->uses(extra->rawLeft) : NULL;
  8612. if (matchLeft)
  8613. {
  8614. childDatasetType dsType = getChildDatasetType(expr);
  8615. IHqlExpression * left = transformed->queryChild(0);
  8616. IHqlExpression * right = hasRight(dsType) ? (hasSameLeftRight(dsType) ? left : transformed->queryChild(1)) : NULL;
  8617. IHqlExpression * oldSelSeq = querySelSeq(expr);
  8618. OwnedHqlExpr newSelSeq = createSelectorSequence(matchLeft->depth);
  8619. OwnedHqlExpr oldLeft = createSelector(no_left, left, oldSelSeq);
  8620. OwnedHqlExpr newLeft = createSelector(no_left, left, newSelSeq);
  8621. //Replace dataset with an aliased variety, and remap all the selectors
  8622. HqlExprArray mapped;
  8623. replaceSelectors(mapped, transformed, 1, oldLeft, newLeft);
  8624. if (right)
  8625. {
  8626. OwnedHqlExpr oldRight = createSelector(no_right, right, oldSelSeq);
  8627. OwnedHqlExpr newRight = createSelector(no_right, right, newSelSeq);
  8628. unsigned firstArg = (hasSameLeftRight(dsType) ? 0 : 1);
  8629. replaceSelectors(mapped, firstArg, oldRight, newRight);
  8630. }
  8631. HqlExprArray args;
  8632. args.append(*LINK(left));
  8633. appendArray(args, mapped);
  8634. args.zap(*oldSelSeq);
  8635. args.append(*LINK(newSelSeq));
  8636. transformed.setown(transformed->clone(args));
  8637. }
  8638. return transformed.getClear();
  8639. }
  8640. void LeftRightTransformer::process(HqlExprArray & exprs)
  8641. {
  8642. analyseArray(exprs, 0);
  8643. if (!seenShared)
  8644. return;
  8645. analyseArray(exprs, 1);
  8646. HqlExprArray transformed;
  8647. transformRoot(exprs, transformed);
  8648. replaceArray(exprs, transformed);
  8649. }
  8650. //---------------------------------------------------------------------------------------------------------------------
  8651. /*
  8652. Common up expressions so that all references to the same expression have identical symbols, annotations.
  8653. Generally it improves the code a lot - especially when macros are used. However there are occasional problems....
  8654. a) ut.CleanCompany(ds.x) and ut.cleanCompany(left.x).
  8655. If a component one of them is commoned up with another occurrence, then you can get different named symbols within the expanded function. When we
  8656. then test to see if something is sorted it can incorrectly mismatch (see busheader.xhql dnb_combined_append)
  8657. */
  8658. static void unwindAnnotations(HqlExprCopyArray & unwound, IHqlExpression * expr)
  8659. {
  8660. if (expr->getAnnotationKind() == annotate_none)
  8661. return;
  8662. unwindAnnotations(unwound, expr->queryBody(true));
  8663. unwound.append(*expr);
  8664. }
  8665. IHqlExpression * AnnotationTransformInfo::cloneAnnotations(IHqlExpression * newBody)
  8666. {
  8667. if (annotations.ordinality() == 0)
  8668. return LINK(newBody);
  8669. return annotations.item(0).cloneAllAnnotations(newBody);
  8670. LinkedHqlExpr ret = newBody;
  8671. #if 1
  8672. ForEachItemIn(i, annotations)
  8673. ret.setown(annotations.item(i).cloneAllAnnotations(ret));
  8674. #else
  8675. //Code saved once we start removing duplicate annotations (e.g., locations)
  8676. HqlExprCopyArray toApply;
  8677. ForEachItemIn(i, annotations)
  8678. unwindAnnotations(toApply, &annotations.item(i));
  8679. ForEachItemIn(i2, toApply)
  8680. {
  8681. IHqlExpression & curAnnotate = toApply.item(i2);
  8682. ret.setown(curAnnotate.cloneAnnotation(ret));
  8683. }
  8684. #endif
  8685. return ret.getClear();
  8686. }
  8687. void AnnotationTransformInfo::noteAnnotation(IHqlExpression * annotation)
  8688. {
  8689. //MORE: Need more intelligence to see if this is a subset of what we already have..
  8690. annotations.append(*annotation);
  8691. }
  8692. static HqlTransformerInfo annotationNormalizerInfo("AnnotationNormalizerTransformer");
  8693. AnnotationNormalizerTransformer::AnnotationNormalizerTransformer()
  8694. : NewHqlTransformer(annotationNormalizerInfo)
  8695. {
  8696. }
  8697. ANewTransformInfo * AnnotationNormalizerTransformer::createTransformInfo(IHqlExpression * expr)
  8698. {
  8699. return CREATE_NEWTRANSFORMINFO(AnnotationTransformInfo, expr);
  8700. }
  8701. void AnnotationNormalizerTransformer::analyseExpr(IHqlExpression * expr)
  8702. {
  8703. if (alreadyVisited(expr))
  8704. return;
  8705. IHqlExpression * body = expr->queryBody();
  8706. if (expr != body)
  8707. {
  8708. queryLocationIndependentExtra(body)->noteAnnotation(expr);
  8709. //Note: expr already tested if expr == body...
  8710. if (alreadyVisited(body))
  8711. return;
  8712. }
  8713. node_operator op = body->getOperator();
  8714. switch (op)
  8715. {
  8716. case no_attr_expr:
  8717. analyseChildren(body);
  8718. return;
  8719. }
  8720. NewHqlTransformer::analyseExpr(body);
  8721. }
  8722. IHqlExpression * AnnotationNormalizerTransformer::createTransformed(IHqlExpression * expr)
  8723. {
  8724. node_operator op = expr->getOperator();
  8725. IHqlExpression * body = expr->queryBody();
  8726. switch (op)
  8727. {
  8728. case no_list:
  8729. {
  8730. if (body->numChildren() == 0)
  8731. return LINK(body);
  8732. break;
  8733. }
  8734. case no_constant:
  8735. // case no_null:
  8736. {
  8737. //AnnotationTransformInfo * extra = queryLocationIndependentExtra(body);
  8738. //Don't common up the location information for this, otherwise it gets silly! Possibly worth removing altogether if ambiguous?
  8739. //MORE: This should probably depend on whether there is more than one annotation on the constant.
  8740. return LINK(body);
  8741. }
  8742. }
  8743. if (expr != body)
  8744. return transform(body);
  8745. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  8746. return queryLocationIndependentExtra(body)->cloneAnnotations(transformed);
  8747. }
  8748. AnnotationTransformInfo * AnnotationNormalizerTransformer::queryLocationIndependentExtra(IHqlExpression * expr)
  8749. {
  8750. return static_cast<AnnotationTransformInfo *>(queryTransformExtra(queryLocationIndependent(expr)));
  8751. }
  8752. void normalizeAnnotations(HqlCppTranslator & translator, HqlExprArray & exprs)
  8753. {
  8754. //First iterate through the expressions and call queryLocationIndependent() to avoid nested transforms (which are less efficient)
  8755. ForEachItemIn(iInit, exprs)
  8756. queryLocationIndependent(&exprs.item(iInit));
  8757. translator.traceExpressions("before annotation normalize", exprs);
  8758. unsigned time = msTick();
  8759. AnnotationNormalizerTransformer normalizer;
  8760. HqlExprArray transformed;
  8761. normalizer.analyseArray(exprs, 0);
  8762. normalizer.transformRoot(exprs, transformed);
  8763. replaceArray(exprs, transformed);
  8764. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.annotations", msTick()-time);
  8765. }
  8766. void normalizeAnnotations(HqlCppTranslator & translator, WorkflowArray & workflow)
  8767. {
  8768. ForEachItemIn(i, workflow)
  8769. normalizeAnnotations(translator, workflow.item(i).queryExprs());
  8770. }
  8771. //---------------------------------------------------------------------------
  8772. static HqlTransformerInfo containsCompoundTransformerInfo("ContainsCompoundTransformer");
  8773. ContainsCompoundTransformer::ContainsCompoundTransformer()
  8774. : QuickHqlTransformer(containsCompoundTransformerInfo, NULL)
  8775. {
  8776. containsCompound = false;
  8777. }
  8778. //NB: This cannot be short circuited, because it is also gathering information about whether or
  8779. void ContainsCompoundTransformer::doAnalyseBody(IHqlExpression * expr)
  8780. {
  8781. if (containsCompound)
  8782. return;
  8783. switch (expr->getOperator())
  8784. {
  8785. case no_compound:
  8786. if (!expr->isAction())
  8787. {
  8788. containsCompound = true;
  8789. return;
  8790. }
  8791. break;
  8792. case no_colon:
  8793. case no_cluster:
  8794. case no_sequential:
  8795. case no_allnodes:
  8796. case no_thisnode:
  8797. //Need to recursively handle these
  8798. containsCompound = true;
  8799. return;
  8800. case no_record:
  8801. case no_field:
  8802. case no_attr:
  8803. case no_attr_link:
  8804. case no_left:
  8805. case no_right:
  8806. case no_self:
  8807. case no_top:
  8808. case no_workunit_dataset:
  8809. case no_assertwild:
  8810. case no_getresult:
  8811. case no_getgraphresult:
  8812. case no_activerow:
  8813. case no_newkeyindex:
  8814. return;
  8815. case no_list:
  8816. if (expr->isConstant())
  8817. return;
  8818. break;
  8819. case no_select:
  8820. // if (expr->hasProperty(newAtom))
  8821. analyse(expr->queryChild(0));
  8822. return;
  8823. case no_assign:
  8824. analyse(expr->queryChild(1));
  8825. return;
  8826. }
  8827. QuickHqlTransformer::doAnalyseBody(expr);
  8828. }
  8829. bool containsCompound(const HqlExprArray & exprs)
  8830. {
  8831. ContainsCompoundTransformer spotter;
  8832. spotter.analyseArray(exprs);
  8833. return spotter.containsCompound;
  8834. }
  8835. bool containsCompound(IHqlExpression * expr)
  8836. {
  8837. ContainsCompoundTransformer spotter;
  8838. spotter.analyse(expr);
  8839. return spotter.containsCompound;
  8840. }
  8841. static HqlTransformerInfo nestedCompoundTransformerInfo("NestedCompoundTransformer");
  8842. NestedCompoundTransformer::NestedCompoundTransformer(HqlCppTranslator & _translator)
  8843. : HoistingHqlTransformer(nestedCompoundTransformerInfo, CTFnoteifactions), translator(_translator), translatorOptions(_translator.queryOptions())
  8844. {
  8845. }
  8846. //For the moment allow simple external calls in scalar setting
  8847. //to make logging much easier...
  8848. static bool isSimpleSideeffect(IHqlExpression * expr)
  8849. {
  8850. switch (expr->getOperator())
  8851. {
  8852. case no_externalcall:
  8853. case no_attr:
  8854. case no_attr_expr:
  8855. case no_attr_link:
  8856. return true;
  8857. case no_comma:
  8858. case no_compound:
  8859. case no_parallel:
  8860. {
  8861. ForEachChild(i, expr)
  8862. {
  8863. if (!isSimpleSideeffect(expr->queryChild(i)))
  8864. return false;
  8865. }
  8866. return true;
  8867. }
  8868. case no_if:
  8869. {
  8870. ForEachChildFrom(i, expr, 1)
  8871. {
  8872. if (!isSimpleSideeffect(expr->queryChild(i)))
  8873. return false;
  8874. }
  8875. return true;
  8876. }
  8877. }
  8878. return false;
  8879. }
  8880. static bool isCalloutSideeffect(IHqlExpression * expr)
  8881. {
  8882. if (!expr->queryType()->isScalar())
  8883. return false;
  8884. return isSimpleSideeffect(expr->queryChild(0));
  8885. }
  8886. IHqlExpression * NestedCompoundTransformer::createTransformed(IHqlExpression * expr)
  8887. {
  8888. if (expr->isConstant())
  8889. return LINK(expr);
  8890. IHqlExpression * ret = queryTransformAnnotation(expr);
  8891. if (ret)
  8892. return ret;
  8893. node_operator op = expr->getOperator();
  8894. switch (op)
  8895. {
  8896. case no_compound:
  8897. if (isUsedUnconditionally(expr) && !expr->isAction() && !isCalloutSideeffect(expr))
  8898. {
  8899. IHqlExpression * sideEffect = expr->queryChild(0);
  8900. IHqlExpression * value = expr->queryChild(1);
  8901. if (!isIndependentOfScope(sideEffect))
  8902. {
  8903. StringBuffer s;
  8904. if (sideEffect->queryName())
  8905. s.appendf(" '%s'", sideEffect->queryName()->str());
  8906. else if (value->queryName())
  8907. s.appendf(" '%s'", value->queryName()->str());
  8908. else
  8909. s.append(" ").append(getOpString(sideEffect->getOperator()));
  8910. IHqlExpression * location = queryLocation(sideEffect);
  8911. if (!location)
  8912. location = queryLocation(value);
  8913. if (!location)
  8914. location = queryActiveLocation();
  8915. if (!isSimpleSideeffect(sideEffect))
  8916. {
  8917. //MORE: This should be an error, but there are still occasional false positives e.g., OUTPUT(ds1.childds)
  8918. //so needs to stay a warning.
  8919. // translator.ERRORAT1(location, HQLERR_GlobalSideEffectDependent, s.str());
  8920. translator.WARNINGAT1(location, HQLWRN_GlobalSideEffectDependent, s.str());
  8921. }
  8922. break;
  8923. }
  8924. if (!translatorOptions.workunitTemporaries)
  8925. {
  8926. StringBuffer s;
  8927. if (expr->queryName())
  8928. s.append(expr->queryName()).append(": ");
  8929. getExprECL(sideEffect, s);
  8930. throwError1(HQLERR_LibrariesCannotContainSideEffects, s.str());
  8931. }
  8932. appendToTarget(*transform(sideEffect));
  8933. return transform(value);
  8934. }
  8935. break;
  8936. }
  8937. return HoistingHqlTransformer::createTransformed(expr);
  8938. }
  8939. //---------------------------------------------------------------------------
  8940. class LocationInfo : public CInterface
  8941. {
  8942. public:
  8943. HqlExprArray matches;
  8944. };
  8945. static HqlTransformerInfo duplicateCodeSpotterInfo("DuplicateCodeSpotter");
  8946. class DuplicateCodeSpotter : public QuickHqlTransformer
  8947. {
  8948. public:
  8949. DuplicateCodeSpotter() : QuickHqlTransformer(duplicateCodeSpotterInfo, NULL) {}
  8950. inline bool checkExpr(IHqlExpression * expr)
  8951. {
  8952. if (!expr->isDataset())
  8953. return false;
  8954. switch (expr->getOperator())
  8955. {
  8956. case no_join:
  8957. break;
  8958. default:
  8959. return false;
  8960. }
  8961. if (expr->queryName() != createIdentifierAtom("ds_raw"))
  8962. return false;
  8963. return true;
  8964. }
  8965. virtual void doAnalyse(IHqlExpression * expr)
  8966. {
  8967. if (checkExpr(expr))
  8968. {
  8969. IHqlExpression * location = queryLocation(expr);
  8970. if (location)
  8971. {
  8972. OwnedHqlExpr attr = createLocationAttr(location->querySourcePath(), location->getStartLine(), location->getStartColumn(), 0);
  8973. Linked<LocationInfo> info;
  8974. Shared<LocationInfo> * match = map.getValue(attr);
  8975. if (match)
  8976. info.set(*match);
  8977. else
  8978. {
  8979. info.setown(new LocationInfo);
  8980. map.setValue(attr, info);
  8981. }
  8982. IHqlExpression * body = expr->queryBody();
  8983. if (!info->matches.contains(*body))
  8984. {
  8985. ForEachItemIn(i, info->matches)
  8986. {
  8987. debugFindFirstDifference(body, &info->matches.item(i));
  8988. }
  8989. info->matches.append(*LINK(body));
  8990. }
  8991. }
  8992. }
  8993. QuickHqlTransformer::doAnalyse(expr);
  8994. }
  8995. MapOwnedToOwned<IHqlExpression, LocationInfo> map;
  8996. };
  8997. void spotPotentialDuplicateCode(HqlExprArray & exprs)
  8998. {
  8999. DuplicateCodeSpotter spotter;
  9000. spotter.analyseArray(exprs);
  9001. }
  9002. //---------------------------------------------------------------------------
  9003. static bool isUniqueAttributeName(_ATOM name)
  9004. {
  9005. const char * nameText = name->str();
  9006. unsigned len = strlen(nameText);
  9007. if (len > 3)
  9008. {
  9009. if ((nameText[len-2] == '_') && (nameText[len-1] == '_') && isdigit((unsigned char)nameText[len-3]))
  9010. return true;
  9011. }
  9012. return false;
  9013. }
  9014. static _ATOM simplifyUniqueAttributeName(_ATOM name)
  9015. {
  9016. //Rename all attributes __x__1234__ to __x__
  9017. const char * nameText = name->str();
  9018. unsigned len = strlen(nameText);
  9019. if (len > 3)
  9020. {
  9021. if ((nameText[len-2] == '_') && (nameText[len-1] == '_') && isdigit((unsigned char)nameText[len-3]))
  9022. {
  9023. len -= 3;
  9024. while (len && isdigit((unsigned char)nameText[len-1]))
  9025. len--;
  9026. if (len)
  9027. {
  9028. StringAttr truncName;
  9029. truncName.set(nameText, len);
  9030. return createIdentifierAtom(truncName);
  9031. }
  9032. }
  9033. }
  9034. return NULL;
  9035. }
  9036. static bool exprIsSelfConstant(IHqlExpression * expr)
  9037. {
  9038. if (expr->isConstant())
  9039. return true;
  9040. switch (expr->getOperator())
  9041. {
  9042. case no_select:
  9043. {
  9044. IHqlExpression * selector = expr->queryChild(0);
  9045. while (selector->getOperator() == no_select)
  9046. selector = selector->queryChild(0);
  9047. return (selector->getOperator() == no_selfref);
  9048. }
  9049. }
  9050. if (expr->isDataset() && (getNumChildTables(expr) == 0))
  9051. return false;
  9052. ForEachChild(i, expr)
  9053. {
  9054. IHqlExpression * cur = expr->queryChild(i);
  9055. if (!exprIsSelfConstant(cur))
  9056. return false;
  9057. }
  9058. return true;
  9059. }
  9060. static _ATOM queryPatUseModule(IHqlExpression * expr)
  9061. {
  9062. IHqlExpression * moduleAttr = expr->queryProperty(moduleAtom);
  9063. if (moduleAttr)
  9064. return moduleAttr->queryChild(0)->queryBody()->queryName();
  9065. return NULL;
  9066. }
  9067. static _ATOM queryPatUseName(IHqlExpression * expr)
  9068. {
  9069. IHqlExpression * nameAttr = expr->queryProperty(nameAtom);
  9070. return nameAttr->queryChild(0)->queryBody()->queryName();
  9071. }
  9072. void HqlTreeNormalizerInfo::noteSymbol(IHqlExpression * _symbol)
  9073. {
  9074. if (!symbol || isUniqueAttributeName(symbol->queryName()))
  9075. symbol = _symbol;
  9076. }
  9077. static HqlTransformerInfo hqlTreeNormalizerInfo("HqlTreeNormalizer");
  9078. HqlTreeNormalizer::HqlTreeNormalizer(HqlCppTranslator & _translator) : NewHqlTransformer(hqlTreeNormalizerInfo), translator(_translator)
  9079. {
  9080. seenForceLocal = false;
  9081. seenLocalUpload = false;
  9082. const HqlCppOptions & translatorOptions = translator.queryOptions();
  9083. options.removeAsserts = !translatorOptions.checkAsserts;
  9084. options.commonUniqueNameAttributes = translatorOptions.commonUniqueNameAttributes;
  9085. options.sortIndexPayload = translatorOptions.sortIndexPayload;
  9086. options.allowSections = translatorOptions.allowSections;
  9087. options.normalizeExplicitCasts = translatorOptions.normalizeExplicitCasts;
  9088. options.ensureRecordsHaveSymbols = translatorOptions.ensureRecordsHaveSymbols;
  9089. options.outputRowsAsDatasets = translator.targetRoxie();
  9090. options.constantFoldNormalize = translatorOptions.constantFoldNormalize;
  9091. options.allowActivityForKeyedJoin = translatorOptions.allowActivityForKeyedJoin;
  9092. options.implicitSubSort = translatorOptions.implicitBuildIndexSubSort;
  9093. errors = translator.queryErrors();
  9094. nextSequenceValue = 1;
  9095. }
  9096. ANewTransformInfo * HqlTreeNormalizer::createTransformInfo(IHqlExpression * expr)
  9097. {
  9098. return CREATE_NEWTRANSFORMINFO(HqlTreeNormalizerInfo, expr);
  9099. }
  9100. HqlTreeNormalizerInfo * HqlTreeNormalizer::queryLocationIndependentExtra(IHqlExpression * expr)
  9101. {
  9102. return static_cast<HqlTreeNormalizerInfo *>(queryTransformExtra(queryLocationIndependent(expr)));
  9103. }
  9104. void HqlTreeNormalizer::convertRecordToAssigns(HqlExprArray & assigns, IHqlExpression * oldRecord, IHqlExpression * targetSelector, bool canOmit, bool convertTempTable)
  9105. {
  9106. ForEachChild(idx, oldRecord)
  9107. {
  9108. IHqlExpression * oldField = oldRecord->queryChild(idx);
  9109. OwnedHqlExpr newField = transform(oldField);
  9110. switch (oldField->getOperator())
  9111. {
  9112. case no_ifblock:
  9113. convertRecordToAssigns(assigns, oldField->queryChild(1), targetSelector, canOmit, convertTempTable);
  9114. break;
  9115. case no_record:
  9116. convertRecordToAssigns(assigns, oldField, targetSelector, canOmit, convertTempTable);
  9117. break;
  9118. case no_field:
  9119. {
  9120. IHqlExpression * oldFieldRecord = oldField->queryRecord();
  9121. IHqlExpression * value = queryRealChild(oldField, 0);
  9122. OwnedHqlExpr newTargetSelector = createSelectExpr(LINK(targetSelector), LINK(newField));
  9123. if (oldFieldRecord && !oldField->isDataset() && !value)
  9124. {
  9125. if (convertTempTable)
  9126. convertRecordToAssigns(assigns, oldFieldRecord, newTargetSelector, canOmit, convertTempTable);
  9127. else
  9128. {
  9129. IHqlExpression * newRecord = newField->queryRecord();
  9130. OwnedHqlExpr newSelf = getSelf(newRecord);
  9131. HqlExprArray newAssigns;
  9132. convertRecordToAssigns(newAssigns, oldFieldRecord, newSelf, canOmit, convertTempTable);
  9133. IHqlExpression * transform = createValue(no_newtransform, makeTransformType(newRecord->getType()), newAssigns);
  9134. IHqlExpression * newValue = createRow(no_createrow, transform);
  9135. assigns.append(*createAssign(LINK(newTargetSelector), newValue));
  9136. }
  9137. }
  9138. else
  9139. {
  9140. assertex(value || canOmit);
  9141. if (value && (!convertTempTable || exprIsSelfConstant(value)))
  9142. assigns.append(*createAssign(LINK(newTargetSelector), transform(value)));
  9143. if (oldFieldRecord && convertTempTable)
  9144. assigns.append(*createExprAttribute(defaultAtom, createExprAttribute(defaultAtom, LINK(newTargetSelector)), convertRecordToAssigns(oldFieldRecord, canOmit, convertTempTable)));
  9145. }
  9146. break;
  9147. }
  9148. case no_attr:
  9149. case no_attr_link:
  9150. case no_attr_expr:
  9151. break;
  9152. default:
  9153. UNIMPLEMENTED;
  9154. }
  9155. }
  9156. }
  9157. IHqlExpression * HqlTreeNormalizer::convertRecordToAssigns(IHqlExpression * oldRecord, bool canOmit, bool convertTempTable)
  9158. {
  9159. OwnedHqlExpr newRecord = transform(oldRecord);
  9160. HqlExprArray assigns;
  9161. OwnedHqlExpr self = getSelf(newRecord);
  9162. convertRecordToAssigns(assigns, oldRecord, self, canOmit, convertTempTable);
  9163. return createValue(no_transform, makeTransformType(newRecord->getType()), assigns);
  9164. }
  9165. // Problems occur if a record used in a select fields is also used for some other linked purpose.
  9166. // Thankfully the only one so far is BUILDINDEX(index)
  9167. IHqlExpression * HqlTreeNormalizer::convertSelectToProject(IHqlExpression * newRecord, IHqlExpression * expr)
  9168. {
  9169. OwnedHqlExpr newDataset = transform(expr->queryChild(0));
  9170. IHqlExpression * oldRecord = expr->queryChild(1);
  9171. if (oldRecord->getOperator() == no_null)
  9172. return newDataset.getClear();
  9173. HqlExprArray assigns;
  9174. OwnedHqlExpr self = getSelf(newRecord);
  9175. convertRecordToAssigns(assigns, oldRecord, self, false, false);
  9176. OwnedHqlExpr newTransform = createValue(no_newtransform, makeTransformType(LINK(newRecord->queryRecordType())), assigns);
  9177. newTransform.setown(newRecord->cloneAllAnnotations(newTransform));
  9178. HqlExprArray args;
  9179. args.append(*newDataset.getClear());
  9180. args.append(*LINK(newRecord));
  9181. args.append(*newTransform.getClear());
  9182. unsigned numChildren = expr->numChildren();
  9183. for (unsigned idx = 2; idx < numChildren; idx++)
  9184. args.append(*transform(expr->queryChild(idx)));
  9185. OwnedHqlExpr project = createDataset(no_newusertable, args);
  9186. return expr->cloneAllAnnotations(project);
  9187. }
  9188. IHqlExpression * HqlTreeNormalizer::removeDefaultsFromExpr(IHqlExpression * expr, unsigned recordChildIndex, node_operator newOp)
  9189. {
  9190. IHqlExpression * oldRecord = expr->queryChild(recordChildIndex);
  9191. OwnedHqlExpr newRecord = transform(oldRecord);
  9192. IHqlExpression * ds = expr->queryChild(0);
  9193. HqlExprArray assigns;
  9194. OwnedHqlExpr self = getSelf(newRecord);
  9195. convertRecordToAssigns(assigns, oldRecord, self, false, false);
  9196. IHqlExpression * newTransform = createValue(no_newtransform, makeTransformType(LINK(newRecord->queryRecordType())), assigns);
  9197. HqlExprArray args;
  9198. args.append(*transform(expr->queryChild(0)));
  9199. for (unsigned i= 1; i < recordChildIndex; i++)
  9200. args.append(*transform(expr->queryChild(i)));
  9201. args.append(*LINK(newRecord));
  9202. args.append(*newTransform);
  9203. unsigned numChildren = expr->numChildren();
  9204. for (unsigned idx = recordChildIndex+1; idx < numChildren; idx++)
  9205. args.append(*transform(expr->queryChild(idx)));
  9206. OwnedHqlExpr project;
  9207. if (expr->isDataset())
  9208. project.setown(createDataset(newOp, args));
  9209. else if (expr->isDatarow())
  9210. project.setown(createRow(newOp, args));
  9211. else
  9212. project.setown(createValue(newOp, makeVoidType(), args));
  9213. return expr->cloneAllAnnotations(project);
  9214. }
  9215. ITypeInfo * HqlTreeNormalizer::transformType(ITypeInfo * type)
  9216. {
  9217. switch (type->queryModifier())
  9218. {
  9219. case typemod_original:
  9220. {
  9221. switch (type->getTypeCode())
  9222. {
  9223. case type_record:
  9224. case type_transform:
  9225. case type_row:
  9226. case type_table:
  9227. case type_groupedtable:
  9228. //Strip all original annotations - they cause branches to not be commoned up
  9229. return transformType(type->queryTypeBase());
  9230. }
  9231. //But keep annotations used for typedef information, they should probably work differently
  9232. break;
  9233. }
  9234. case typemod_none:
  9235. {
  9236. //Ensure all records with the same format get the same original modifier
  9237. Owned<ITypeInfo> transformedType = NewHqlTransformer::transformType(type);
  9238. if (type->getTypeCode() == type_record)
  9239. {
  9240. IHqlExpression * record = queryExpression(type);
  9241. if (record && record->getOperator() == no_record)
  9242. {
  9243. OwnedHqlExpr transformedRecord = transform(record);
  9244. if (transformedRecord->queryBody() != transformedRecord)
  9245. return makeOriginalModifier(LINK(transformedType), LINK(transformedRecord));
  9246. }
  9247. }
  9248. return transformedType.getClear();
  9249. }
  9250. break;
  9251. }
  9252. return NewHqlTransformer::transformType(type);
  9253. }
  9254. bool isVoidOrDatasetOrList(IHqlExpression * expr)
  9255. {
  9256. ITypeInfo * type = expr->queryType();
  9257. switch (type->getTypeCode())
  9258. {
  9259. case type_void:
  9260. case type_table:
  9261. case type_row:
  9262. case type_groupedtable:
  9263. case type_set:
  9264. return true;
  9265. default:
  9266. return false;
  9267. }
  9268. }
  9269. inline IHqlExpression * createColon(IHqlExpression * l, HqlExprArray & actions)
  9270. {
  9271. HqlExprArray args;
  9272. args.append(*l);
  9273. ForEachItemIn(i, actions)
  9274. args.append(OLINK(actions.item(i)));
  9275. return createWrapper(no_colon, args);
  9276. }
  9277. void HqlTreeNormalizer::analyseExpr(IHqlExpression * expr)
  9278. {
  9279. IHqlExpression * body = expr->queryBody();
  9280. node_operator op = body->getOperator();
  9281. if ((op == no_record) && (expr != body))
  9282. {
  9283. IHqlExpression * symbol = queryNamedSymbol(expr);
  9284. if (symbol)
  9285. queryLocationIndependentExtra(body)->noteSymbol(expr);
  9286. }
  9287. if (alreadyVisited(body))
  9288. return;
  9289. //Record a list of all USE(name[,name]) so we know what needs fixing up, and all patterns with explicit defines already
  9290. switch (op)
  9291. {
  9292. case no_pat_use:
  9293. if (body->hasProperty(nameAtom))
  9294. forwardReferences.append(*LINK(body));
  9295. break;
  9296. case no_pat_instance:
  9297. if (body->queryChild(0)->getOperator() == no_define)
  9298. defines.append(*LINK(body));
  9299. break;
  9300. case no_libraryscopeinstance:
  9301. analyseExpr(body->queryDefinition());
  9302. break;
  9303. case no_transform:
  9304. case no_call:
  9305. case no_externalcall:
  9306. {
  9307. IHqlExpression * record = queryOriginalRecord(body->queryType());
  9308. if (record)
  9309. analyseExpr(record);
  9310. break;
  9311. }
  9312. case no_attr_expr:
  9313. case no_record:
  9314. case no_ifblock:
  9315. case no_select:
  9316. analyseChildren(body);
  9317. return;
  9318. case no_field:
  9319. {
  9320. IHqlExpression * record = queryOriginalRecord(body->queryType());
  9321. if (record)
  9322. analyseExpr(record);
  9323. analyseChildren(body);
  9324. break;
  9325. }
  9326. }
  9327. Parent::analyseExpr(body);
  9328. }
  9329. IHqlExpression * HqlTreeNormalizer::makeRecursiveName(_ATOM searchModule, _ATOM searchName)
  9330. {
  9331. //If this symbol is already has a user define, use that instead of creating our own,
  9332. //because I don't cope very well with multiple defines on the same pattern instance.
  9333. ForEachItemIn(i, defines)
  9334. {
  9335. IHqlExpression & cur = defines.item(i);
  9336. IHqlExpression * moduleExpr = cur.queryChild(2);
  9337. _ATOM module = moduleExpr ? moduleExpr->queryBody()->queryName() : NULL;
  9338. _ATOM name = cur.queryChild(1)->queryBody()->queryName();
  9339. if (name == searchName && module == searchModule)
  9340. return LINK(cur.queryChild(0)->queryChild(1));
  9341. }
  9342. StringBuffer s;
  9343. s.append("$").append(searchModule).append(".").append(searchName);
  9344. return createConstant(s.str());
  9345. }
  9346. IHqlExpression * HqlTreeNormalizer::queryTransformPatternDefine(IHqlExpression * expr)
  9347. {
  9348. if (expr->queryChild(0)->getOperator() == no_define)
  9349. return NULL;
  9350. IHqlExpression * moduleExpr = expr->queryChild(2);
  9351. _ATOM module = moduleExpr ? moduleExpr->queryBody()->queryName() : NULL;
  9352. _ATOM name = expr->queryChild(1)->queryBody()->queryName();
  9353. ForEachItemIn(i, forwardReferences)
  9354. {
  9355. IHqlExpression * cur = &forwardReferences.item(i);
  9356. if ((name == queryPatUseName(cur)) && (module == queryPatUseModule(cur)))
  9357. {
  9358. IHqlExpression * base = transform(expr->queryChild(0));
  9359. HqlExprArray args;
  9360. args.append(*createValue(no_define, base->getType(), base, makeRecursiveName(module, name)));
  9361. unwindChildren(args, expr, 1);
  9362. return expr->clone(args);
  9363. }
  9364. }
  9365. return NULL;
  9366. }
  9367. IHqlExpression * HqlTreeNormalizer::transformActionList(IHqlExpression * expr)
  9368. {
  9369. HqlExprArray args;
  9370. ForEachChild(i, expr)
  9371. {
  9372. IHqlExpression * cur = expr->queryChild(i);
  9373. if (cur->getOperator() != no_setmeta)
  9374. {
  9375. OwnedHqlExpr transformed = transform(cur);
  9376. if ((transformed->getOperator() != no_null) || !transformed->isAction())
  9377. args.append(*transformed.getClear());
  9378. }
  9379. }
  9380. return createActionList(args);
  9381. }
  9382. IHqlExpression * HqlTreeNormalizer::transformCaseToIfs(IHqlExpression * expr)
  9383. {
  9384. unsigned max = numRealChildren(expr);
  9385. OwnedHqlExpr testVar = transform(expr->queryChild(0));
  9386. OwnedHqlExpr elseExpr = transform(expr->queryChild(max-1));
  9387. for (unsigned idx = max-2; idx != 0; idx--)
  9388. {
  9389. IHqlExpression * cur = expr->queryChild(idx);
  9390. IHqlExpression * curValue = cur->queryChild(0);
  9391. Owned<ITypeInfo> type = ::getPromotedECLType(testVar->queryType(), curValue->queryType());
  9392. OwnedHqlExpr castCurValue = ensureExprType(curValue, type);
  9393. OwnedHqlExpr test = createBoolExpr(no_eq, ensureExprType(testVar, type), transform(castCurValue));
  9394. if (options.constantFoldNormalize)
  9395. test.setown(foldConstantOperator(test, 0, NULL));
  9396. OwnedHqlExpr trueExpr = transform(cur->queryChild(1));
  9397. elseExpr.setown(createIf(test.getClear(), trueExpr.getClear(), elseExpr.getClear()));
  9398. if (options.constantFoldNormalize)
  9399. elseExpr.setown(foldConstantOperator(elseExpr, 0, NULL));
  9400. }
  9401. return elseExpr.getClear();
  9402. }
  9403. IHqlExpression * HqlTreeNormalizer::transformCaseToChoose(IHqlExpression * expr)
  9404. {
  9405. //For the moment only convert datasets to choose format. (Partly to test implementation.)
  9406. //Datarows are unlikely to benefit, and will cause additional work.
  9407. //Converting actions has implications for needing new activity kinds, and support in thor.
  9408. if (!expr->isDataset())
  9409. return transformCaseToIfs(expr);
  9410. unsigned max = numRealChildren(expr);
  9411. HqlExprArray branches;
  9412. OwnedHqlExpr testVar = transform(expr->queryChild(0));
  9413. HqlExprArray caseArgs;
  9414. caseArgs.append(*LINK(testVar));
  9415. bool isNullMapping = true;
  9416. for (unsigned i1=1; i1 < max-1; i1++)
  9417. {
  9418. IHqlExpression * mapto = expr->queryChild(i1);
  9419. OwnedHqlExpr key = transform(mapto->queryChild(0));
  9420. OwnedHqlExpr branch = transform(mapto->queryChild(1));
  9421. unsigned matchIndex = branches.find(*branch);
  9422. if (matchIndex == NotFound)
  9423. {
  9424. matchIndex = branches.ordinality();
  9425. branches.append(*branch.getClear());
  9426. }
  9427. OwnedHqlExpr value = getSizetConstant(matchIndex+1);
  9428. //MORE: Could calculate a delta and add/subtract it from testVar
  9429. if (!key->queryValue() || !matchesConstantValue(key, matchIndex+1))
  9430. isNullMapping = false;
  9431. caseArgs.append(*createValue(no_mapto, value->getType(), key.getClear(), LINK(value)));
  9432. }
  9433. caseArgs.append(*getSizetConstant(max-1));
  9434. HqlExprArray args;
  9435. if (isNullMapping)
  9436. args.append(*LINK(testVar));
  9437. else
  9438. args.append(*createValue(no_case, LINK(sizetType), caseArgs));
  9439. appendArray(args, branches);
  9440. args.append(*transform(expr->queryChild(max-1)));
  9441. if (expr->isDataset())
  9442. return createDataset(no_chooseds, args);
  9443. return createAction(no_choose, args);
  9444. }
  9445. IHqlExpression * HqlTreeNormalizer::transformEvaluate(IHqlExpression * expr)
  9446. {
  9447. //Evaluate causes chaos - so translate it to a different form.
  9448. //following cases supported so far:
  9449. //EVALUATE(LEFT/RIGHT, g()) -> g(LEFT)
  9450. //EVAlUATE(x, field) -> x.field;
  9451. //EVALUATE(t[n], e) -> table(t,{f1 := e})[n].f1;
  9452. IHqlExpression * ds = expr->queryChild(0);
  9453. IHqlExpression * attr = expr->queryChild(1);
  9454. OwnedHqlExpr transformed;
  9455. OwnedHqlExpr activeTable = getActiveTableSelector();
  9456. if ((attr->getOperator() == no_select) && (attr->queryChild(0) == activeTable))
  9457. {
  9458. //EVAlUATE(x, field) -> x.field;
  9459. transformed.setown(createSelectExpr(LINK(ds), LINK(attr->queryChild(1))));
  9460. }
  9461. else if (attr->isConstant())
  9462. transformed.set(attr);
  9463. else
  9464. {
  9465. switch (ds->getOperator())
  9466. {
  9467. case no_left:
  9468. case no_right:
  9469. //EVALUATE(LEFT/RIGHT, g()) -> g(LEFT)
  9470. //May change too many datasets?
  9471. transformed.setown(replaceSelector(attr, activeTable, ds));
  9472. break;
  9473. case no_select:
  9474. //EVALUATE(x.y, g()) -> EVALUATE(x, g(y))
  9475. //May change too many datasets?
  9476. transformed.setown(createValue(no_evaluate, attr->getType(), LINK(ds->queryChild(0)), replaceSelector(attr, activeTable, ds->queryChild(1))));
  9477. break;
  9478. case no_selectnth:
  9479. {
  9480. IHqlExpression * baseDs = ds->queryChild(0);
  9481. if ((attr->getOperator() == no_select) && (attr->queryChild(0)->queryNormalizedSelector() == baseDs->queryNormalizedSelector()))
  9482. {
  9483. //Special case a select same as field...
  9484. transformed.setown(createSelectExpr(LINK(ds), LINK(attr->queryChild(1))));
  9485. }
  9486. else
  9487. {
  9488. //EVALUATE(t[n], e) -> table(t,{f1 := e})[n].f1;
  9489. OwnedHqlExpr field = createField(valueAtom, expr->getType(), NULL);
  9490. IHqlExpression * aggregateRecord = createRecord(field);
  9491. IHqlExpression * newAttr = replaceSelector(attr, activeTable, baseDs);
  9492. IHqlExpression * assign = createAssign(createSelectExpr(getSelf(aggregateRecord), LINK(field)), newAttr);
  9493. IHqlExpression * transform = createValue(no_newtransform, makeTransformType(aggregateRecord->getType()), assign);
  9494. IHqlExpression * project = createDataset(no_newusertable, LINK(baseDs), createComma(aggregateRecord, transform));
  9495. project = createRow(no_selectnth, project, LINK(ds->queryChild(1)));
  9496. transformed.setown(createSelectExpr(project, LINK(field)));
  9497. }
  9498. break;
  9499. }
  9500. default:
  9501. UNIMPLEMENTED;
  9502. }
  9503. }
  9504. return transform(transformed);
  9505. }
  9506. IHqlExpression * HqlTreeNormalizer::transformMap(IHqlExpression * expr)
  9507. {
  9508. unsigned max = numRealChildren(expr);
  9509. OwnedHqlExpr elseExpr = transform(expr->queryChild(max-1));
  9510. for (unsigned idx = max-1; idx-- != 0; )
  9511. {
  9512. IHqlExpression * cur = expr->queryChild(idx);
  9513. elseExpr.setown(createIf(transform(cur->queryChild(0)), transform(cur->queryChild(1)), elseExpr.getClear()));
  9514. if (options.constantFoldNormalize)
  9515. elseExpr.setown(foldConstantOperator(elseExpr, 0, NULL));
  9516. }
  9517. return elseExpr.getClear();
  9518. }
  9519. class AbortingErrorReceiver : extends CInterface, implements IErrorReceiver
  9520. {
  9521. public:
  9522. AbortingErrorReceiver(IErrorReceiver * _errors)
  9523. {
  9524. errors = _errors ? _errors : &defaultReporter;
  9525. }
  9526. IMPLEMENT_IINTERFACE
  9527. virtual void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
  9528. {
  9529. errors->reportError(errNo, msg, filename, lineno, column, pos);
  9530. throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
  9531. }
  9532. virtual void report(IECLError* error)
  9533. {
  9534. errors->report(error);
  9535. throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
  9536. }
  9537. virtual void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
  9538. {
  9539. errors->reportWarning(warnNo, msg, filename, lineno, column, pos);
  9540. }
  9541. virtual size32_t errCount()
  9542. {
  9543. return errors->errCount();
  9544. }
  9545. virtual size32_t warnCount()
  9546. {
  9547. return errors->warnCount();
  9548. }
  9549. protected:
  9550. IErrorReceiver * errors;
  9551. ThrowingErrorReceiver defaultReporter;
  9552. };
  9553. IHqlExpression * HqlTreeNormalizer::transformTempRow(IHqlExpression * expr)
  9554. {
  9555. ECLlocation dummyLocation(0, 0, 0, NULL);
  9556. AbortingErrorReceiver errorReporter(errors);
  9557. OwnedHqlExpr createRow = convertTempRowToCreateRow(&errorReporter, dummyLocation, expr);
  9558. return transform(createRow);
  9559. }
  9560. IHqlExpression * HqlTreeNormalizer::transformTempTable(IHqlExpression * expr)
  9561. {
  9562. ECLlocation dummyLocation(0, 0, 0, NULL);
  9563. AbortingErrorReceiver errorReporter(errors);
  9564. OwnedHqlExpr inlineTable = convertTempTableToInlineTable(&errorReporter, dummyLocation, expr);
  9565. if (expr != inlineTable)
  9566. return transform(inlineTable);
  9567. IHqlExpression * oldValues = expr->queryChild(0);
  9568. IHqlExpression * oldRecord = expr->queryChild(1);
  9569. OwnedHqlExpr values = normalizeListCasts(oldValues);
  9570. OwnedHqlExpr newRecord = transform(oldRecord);
  9571. node_operator valueOp = values->getOperator();
  9572. if ((valueOp != no_recordlist) && (valueOp != no_list))
  9573. {
  9574. if (queryRealChild(expr, 2))
  9575. return Parent::createTransformed(expr);
  9576. HqlExprArray children;
  9577. children.append(*transform(oldValues));
  9578. children.append(*LINK(newRecord));
  9579. children.append(*convertRecordToAssigns(oldRecord, true, true));
  9580. return expr->clone(children);
  9581. }
  9582. //should have already been handled by convertTempTableToInlineTable();
  9583. throwUnexpected();
  9584. }
  9585. IHqlExpression * HqlTreeNormalizer::transformNewKeyIndex(IHqlExpression * expr)
  9586. {
  9587. IHqlExpression * ds = expr->queryChild(0);
  9588. //If dataset is already null, then do standard
  9589. if (ds->getOperator() == no_null)
  9590. return completeTransform(expr);
  9591. //Before we do anything replace the dataset with a null dataset. This ensures we do the minimum transformation on the rest of the tree
  9592. OwnedHqlExpr newDs = createDataset(no_null, LINK(ds->queryRecord()));
  9593. HqlExprArray args;
  9594. args.append(*ds->cloneAllAnnotations(newDs));
  9595. args.append(*LINK(expr->queryChild(1)));
  9596. args.append(*quickFullReplaceExpression(expr->queryChild(2), ds->queryNormalizedSelector(), newDs));
  9597. unwindChildren(args, expr, 3);
  9598. OwnedHqlExpr ret = expr->clone(args);
  9599. return transform(ret);
  9600. }
  9601. IHqlExpression * HqlTreeNormalizer::transformKeyIndex(IHqlExpression * expr)
  9602. {
  9603. //Before we do anything replace the dataset with a null dataset. This ensures we do the minimum transformation on the rest of the tree
  9604. IHqlExpression * ds = expr->queryChild(0);
  9605. OwnedHqlExpr newDs = createDataset(no_null, LINK(ds->queryRecord()));
  9606. HqlExprArray args;
  9607. args.append(*ds->cloneAllAnnotations(newDs));
  9608. args.append(*quickFullReplaceExpression(expr->queryChild(1), ds->queryNormalizedSelector(), newDs));
  9609. unwindChildren(args, expr, 2);
  9610. OwnedHqlExpr normalized = expr->clone(args);
  9611. //Now convert from the no_keyindex format to the no_newkeyindex format.
  9612. //force the 1st argument to be processed..
  9613. OwnedHqlExpr transformed = completeTransform(normalized);
  9614. HqlExprArray assigns;
  9615. OwnedHqlExpr self = getSelf(transformed);
  9616. convertRecordToAssigns(assigns, normalized->queryChild(1), self, true, false); // fpos may not have a value...
  9617. args.kill();
  9618. unwindChildren(args, transformed);
  9619. args.add(*createValue(no_newtransform, makeTransformType(transformed->queryChild(1)->getType()), assigns), 2);
  9620. OwnedHqlExpr ret = createDataset(no_newkeyindex, args);
  9621. //MORE: This would be the place to add a FILTERED() attribute derived from any filters applied to the dataset
  9622. return expr->cloneAllAnnotations(ret);
  9623. }
  9624. IHqlExpression * HqlTreeNormalizer::transformMerge(IHqlExpression * expr)
  9625. {
  9626. HqlExprArray children;
  9627. transformChildren(expr, children);
  9628. HqlExprArray args;
  9629. reorderAttributesToEnd(args, children);
  9630. return expr->clone(args);
  9631. }
  9632. IHqlExpression * HqlTreeNormalizer::transformPatNamedUse(IHqlExpression * expr)
  9633. {
  9634. OwnedHqlExpr define = makeRecursiveName(queryPatUseModule(expr), queryPatUseName(expr));
  9635. HqlExprArray args;
  9636. ForEachChild(i, expr)
  9637. {
  9638. IHqlExpression * cur = queryRealChild(expr, i);
  9639. if (cur)
  9640. args.append(*LINK(cur));
  9641. }
  9642. args.append(*define.getClear());
  9643. return expr->clone(args);
  9644. }
  9645. IHqlExpression * HqlTreeNormalizer::transformPatCheckIn(IHqlExpression * expr)
  9646. {
  9647. OwnedHqlExpr set = transform(expr->queryChild(1));
  9648. //because this is a check pattern, we are free to remove any instance tags - they can't be used for matching.
  9649. while (set->getOperator() == no_pat_instance)
  9650. set.set(set->queryChild(0));
  9651. if (set->getOperator() == no_pat_set)
  9652. {
  9653. IHqlExpression * notAttr = expr->queryProperty(notAtom);
  9654. if (!notAttr)
  9655. return LINK(set);
  9656. HqlExprArray args;
  9657. unwindChildren(args, set);
  9658. if (args.find(*notAttr) == NotFound)
  9659. args.append(*LINK(notAttr));
  9660. else
  9661. args.zap(*notAttr);
  9662. return set->clone(args);
  9663. }
  9664. HqlExprArray values, newValues;
  9665. set->unwindList(values, no_pat_or);
  9666. ForEachItemIn(idx, values)
  9667. {
  9668. IHqlExpression * cur = &values.item(idx);
  9669. while (cur->getOperator() == no_pat_instance)
  9670. cur = cur->queryChild(0);
  9671. if (cur->getOperator() != no_pat_const)
  9672. return NULL;
  9673. IValue * value = cur->queryChild(0)->queryValue();
  9674. if (!value)
  9675. return NULL;
  9676. ITypeInfo * type = value->queryType();
  9677. if (type->getStringLen() != 1)
  9678. return NULL;
  9679. switch (type->getTypeCode())
  9680. {
  9681. case type_string:
  9682. newValues.append(*createConstant((int)*(const byte *)value->queryValue()));
  9683. break;
  9684. case type_unicode:
  9685. newValues.append(*createConstant((int)*(const UChar *)value->queryValue()));
  9686. break;
  9687. case type_utf8:
  9688. newValues.append(*createConstant((int)rtlUtf8Char((const char *)value->queryValue())));
  9689. break;
  9690. default:
  9691. return NULL;
  9692. }
  9693. }
  9694. if (expr->hasProperty(notAtom))
  9695. newValues.append(*createAttribute(notAtom));
  9696. return createValue(no_pat_set, makePatternType(), newValues);
  9697. }
  9698. IHqlExpression * HqlTreeNormalizer::transformTable(IHqlExpression * untransformed)
  9699. {
  9700. //Convert DATASET('xx', rec, PIPE('z'))
  9701. //DATASET('xx', rec, THOR) | PIPE('z')
  9702. OwnedHqlExpr transformed = completeTransform(untransformed);
  9703. IHqlExpression * mode = transformed->queryChild(2);
  9704. if (mode->getOperator() != no_pipe)
  9705. return transformed.getClear();
  9706. IHqlExpression * filename = transformed->queryChild(0);
  9707. StringBuffer s;
  9708. if (getStringValue(s, filename, NULL).length() == 0)
  9709. return transformed.getClear();
  9710. OwnedHqlExpr modeThor = createValue(no_thor);
  9711. IHqlExpression * diskRead = replaceChild(transformed, 2, modeThor);
  9712. HqlExprArray args;
  9713. args.append(*diskRead);
  9714. unwindChildren(args, mode);
  9715. return createDataset(no_pipe, args);
  9716. }
  9717. IHqlExpression * HqlTreeNormalizer::optimizeAssignSkip(HqlExprArray & children, IHqlExpression * expr, IHqlExpression * cond, unsigned depth)
  9718. {
  9719. if (!containsSkip(expr))
  9720. return LINK(expr);
  9721. switch (expr->getOperator())
  9722. {
  9723. case no_skip:
  9724. children.append(*createValue(no_skip, makeVoidType(), LINK(cond)));
  9725. return NULL;
  9726. case no_cast:
  9727. case no_implicitcast:
  9728. {
  9729. bool same= true;
  9730. HqlExprArray args;
  9731. ForEachChild(i, expr)
  9732. {
  9733. IHqlExpression * cur = expr->queryChild(i);
  9734. IHqlExpression * ret = optimizeAssignSkip(children, cur, cond, depth);
  9735. if (!ret)
  9736. return NULL;
  9737. args.append(*ret);
  9738. if (cur != ret)
  9739. same = false;
  9740. }
  9741. if (same)
  9742. return LINK(expr);
  9743. return expr->clone(args);
  9744. }
  9745. //could try and handle map/case/choose, but less common, and more complicated.
  9746. case no_if:
  9747. {
  9748. //For the moment only hoist SKIPS within a single level of IF() conditions.
  9749. //Multi level rarely occur, and don't significantly improve the code
  9750. if (depth != 0)
  9751. return LINK(expr);
  9752. IHqlExpression * thisCond = expr->queryChild(0);
  9753. IHqlExpression * left = expr->queryChild(1);
  9754. IHqlExpression * right = expr->queryChild(2);
  9755. if (!right)
  9756. return LINK(expr);
  9757. OwnedHqlExpr leftCond = extendConditionOwn(no_and, LINK(cond), LINK(thisCond));
  9758. OwnedHqlExpr inverseCond = createValue(no_not, makeBoolType(), LINK(thisCond));
  9759. OwnedHqlExpr rightCond = extendConditionOwn(no_and, LINK(cond), LINK(inverseCond));
  9760. OwnedHqlExpr newLeft = optimizeAssignSkip(children, left, leftCond, depth+1);
  9761. OwnedHqlExpr newRight = optimizeAssignSkip(children, right, rightCond, depth+1);
  9762. if (!newLeft && !newRight)
  9763. return NULL;
  9764. //if cond is true, then it will skip => no need to check the condition
  9765. if (!newLeft)
  9766. return LINK(newRight);
  9767. if (!newRight)
  9768. return LINK(newLeft);
  9769. if (left == newLeft && right == newRight)
  9770. return LINK(expr);
  9771. HqlExprArray args;
  9772. unwindChildren(args, expr);
  9773. args.replace(*newLeft.getClear(), 1);
  9774. args.replace(*newRight.getClear(), 2);
  9775. return expr->clone(args);
  9776. }
  9777. default:
  9778. return LINK(expr);
  9779. }
  9780. }
  9781. bool HqlTreeNormalizer::transformTransform(HqlExprArray & children, IHqlExpression * expr)
  9782. {
  9783. bool same = true;
  9784. ForEachChild(i, expr)
  9785. {
  9786. IHqlExpression * cur = expr->queryChild(i);
  9787. switch (cur->getOperator())
  9788. {
  9789. case no_assignall:
  9790. transformTransform(children, cur);
  9791. same = false; // assign all is removed and assigns expanded in its place
  9792. break;
  9793. case no_assign:
  9794. {
  9795. OwnedHqlExpr assign = transform(cur);
  9796. if (cur->getInfoFlags() & HEFcontainsSkip)
  9797. {
  9798. IHqlExpression * rhs = assign->queryChild(1);
  9799. OwnedHqlExpr newRhs = optimizeAssignSkip(children, rhs, NULL, 0);
  9800. if (rhs != newRhs)
  9801. {
  9802. IHqlExpression * lhs = assign->queryChild(0);
  9803. if (!newRhs)
  9804. newRhs.setown(createNullExpr(rhs));
  9805. assign.setown(createAssign(LINK(lhs), newRhs.getClear()));
  9806. }
  9807. }
  9808. if (assign != cur)
  9809. same = false;
  9810. children.append(*assign.getClear());
  9811. break;
  9812. }
  9813. default:
  9814. {
  9815. IHqlExpression * next = transform(cur);
  9816. children.append(*next);
  9817. if (next != cur)
  9818. same = false;
  9819. }
  9820. break;
  9821. }
  9822. }
  9823. return same;
  9824. }
  9825. IHqlExpression * HqlTreeNormalizer::transformTransform(IHqlExpression * expr)
  9826. {
  9827. HqlExprArray children;
  9828. IHqlExpression * oldRecord = queryOriginalRecord(expr);
  9829. OwnedHqlExpr newRecord = transform(oldRecord);
  9830. bool same = transformTransform(children, expr);
  9831. if ((oldRecord != newRecord) || !same)
  9832. {
  9833. ITypeInfo * newRecordType = createRecordType(newRecord);
  9834. OwnedHqlExpr ret = createValue(expr->getOperator(), makeTransformType(newRecordType), children);
  9835. return expr->cloneAllAnnotations(ret);
  9836. }
  9837. return LINK(expr);
  9838. }
  9839. IHqlExpression * HqlTreeNormalizer::transformIfAssert(node_operator newOp, IHqlExpression * expr)
  9840. {
  9841. unsigned max = expr->numChildren();
  9842. HqlExprArray children;
  9843. bool same = transformChildren(expr, children);
  9844. if (expr->hasProperty(assertAtom) && !options.removeAsserts)
  9845. {
  9846. OwnedHqlExpr ret = createDataset(newOp, children);
  9847. return expr->cloneAllAnnotations(ret);
  9848. }
  9849. if (!same)
  9850. return expr->clone(children);
  9851. return LINK(expr);
  9852. }
  9853. IHqlExpression * HqlTreeNormalizer::transformExecuteWhen(IHqlExpression * expr)
  9854. {
  9855. OwnedHqlExpr transformedAction = transform(expr->queryChild(1));
  9856. if ((transformedAction->getOperator() == no_setmeta) ||
  9857. ((transformedAction->getOperator() == no_null) && transformedAction->isAction()))
  9858. return transform(expr->queryChild(0));
  9859. HqlExprArray children;
  9860. if (translator.queryOptions().convertWhenExecutedToCompound && !expr->queryChild(2))
  9861. {
  9862. //For the moment, for maximal compatibility, convert no_executewhen to a no_compound
  9863. children.append(*transformedAction.getClear());
  9864. children.append(*transform(expr->queryChild(0)));
  9865. OwnedHqlExpr ret = createCompound(children);
  9866. return expr->cloneAllAnnotations(ret);
  9867. }
  9868. //Need to create a unique id to differentiate the different side effects.
  9869. transformChildren(expr, children);
  9870. assertex(!expr->hasProperty(_uid_Atom));
  9871. children.append(*createUniqueId());
  9872. return expr->clone(children);
  9873. }
  9874. IHqlExpression * HqlTreeNormalizer::transformWithinFilter(IHqlExpression * expr)
  9875. {
  9876. OwnedHqlExpr ds = transform(expr->queryChild(0));
  9877. HqlExprArray children;
  9878. children.append(*LINK(ds));
  9879. ForEachChildFrom(i, expr, 1)
  9880. {
  9881. IHqlExpression * filter = expr->queryChild(i);
  9882. if (filter->getOperator() == no_within)
  9883. {
  9884. IHqlExpression * scope = filter->queryChild(0);
  9885. while (scope->getOperator() == no_filter)
  9886. {
  9887. ForEachChildFrom(i2, scope, 1)
  9888. children.append(*transform(scope->queryChild(i2)));
  9889. scope = scope->queryChild(0);
  9890. }
  9891. ds.setown(createDataset(no_related, LINK(ds), transform(scope)));
  9892. }
  9893. else
  9894. children.append(*transform(filter));
  9895. }
  9896. if (children.ordinality() == 1)
  9897. return ds.getClear();
  9898. children.replace(*ds.getClear(), 0);
  9899. return expr->clone(children);
  9900. }
  9901. IHqlExpression * HqlTreeNormalizer::validateKeyedJoin(IHqlExpression * expr)
  9902. {
  9903. //Transform join(x, local(key), ....) to join(x, key, ...., local);
  9904. HqlExprArray children;
  9905. transformChildren(expr, children);
  9906. unsigned prevChildren = children.ordinality();
  9907. IHqlExpression * rhs = &children.item(1);
  9908. loop
  9909. {
  9910. node_operator op = rhs->getOperator();
  9911. if (op == no_forcelocal)
  9912. children.append(*createLocalAttribute());
  9913. else if (op == no_forcenolocal)
  9914. children.append(*createAttribute(noLocalAtom));
  9915. else if ((op == no_section) || (op == no_sectioninput))
  9916. {
  9917. //remove the section
  9918. }
  9919. else
  9920. break;
  9921. rhs = rhs->queryChild(0);
  9922. }
  9923. if (prevChildren != children.ordinality())
  9924. {
  9925. if (isKey(rhs))
  9926. children.replace(*LINK(rhs), 1);
  9927. else
  9928. children.trunc(prevChildren);
  9929. }
  9930. //Now check that a join marked as keyed has a key as the rhs.
  9931. IHqlExpression * keyed = expr->queryProperty(keyedAtom);
  9932. if (!keyed || keyed->queryChild(0) || isKey(rhs))
  9933. return expr->clone(children);
  9934. if (options.allowActivityForKeyedJoin)
  9935. {
  9936. children.append(*createAttribute(_complexKeyed_Atom));
  9937. return expr->clone(children);
  9938. }
  9939. StringBuffer s;
  9940. if (expr->queryName())
  9941. s.append(" (").append(expr->queryName()).append(")");
  9942. throwError1(HQLERR_RhsKeyedNotKey, s.str());
  9943. return NULL;
  9944. }
  9945. //A bit of a nasty dependency - this should match the capabilities of the code in hqlsource for finding selectors
  9946. static void gatherPotentialSelectors(HqlExprArray & args, IHqlExpression * expr)
  9947. {
  9948. node_operator op = expr->getOperator();
  9949. switch (op)
  9950. {
  9951. case no_and:
  9952. case no_or:
  9953. case no_eq:
  9954. case no_ne:
  9955. case no_gt:
  9956. case no_lt:
  9957. case no_ge:
  9958. case no_le:
  9959. gatherPotentialSelectors(args, expr->queryChild(0));
  9960. gatherPotentialSelectors(args, expr->queryChild(1));
  9961. break;
  9962. case no_if:
  9963. case no_case:
  9964. case no_map:
  9965. case no_mapto:
  9966. {
  9967. ForEachChild(i, expr)
  9968. gatherPotentialSelectors(args, expr->queryChild(i));
  9969. break;
  9970. }
  9971. case no_assertkeyed:
  9972. case no_assertstepped:
  9973. case no_not:
  9974. case no_between:
  9975. case no_notbetween:
  9976. case no_cast:
  9977. case no_implicitcast:
  9978. case no_notin:
  9979. case no_in:
  9980. case no_add:
  9981. case no_sub:
  9982. case no_substring:
  9983. gatherPotentialSelectors(args, expr->queryChild(0));
  9984. break;
  9985. case no_select:
  9986. {
  9987. IHqlExpression * selector = expr->queryNormalizedSelector();
  9988. if (!args.contains(*selector))
  9989. args.append(*LINK(selector));
  9990. break;
  9991. }
  9992. }
  9993. }
  9994. IHqlExpression * HqlTreeNormalizer::transformChildrenNoAnnotations(IHqlExpression * expr)
  9995. {
  9996. HqlExprArray args;
  9997. ForEachChild(i, expr)
  9998. args.append(*transform(expr->queryChild(i)->queryBody()));
  9999. return completeTransform(expr, args);
  10000. }
  10001. //The following symbol removal code works, but I'm not sure I want to do it at the moment because of the changes to the HOLe queries
  10002. //Remove as many named symbols as we can - try and keep for datasets and statements so can go in the tree.
  10003. IHqlExpression * HqlTreeNormalizer::createTransformed(IHqlExpression * expr)
  10004. {
  10005. IHqlExpression * body = expr->queryBody(true);
  10006. node_operator op = expr->getOperator();
  10007. if (expr != body)
  10008. {
  10009. OwnedHqlExpr transformedBody;
  10010. try
  10011. {
  10012. transformedBody.setown(transform(body));
  10013. }
  10014. catch (IException * e)
  10015. {
  10016. if (dynamic_cast<IECLError *>(e))
  10017. throw;
  10018. IHqlExpression * location = queryLocation(expr);
  10019. if (location)
  10020. {
  10021. IECLError * error = annotateExceptionWithLocation(e, location);
  10022. e->Release();
  10023. throw error;
  10024. }
  10025. throw;
  10026. }
  10027. //Don't retain any annotations on records - except for a symbol which maybe added in the createTransform()
  10028. //code. Otherwise expressions that would otherwise be commoned up are treated as different.
  10029. if (op == no_record)
  10030. return transformedBody.getClear();
  10031. switch (expr->getAnnotationKind())
  10032. {
  10033. case annotate_warning:
  10034. case annotate_parsemeta:
  10035. return transformedBody.getClear();
  10036. case annotate_javadoc:
  10037. return expr->cloneAnnotation(transformedBody);
  10038. case annotate_meta:
  10039. {
  10040. HqlExprArray preservedMeta;
  10041. IHqlExpression * cur;
  10042. bool changed = false;
  10043. for (unsigned i=0; (cur = expr->queryAnnotationParameter(i)) != 0; i++)
  10044. {
  10045. _ATOM name = cur->queryName();
  10046. bool keep = true;
  10047. if (name == deprecatedAtom)
  10048. keep = false;
  10049. else if (!options.allowSections && (name == sectionAtom))
  10050. keep = false;
  10051. if (keep)
  10052. preservedMeta.append(*LINK(cur));
  10053. else
  10054. changed = true;
  10055. }
  10056. if (changed)
  10057. {
  10058. if (preservedMeta.ordinality() == 0)
  10059. return transformedBody.getClear();
  10060. return createMetaAnnotation(transformedBody.getClear(), preservedMeta);
  10061. }
  10062. break; // default action
  10063. }
  10064. case annotate_symbol:
  10065. {
  10066. if (hasNamedSymbol(transformedBody))
  10067. return transformedBody.getClear();
  10068. _ATOM name = expr->queryName();
  10069. if (options.commonUniqueNameAttributes)
  10070. {
  10071. _ATOM simpleName = simplifyUniqueAttributeName(name);
  10072. if (simpleName)
  10073. return cloneSymbol(expr, simpleName, transformedBody, NULL, NULL);
  10074. }
  10075. break;
  10076. }
  10077. } // switch(kind)
  10078. if (body == transformedBody)
  10079. return LINK(expr);
  10080. return expr->cloneAnnotation(transformedBody);
  10081. }
  10082. //MORE: Types of all pattern attributes should also be normalized. Currently they aren't which causes discrepancies between types
  10083. //for ghoogle.hql. It could conceivably cause problems later on.
  10084. if (forwardReferences.ordinality())
  10085. {
  10086. if (op == no_pat_use && expr->hasProperty(nameAtom))
  10087. return transformPatNamedUse(expr);
  10088. if (op == no_pat_instance)
  10089. {
  10090. OwnedHqlExpr ret = queryTransformPatternDefine (expr);
  10091. if (ret)
  10092. return ret.getClear();
  10093. }
  10094. }
  10095. IHqlExpression * sideEffects = expr->queryProperty(_sideEffect_Atom);
  10096. if (sideEffects)
  10097. {
  10098. HqlExprArray args;
  10099. unwindChildren(args, expr);
  10100. args.zap(*sideEffects);
  10101. OwnedHqlExpr next = createCompound(LINK(sideEffects->queryChild(0)), expr->clone(args));
  10102. return transform(next);
  10103. }
  10104. if (!options.constantFoldNormalize)
  10105. return createTransformedBody(expr);
  10106. switch (op)
  10107. {
  10108. case no_if:
  10109. {
  10110. OwnedHqlExpr cond = transform(expr->queryChild(0));
  10111. IValue * condValue = cond->queryValue();
  10112. if (condValue)
  10113. {
  10114. unsigned idx = condValue->getBoolValue() ? 1 : 2;
  10115. IHqlExpression * branch = expr->queryChild(idx);
  10116. if (branch)
  10117. return transform(branch);
  10118. assertex(expr->isAction());
  10119. return createValue(no_null, makeVoidType());
  10120. }
  10121. break;
  10122. }
  10123. case no_choose:
  10124. case no_chooseds:
  10125. {
  10126. OwnedHqlExpr cond = transform(expr->queryChild(0));
  10127. IValue * condValue = cond->queryValue();
  10128. if (condValue)
  10129. {
  10130. unsigned idx = (unsigned)condValue->getIntValue();
  10131. IHqlExpression * branch = queryRealChild(expr, idx);
  10132. if (branch)
  10133. return transform(branch);
  10134. IHqlExpression * defaultExpr = queryLastNonAttribute(expr);
  10135. return transform(defaultExpr);
  10136. }
  10137. break;
  10138. }
  10139. case no_and:
  10140. {
  10141. IHqlExpression * left = expr->queryChild(0);
  10142. IHqlExpression * right = expr->queryChild(1);
  10143. OwnedHqlExpr simpleRight = transformSimpleConst(right);
  10144. if (simpleRight->queryValue())
  10145. {
  10146. if (simpleRight->queryValue()->getBoolValue())
  10147. return transform(left);
  10148. return simpleRight.getClear();
  10149. }
  10150. OwnedHqlExpr newLeft = transform(left);
  10151. IValue * leftValue = newLeft->queryValue();
  10152. if (leftValue)
  10153. {
  10154. if (!leftValue->getBoolValue())
  10155. return newLeft.getClear();
  10156. return transform(right);
  10157. }
  10158. break;
  10159. }
  10160. case no_or:
  10161. {
  10162. IHqlExpression * left = expr->queryChild(0);
  10163. IHqlExpression * right = expr->queryChild(1);
  10164. OwnedHqlExpr simpleRight = transformSimpleConst(right);
  10165. if (simpleRight->queryValue())
  10166. {
  10167. if (!simpleRight->queryValue()->getBoolValue())
  10168. return transform(left);
  10169. return simpleRight.getClear();
  10170. }
  10171. OwnedHqlExpr newLeft = transform(left);
  10172. IValue * leftValue = newLeft->queryValue();
  10173. if (leftValue)
  10174. {
  10175. if (leftValue->getBoolValue())
  10176. return newLeft.getClear();
  10177. return transform(right);
  10178. }
  10179. break;
  10180. }
  10181. case no_attr:
  10182. if (expr->queryName() == _original_Atom)
  10183. return LINK(expr);
  10184. break;
  10185. }
  10186. OwnedHqlExpr transformed = createTransformedBody(expr);
  10187. return foldConstantOperator(transformed, 0, NULL);
  10188. }
  10189. IHqlExpression * HqlTreeNormalizer::createTransformedBody(IHqlExpression * expr)
  10190. {
  10191. node_operator op = expr->getOperator();
  10192. switch (op)
  10193. {
  10194. case no_constant:
  10195. return LINK(expr); // avoid creating an array in default code...
  10196. case no_case:
  10197. if (isVoidOrDatasetOrList(expr) || expr->isDictionary())
  10198. return transformCaseToChoose(expr);
  10199. break;
  10200. case no_map:
  10201. if (isVoidOrDatasetOrList(expr) || expr->isDictionary())
  10202. return transformMap(expr);
  10203. break;
  10204. case no_transform:
  10205. //optimize location of skips
  10206. return transformTransform(expr);
  10207. case no_getresult:
  10208. case no_newtransform:
  10209. {
  10210. IHqlExpression * record = queryOriginalRecord(expr);
  10211. if (record)
  10212. ::Release(transform(record));
  10213. LinkedHqlExpr cleaned = expr;
  10214. //remove any no_assignall children... could really do for no_transform as well... would reduce clarity of graph ecl
  10215. if ((op == no_newtransform) && queryChildOperator(no_assignall, expr))
  10216. {
  10217. HqlExprArray args;
  10218. ForEachChild(i, expr)
  10219. expr->queryChild(i)->unwindList(args, no_assignall);
  10220. cleaned.setown(expr->clone(args));
  10221. }
  10222. return Parent::createTransformed(cleaned);
  10223. }
  10224. case no_usertable:
  10225. case no_selectfields:
  10226. {
  10227. OwnedHqlExpr newRecord = transform(expr->queryChild(1));
  10228. return convertSelectToProject(newRecord, expr);
  10229. }
  10230. case no_parse:
  10231. return removeDefaultsFromExpr(expr, 3, no_newparse);
  10232. case no_xmlparse:
  10233. return removeDefaultsFromExpr(expr, 2, no_newxmlparse);
  10234. case no_soapcall:
  10235. return removeDefaultsFromExpr(expr, 2, no_newsoapcall);
  10236. case no_soapcall_ds:
  10237. return removeDefaultsFromExpr(expr, 3, no_newsoapcall_ds);
  10238. case no_soapaction_ds:
  10239. return removeDefaultsFromExpr(expr, 3, no_newsoapaction_ds);
  10240. #ifdef OPTIMIZE_IMPLICIT_CAST
  10241. //Following is a good idea, but makes some things worse because of the way we currently spot table invariants.
  10242. case no_implicitcast:
  10243. {
  10244. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  10245. return ensureExprType(transformed->queryChild(0), transformed->queryType());
  10246. }
  10247. #endif
  10248. case no_record:
  10249. {
  10250. OwnedHqlExpr transformed = completeTransform(expr);
  10251. if (transformed->hasProperty(packedAtom))
  10252. transformed.setown(getPackedRecord(transformed));
  10253. if (options.ensureRecordsHaveSymbols)
  10254. {
  10255. //Ensure all records only have a single unique name, and transform it here so that record types also map to that unique name
  10256. IHqlExpression * recordSymbol = queryLocationIndependentExtra(expr)->symbol;
  10257. if (recordSymbol)
  10258. {
  10259. _ATOM name = recordSymbol->queryName();
  10260. _ATOM simpleName = simplifyUniqueAttributeName(name);
  10261. if (simpleName)
  10262. name = simpleName;
  10263. return createSymbol(name, transformed.getClear(), ob_private);
  10264. }
  10265. }
  10266. return transformed.getClear();
  10267. }
  10268. case no_left:
  10269. case no_right:
  10270. case no_top:
  10271. case no_self:
  10272. {
  10273. HqlExprArray children;
  10274. IHqlExpression * record = expr->queryChild(0);
  10275. //Ensure that the first parameter to one of these nodes is the body of the record, not a named symbol
  10276. if (record)
  10277. {
  10278. OwnedHqlExpr transformedRecord = transform(record);
  10279. children.append(*LINK(transformedRecord->queryBody()));
  10280. }
  10281. return completeTransform(expr, children);
  10282. }
  10283. case no_field:
  10284. {
  10285. //Remove the default values...
  10286. HqlExprArray children;
  10287. bool same = true;
  10288. ForEachChild(idx, expr)
  10289. {
  10290. IHqlExpression * cur = expr->queryChild(idx);
  10291. if (cur->isAttribute())
  10292. {
  10293. IHqlExpression * transformed = transform(cur);
  10294. children.append(*transformed);
  10295. if (cur != transformed)
  10296. same = false;
  10297. }
  10298. else
  10299. same = false;
  10300. }
  10301. ITypeInfo * type = expr->queryType();
  10302. OwnedITypeInfo newType = transformType(type);
  10303. if (type != newType)
  10304. return createField(expr->queryName(), newType.getClear(), children);
  10305. if (same)
  10306. return LINK(expr);
  10307. return expr->clone(children);
  10308. }
  10309. case no_trim:
  10310. //TRIM(x,RIGHT) should be represented the same way as TRIM(x) - and it's more efficient
  10311. if ((expr->numChildren() == 2) && (expr->queryChild(1)->queryName() == rightAtom))
  10312. {
  10313. HqlExprArray children;
  10314. children.append(*transform(expr->queryChild(0)));
  10315. return expr->clone(children);
  10316. }
  10317. break;
  10318. case no_pat_pattern:
  10319. return LINK(expr->queryChild(1));
  10320. case no_temptable:
  10321. return transformTempTable(expr);
  10322. case no_temprow:
  10323. return transformTempRow(expr);
  10324. case no_keyindex:
  10325. return transformKeyIndex(expr);
  10326. case no_newkeyindex:
  10327. // seenIndex = true;
  10328. return transformNewKeyIndex(expr);
  10329. case no_table:
  10330. if (expr->hasProperty(localUploadAtom))
  10331. seenLocalUpload = true;
  10332. return transformTable(expr);
  10333. case no_pat_checkin:
  10334. if (expr->queryChild(0)->getOperator() == no_pat_anychar)
  10335. {
  10336. IHqlExpression * transformed = transformPatCheckIn(expr);
  10337. if (transformed)
  10338. return transformed;
  10339. }
  10340. break;
  10341. case no_denormalize:
  10342. case no_denormalizegroup:
  10343. {
  10344. OwnedHqlExpr transformed = validateKeyedJoin(expr);
  10345. //Explicitly add a left outer flag to a denormalize if no other join type is specified.
  10346. //Do here rather than in parser so crc for persists isn't changed.
  10347. if (!transformed->hasProperty(innerAtom) &&
  10348. !transformed->hasProperty(leftonlyAtom) && !transformed->hasProperty(leftouterAtom) &&
  10349. !transformed->hasProperty(rightonlyAtom) && !transformed->hasProperty(rightouterAtom) &&
  10350. !transformed->hasProperty(fullonlyAtom) && !transformed->hasProperty(fullouterAtom))
  10351. {
  10352. return appendOwnedOperand(transformed, createAttribute(leftouterAtom));
  10353. }
  10354. return transformed.getClear();
  10355. }
  10356. case no_colon:
  10357. {
  10358. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  10359. LinkedHqlExpr value = transformed->queryChild(0);
  10360. bool same = true;
  10361. bool needToPreserveOriginal = false;
  10362. HqlExprArray actions, scheduleActions;
  10363. unwindChildren(actions, transformed, 1);
  10364. ForEachItemInRev(i, actions)
  10365. {
  10366. IHqlExpression & cur = actions.item(i);
  10367. IHqlExpression * replacement = NULL;
  10368. switch (cur.getOperator())
  10369. {
  10370. case no_global:
  10371. {
  10372. HqlExprArray scopeArgs;
  10373. scopeArgs.append(*LINK(value));
  10374. unwindChildren(scopeArgs, &cur);
  10375. replacement = createWrapper(no_globalscope, scopeArgs);
  10376. break;
  10377. }
  10378. case no_persist:
  10379. {
  10380. needToPreserveOriginal = true;
  10381. same = false;
  10382. break;
  10383. }
  10384. case no_attr:
  10385. case no_attr_expr:
  10386. case no_attr_link:
  10387. if (cur.queryName() == defineAtom)
  10388. replacement = createValue(no_define, transformed->getType(), LINK(value), LINK(cur.queryChild(0)));
  10389. break;
  10390. //Separate scheduled items into a separate no_colon.
  10391. case no_when:
  10392. case no_priority:
  10393. scheduleActions.append(OLINK(cur));
  10394. actions.remove(i);
  10395. same = false;
  10396. break;
  10397. }
  10398. if (replacement)
  10399. {
  10400. value.setown(replacement);
  10401. actions.remove(i);
  10402. same = false;
  10403. }
  10404. }
  10405. if (same)
  10406. return transformed.getClear();
  10407. if (needToPreserveOriginal)
  10408. actions.append(*createAttribute(_original_Atom, LINK(expr->queryChild(0))));
  10409. OwnedHqlExpr result;
  10410. if (actions.ordinality() == 0)
  10411. result.set(value);
  10412. else
  10413. result.setown(createColon(LINK(value), actions));
  10414. if (scheduleActions.ordinality())
  10415. result.setown(createColon(result.getClear(), scheduleActions));
  10416. return result.getClear();
  10417. }
  10418. case no_evaluate:
  10419. return transformEvaluate(expr);
  10420. case no_selectnth:
  10421. {
  10422. IHqlExpression * ds = expr->queryChild(0);
  10423. if (isGrouped(ds))
  10424. {
  10425. OwnedHqlExpr newChild = createDataset(no_group, LINK(ds));
  10426. OwnedHqlExpr mapped = replaceChild(expr, 0, newChild);
  10427. return transform(mapped);
  10428. }
  10429. break;
  10430. }
  10431. case no_assert_ds:
  10432. if (options.removeAsserts)
  10433. return transform(expr->queryChild(0));
  10434. break;
  10435. case no_section:
  10436. case no_sectioninput:
  10437. if (!options.allowSections)
  10438. return transform(expr->queryChild(0));
  10439. break;
  10440. case no_type:
  10441. return transformAlienType(expr);
  10442. case no_param:
  10443. {
  10444. //no_param may be retained by library call definitions + they need the type transforming for consistency
  10445. ITypeInfo * type = expr->queryType();
  10446. OwnedITypeInfo newType = transformType(type);
  10447. if (type != newType)
  10448. {
  10449. //Attributes shouldn't need transforming, but simplest
  10450. HqlExprArray attrs;
  10451. transformChildren(expr, attrs);
  10452. return createParameter(expr->queryName(), (unsigned)expr->querySequenceExtra(), newType.getClear(), attrs);
  10453. }
  10454. break;
  10455. }
  10456. case no_libraryscope:
  10457. {
  10458. OwnedHqlExpr ret = transformScope(expr);
  10459. if (translator.targetHThor())
  10460. return appendOwnedOperand(ret, createAttribute(_noStreaming_Atom));
  10461. return ret.getClear();
  10462. }
  10463. case no_virtualscope:
  10464. return transformScope(expr);
  10465. case no_libraryscopeinstance:
  10466. {
  10467. IHqlExpression * oldFunction = expr->queryDefinition();
  10468. OwnedHqlExpr newFunction = transform(oldFunction);
  10469. HqlExprArray children;
  10470. bool same = true;
  10471. ForEachChild(i, expr)
  10472. {
  10473. LinkedHqlExpr cur = expr->queryChild(i);
  10474. if (cur->getOperator() == no_virtualscope)
  10475. {
  10476. cur.setown(checkCreateConcreteModule(NULL, cur, cur->queryProperty(_location_Atom)));
  10477. assertex(cur->getOperator() != no_virtualscope);
  10478. same = false;
  10479. }
  10480. else if (cur->getOperator() == no_purevirtual)
  10481. {
  10482. _ATOM name = cur->queryName();
  10483. throwError1(HQLERR_LibraryMemberArgNotDefined, name ? name->str() : "");
  10484. }
  10485. IHqlExpression * transformed = transform(cur);
  10486. children.append(*transformed);
  10487. if (cur != transformed)
  10488. same = false;
  10489. }
  10490. if (same && (oldFunction == newFunction))
  10491. return LINK(expr);
  10492. return createLibraryInstance(newFunction.getClear(), children);
  10493. }
  10494. case no_transformascii:
  10495. case no_transformebcdic:
  10496. {
  10497. HqlExprArray children;
  10498. transformChildren(expr, children);
  10499. OwnedHqlExpr transformed = createDataset(no_hqlproject, children);
  10500. return transform(transformed);
  10501. }
  10502. case no_join:
  10503. {
  10504. OwnedHqlExpr transformed = validateKeyedJoin(expr);
  10505. if (isSelfJoin(expr))
  10506. {
  10507. HqlExprArray children;
  10508. unwindChildren(children, transformed);
  10509. children.replace(*createAttribute(_selfJoinPlaceholder_Atom), 1); // replace the 1st dataset with an attribute so parameters are still in the same place.
  10510. return createDataset(no_selfjoin, children);
  10511. }
  10512. if (isKeyedJoin(transformed) && translator.targetRoxie() && !expr->hasProperty(_ordered_Atom))
  10513. return appendOwnedOperand(transformed, createAttribute(_ordered_Atom));
  10514. return transformed.getClear();
  10515. }
  10516. case no_projectrow:
  10517. {
  10518. //Work around a problem where left is ambiguous - either outer LEFT, or left within this ROW
  10519. //Not a full solution since PROJECT(PROJECT(LEFT),t(LEFT)) where project(LEFT) doesn't change types
  10520. //would suffer from the same problem.
  10521. //Remove as many instances of PROJECT(row, transform) as we can since ROW(transform) is handled more efficient.
  10522. HqlExprArray children;
  10523. OwnedHqlExpr ds = transform(expr->queryChild(0));
  10524. node_operator dsOp = ds->getOperator();
  10525. if (dsOp == no_left)
  10526. // if (isAlwaysActiveRow(ds))
  10527. {
  10528. //MORE: The call to replaceExpression below isn't actually correct unless selectors are unique
  10529. //this optimization may have to move elsewhere.
  10530. OwnedHqlExpr newTransform = transform(expr->queryChild(1));
  10531. OwnedHqlExpr newSel = transform(querySelSeq(expr));
  10532. OwnedHqlExpr myLeft = createSelector(no_left, ds, newSel);
  10533. OwnedHqlExpr replaced = quickFullReplaceExpression(newTransform, myLeft, ds);
  10534. return createRow(no_createrow, LINK(replaced));
  10535. }
  10536. children.append(*ds.getClear());
  10537. return completeTransform(expr, children);
  10538. }
  10539. case no_sorted:
  10540. return transformIfAssert(no_assertsorted, expr);
  10541. case no_grouped:
  10542. return transformIfAssert(no_assertgrouped, expr);
  10543. case no_distributed:
  10544. //remove distributed(x)
  10545. if (expr->hasProperty(unknownAtom))
  10546. return transform(expr->queryChild(0));
  10547. return transformIfAssert(no_assertdistributed, expr);
  10548. #if defined(MAP_PROJECT_TO_USERTABLE)
  10549. case no_hqlproject:
  10550. if (!isCountProject(expr))
  10551. {
  10552. HqlExprArray children;
  10553. transformChildren(expr, children);
  10554. IHqlExpression * ds = &children.item(0);
  10555. OwnedHqlExpr left = createSelector(no_left, ds, querySelSeq(expr));
  10556. OwnedHqlExpr mapped = replaceExpression(&children.item(1), left, ds->queryNormalizedSelector());
  10557. children.add(*LINK(mapped->queryRecord()), 1);
  10558. HqlExprArray assigns;
  10559. unwindChildren(assigns, mapped);
  10560. children.replace(*createValue(no_newtransform, mapped->getType(), assigns), 2);
  10561. OwnedHqlExpr transformed = createDataset(no_newusertable, children);
  10562. return transform(transformed);
  10563. }
  10564. break;
  10565. #endif
  10566. case no_comma:
  10567. case no_compound:
  10568. if (expr->queryChild(0)->getOperator() == no_setmeta)
  10569. return transform(expr->queryChild(1));
  10570. if ((op == no_compound) && expr->isAction())
  10571. {
  10572. HqlExprArray args;
  10573. expr->unwindList(args, no_compound);
  10574. OwnedHqlExpr compound = createAction(no_actionlist, args);
  10575. return transform(compound);
  10576. }
  10577. break;
  10578. case no_actionlist:
  10579. return transformActionList(expr);
  10580. case no_forcelocal:
  10581. case no_forcenolocal:
  10582. case no_allnodes:
  10583. case no_thisnode:
  10584. seenForceLocal = true;
  10585. break;
  10586. case no_enth:
  10587. {
  10588. HqlExprArray children;
  10589. bool same = transformChildren(expr, children);
  10590. IHqlExpression * denom = queryRealChild(expr, 2);
  10591. if (!denom && !expr->queryProperty(localAtom))
  10592. {
  10593. children.add(*createValue(no_count, LINK(defaultIntegralType), LINK(&children.item(0))), 2);
  10594. same = false;
  10595. }
  10596. if (!same)
  10597. return expr->clone(children);
  10598. return LINK(expr);
  10599. }
  10600. case no_assertconstant:
  10601. {
  10602. IHqlExpression * child = expr->queryChild(0);
  10603. OwnedHqlExpr ret = transform(child);
  10604. OwnedHqlExpr folded = foldHqlExpression(ret, NULL, HFOforcefold);
  10605. if (!folded->isConstant())
  10606. {
  10607. StringBuffer s;
  10608. getExprECL(child, s);
  10609. translator.ERRORAT1(expr->queryChild(1), HQLERR_ExpectedConstant, s.str());
  10610. }
  10611. return folded.getClear();
  10612. }
  10613. case no_pat_instance:
  10614. {
  10615. OwnedHqlExpr child = transform(expr->queryChild(0));
  10616. if (child->getOperator() == no_pat_instance && child->hasProperty(tempAtom))
  10617. return createValue(no_pat_instance, child->getType(), LINK(child->queryChild(0)));
  10618. //default action
  10619. break;
  10620. }
  10621. case no_if:
  10622. {
  10623. //Parameters are being used a lot to select between two items in inside a function/module
  10624. //so much better if we trim the tree earlier....
  10625. IValue * value = expr->queryChild(0)->queryValue();
  10626. if (value && !expr->isAction())
  10627. {
  10628. unsigned branch = value->getBoolValue() ? 1 : 2;
  10629. IHqlExpression * arg = expr->queryChild(branch);
  10630. if (arg)
  10631. return transform(arg);
  10632. }
  10633. break;
  10634. }
  10635. case no_stored:
  10636. {
  10637. HqlExprArray children;
  10638. OwnedHqlExpr name = transform(expr->queryChild(0));
  10639. children.append(*lowerCaseHqlExpr(name));
  10640. return completeTransform(expr, children);
  10641. }
  10642. case no_merge:
  10643. return transformMerge(expr);
  10644. //yuk: Sets of datasets need special casing because their type isn't implicitly calculated from their inputs.
  10645. case no_datasetlist:
  10646. case no_rowset:
  10647. {
  10648. HqlExprArray children;
  10649. transformChildren(expr, children);
  10650. OwnedITypeInfo setType = makeSetType(children.item(0).getType());
  10651. return createValue(expr->getOperator(), setType.getClear(), children);
  10652. }
  10653. case no_rowsetrange:
  10654. {
  10655. HqlExprArray children;
  10656. transformChildren(expr, children);
  10657. OwnedITypeInfo setType = children.item(0).getType();
  10658. return createValue(expr->getOperator(), setType.getClear(), children);
  10659. }
  10660. case no_buildindex:
  10661. {
  10662. //Normalize the index build by splitting out the sort here, so that constant percolating
  10663. //is also done on these parameters
  10664. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  10665. loop
  10666. {
  10667. IHqlExpression * ret = normalizeIndexBuild(transformed, options.sortIndexPayload, !translator.targetThor(), options.implicitSubSort);
  10668. if (!ret)
  10669. return LINK(transformed);
  10670. transformed.setown(ret);
  10671. }
  10672. }
  10673. case no_keyed:
  10674. {
  10675. HqlExprArray args;
  10676. bool same = transformChildren(expr, args);
  10677. IHqlExpression * ds = &args.item(0);
  10678. if ((ds->getOperator() == no_section) || (ds->getOperator() == no_sectioninput))
  10679. {
  10680. args.replace(*LINK(ds->queryChild(0)), 0);
  10681. same = false;
  10682. }
  10683. if (!same)
  10684. return expr->clone(args);
  10685. return LINK(expr);
  10686. }
  10687. case no_eclcrc:
  10688. {
  10689. OwnedHqlExpr arg = transform(expr->queryChild(0)->queryChild(0));
  10690. return createConstant(expr->queryType()->castFrom(true, (__int64)getExpressionCRC(arg)));
  10691. }
  10692. case no_cast:
  10693. if (options.normalizeExplicitCasts)
  10694. {
  10695. Owned<ITypeInfo> type = transformType(expr->queryType());
  10696. OwnedHqlExpr arg = transform(expr->queryChild(0));
  10697. return createValue(no_implicitcast, type.getClear(), arg.getClear());
  10698. }
  10699. break;
  10700. #if 0
  10701. //This code adds a assertsorted activity after an nary-join, but I don't think it is actually correct, so removed. I may revisit.
  10702. case no_nwayjoin:
  10703. if (expr->hasProperty(assertAtom) && !removeAsserts)
  10704. {
  10705. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);;
  10706. IHqlExpression * ds = transformed->queryChild(0);
  10707. IHqlExpression * selSeq = querySelSeq(transformed);
  10708. OwnedHqlExpr left = createSelector(no_left, ds, selSeq);
  10709. IHqlExpression * sortOrder = transformed->queryChild(3);
  10710. HqlExprArray args;
  10711. args.append(*LINK(transformed));
  10712. //MORE: Need fixing once join can have a different output format
  10713. args.append(*replaceSelector(sortOrder, left, transformed->queryNormalizedSelector()));
  10714. return createDataset(no_assertsorted, args);
  10715. }
  10716. break;
  10717. #endif
  10718. case no_attr:
  10719. case no_attr_link:
  10720. case no_attr_expr:
  10721. {
  10722. _ATOM name = expr->queryName();
  10723. if ((name == _uid_Atom) && (expr->numChildren() > 0))
  10724. {
  10725. //Make sure we ignore any line number information on the parameters mangled with the uid - otherwise
  10726. //they may create too many unique ids.
  10727. IHqlExpression * normalForm = queryLocationIndependent(expr);
  10728. if (normalForm != expr)
  10729. return transform(normalForm);
  10730. return ::createUniqueId();
  10731. }
  10732. #ifdef USE_SELSEQ_UID
  10733. if (name == _selectorSequence_Atom)
  10734. {
  10735. //Ensure parameterised sequences generate a unique sequence number...
  10736. //Not sure the following is really necessary, but will reduce in memory tree size....
  10737. //also saves complications from having weird attributes in the tree
  10738. if (expr->numChildren() > 0)
  10739. {
  10740. //Make sure we ignore any line number information on the parameters mangled with the uid - otherwise
  10741. //they may create too many unique ids.
  10742. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  10743. IHqlExpression * normalForm = queryLocationIndependent(transformed);
  10744. OwnedHqlExpr ret;
  10745. if (normalForm != expr)
  10746. {
  10747. IHqlExpression * mapped = queryAlreadyTransformed(normalForm);
  10748. if (!mapped)
  10749. {
  10750. ret.setown(createSelectorSequence());
  10751. setTransformed(normalForm, ret);
  10752. }
  10753. else
  10754. ret.set(mapped);
  10755. }
  10756. else
  10757. ret.setown(createSelectorSequence());
  10758. return ret.getClear();
  10759. }
  10760. }
  10761. #endif
  10762. //If a named symbol is used as an argument to maxlength you can end up with a situation
  10763. //where records are identical except for that named symbol.
  10764. //If f(a + b) is then optimized to b this can lead to incompatible selectors, since
  10765. //a and b are "compatible", but not identical.
  10766. //This then causes chaos, so strip them as a precaution... but it is only a partial solution.
  10767. if (name == maxLengthAtom || name == maxCountAtom)
  10768. return transformChildrenNoAnnotations(expr);
  10769. break;
  10770. }
  10771. case no_call:
  10772. return transformCall(expr);
  10773. case no_externalcall:
  10774. //Yuk.... Because we ensure that all records have a name, we need to make sure that external functions that return records
  10775. //also have there return value normalized - otherwise (jtolbert2.xhql) you can create an ambiguity
  10776. //We could also want to do this for user functions - but better would be to have a different node type.
  10777. if (options.ensureRecordsHaveSymbols)
  10778. {
  10779. if (expr->queryRecord())
  10780. return transformExternalCall(expr);
  10781. }
  10782. break;
  10783. case no_external:
  10784. {
  10785. ITypeInfo * type = expr->queryType();
  10786. OwnedITypeInfo newType = transformType(type);
  10787. HqlExprArray args;
  10788. bool same = transformChildren(expr, args);
  10789. if (same && (type == newType))
  10790. return LINK(expr);
  10791. return createExternalReference(expr->queryName(), newType.getClear(), args);
  10792. }
  10793. case no_outputscalar:
  10794. if (options.outputRowsAsDatasets && expr->queryChild(0)->isDatarow())
  10795. {
  10796. HqlExprArray args;
  10797. bool same = transformChildren(expr, args);
  10798. args.replace(*createDatasetFromRow(LINK(&args.item(0))), 0);
  10799. return createValue(no_output, makeVoidType(), args);
  10800. }
  10801. break;
  10802. case no_nameof:
  10803. {
  10804. OwnedHqlExpr newChild = transform(expr->queryChild(0));
  10805. switch (newChild->getOperator())
  10806. {
  10807. case no_newkeyindex:
  10808. return LINK(newChild->queryChild(3));
  10809. case no_table:
  10810. return LINK(newChild->queryChild(0));
  10811. default:
  10812. throwError(HQLERR_CannotDeduceNameDataset);
  10813. }
  10814. break;
  10815. }
  10816. case no_assertkeyed:
  10817. {
  10818. //Ensure assertkeyed is tagged with the selectors of each of the fields that are keyed, otherwise
  10819. //when expressions are constant folded, the information about keyed fields is lost.
  10820. HqlExprArray children;
  10821. transformChildren(expr, children);
  10822. HqlExprArray args;
  10823. gatherPotentialSelectors(args, expr);
  10824. OwnedHqlExpr selectors = createExprAttribute(_selectors_Atom, args);
  10825. children.append(*transform(selectors));
  10826. return expr->clone(children);
  10827. }
  10828. case no_sequence:
  10829. return getSizetConstant(nextSequenceValue++);
  10830. case no_filter:
  10831. return transformWithinFilter(expr);
  10832. case no_executewhen:
  10833. return transformExecuteWhen(expr);
  10834. case no_funcdef:
  10835. {
  10836. HqlExprArray children;
  10837. if (transformChildren(expr, children))
  10838. return LINK(expr);
  10839. return createFunctionDefinition(expr->queryName(), children);
  10840. }
  10841. case no_debug_option_value:
  10842. {
  10843. if (!matchesConstantString(expr->queryChild(0), "targetClusterType", true))
  10844. return getDebugValueExpr(translator.wu(), expr);
  10845. break;
  10846. }
  10847. case no_loop:
  10848. {
  10849. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  10850. IHqlExpression * loopCond = queryRealChild(transformed, 3);
  10851. if (loopCond)
  10852. {
  10853. //Create a firstCond attribute so that the condition for whether to execute the loop
  10854. //the first time will be efficiently optimized.
  10855. IHqlExpression * dataset = transformed->queryChild(0);
  10856. IHqlExpression * filter = queryRealChild(transformed, 2);
  10857. IHqlExpression * rowsid = transformed->queryProperty(_rowsid_Atom);
  10858. IHqlExpression * selSeq = querySelSeq(transformed);
  10859. IHqlExpression * counter = queryPropertyChild(expr, _countProject_Atom, 0);
  10860. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  10861. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(left), LINK(rowsid));
  10862. OwnedHqlExpr initialLoopDataset = LINK(dataset);
  10863. if (filter)
  10864. {
  10865. //If there is a loop filter then the global condition is applied to dataset filtered by that.
  10866. OwnedHqlExpr mappedFilter = replaceSelector(filter, left, dataset);
  10867. initialLoopDataset.setown(createDataset(no_filter, initialLoopDataset.getClear(), LINK(mappedFilter)));
  10868. }
  10869. OwnedHqlExpr firstCond = replaceExpression(loopCond, rowsExpr, initialLoopDataset);
  10870. if (counter)
  10871. {
  10872. //Whether to evaluate the 1st time round the loop requires COUNTER=1
  10873. OwnedHqlExpr one = createConstant(createIntValue(1, counter->getType()));
  10874. firstCond.setown(replaceExpression(firstCond, counter, one));
  10875. }
  10876. return appendOwnedOperand(transformed, createExprAttribute(_loopFirst_Atom, firstCond.getClear()));
  10877. }
  10878. return transformed.getClear();
  10879. }
  10880. break;
  10881. }
  10882. unsigned max = expr->numChildren();
  10883. if (max == 0)
  10884. return LINK(expr);
  10885. bool same = true;
  10886. HqlExprArray children;
  10887. children.ensure(max);
  10888. for (unsigned idx=0;idx<max;idx++)
  10889. {
  10890. IHqlExpression * child = expr->queryChild(idx);
  10891. IHqlExpression * tchild = transform(child);
  10892. children.append(*tchild);
  10893. if (child != tchild)
  10894. same = false;
  10895. }
  10896. //MORE: Test for pattern type here!
  10897. if (!same)
  10898. return expr->clone(children);
  10899. return LINK(expr);
  10900. }
  10901. IHqlExpression * HqlTreeNormalizer::createTransformedSelector(IHqlExpression * expr)
  10902. {
  10903. throwUnexpected();
  10904. }
  10905. IHqlExpression * normalizeRecord(HqlCppTranslator & translator, IHqlExpression * record)
  10906. {
  10907. HqlTreeNormalizer normalizer(translator);
  10908. HqlExprArray transformed;
  10909. return normalizer.transformRoot(record);
  10910. }
  10911. void normalizeHqlTree(HqlCppTranslator & translator, HqlExprArray & exprs)
  10912. {
  10913. bool seenForceLocal;
  10914. bool seenLocalUpload;
  10915. {
  10916. //First iterate through the expressions and call queryLocationIndependent() to avoid nested transforms (which are less efficient)
  10917. // ForEachItemIn(iInit, exprs)
  10918. // queryLocationIndependent(&exprs.item(iInit));
  10919. unsigned time = msTick();
  10920. HqlTreeNormalizer normalizer(translator);
  10921. HqlExprArray transformed;
  10922. normalizer.analyseArray(exprs, 0);
  10923. normalizer.transformRoot(exprs, transformed);
  10924. // logTreeStats(exprs);
  10925. // logTreeStats(transformed);
  10926. // DBGLOG("Before normalize %u unique expressions, after normalize %u unique expressions", getNumUniqueExpressions(exprs), getNumUniqueExpressions(transformed));
  10927. replaceArray(exprs, transformed);
  10928. seenForceLocal = normalizer.querySeenForceLocal();
  10929. seenLocalUpload = normalizer.querySeenLocalUpload();
  10930. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.initial", msTick()-time);
  10931. }
  10932. if (translator.queryOptions().constantFoldPostNormalize)
  10933. {
  10934. unsigned time = msTick();
  10935. HqlExprArray transformed;
  10936. quickFoldExpressions(transformed, exprs, NULL, 0);
  10937. replaceArray(exprs, transformed);
  10938. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.fold", msTick()-time);
  10939. }
  10940. translator.traceExpressions("before scope tag", exprs);
  10941. {
  10942. unsigned time = msTick();
  10943. HqlScopeTagger normalizer(translator.queryErrors());
  10944. HqlExprArray transformed;
  10945. normalizer.transformRoot(exprs, transformed);
  10946. replaceArray(exprs, transformed);
  10947. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.scope", msTick()-time);
  10948. normalizer.reportWarnings();
  10949. }
  10950. if (translator.queryOptions().normalizeLocations)
  10951. normalizeAnnotations(translator, exprs);
  10952. translator.traceExpressions("after scope tag", exprs);
  10953. {
  10954. unsigned time = msTick();
  10955. HqlLinkedChildRowTransformer transformer(translator.queryOptions().implicitLinkedChildRows);
  10956. HqlExprArray transformed;
  10957. transformer.transformArray(exprs, transformed);
  10958. replaceArray(exprs, transformed);
  10959. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.linkedChildRows", msTick()-time);;
  10960. }
  10961. if (seenLocalUpload)
  10962. {
  10963. LocalUploadTransformer transformer(translator.wu());
  10964. HqlExprArray transformed;
  10965. transformer.transformRoot(exprs, transformed);
  10966. replaceArray(exprs, transformed);
  10967. }
  10968. if (seenForceLocal)
  10969. {
  10970. //Add ,local to all sources, so that count(x) inside local() is differentiated from a global count(x)
  10971. ForceLocalTransformer localizer(translator.getTargetClusterType());
  10972. HqlExprArray transformed;
  10973. localizer.transformRoot(exprs, transformed);
  10974. replaceArray(exprs, transformed);
  10975. }
  10976. #ifdef USE_SELSEQ_UID
  10977. if (translator.queryOptions().detectAmbiguousSelector || translator.queryOptions().allowAmbiguousSelector)
  10978. {
  10979. LeftRightSelectorNormalizer transformer(translator.queryOptions().allowAmbiguousSelector);
  10980. transformer.analyseArray(exprs, 0);
  10981. if (!transformer.containsAmbiguity())
  10982. {
  10983. HqlExprArray transformed;
  10984. transformer.transformRoot(exprs, transformed);
  10985. replaceArray(exprs, transformed);
  10986. }
  10987. }
  10988. #endif
  10989. if (false)
  10990. {
  10991. NestedSelectorNormalizer transformer;
  10992. transformer.analyseArray(exprs, 0);
  10993. if (transformer.requiresTransforming())
  10994. {
  10995. HqlExprArray transformed;
  10996. transformer.transformRoot(exprs, transformed);
  10997. replaceArray(exprs, transformed);
  10998. }
  10999. }
  11000. #if 0
  11001. if (seenIndex)
  11002. {
  11003. FilteredIndexOptimizer transformer(true, false);
  11004. HqlExprArray transformed;
  11005. transformer.transformRoot(exprs, transformed);
  11006. replaceArray(exprs, transformed);
  11007. }
  11008. #endif
  11009. #ifdef _DEBUG
  11010. //spotPotentialDuplicateCode(exprs);
  11011. #endif
  11012. }
  11013. IHqlExpression * normalizeHqlTree(HqlCppTranslator & translator, IHqlExpression * expr)
  11014. {
  11015. HqlExprArray exprs;
  11016. expr->unwindList(exprs, no_comma);
  11017. normalizeHqlTree(translator, exprs);
  11018. return createComma(exprs);
  11019. }
  11020. void hoistNestedCompound(HqlCppTranslator & translator, HqlExprArray & exprs)
  11021. {
  11022. if (containsCompound(exprs))
  11023. {
  11024. NestedCompoundTransformer normalizer(translator);
  11025. normalizer.analyseArray(exprs, 0);
  11026. HqlExprArray transformed;
  11027. normalizer.transformRoot(exprs, transformed);
  11028. replaceArray(exprs, transformed);
  11029. }
  11030. }
  11031. void hoistNestedCompound(HqlCppTranslator & translator, WorkflowArray & workflow)
  11032. {
  11033. ForEachItemIn(i, workflow)
  11034. hoistNestedCompound(translator, workflow.item(i).queryExprs());
  11035. }
  11036. //---------------------------------------------------------------------------
  11037. static IHqlExpression * substituteClusterSize(unsigned numNodes, IHqlExpression * expr, ICodegenContextCallback * ctxCallback, IWorkUnit * wu);
  11038. static HqlTransformerInfo clusterSubstitueTransformerInfo("ClusterSubstitueTransformer");
  11039. class ClusterSubstitueTransformer : public NewHqlTransformer
  11040. {
  11041. public:
  11042. ClusterSubstitueTransformer(unsigned size, ICodegenContextCallback * _ctxCallback, IWorkUnit * _wu)
  11043. : NewHqlTransformer(clusterSubstitueTransformerInfo)
  11044. {
  11045. ctxCallback = _ctxCallback;
  11046. wu = _wu;
  11047. OwnedHqlExpr clusterSizeExpr = createValue(no_clustersize, makeIntType(4, false));
  11048. if (size)
  11049. clusterSizeValue.setown(getSizetConstant(size));
  11050. setTransformed(clusterSizeExpr, clusterSizeValue);
  11051. }
  11052. protected:
  11053. IHqlExpression * createTransformed(IHqlExpression * expr)
  11054. {
  11055. if (expr->isConstant())
  11056. return LINK(expr);
  11057. switch (expr->getOperator())
  11058. {
  11059. case no_clustersize:
  11060. //Cope if CLUSTERSIZE is assigned to a named symbol
  11061. if (clusterSizeValue)
  11062. return LINK(clusterSizeValue);
  11063. break;
  11064. case no_cluster:
  11065. return createSubstitutedChild(expr, expr->queryChild(1));
  11066. case no_colon:
  11067. {
  11068. ForEachChild(i, expr)
  11069. {
  11070. IHqlExpression * child = expr->queryChild(i);
  11071. if (child->getOperator() == no_persist)
  11072. {
  11073. IHqlExpression * cluster = queryRealChild(child, 1);
  11074. if (cluster && !isBlankString(cluster))
  11075. return createSubstitutedChild(expr, cluster);
  11076. }
  11077. else if (child->getOperator() == no_global)
  11078. {
  11079. IHqlExpression * cluster = queryRealChild(child, 0);
  11080. if (cluster && !isBlankString(cluster))
  11081. return createSubstitutedChild(expr, cluster);
  11082. }
  11083. }
  11084. break;
  11085. }
  11086. }
  11087. return NewHqlTransformer::createTransformed(expr);
  11088. }
  11089. IHqlExpression * createSubstitutedChild(IHqlExpression * expr, IHqlExpression * cluster)
  11090. {
  11091. StringBuffer clusterText;
  11092. getStringValue(clusterText, cluster);
  11093. if (clusterText.length())
  11094. ctxCallback->noteCluster(clusterText.str());
  11095. #if 0
  11096. Owned<IConstWUClusterInfo> clusterInfo = wu->getClusterInfo(clusterText.str());
  11097. if (clusterInfo)
  11098. {
  11099. unsigned numNodes = clusterInfo->getSize();
  11100. if (numNodes == 0) numNodes = 1;
  11101. HqlExprArray args;
  11102. unwindChildren(args, expr);
  11103. args.replace(*substituteClusterSize(numNodes, &args.item(0), ctxCallback, wu), 0);
  11104. return expr->clone(args);
  11105. }
  11106. #endif
  11107. return LINK(expr);
  11108. }
  11109. protected:
  11110. ICodegenContextCallback * ctxCallback;
  11111. IWorkUnit * wu;
  11112. OwnedHqlExpr clusterSizeValue;
  11113. };
  11114. IHqlExpression * substituteClusterSize(unsigned numNodes, IHqlExpression * expr, ICodegenContextCallback * ctxCallback, IWorkUnit * wu)
  11115. {
  11116. ClusterSubstitueTransformer transformer(numNodes, ctxCallback, wu);
  11117. return transformer.transformRoot(expr);
  11118. }
  11119. void HqlCppTranslator::substituteClusterSize(HqlExprArray & exprs)
  11120. {
  11121. unsigned numNodes = options.specifiedClusterSize;
  11122. ClusterSubstitueTransformer transformer(numNodes, ctxCallback, wu());
  11123. HqlExprArray transformed;
  11124. ForEachItemIn(i, exprs)
  11125. transformed.append(*transformer.transformRoot(&exprs.item(i)));
  11126. replaceArray(exprs, transformed);
  11127. }
  11128. IHqlExpression * HqlCppTranslator::separateLibraries(IHqlExpression * query, HqlExprArray & internalLibraries)
  11129. {
  11130. HqlExprArray exprs;
  11131. query->unwindList(exprs, no_comma);
  11132. traceExpressions("before transform graph for generation", exprs);
  11133. //Remove any meta entries from the tree.
  11134. ForEachItemInRev(i, exprs)
  11135. if (exprs.item(i).getOperator() == no_setmeta)
  11136. exprs.remove(i);
  11137. processEmbeddedLibraries(exprs, internalLibraries, isLibraryScope(query));
  11138. return createComma(exprs);
  11139. }
  11140. bool HqlCppTranslator::transformGraphForGeneration(HqlQueryContext & query, WorkflowArray & workflow)
  11141. {
  11142. HqlExprArray exprs;
  11143. if (isLibraryScope(query.expr))
  11144. outputLibrary->mapLogicalToImplementation(exprs, query.expr);
  11145. else
  11146. query.expr->unwindList(exprs, no_comma);
  11147. //Ensure the incoming query will be freed up when no longer used
  11148. query.expr.clear();
  11149. traceExpressions("before transform graph for generation", exprs);
  11150. //Don't change the engine if libraries are involved, otherwise things will get very confused.
  11151. unsigned timeCall = msTick();
  11152. expandDelayedFunctionCalls(queryErrors(), exprs);
  11153. DEBUG_TIMER("EclServer: tree transform: expand delayed calls", msTick()-timeCall);
  11154. unsigned time1 = msTick();
  11155. traceExpressions("before normalize", exprs);
  11156. normalizeHqlTree(*this, exprs);
  11157. DEBUG_TIMER("EclServer: tree transform: normalize", msTick()-time1);
  11158. if (wu()->getDebugValueBool("dumpIR", false))
  11159. EclIR::dump_ir(exprs);
  11160. checkNormalized(exprs);
  11161. #ifdef PICK_ENGINE_EARLY
  11162. if (options.pickBestEngine)
  11163. pickBestEngine(exprs);
  11164. #endif
  11165. allocateSequenceNumbers(exprs); // Added to all expressions/output statements etc.
  11166. traceExpressions("allocate Sequence", exprs);
  11167. checkNormalized(exprs);
  11168. if (options.generateLogicalGraph || options.generateLogicalGraphOnly)
  11169. {
  11170. LogicalGraphCreator creator(wu());
  11171. creator.createLogicalGraph(exprs);
  11172. if (options.generateLogicalGraphOnly)
  11173. return false;
  11174. curActivityId = creator.queryMaxActivityId();
  11175. }
  11176. traceExpressions("begin transformGraphForGeneration", exprs);
  11177. checkNormalized(exprs);
  11178. {
  11179. unsigned startTime = msTick();
  11180. substituteClusterSize(exprs);
  11181. DEBUG_TIMER("EclServer: tree transform: substituteClusterSize", msTick()-startTime);
  11182. }
  11183. if (options.globalFold)
  11184. {
  11185. unsigned startTime = msTick();
  11186. HqlExprArray folded;
  11187. unsigned foldOptions = DEFAULT_FOLD_OPTIONS;
  11188. if (options.foldConstantDatasets) foldOptions |= HFOconstantdatasets;
  11189. if (options.percolateConstants) foldOptions |= HFOpercolateconstants;
  11190. if (options.percolateFilters) foldOptions |= HFOpercolatefilters;
  11191. if (options.globalFoldOptions != (unsigned)-1)
  11192. foldOptions = options.globalFoldOptions;
  11193. foldHqlExpression(folded, exprs, foldOptions);
  11194. replaceArray(exprs, folded);
  11195. DEBUG_TIMER("EclServer: tree transform: global fold", msTick()-startTime);
  11196. }
  11197. traceExpressions("after global fold", exprs);
  11198. checkNormalized(exprs);
  11199. if (options.globalOptimize)
  11200. {
  11201. unsigned startTime = msTick();
  11202. HqlExprArray folded;
  11203. optimizeHqlExpression(folded, exprs, options.globalFold ? HOOfold : 0);
  11204. replaceArray(exprs, folded);
  11205. DEBUG_TIMER("EclServer: tree transform: global optimize", msTick()-startTime);
  11206. }
  11207. traceExpressions("alloc", exprs);
  11208. checkNormalized(exprs);
  11209. modifyOutputLocations(exprs);
  11210. if (exprs.ordinality() == 0)
  11211. return false; // No action needed
  11212. unsigned time4 = msTick();
  11213. ::extractWorkflow(*this, exprs, workflow);
  11214. traceExpressions("workflow", workflow);
  11215. checkNormalized(workflow);
  11216. DEBUG_TIMER("EclServer: tree transform: stored results", msTick()-time4);
  11217. #ifdef USE_SELSEQ_UID
  11218. if (options.normalizeSelectorSequence)
  11219. {
  11220. unsigned time = msTick();
  11221. ForEachItemIn(i, workflow)
  11222. {
  11223. LeftRightTransformer normalizer;
  11224. normalizer.process(workflow.item(i).queryExprs());
  11225. }
  11226. DEBUG_TIMERX(queryTimeReporter(), "EclServer: tree transform: left right", msTick()-time);
  11227. //traceExpressions("after implicit alias", workflow);
  11228. }
  11229. #endif
  11230. if (queryOptions().createImplicitAliases)
  11231. {
  11232. unsigned time = msTick();
  11233. ForEachItemIn(i, workflow)
  11234. {
  11235. ImplicitAliasTransformer normalizer;
  11236. normalizer.process(workflow.item(i).queryExprs());
  11237. }
  11238. DEBUG_TIMERX(queryTimeReporter(), "EclServer: tree transform: implicit alias", msTick()-time);
  11239. //traceExpressions("after implicit alias", workflow);
  11240. }
  11241. if (outputLibrary && workflow.ordinality() > 1)
  11242. {
  11243. unsigned cnt = 0;
  11244. ForEachItemIn(i, workflow)
  11245. {
  11246. if (!workflow.item(i).isFunction())
  11247. cnt++;
  11248. }
  11249. if (cnt > 1)
  11250. {
  11251. SCMStringBuffer libraryName;
  11252. getOutputLibraryName(libraryName, wu());
  11253. throwError2(HQLERR_LibraryCannotContainWorkflow, libraryName.str(), "");
  11254. }
  11255. }
  11256. {
  11257. unsigned startTime = msTick();
  11258. hoistNestedCompound(*this, workflow);
  11259. DEBUG_TIMER("EclServer: tree transform: hoist nested compound", msTick()-startTime);
  11260. }
  11261. if (options.optimizeNestedConditional)
  11262. {
  11263. cycle_t time = msTick();
  11264. ForEachItemIn(idx, workflow)
  11265. optimizeNestedConditional(workflow.item(idx).queryExprs());
  11266. DEBUG_TIMER("EclServer: optimize nested conditional", msTick()-time);
  11267. traceExpressions("nested", workflow);
  11268. checkNormalized(workflow);
  11269. }
  11270. checkNormalized(workflow);
  11271. //sort(x)[n] -> topn(x, n)[]n, count(x)>n -> count(choosen(x,n+1)) > n and possibly others
  11272. {
  11273. unsigned startTime = msTick();
  11274. optimizeActivities(workflow, !targetThor(), options.optimizeNonEmpty);
  11275. DEBUG_TIMER("EclServer: tree transform: optimize activities", msTick()-startTime);
  11276. }
  11277. checkNormalized(workflow);
  11278. unsigned time5 = msTick();
  11279. migrateExprToNaturalLevel(workflow, wu(), *this); // Ensure expressions are evaluated at the best level - e.g., counts moved to most appropriate level.
  11280. DEBUG_TIMER("EclServer: tree transform: migrate", msTick()-time5);
  11281. //transformToAliases(exprs);
  11282. traceExpressions("migrate", workflow);
  11283. checkNormalized(workflow);
  11284. unsigned time2 = msTick();
  11285. markThorBoundaries(workflow); // work out which engine is going to perform which operation.
  11286. DEBUG_TIMER("EclServer: tree transform: thor hole", msTick()-time2);
  11287. traceExpressions("boundary", workflow);
  11288. checkNormalized(workflow);
  11289. if (options.optimizeGlobalProjects)
  11290. {
  11291. cycle_t time = msTick();
  11292. ForEachItemIn(idx, workflow)
  11293. insertImplicitProjects(*this, workflow.item(idx).queryExprs());
  11294. DEBUG_TIMER("EclServer: global implicit projects", msTick()-time);
  11295. traceExpressions("implicit", workflow);
  11296. checkNormalized(workflow);
  11297. }
  11298. unsigned time3 = msTick();
  11299. normalizeResultFormat(workflow, options);
  11300. DEBUG_TIMER("EclServer: tree transform: normalize result", msTick()-time3);
  11301. traceExpressions("results", workflow);
  11302. checkNormalized(workflow);
  11303. optimizePersists(workflow);
  11304. traceExpressions("per", workflow);
  11305. checkNormalized(workflow);
  11306. // flattenDatasets(workflow);
  11307. // traceExpressions("flatten", workflow);
  11308. {
  11309. unsigned startTime = msTick();
  11310. mergeThorGraphs(workflow, options.resourceConditionalActions, options.resourceSequential); // reduces number of graphs sent to thor
  11311. DEBUG_TIMER("EclServer: tree transform: merge thor", msTick()-startTime);
  11312. }
  11313. traceExpressions("merged", workflow);
  11314. checkNormalized(workflow);
  11315. if (queryOptions().normalizeLocations)
  11316. normalizeAnnotations(*this, workflow);
  11317. spotGlobalCSE(workflow); // spot CSE within those graphs, and create some more
  11318. checkNormalized(workflow);
  11319. //expandGlobalDatasets(workflow, wu(), *this);
  11320. {
  11321. unsigned startTime = msTick();
  11322. mergeThorGraphs(workflow, options.resourceConditionalActions, options.resourceSequential);
  11323. DEBUG_TIMER("EclServer: tree transform: merge thor", msTick()-startTime);
  11324. }
  11325. checkNormalized(workflow);
  11326. removeTrivialGraphs(workflow);
  11327. checkNormalized(workflow);
  11328. #ifndef PICK_ENGINE_EARLY
  11329. if (options.pickBestEngine)
  11330. pickBestEngine(workflow);
  11331. #endif
  11332. updateClusterType();
  11333. traceExpressions("before convert to logical", workflow);
  11334. convertLogicalToActivities(workflow); // e.g., merge disk reads, transform group, all to sort etc.
  11335. #ifndef _DEBUG
  11336. if (options.regressionTest)
  11337. #endif
  11338. {
  11339. unsigned startTime = msTick();
  11340. ForEachItemIn(icheck, workflow)
  11341. checkDependencyConsistency(workflow.item(icheck).queryExprs());
  11342. DEBUG_TIMER("EclServer: tree transform: check dependency", msTick()-startTime);
  11343. }
  11344. traceExpressions("end transformGraphForGeneration", workflow);
  11345. checkNormalized(workflow);
  11346. return true;
  11347. }
  11348. //---------------------------------------------------------------------------
  11349. /*
  11350. Different transformers:
  11351. merge: required if a child get removed or merged with a parent of a non-table dataset.
  11352. adding is not a problem (unless tables are inserted) because all refs to ds.x will remain valid.
  11353. but if tables can be deleted/modified then then it will cause problems, since ds.x needs to be translated to ds'.x within the scope
  11354. It is also ok if only scalars are transformed.
  11355. Transformer base merge dependants [should be]
  11356. filterExtractor simple N
  11357. resource Scoped (Y) complex - could possibly derive from merging...? why scoped?
  11358. HqlThorBoundary New N
  11359. HqlResult New N isConditional,insideThor,insideCondition
  11360. creation of getresult only done on scalars, so I think it is ok.
  11361. could possibly remove the scoping if count() etc. were tagged as outer level or not
  11362. ThorHql Merging Y Again scoped because of no_count etc.
  11363. CompoundSource New add* Either added, or non-tables(limits) are cloned, so no merging issues.
  11364. CompoundActivity Merging Y When limit merged into a dataset. [ need a new way? ]
  11365. Workflow New [inTransform] I think no for the same reason as above, or it adds. layers.
  11366. NewScopeMigrate New ? I think it might be ok, because doesn't modify any tables, only scalars
  11367. ThorCount New N no issues.
  11368. Cse New ? Probably, but ok, if only done on scalars.
  11369. HqlTreeNormalizer Scoped * I don't think it does any, but need to be careful none are introduced.
  11370. */
  11371. /*
  11372. NOTES:
  11373. Consider adding a hqlmeta.hpp that defines all the characteristics of an IHqlExpression node - e.g.,
  11374. is it constant, number of child files, text, what filenames does it generate? what does it read,
  11375. what results does it read/write.
  11376. Dependancy code:
  11377. 1. In the resourcer
  11378. 2. TableDependencies In hqlttcpp to stop reordering when not valid.
  11379. ?Is GetResultHash called on globals that haven't been calculated???
  11380. */