hqlttcpp.cpp 437 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "platform.h"
  15. #include "jlib.hpp"
  16. #include "jmisc.hpp"
  17. #include "jstream.ipp"
  18. #include "eclrtl.hpp"
  19. #include "hql.hpp"
  20. #include "hqlttcpp.ipp"
  21. #include "hqlmeta.hpp"
  22. #include "hqlutil.hpp"
  23. #include "hqlcpputil.hpp"
  24. #include "hqlthql.hpp"
  25. #include "hqlhtcpp.ipp"
  26. #include "hqltcppc.ipp"
  27. #include "hqlcatom.hpp"
  28. #include "hqlfold.hpp"
  29. #include "hqlgraph.ipp"
  30. #include "hqllib.ipp"
  31. #include "hqlpmap.hpp"
  32. #include "hqlopt.hpp"
  33. #include "hqlcerrors.hpp"
  34. #include "hqlsource.ipp"
  35. #include "hqlvalid.hpp"
  36. #include "hqlerror.hpp"
  37. #include "hqlalias.hpp"
  38. #define TraceExprPrintLog(x, expr) TOSTRLOG(MCdebugInfo(300), unknownJob, x, (expr)->toString);
  39. //Following are for code that currently cause problems, but are probably a good idea
  40. //#define MAP_PROJECT_TO_USERTABLE
  41. //#define REMOVE_NAMED_SCALARS
  42. //#define OPTIMIZE_IMPLICIT_CAST
  43. #define REMOVE_GLOBAL_ANNOTATION // This should improve cse. It currently does for some, but not others...
  44. #define DEFAULT_FOLD_OPTIONS HFOfoldfilterproject
  45. //#define PICK_ENGINE_EARLY
  46. //===========================================================================
  47. static bool isWorthHoisting(IHqlExpression * expr, bool asSubQuery)
  48. {
  49. bool isFiltered = false;
  50. loop
  51. {
  52. switch (expr->getOperator())
  53. {
  54. case no_newkeyindex:
  55. case no_table:
  56. case no_temptable:
  57. case no_inlinetable:
  58. case no_globalscope:
  59. case no_global:
  60. case no_independent:
  61. case no_field:
  62. case no_datasetfromrow:
  63. case no_null:
  64. case no_workunit_dataset:
  65. case no_colon:
  66. //compound activities not in list because not created at this point.
  67. return (isFiltered && asSubQuery);
  68. case no_select:
  69. return !isTargetSelector(expr);
  70. case no_filter:
  71. expr = expr->queryChild(0);
  72. isFiltered = true;
  73. break;
  74. case no_compound_diskread:
  75. case no_compound_indexread:
  76. case no_hqlproject:
  77. case no_newusertable:
  78. case no_limit:
  79. case no_catchds:
  80. case no_keyedlimit:
  81. case no_sorted:
  82. case no_grouped:
  83. case no_stepped:
  84. case no_distributed:
  85. case no_preservemeta:
  86. case no_nofold:
  87. case no_nohoist:
  88. case no_section:
  89. case no_sectioninput:
  90. case no_dataset_alias:
  91. case no_forcegraph:
  92. expr = expr->queryChild(0);
  93. break;
  94. case no_fail:
  95. return false;
  96. default:
  97. return true;
  98. }
  99. }
  100. }
  101. IHqlExpression * getDebugValueExpr(IConstWorkUnit * wu, IHqlExpression * expr)
  102. {
  103. StringBuffer name;
  104. getStringValue(name, expr->queryChild(0));
  105. SCMStringBuffer value;
  106. wu->getDebugValue(name, value);
  107. ITypeInfo * exprType = expr->queryType();
  108. if (exprType->getTypeCode() == type_boolean)
  109. return createConstant(clipStrToBool(value.length(), value.str()));
  110. return createConstant(exprType->castFrom(value.length(), value.str()));
  111. }
  112. //===========================================================================
  113. struct GlobalAttributeInfo
  114. {
  115. public:
  116. GlobalAttributeInfo(const char * _filePrefix, const char * _storedPrefix) { setOp = no_none; persistOp = no_none; few = false; filePrefix = _filePrefix; storedPrefix = _storedPrefix; }
  117. void extractCluster(IHqlExpression * expr, bool isRoxie);
  118. void extractGlobal(IHqlExpression * expr, bool isRoxie);
  119. void extractStoredInfo(IHqlExpression * expr, IHqlExpression * originalValue, bool isRoxie);
  120. void checkFew(HqlCppTranslator & translator, IHqlExpression * value);
  121. void splitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie);
  122. IHqlExpression * getStoredKey();
  123. void preventDiskSpill() { few = true; }
  124. IHqlExpression * queryCluster() const { return cluster; }
  125. protected:
  126. void doSplitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie);
  127. IHqlExpression * createSetValue(IHqlExpression * value, IHqlExpression * aliasName);
  128. void createSmallOutput(IHqlExpression * value, SharedHqlExpr & setOutput);
  129. IHqlExpression * queryAlias(IHqlExpression * value);
  130. IHqlExpression * queryFilename(IHqlExpression * value, IConstWorkUnit * wu, bool isRoxie);
  131. void splitSmallDataset(IHqlExpression * value, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput);
  132. void setCluster(IHqlExpression * expr);
  133. public:
  134. OwnedHqlExpr storedName;
  135. OwnedHqlExpr sequence;
  136. node_operator setOp;
  137. node_operator persistOp;
  138. protected:
  139. OwnedHqlExpr aliasName;
  140. OwnedHqlExpr cachedFilename;
  141. OwnedHqlExpr cluster;
  142. OwnedHqlExpr extraSetAttr;
  143. OwnedHqlExpr extraOutputAttr;
  144. const char * filePrefix;
  145. const char * storedPrefix;
  146. bool few;
  147. };
  148. static bool isTrivialInlineOutput(IHqlExpression * expr)
  149. {
  150. if (queryRealChild(expr, 1))
  151. return false;
  152. IHqlExpression * ds = expr->queryChild(0);
  153. if ((ds->getOperator() != no_null) || !ds->isDataset())
  154. return false;
  155. IHqlExpression * seq = querySequence(expr);
  156. if (getIntValue(seq, -1) >= 0)
  157. return false;
  158. return true;
  159. }
  160. //---------------------------------------------------------------------------
  161. IHqlExpression * createNextStringValue(IHqlExpression * value, const char * prefix = NULL)
  162. {
  163. StringBuffer valueText;
  164. valueText.append(prefix ? prefix : "a");
  165. getUniqueId(valueText);
  166. #if 0
  167. if (value)
  168. {
  169. const char * nameText = value->queryName()->str();
  170. if (nameText)
  171. valueText.append("__").appendLower(strlen(nameText), nameText);
  172. //otherwise append the operator?
  173. }
  174. #endif
  175. #if 0
  176. #ifdef _DEBUG
  177. //Following lines are here to add a break point when debugging
  178. if (stricmp(valueText.str(), "aQ") == 0)
  179. valueText.length();
  180. if (stricmp(valueText.str(), "aDR1") == 0)
  181. valueText.length();
  182. #endif
  183. #endif
  184. return createConstant(valueText.str());
  185. }
  186. IHqlExpression * createSetResult(IHqlExpression * value)
  187. {
  188. HqlExprArray args;
  189. args.append(*LINK(value));
  190. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  191. args.append(*createAttribute(namedAtom, createNextStringValue(value)));
  192. return createSetResult(args);
  193. }
  194. static IHqlExpression * addAttrOwnToDataset(IHqlExpression * dataset, IHqlExpression * attr)
  195. {
  196. HqlExprArray args;
  197. unwindChildren(args, dataset);
  198. args.append(*attr);
  199. return dataset->clone(args);
  200. }
  201. static IHqlExpression * mergeLimitIntoDataset(IHqlExpression * dataset, IHqlExpression * limit)
  202. {
  203. return addAttrOwnToDataset(dataset, createAttribute(limitAtom, LINK(limit->queryChild(1)), LINK(limit->queryChild(2))));
  204. }
  205. void checkDependencyConsistency(WorkflowArray & workflow)
  206. {
  207. ForEachItemIn(icheck, workflow)
  208. checkDependencyConsistency(workflow.item(icheck).queryExprs());
  209. }
  210. //---------------------------------------------------------------------------
  211. static bool isOptionTooLate(const char * name)
  212. {
  213. if (stricmp(name, "gatherDependencies") == 0) return true;
  214. if (stricmp(name, "gatherDependenciesSelection") == 0) return true;
  215. if (stricmp(name, "archiveToCpp") == 0) return true;
  216. if (stricmp(name, "importAllModules") == 0) return true;
  217. if (stricmp(name, "importImplicitModules") == 0) return true;
  218. if (stricmp(name, "noCache") == 0) return true;
  219. if (stricmp(name, "linkOptions") == 0) return true;
  220. if (stricmp(name, "compileOptions") == 0) return true;
  221. return false;
  222. }
  223. static HqlTransformerInfo newThorStoredReplacerInfo("NewThorStoredReplacer");
  224. NewThorStoredReplacer::NewThorStoredReplacer(HqlCppTranslator & _translator, IWorkUnit * _wu, ICodegenContextCallback * _ctxCallback)
  225. : QuickHqlTransformer(newThorStoredReplacerInfo, NULL), translator(_translator)
  226. {
  227. wu = _wu;
  228. ctxCallback = _ctxCallback;
  229. foldStored = false;
  230. seenMeta = false;
  231. }
  232. void NewThorStoredReplacer::doAnalyseBody(IHqlExpression * expr)
  233. {
  234. //NOTE: This is called very early before no_assertconstant has been processed, so we need to explicitly
  235. //constant fold, and check it is constant (bug 26963)
  236. node_operator op = expr->getOperator();
  237. if (op == no_setmeta)
  238. {
  239. StringBuffer errorTemp;
  240. seenMeta = true;
  241. _ATOM kind = expr->queryChild(0)->queryName();
  242. if (kind == debugAtom)
  243. {
  244. OwnedHqlExpr foldedName = foldHqlExpression(expr->queryChild(1));
  245. OwnedHqlExpr foldedValue = foldHqlExpression(expr->queryChild(2));
  246. IValue * name = foldedName->queryValue();
  247. IValue * value = foldedValue->queryValue();
  248. if (!name)
  249. throwError1(HQLERR_ExpectedConstantDebug, getExprECL(foldedName, errorTemp).str());
  250. if (!value)
  251. throwError1(HQLERR_ExpectedConstantDebug, getExprECL(foldedValue, errorTemp).str());
  252. StringBuffer nameText,valueText;
  253. name->getStringValue(nameText);
  254. if (isOptionTooLate(nameText.str()))
  255. translator.reportWarning(HQLWRN_OptionSetToLate, HQLWRN_OptionSetToLate_Text, nameText.str());
  256. if (value->queryType()->getTypeCode() == type_boolean)
  257. valueText.append(value->getBoolValue() ? 1 : 0);
  258. else
  259. value->getStringValue(valueText);
  260. wu->setDebugValue(nameText.str(), valueText, true);
  261. }
  262. else if (kind == workunitAtom)
  263. {
  264. OwnedHqlExpr foldedName = foldHqlExpression(expr->queryChild(1));
  265. OwnedHqlExpr foldedValue = foldHqlExpression(expr->queryChild(2));
  266. IValue * name = foldedName->queryValue();
  267. IValue * value = foldedValue->queryValue();
  268. if (!name)
  269. throwError1(HQLERR_ExpectedConstantWorkunit, getExprECL(foldedName, errorTemp).str());
  270. if (!value)
  271. throwError1(HQLERR_ExpectedConstantWorkunit, getExprECL(foldedValue, errorTemp).str());
  272. StringBuffer nameText,valueText;
  273. name->getStringValue(nameText);
  274. value->getStringValue(valueText);
  275. if (stricmp(nameText.str(), "name") == 0)
  276. wu->setJobName(valueText.str());
  277. else if (stricmp(nameText.str(), "priority") == 0)
  278. {
  279. if (isStringType(value->queryType()))
  280. {
  281. WUPriorityClass prio = PriorityClassUnknown;
  282. if (stricmp(valueText.str(), "low") == 0)
  283. prio = PriorityClassLow;
  284. else if (stricmp(valueText.str(), "normal") == 0)
  285. prio = PriorityClassNormal;
  286. else if (stricmp(valueText.str(), "high") == 0)
  287. prio = PriorityClassHigh;
  288. wu->setPriority(prio);
  289. }
  290. else
  291. wu->setPriorityLevel((int)value->getIntValue());
  292. }
  293. else if (stricmp(nameText.str(), "cluster") == 0)
  294. {
  295. ctxCallback->noteCluster(valueText.str());
  296. wu->setClusterName(valueText.str());
  297. }
  298. else if (stricmp(nameText.str(), "protect") == 0)
  299. {
  300. wu->protect(value->getBoolValue());
  301. }
  302. else if (stricmp(nameText.str(), "scope") == 0)
  303. {
  304. wu->setWuScope(valueText.str());
  305. }
  306. else
  307. throwError1(HQLERR_UnsupportedHashWorkunit, nameText.str());
  308. }
  309. else if (kind == linkAtom)
  310. {
  311. OwnedHqlExpr foldedName = foldHqlExpression(expr->queryChild(1));
  312. StringBuffer libraryText;
  313. if (getStringValue(libraryText, foldedName).length())
  314. translator.useLibrary(libraryText);
  315. }
  316. else if ((kind == constAtom) || (kind == storedAtom))
  317. {
  318. //assume there won't be many of these... otherwise we should use a hash table
  319. OwnedHqlExpr lowerName = lowerCaseHqlExpr(expr->queryChild(1));
  320. //Use lowerName->queryBody() to remove named symbols/location annotations etc.
  321. storedNames.append(*LINK(lowerName->queryBody()));
  322. storedValues.append(*LINK(expr->queryChild(2)));
  323. storedIsConstant.append(kind == constAtom);
  324. }
  325. else if (kind == onWarningAtom)
  326. translator.addGlobalOnWarning(expr);
  327. }
  328. else if (op == no_colon)
  329. {
  330. if (queryPropertyInList(labeledAtom, expr->queryChild(1)))
  331. seenMeta = true;
  332. }
  333. QuickHqlTransformer::doAnalyseBody(expr);
  334. }
  335. bool NewThorStoredReplacer::needToTransform()
  336. {
  337. //foldStored = translator.queryOptions().foldStored; // NB: options isn't initialised correctly at this point.
  338. foldStored = wu->getDebugValueBool("foldStored", false);
  339. return (foldStored || seenMeta);
  340. }
  341. // This works on unnormalized trees, so based on QuickHqlTransformer
  342. IHqlExpression * NewThorStoredReplacer::createTransformed(IHqlExpression * expr)
  343. {
  344. switch (expr->getOperator())
  345. {
  346. case no_colon:
  347. {
  348. HqlExprArray actions;
  349. expr->queryChild(1)->unwindList(actions, no_comma);
  350. OwnedHqlExpr replacement;
  351. OwnedHqlExpr matchedName;
  352. bool onlyStored = true;
  353. bool forceConstant = foldStored;
  354. ForEachItemIn(idx, actions)
  355. {
  356. IHqlExpression & cur = actions.item(idx);
  357. switch (cur.getOperator())
  358. {
  359. case no_stored:
  360. {
  361. OwnedHqlExpr storedName = lowerCaseHqlExpr(cur.queryChild(0));
  362. IHqlExpression * searchName = storedName->queryBody();
  363. unsigned match = storedNames.find(*searchName);
  364. if (match != NotFound)
  365. {
  366. if (storedIsConstant.item(match))
  367. forceConstant = true;
  368. matchedName.set(searchName);
  369. replacement.set(&storedValues.item(match));
  370. }
  371. break;
  372. }
  373. case no_attr:
  374. case no_attr_expr:
  375. if (cur.queryName() == labeledAtom)
  376. {
  377. OwnedHqlExpr storedName = lowerCaseHqlExpr(cur.queryChild(0));
  378. IHqlExpression * searchName = storedName->queryBody();
  379. unsigned match = storedNames.find(*searchName);
  380. if (match != NotFound)
  381. {
  382. matchedName.set(searchName);
  383. replacement.set(&storedValues.item(match));
  384. }
  385. else
  386. replacement.set(expr->queryChild(0));
  387. forceConstant = true;
  388. break;
  389. }
  390. default:
  391. onlyStored = false;
  392. break;
  393. }
  394. }
  395. if (matchedName)
  396. {
  397. unsigned activeMatch = activeReplacements.find(*matchedName);
  398. if (activeMatch != NotFound)
  399. {
  400. StringBuffer nameText;
  401. getExprECL(matchedName, nameText);
  402. if (activeMatch+1 != activeReplacements.ordinality())
  403. {
  404. StringBuffer othersText;
  405. for (unsigned i=activeMatch+1; i < activeReplacements.ordinality(); i++)
  406. {
  407. othersText.append(",");
  408. getExprECL(&activeReplacements.item(i), othersText);
  409. }
  410. throwError3(HQLERR_RecursiveStoredOther, forceConstant ? "CONSTANT" : "STORED", nameText.str(), othersText.str()+1);
  411. }
  412. else
  413. throwError2(HQLERR_RecursiveStored, forceConstant ? "CONSTANT" : "STORED", nameText.str());
  414. }
  415. ITypeInfo * exprType = expr->queryType();
  416. ITypeInfo * replacementType = replacement->queryType();
  417. type_t etc = exprType->getTypeCode();
  418. type_t rtc = replacementType->getTypeCode();
  419. StringBuffer nameText, exprTypeText, replacementTypeText;
  420. switch (etc)
  421. {
  422. case type_groupedtable:
  423. case type_table:
  424. case type_row:
  425. case type_record:
  426. case type_transform:
  427. case type_void:
  428. {
  429. if (etc != rtc)
  430. {
  431. getExprECL(matchedName, nameText);
  432. getFriendlyTypeStr(exprType, exprTypeText);
  433. getFriendlyTypeStr(replacementType, replacementTypeText);
  434. throwError3(HQLERR_HashStoredTypeMismatch, nameText.str(), exprTypeText.str(), replacementTypeText.str());
  435. }
  436. else if (expr->queryRecord() != replacement->queryRecord())
  437. {
  438. StringBuffer s;
  439. throwError1(HQLERR_HashStoredRecordMismatch, getExprECL(matchedName, s).str());
  440. }
  441. }
  442. break;
  443. case type_set:
  444. case type_array:
  445. {
  446. if ((rtc != type_set) && (rtc != type_array))
  447. {
  448. getExprECL(matchedName, nameText);
  449. getFriendlyTypeStr(exprType, exprTypeText);
  450. getFriendlyTypeStr(replacementType, replacementTypeText);
  451. throwError3(HQLERR_HashStoredTypeMismatch, nameText.str(), exprTypeText.str(), replacementTypeText.str());
  452. }
  453. replacement.setown(ensureExprType(replacement, exprType));
  454. break;
  455. }
  456. default:
  457. {
  458. switch (rtc)
  459. {
  460. case type_groupedtable:
  461. case type_table:
  462. case type_row:
  463. case type_record:
  464. case type_transform:
  465. case type_void:
  466. {
  467. getExprECL(matchedName, nameText);
  468. getFriendlyTypeStr(exprType, exprTypeText);
  469. getFriendlyTypeStr(replacementType, replacementTypeText);
  470. throwError3(HQLERR_HashStoredTypeMismatch, nameText.str(), exprTypeText.str(), replacementTypeText.str());
  471. }
  472. default:
  473. replacement.setown(ensureExprType(replacement, exprType));
  474. }
  475. }
  476. break;
  477. }
  478. }
  479. LinkedHqlExpr result;
  480. if (matchedName)
  481. activeReplacements.append(*matchedName);
  482. if (onlyStored)
  483. {
  484. if (forceConstant && replacement)
  485. result.setown(transform(replacement));
  486. else if (foldStored)
  487. result.setown(transform(expr->queryChild(0)));
  488. }
  489. if (replacement && !result)
  490. {
  491. HqlExprArray args;
  492. args.append(*transform(replacement));
  493. result.setown(completeTransform(expr, args));
  494. }
  495. if (matchedName)
  496. activeReplacements.pop();
  497. if (result)
  498. return result.getClear();
  499. break;
  500. }
  501. case no_comma:
  502. case no_compound:
  503. if (expr->queryChild(0)->getOperator() == no_setmeta)
  504. return transform(expr->queryChild(1));
  505. if (expr->queryChild(1)->getOperator() == no_setmeta)
  506. return transform(expr->queryChild(0));
  507. break;
  508. case no_actionlist:
  509. {
  510. HqlExprArray actions;
  511. ForEachChild(i, expr)
  512. {
  513. IHqlExpression * cur = expr->queryChild(i);
  514. if (cur->getOperator() != no_setmeta)
  515. actions.append(*transform(cur));
  516. }
  517. if (actions.ordinality() != 0)
  518. return expr->clone(actions);
  519. return transform(expr->queryChild(0));
  520. }
  521. }
  522. return QuickHqlTransformer::createTransformed(expr);
  523. }
  524. //---------------------------------------------------------------------------
  525. // NB: This is called after no_setresults are added, but before any normalization.
  526. static HqlTransformerInfo hqlThorBoundaryTransformerInfo("HqlThorBoundaryTransformer");
  527. HqlThorBoundaryTransformer::HqlThorBoundaryTransformer(IConstWorkUnit * _wu, bool _isRoxie, unsigned _maxRootMaybes, bool _resourceConditionalActions, bool _resourceSequential)
  528. : NewHqlTransformer(hqlThorBoundaryTransformerInfo)
  529. {
  530. wu = _wu;
  531. isRoxie = _isRoxie;
  532. maxRootMaybes = _maxRootMaybes;
  533. resourceConditionalActions = _resourceConditionalActions;
  534. resourceSequential = _resourceSequential;
  535. }
  536. void HqlThorBoundaryTransformer::transformCompound(HqlExprArray & result, node_operator compoundOp, const HqlExprArray & args, unsigned MaxMaybes)
  537. {
  538. UnsignedArray normalizeOptions;
  539. ForEachItemIn(i, args)
  540. {
  541. IHqlExpression & cur = args.item(i);
  542. normalizeOptions.append(normalizeThor(&cur));
  543. }
  544. //If any "yes" or "some" values are separated by maybes then convert the maybes (and "somes") into yes
  545. unsigned lastYes = NotFound;
  546. unsigned numMaybes = 0;
  547. ForEachItemIn(i2, args)
  548. {
  549. switch (normalizeOptions.item(i2))
  550. {
  551. case OptionYes:
  552. case OptionSome:
  553. if (lastYes != NotFound)
  554. {
  555. if (numMaybes <= MaxMaybes)
  556. {
  557. for (unsigned j = lastYes; j <= i2; j++)
  558. normalizeOptions.replace(OptionYes, j);
  559. }
  560. }
  561. numMaybes = 0;
  562. lastYes = i2;
  563. break;
  564. case OptionMaybe:
  565. numMaybes++;
  566. break;
  567. case OptionNo:
  568. lastYes = NotFound;
  569. break;
  570. }
  571. }
  572. //Do thor and non-thor parallel actions independently
  573. HqlExprArray thor;
  574. ForEachItemIn(idx, args)
  575. {
  576. IHqlExpression * cur = &args.item(idx);
  577. if (normalizeOptions.item(idx) == OptionYes)
  578. thor.append(*LINK(cur));
  579. else
  580. {
  581. if (thor.ordinality())
  582. {
  583. result.append(*createWrapper(no_thor, createCompound(compoundOp, thor)));
  584. thor.kill();
  585. }
  586. result.append(*createTransformed(cur));
  587. }
  588. }
  589. if (thor.ordinality())
  590. result.append(*createWrapper(no_thor, createCompound(compoundOp, thor)));
  591. }
  592. IHqlExpression * HqlThorBoundaryTransformer::createTransformed(IHqlExpression * expr)
  593. {
  594. node_operator op = expr->getOperator();
  595. switch (op)
  596. {
  597. case no_field:
  598. case no_constant:
  599. case no_attr:
  600. case no_attr_expr:
  601. case no_attr_link:
  602. case no_getresult:
  603. case no_left:
  604. case no_right:
  605. return LINK(expr);
  606. case no_sizeof:
  607. case no_offsetof:
  608. return getTransformedChildren(expr);
  609. }
  610. //Unusually, wrap the expression in a thor node before processing annotations.
  611. //This ensures that the location/named symbol stays with the action.
  612. //MORE: If this is a dataset then it needs to turn it into a setResult()/getResult() pair.
  613. if (normalizeThor(expr) == OptionYes)
  614. {
  615. if (!expr->isTransform())
  616. return createWrapper(no_thor, LINK(expr));
  617. }
  618. IHqlExpression * ret = queryTransformAnnotation(expr);
  619. if (ret)
  620. return ret;
  621. switch (op)
  622. {
  623. case no_actionlist:
  624. {
  625. HqlExprArray nonThor, args;
  626. expr->unwindList(args, op);
  627. transformCompound(nonThor, op, args, (unsigned)-1);
  628. return createCompound(op, nonThor);
  629. }
  630. case no_parallel:
  631. {
  632. HqlExprArray expanded;
  633. expr->unwindList(expanded, no_parallel);
  634. //Similar to compound, but possible to reorder branches...
  635. unsigned numThor = 0;
  636. UnsignedArray normalizeOptions;
  637. ForEachItemIn(idx, expanded)
  638. {
  639. YesNoOption option = normalizeThor(&expanded.item(idx));
  640. normalizeOptions.append(option);
  641. if ((option == OptionYes) || (option == OptionSome))
  642. numThor++;
  643. }
  644. if (numThor > 1)
  645. {
  646. HqlExprArray thor, nonThor;
  647. ForEachItemIn(idx, expanded)
  648. {
  649. IHqlExpression * cur = &expanded.item(idx);
  650. switch (normalizeOptions.item(idx))
  651. {
  652. case OptionYes:
  653. case OptionSome:
  654. thor.append(*LINK(cur));
  655. break;
  656. default:
  657. nonThor.append(*createTransformed(cur));
  658. break;
  659. }
  660. }
  661. if (nonThor.ordinality() == 0)
  662. {
  663. //can happen if inputs are a mixture of yes and some.
  664. return createWrapper(no_thor, LINK(expr));
  665. }
  666. nonThor.append(*createWrapper(no_thor, createValue(no_parallel, makeVoidType(), thor)));
  667. return expr->clone(nonThor);
  668. }
  669. break;
  670. }
  671. case no_nothor:
  672. return LINK(expr);
  673. }
  674. return NewHqlTransformer::createTransformed(expr);
  675. }
  676. static YesNoOption combine(YesNoOption left, YesNoOption right, bool isUnion)
  677. {
  678. if ((left == OptionNo) || (right == OptionNo))
  679. return OptionNo;
  680. if (left == OptionUnknown)
  681. return right;
  682. if (right == OptionUnknown)
  683. return left;
  684. //Yes,Some,Maybe
  685. if (isUnion)
  686. {
  687. //return definite if both branches may benefit.
  688. switch (left)
  689. {
  690. case OptionYes:
  691. return (right != OptionMaybe) ? OptionYes : OptionSome;
  692. case OptionSome:
  693. return (right != OptionMaybe) ? OptionYes : OptionSome;
  694. case OptionMaybe:
  695. return (right != OptionMaybe) ? OptionSome : OptionMaybe;
  696. }
  697. }
  698. else
  699. {
  700. //Intersection, return definite
  701. switch (left)
  702. {
  703. case OptionYes:
  704. return (right == OptionYes) ? OptionYes : OptionSome;
  705. case OptionSome:
  706. return OptionSome;
  707. case OptionMaybe:
  708. return (right == OptionMaybe) ? OptionMaybe : OptionSome;
  709. }
  710. }
  711. throwUnexpected();
  712. }
  713. //MORE: Needs to be yes, no, possibly.
  714. YesNoOption HqlThorBoundaryTransformer::normalizeThor(IHqlExpression * expr)
  715. {
  716. HqlThorBoundaryInfo * extra = queryBodyExtra(expr);
  717. if (extra->normalize == OptionUnknown)
  718. extra->normalize = calcNormalizeThor(expr);
  719. return extra->normalize;
  720. }
  721. YesNoOption HqlThorBoundaryTransformer::calcNormalizeThor(IHqlExpression * expr)
  722. {
  723. //MORE: This should probably be cached in the extra info & recursed more correctly
  724. node_operator op = expr->getOperator();
  725. ITypeInfo * type = expr->queryType();
  726. switch (op)
  727. {
  728. case no_constant:
  729. case no_field:
  730. case no_record:
  731. case no_attr:
  732. case no_attr_expr:
  733. case no_attr_link:
  734. case no_getresult:
  735. case no_left:
  736. case no_right:
  737. case no_sizeof:
  738. case no_all:
  739. case no_self:
  740. case no_activerow:
  741. return OptionMaybe;
  742. case no_evaluate:
  743. throwUnexpected();
  744. case no_select:
  745. {
  746. bool isNew;
  747. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  748. switch (ds->getOperator())
  749. {
  750. case no_getresult:
  751. case no_call:
  752. case no_externalcall:
  753. return normalizeThor(ds);
  754. case no_self:
  755. return OptionMaybe;
  756. }
  757. return isNew ? OptionYes : OptionMaybe;
  758. }
  759. case NO_AGGREGATE:
  760. case no_executewhen:
  761. return OptionYes;
  762. case NO_ACTION_REQUIRES_GRAPH:
  763. {
  764. if ((op == no_output) && isTrivialInlineOutput(expr))
  765. return OptionMaybe;
  766. return OptionYes;
  767. }
  768. case no_sequential: // do not do inside thor - stops graphs being merged.
  769. if (!resourceSequential)
  770. return OptionNo;
  771. // fallthrough
  772. case no_actionlist:
  773. case no_parallel:
  774. {
  775. YesNoOption option = OptionUnknown;
  776. ForEachChild(idx, expr)
  777. {
  778. YesNoOption childOption = normalizeThor(expr->queryChild(idx));
  779. if (childOption == OptionNo)
  780. return OptionNo;
  781. option = combine(option, childOption, (op == no_sequential)); // can reorder parallel - so intersection is better
  782. }
  783. return option;
  784. }
  785. case no_cluster:
  786. case no_nothor:
  787. return OptionNo;
  788. case no_if:
  789. if (type && (type->getTypeCode() == type_void))
  790. {
  791. if (resourceConditionalActions)
  792. {
  793. IHqlExpression * falseExpr = expr->queryChild(2);
  794. YesNoOption leftOption = normalizeThor(expr->queryChild(1));
  795. YesNoOption rightOption = falseExpr ? normalizeThor(falseExpr) : OptionMaybe;
  796. YesNoOption branchOption = combine(leftOption, rightOption, true);
  797. YesNoOption condOption = normalizeThor(expr->queryChild(0));
  798. if ((branchOption == OptionYes) && (condOption != OptionNo))
  799. return OptionYes;
  800. // if ((condOption == OptionYes) && (branchOption != OptionNo))
  801. // return OptionYes;
  802. return combine(condOption, branchOption, true);
  803. }
  804. return OptionNo; // not supported
  805. }
  806. // default action. Not completely convinced it is correct....
  807. break;
  808. case no_setresult:
  809. {
  810. IHqlExpression * value = expr->queryChild(0);
  811. YesNoOption valueOption = normalizeThor(value);
  812. //Probably worth doing the whole thing in thor if some part if it needs to be - will improve commoning up if nothing else.
  813. if (valueOption == OptionSome)
  814. return OptionYes;
  815. return valueOption;
  816. }
  817. case no_extractresult:
  818. {
  819. IHqlExpression * ds = expr->queryChild(0);
  820. OwnedHqlExpr transformedDs = transform(ds);
  821. if (transformedDs != ds)
  822. return OptionYes;
  823. //Probably worth doing the whole thing in thor if some part if it needs to be - will improve commoning up if nothing else.
  824. return normalizeThor(expr->queryChild(1));
  825. }
  826. case no_compound:
  827. {
  828. YesNoOption leftOption = normalizeThor(expr->queryChild(0));
  829. YesNoOption rightOption = normalizeThor(expr->queryChild(1));
  830. return combine(leftOption, rightOption, true);
  831. }
  832. case no_call:
  833. {
  834. YesNoOption bodyOption = normalizeThor(expr->queryBody()->queryFunctionDefinition());
  835. //do Something with it
  836. break;
  837. }
  838. case no_externalcall:
  839. {
  840. IHqlExpression * func = expr->queryExternalDefinition();
  841. IHqlExpression * funcDef = func->queryChild(0);
  842. if (funcDef->hasProperty(gctxmethodAtom) || funcDef->hasProperty(globalContextAtom))
  843. return OptionNo;
  844. // if (funcDef->hasProperty(graphAtom))
  845. // return OptionYes;
  846. if (!resourceConditionalActions && expr->isAction())
  847. return OptionNo;
  848. //depends on the results of the arguments..
  849. type = NULL; // don't check the return type
  850. break;
  851. }
  852. case no_setworkflow_cond:
  853. case no_ensureresult:
  854. return OptionNo;
  855. case no_null:
  856. return OptionMaybe;
  857. }
  858. //NB: things like NOT EXISTS we want evaluated as NOT THOR(EXISTS()), or as part of a larger context
  859. //otherwise things like klogermann14.xhql don't get EXISTS() csed between graphs.
  860. YesNoOption option = OptionMaybe;
  861. ForEachChild(idx, expr)
  862. {
  863. YesNoOption childOption = normalizeThor(expr->queryChild(idx));
  864. if (childOption == OptionNo)
  865. return OptionNo;
  866. option = combine(option, childOption, true);
  867. }
  868. if (type)
  869. {
  870. switch (type->getTypeCode())
  871. {
  872. case type_row:
  873. switch (op)
  874. {
  875. case no_fromxml:
  876. return option;
  877. case no_createrow:
  878. //MORE: There are more cases that could be evaluated outside of thor, but playing safe.
  879. if (expr->queryChild(0)->isConstant())
  880. return option;
  881. break;
  882. }
  883. return OptionYes;
  884. case type_groupedtable:
  885. case type_table:
  886. //must be a dataset parameter to a call, or an argument to a comparison
  887. //Need to know whether it can be evaluate inline or not.
  888. //if it does require thor, then we will need to generate a setresult/get result pair to do it.
  889. return !canProcessInline(NULL, expr) ? OptionYes : OptionMaybe;
  890. }
  891. }
  892. return option;
  893. }
  894. void HqlThorBoundaryTransformer::transformRoot(const HqlExprArray & in, HqlExprArray & out)
  895. {
  896. //NewHqlTransformer::transformArray(in, out);
  897. //following theoretically might improve things, but generally just causes code to become worse,
  898. //because all the global set results are done in activities, and there isn't cse between them
  899. transformCompound(out, no_actionlist, in, maxRootMaybes);
  900. }
  901. void HqlCppTranslator::markThorBoundaries(WorkflowArray & array)
  902. {
  903. HqlThorBoundaryTransformer thorTransformer(wu(), targetRoxie(), options.maxRootMaybeThorActions, options.resourceConditionalActions, options.resourceSequential);
  904. ForEachItemIn(idx, array)
  905. {
  906. HqlExprArray & exprs = array.item(idx).queryExprs();
  907. HqlExprArray bounded;
  908. thorTransformer.transformRoot(exprs, bounded);
  909. replaceArray(exprs, bounded);
  910. }
  911. }
  912. //---------------------------------------------------------------------------
  913. // NB: This is called after no_setresults are added, but before any normalization.
  914. IHqlExpression * ThorScalarTransformer::queryAlreadyTransformed(IHqlExpression * expr)
  915. {
  916. bool conditional = isConditional();
  917. if (conditional)
  918. {
  919. IHqlExpression * ret = queryExtra(expr)->transformed[false];
  920. if (ret)
  921. return ret;
  922. }
  923. return queryExtra(expr)->transformed[isConditional()];
  924. }
  925. IHqlExpression * ThorScalarTransformer::queryAlreadyTransformedSelector(IHqlExpression * expr)
  926. {
  927. return queryExtra(expr)->transformedSelector[isConditional()];
  928. }
  929. void ThorScalarTransformer::setTransformed(IHqlExpression * expr, IHqlExpression * transformed)
  930. {
  931. queryExtra(expr)->transformed[isConditional()].set(transformed);
  932. }
  933. void ThorScalarTransformer::setTransformedSelector(IHqlExpression * expr, IHqlExpression * transformed)
  934. {
  935. queryExtra(expr)->transformedSelector[isConditional()].set(transformed);
  936. }
  937. static HqlTransformerInfo ThorScalarTransformerInfo("ThorScalarTransformer");
  938. ThorScalarTransformer::ThorScalarTransformer(const HqlCppOptions & _options) : HoistingHqlTransformer(ThorScalarTransformerInfo, CTFnoteifactions), options(_options)
  939. {
  940. isConditionalDepth = 0;
  941. seenCandidate = false;
  942. }
  943. void ThorScalarTransformer::doAnalyseExpr(IHqlExpression * expr)
  944. {
  945. switch (expr->getOperator())
  946. {
  947. case no_thor:
  948. {
  949. ITypeInfo * type = expr->queryType();
  950. if (type && (type->isScalar() || type->getTypeCode() == type_row))
  951. seenCandidate = true;
  952. //No point looking further than a no_thor they don't (currently) get nested within each other.
  953. return;
  954. }
  955. }
  956. HoistingHqlTransformer::doAnalyseExpr(expr);
  957. }
  958. void ThorScalarTransformer::createHoisted(IHqlExpression * expr, SharedHqlExpr & setResultStmt, SharedHqlExpr & getResult, bool addWrapper)
  959. {
  960. IHqlExpression * value = expr;
  961. HqlExprArray actions;
  962. while (value->getOperator() == no_compound)
  963. {
  964. unwindCommaCompound(actions, value->queryChild(0));
  965. value = value->queryChild(1);
  966. }
  967. IHqlExpression * setResult = createSetResult(value);
  968. getResult.setown(createGetResultFromSetResult(setResult));
  969. actions.append(*setResult);
  970. setResultStmt.setown(createActionList(actions));
  971. if (addWrapper)
  972. setResultStmt.setown(createValue(no_thor, makeVoidType(), setResultStmt.getClear()));
  973. }
  974. IHqlExpression * ThorScalarTransformer::createTransformed(IHqlExpression * expr)
  975. {
  976. if (expr->isConstant())
  977. {
  978. //THOR(NULL) is marked as constant (probably incorrectly), but still needs hoisting.
  979. // if ((expr->getOperator() != no_thor) || (expr->numChildren() == 0))
  980. return LINK(expr);
  981. }
  982. IHqlExpression * ret = queryTransformAnnotation(expr);
  983. if (ret)
  984. return ret;
  985. node_operator op = expr->getOperator();
  986. switch (op)
  987. {
  988. case no_if:
  989. {
  990. bool isGuard = isFailureGuard(expr);
  991. HqlExprArray children;
  992. children.append(*transform(expr->queryChild(0)));
  993. if (!isGuard)
  994. isConditionalDepth++;
  995. transformChildren(expr, children);
  996. if (!isGuard)
  997. isConditionalDepth--;
  998. return cloneOrLink(expr, children);
  999. }
  1000. case no_thor:
  1001. {
  1002. ITypeInfo * type = expr->queryType();
  1003. // if (isUsedUnconditionally(expr) && type && (type->isScalar() || type->getTypeCode() == type_row))
  1004. if ((type->isScalar() || type->getTypeCode() == type_row))
  1005. {
  1006. //only other solution is to have some kind of graph result which is returned.
  1007. assertex(options.workunitTemporaries);
  1008. OwnedHqlExpr getResult, setResult;
  1009. OwnedHqlExpr transformedChild = transform(expr->queryChild(0));
  1010. createHoisted(transformedChild, setResult, getResult, true);
  1011. //Note sure if this condition is needed any more - I suspect better without.
  1012. if (isConditional())
  1013. return createCompound(setResult.getClear(), getResult.getClear());
  1014. else
  1015. {
  1016. appendToTarget(*setResult.getClear());
  1017. return getResult.getClear();
  1018. }
  1019. }
  1020. return LINK(expr);
  1021. }
  1022. break;
  1023. case no_mapto:
  1024. if (isConditional())
  1025. {
  1026. HqlExprArray children;
  1027. isConditionalDepth--;
  1028. children.append(*transform(expr->queryChild(0)));
  1029. isConditionalDepth++;
  1030. children.append(*transform(expr->queryChild(1)));
  1031. return cloneOrLink(expr, children);
  1032. }
  1033. break;
  1034. case no_case:
  1035. case no_map:
  1036. {
  1037. HqlExprArray children;
  1038. unsigned firstArg = 0;
  1039. unsigned numChildren = expr->numChildren();
  1040. children.ensure(numChildren);
  1041. if (op != no_map)
  1042. {
  1043. firstArg = 1;
  1044. children.append(*transform(expr->queryChild(0)));
  1045. }
  1046. isConditionalDepth++;
  1047. for (unsigned idx=firstArg; idx < numChildren; idx++)
  1048. children.append(*transform(expr->queryChild(idx)));
  1049. isConditionalDepth--;
  1050. return cloneOrLink(expr, children);
  1051. }
  1052. case no_table:
  1053. //Don't look at the default values for fields in the table's record
  1054. return LINK(expr);
  1055. }
  1056. return HoistingHqlTransformer::createTransformed(expr);
  1057. }
  1058. //---------------------------------------------------------------------------
  1059. /*
  1060. Look for expressions like count(x) and abc[1].x inside a condition and convert to
  1061. setresult(<complicated>, 'x')
  1062. getresult('x')
  1063. Problems:
  1064. o it tries to keep get/set results within the conditional branches that need them,
  1065. but that means if it occurs in more than one then it will only get added once.
  1066. o It (and all transformers) should possibly always generate a setresult,getresult locally,
  1067. and then have another pass that moves all the setresults to the optimal place. E.g. to the highest shared location.
  1068. [Alternatively can a global, but conditional, root graph be generated for it?]
  1069. Also converts
  1070. setresult(thor(x)) to thor(setresult(x))
  1071. thor(scalar) to setresult(scalar,'x'),getresult('x')
  1072. */
  1073. static void normalizeResultFormat(WorkflowArray & workflow, const HqlCppOptions & options)
  1074. {
  1075. ForEachItemIn(idx, workflow)
  1076. {
  1077. HqlExprArray & exprs = workflow.item(idx).queryExprs();
  1078. //Until thor has a way of calling a graph and returning a result we need to call this transformer, so that
  1079. //scalars that need to be evaluated in thor are correctly hoisted.
  1080. {
  1081. ThorScalarTransformer transformer(options);
  1082. transformer.analyseArray(exprs, 0);
  1083. if (transformer.needToTransform())
  1084. {
  1085. HqlExprArray transformed;
  1086. transformer.transformRoot(exprs, transformed);
  1087. replaceArray(exprs, transformed);
  1088. }
  1089. }
  1090. }
  1091. }
  1092. //---------------------------------------------------------------------------
  1093. //Try and get the HOLe queries at the start and the Thor queries at the end.
  1094. //Keep track of the dependencies of the statements, so that they don't get reordered
  1095. //too aggressively.
  1096. //---------------------------------------------------------------------------
  1097. static HqlTransformerInfo sequenceNumberAllocatorInfo("SequenceNumberAllocator");
  1098. SequenceNumberAllocator::SequenceNumberAllocator() : NewHqlTransformer(sequenceNumberAllocatorInfo)
  1099. {
  1100. sequence = 0;
  1101. }
  1102. void SequenceNumberAllocator::nextSequence(HqlExprArray & args, IHqlExpression * name, _ATOM overwriteAction, IHqlExpression * value, bool needAttr, bool * duplicate)
  1103. {
  1104. IHqlExpression * seq = NULL;
  1105. if (duplicate)
  1106. *duplicate = false;
  1107. if (name)
  1108. {
  1109. SharedHqlExpr * matched = namedMap.getValue(name);
  1110. if (matched)
  1111. {
  1112. StringBuffer nameText;
  1113. name->toString(nameText);
  1114. IHqlExpression * prev = matched->get();
  1115. if (prev->isAttribute())
  1116. {
  1117. _ATOM prevName = prev->queryName();
  1118. if (!overwriteAction)
  1119. {
  1120. if (prevName == extendAtom)
  1121. throwError1(HQLERR_ExtendMismatch, nameText.str());
  1122. else
  1123. throwError1(HQLERR_OverwriteMismatch, nameText.str());
  1124. }
  1125. else if (prevName != overwriteAction)
  1126. throwError1(HQLERR_ExtendOverwriteMismatch, nameText.str());
  1127. IHqlExpression * prevValue = prev->queryChild(1);
  1128. if (!recordTypesMatch(prevValue->queryType(), value->queryType()))
  1129. throwError1(HQLERR_ExtendTypeMismatch, nameText.str());
  1130. seq = LINK(prev->queryChild(0));
  1131. assertex(duplicate);
  1132. *duplicate = true;
  1133. }
  1134. else
  1135. {
  1136. if (overwriteAction)
  1137. {
  1138. if (overwriteAction == extendAtom)
  1139. throwError1(HQLERR_ExtendMismatch, nameText.str());
  1140. else
  1141. throwError1(HQLERR_OverwriteMismatch, nameText.str());
  1142. }
  1143. else
  1144. throwError1(HQLERR_DuplicateNameOutput, nameText.str());
  1145. }
  1146. }
  1147. if (!seq)
  1148. {
  1149. seq = createConstant(signedType->castFrom(true, (__int64)sequence++));
  1150. OwnedHqlExpr saveValue = overwriteAction ? createAttribute(overwriteAction, LINK(seq), LINK(value)) : LINK(seq);
  1151. namedMap.setValue(name, saveValue);
  1152. }
  1153. }
  1154. else
  1155. seq = createConstant(signedType->castFrom(true, (__int64)sequence++));
  1156. if (needAttr)
  1157. args.append(*createAttribute(sequenceAtom, seq));
  1158. else
  1159. args.append(*seq);
  1160. }
  1161. IHqlExpression * SequenceNumberAllocator::doTransformRootExpr(IHqlExpression * expr)
  1162. {
  1163. node_operator op = expr->getOperator();
  1164. switch(op)
  1165. {
  1166. case no_compound:
  1167. case no_comma:
  1168. case no_parallel:
  1169. case no_sequential:
  1170. case no_actionlist:
  1171. {
  1172. HqlExprArray args;
  1173. ForEachChild(idx, expr)
  1174. args.append(*doTransformRootExpr(expr->queryChild(idx)));
  1175. return cloneOrLink(expr, args);
  1176. }
  1177. case no_buildindex:
  1178. case no_output:
  1179. case no_apply:
  1180. case no_distribution:
  1181. case no_keydiff:
  1182. case no_keypatch:
  1183. case no_outputscalar:
  1184. return createTransformed(expr); //NB: Do not common up!!!
  1185. case no_setmeta:
  1186. return LINK(expr);
  1187. default:
  1188. {
  1189. OwnedHqlExpr transformed = transform(expr);
  1190. ITypeInfo * type = transformed->queryType();
  1191. if (type && type->getTypeCode() != type_void)
  1192. {
  1193. HqlExprArray args;
  1194. bool isOuterWorkflow = (op == no_colon) && workflowContainsSchedule(transformed);
  1195. assertex(!isOuterWorkflow || !workflowContainsNonSchedule(transformed));
  1196. if (isOuterWorkflow)
  1197. args.append(*LINK(transformed->queryChild(0)));
  1198. else
  1199. args.append(*LINK(transformed));
  1200. nextSequence(args, NULL, NULL, NULL, true, NULL);
  1201. IHqlExpression * ret = createSetResult(args);
  1202. if (isOuterWorkflow)
  1203. {
  1204. args.kill();
  1205. args.append(*ret);
  1206. unwindChildren(args, transformed, 1);
  1207. ret = transformed->clone(args);
  1208. }
  1209. return ret;
  1210. }
  1211. return LINK(transformed);
  1212. }
  1213. }
  1214. }
  1215. IHqlExpression * SequenceNumberAllocator::createTransformed(IHqlExpression * expr)
  1216. {
  1217. switch (expr->getOperator())
  1218. {
  1219. case no_actionlist:
  1220. return doTransformRootExpr(expr);
  1221. }
  1222. Owned<IHqlExpression> transformed = NewHqlTransformer::createTransformed(expr);
  1223. return attachSequenceNumber(transformed.get());
  1224. }
  1225. static _ATOM queryOverwriteAction(IHqlExpression * expr)
  1226. {
  1227. if (expr->hasProperty(extendAtom))
  1228. return extendAtom;
  1229. if (expr->hasProperty(overwriteAtom))
  1230. return overwriteAtom;
  1231. if (expr->hasProperty(noOverwriteAtom))
  1232. return noOverwriteAtom;
  1233. return NULL;
  1234. }
  1235. IHqlExpression * SequenceNumberAllocator::attachSequenceNumber(IHqlExpression * expr)
  1236. {
  1237. switch (expr->getOperator())
  1238. {
  1239. case no_buildindex:
  1240. case no_output:
  1241. case no_apply:
  1242. case no_distribution:
  1243. case no_keydiff:
  1244. case no_keypatch:
  1245. {
  1246. queryExtra(expr)->setGetsSequence();
  1247. HqlExprArray args;
  1248. unwindChildren(args, expr);
  1249. bool duplicate = false;
  1250. nextSequence(args, queryResultName(expr), queryOverwriteAction(expr), expr->queryChild(0), true, &duplicate);
  1251. args.append(*createUniqueId());
  1252. return expr->clone(args);
  1253. }
  1254. break;
  1255. case no_outputscalar:
  1256. {
  1257. IHqlExpression * name = queryResultName(expr);
  1258. queryExtra(expr)->setGetsSequence();
  1259. HqlExprArray args;
  1260. args.append(*LINK(expr->queryChild(0)));
  1261. bool duplicate = false;
  1262. nextSequence(args, name, queryOverwriteAction(expr), expr->queryChild(0), true, &duplicate);
  1263. if (name)
  1264. args.append(*createAttribute(namedAtom, LINK(name)));
  1265. args.append(*createAttribute(outputAtom));
  1266. args.append(*createUniqueId());
  1267. return createSetResult(args);
  1268. }
  1269. default:
  1270. return LINK(expr);
  1271. }
  1272. }
  1273. void HqlCppTranslator::allocateSequenceNumbers(HqlExprArray & exprs)
  1274. {
  1275. HqlExprArray sequenced;
  1276. SequenceNumberAllocator transformer;
  1277. transformer.transformRoot(exprs, sequenced);
  1278. replaceArray(exprs, sequenced);
  1279. maxSequence = transformer.getMaxSequence();
  1280. }
  1281. //---------------------------------------------------------------------------
  1282. static void replaceAssignSelector(HqlExprArray & assigns, IHqlExpression * newSelector)
  1283. {
  1284. ForEachItemIn(idx, assigns)
  1285. {
  1286. IHqlExpression & cur = assigns.item(idx);
  1287. IHqlExpression * lhs = cur.queryChild(0);
  1288. IHqlExpression * rhs = cur.queryChild(1);
  1289. assigns.replace(*createAssign(replaceSelector(lhs, queryActiveTableSelector(), newSelector), replaceSelector(rhs, queryActiveTableSelector(), newSelector)), idx);
  1290. }
  1291. }
  1292. static IHqlExpression * createArith(node_operator op, ITypeInfo * type, IHqlExpression * numerator, IHqlExpression * denominator)
  1293. {
  1294. return createValue(op, LINK(type), ensureExprType(numerator, type), ensureExprType(denominator, type));
  1295. }
  1296. //MORE: This might be better as a class, it would reduce the number of parameters
  1297. IHqlExpression * doNormalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts);
  1298. IHqlExpression * evalNormalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts)
  1299. {
  1300. switch (expr->getOperator())
  1301. {
  1302. case no_avegroup:
  1303. //Map this to sum(x)/count(x)
  1304. {
  1305. IHqlExpression * arg = expr->queryChild(0);
  1306. IHqlExpression * cond = expr->queryChild(1);
  1307. Owned<ITypeInfo> sumType = getSumAggType(arg);
  1308. ITypeInfo * exprType = expr->queryType();
  1309. OwnedHqlExpr sum = createValue(no_sumgroup, LINK(sumType), LINK(arg), LINK(cond));
  1310. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1311. //average should be done as a real operation I think, possibly decimal, if argument is decimal
  1312. OwnedHqlExpr avg = createArith(no_div, exprType, sum, count);
  1313. return doNormalizeAggregateExpr(selector, avg, fields, assigns, extraSelectNeeded, false);
  1314. }
  1315. case no_vargroup:
  1316. //Map this to (sum(x^2)-sum(x)^2/count())/count()
  1317. {
  1318. IHqlExpression * arg = expr->queryChild(0);
  1319. IHqlExpression * cond = expr->queryChild(1);
  1320. ITypeInfo * exprType = expr->queryType();
  1321. OwnedHqlExpr xx = createArith(no_mul, exprType, arg, arg);
  1322. OwnedHqlExpr sumxx = createValue(no_sumgroup, LINK(exprType), LINK(xx), LINK(cond));
  1323. OwnedHqlExpr sumx = createValue(no_sumgroup, LINK(exprType), LINK(arg), LINK(cond));
  1324. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1325. //average should be done as a real operation I think, possibly decimal, if argument is decimal
  1326. OwnedHqlExpr n1 = createArith(no_mul, exprType, sumx, sumx);
  1327. OwnedHqlExpr n2 = createArith(no_div, exprType, n1, count);
  1328. OwnedHqlExpr n3 = createArith(no_sub, exprType, sumxx, n2);
  1329. OwnedHqlExpr n4 = createArith(no_div, exprType, n3, count);
  1330. return doNormalizeAggregateExpr(selector, n4, fields, assigns, extraSelectNeeded, false);
  1331. }
  1332. case no_covargroup:
  1333. //Map this to (sum(x.y)-sum(x).sum(y)/count())/count()
  1334. {
  1335. IHqlExpression * argX = expr->queryChild(0);
  1336. IHqlExpression * argY = expr->queryChild(1);
  1337. IHqlExpression * cond = expr->queryChild(2);
  1338. ITypeInfo * exprType = expr->queryType();
  1339. OwnedHqlExpr xy = createArith(no_mul, exprType, argX, argY);
  1340. OwnedHqlExpr sumxy = createValue(no_sumgroup, LINK(exprType), LINK(xy), LINK(cond));
  1341. OwnedHqlExpr sumx = createValue(no_sumgroup, LINK(exprType), LINK(argX), LINK(cond));
  1342. OwnedHqlExpr sumy = createValue(no_sumgroup, LINK(exprType), LINK(argY), LINK(cond));
  1343. OwnedHqlExpr count = createValue(no_countgroup, LINK(defaultIntegralType), LINK(cond));
  1344. //average should be done as a real operation I think, possibly decimal, if argument is decimal
  1345. OwnedHqlExpr n1 = createArith(no_mul, exprType, sumx, sumy);
  1346. OwnedHqlExpr n2 = createArith(no_div, exprType, n1, count);
  1347. OwnedHqlExpr n3 = createArith(no_sub, exprType, sumxy, n2);
  1348. OwnedHqlExpr n4 = createArith(no_div, exprType, n3, count);
  1349. return doNormalizeAggregateExpr(selector, n4, fields, assigns, extraSelectNeeded, false);
  1350. }
  1351. case no_corrgroup:
  1352. //Map this to (covar(x,y)/(var(x).var(y)))
  1353. //== (sum(x.y)*count() - sum(x).sum(y))/sqrt((sum(x.x)*count()-sum(x)^2) * (sum(y.y)*count()-sum(y)^2))
  1354. {
  1355. IHqlExpression * argX = expr->queryChild(0);
  1356. IHqlExpression * argY = expr->queryChild(1);
  1357. IHqlExpression * cond = expr->queryChild(2);
  1358. ITypeInfo * exprType = expr->queryType();
  1359. OwnedHqlExpr xx = createArith(no_mul, exprType, argX, argX);
  1360. OwnedHqlExpr sumxx = createValue(no_sumgroup, LINK(exprType), LINK(xx), LINK(cond));
  1361. OwnedHqlExpr xy = createArith(no_mul, exprType, argX, argY);
  1362. OwnedHqlExpr sumxy = createValue(no_sumgroup, LINK(exprType), LINK(xy), LINK(cond));
  1363. OwnedHqlExpr yy = createArith(no_mul, exprType, argY, argY);
  1364. OwnedHqlExpr sumyy = createValue(no_sumgroup, LINK(exprType), LINK(yy), 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. OwnedHqlExpr n1 = createArith(no_mul, exprType, sumxy, count);
  1369. OwnedHqlExpr n2 = createArith(no_mul, exprType, sumx, sumy);
  1370. OwnedHqlExpr n3 = createArith(no_sub, exprType, n1, n2);
  1371. OwnedHqlExpr n4 = createArith(no_mul, exprType, sumxx, count);
  1372. OwnedHqlExpr n5 = createArith(no_mul, exprType, sumx, sumx);
  1373. OwnedHqlExpr n6 = createArith(no_sub, exprType, n4, n5);
  1374. OwnedHqlExpr n7 = createArith(no_mul, exprType, sumyy, count);
  1375. OwnedHqlExpr n8 = createArith(no_mul, exprType, sumy, sumy);
  1376. OwnedHqlExpr n9 = createArith(no_sub, exprType, n7, n8);
  1377. OwnedHqlExpr n10 = createArith(no_mul, exprType, n6, n9);
  1378. OwnedHqlExpr n11 = createValue(no_sqrt, LINK(exprType), LINK(n10));
  1379. OwnedHqlExpr n12 = createArith(no_div, exprType, n3, n11);
  1380. return doNormalizeAggregateExpr(selector, n12, fields, assigns, extraSelectNeeded, false);
  1381. }
  1382. throwUnexpected();
  1383. case no_variance:
  1384. case no_covariance:
  1385. case no_correlation:
  1386. throwUnexpectedOp(expr->getOperator());
  1387. case no_count:
  1388. case no_sum:
  1389. case no_max:
  1390. case no_min:
  1391. case no_ave:
  1392. case no_select:
  1393. case no_exists:
  1394. case no_field:
  1395. // a count on a child dataset or something else - add it as it is...
  1396. //goes wrong for count(group)*
  1397. return LINK(expr);
  1398. case no_countgroup:
  1399. case no_sumgroup:
  1400. case no_maxgroup:
  1401. case no_mingroup:
  1402. case no_existsgroup:
  1403. {
  1404. ForEachItemIn(idx, assigns)
  1405. {
  1406. IHqlExpression & cur = assigns.item(idx);
  1407. if (cur.queryChild(1) == expr)
  1408. {
  1409. extraSelectNeeded = true;
  1410. return LINK(cur.queryChild(0)); //replaceSelector(cur.queryChild(0), querySelf(), queryActiveTableSelector());
  1411. }
  1412. }
  1413. IHqlExpression * targetField;
  1414. if (selector)
  1415. {
  1416. targetField = LINK(selector->queryChild(1));
  1417. }
  1418. else
  1419. {
  1420. StringBuffer temp;
  1421. temp.append("_agg_").append(assigns.ordinality());
  1422. targetField = createField(createIdentifierAtom(temp.str()), expr->getType(), NULL);
  1423. extraSelectNeeded = true;
  1424. }
  1425. fields.append(*targetField);
  1426. assigns.append(*createAssign(createSelectExpr(getActiveTableSelector(), LINK(targetField)), LINK(expr)));
  1427. return createSelectExpr(getActiveTableSelector(), LINK(targetField));
  1428. }
  1429. case no_cast:
  1430. case no_implicitcast:
  1431. if (selector && canOptimizeCasts)
  1432. {
  1433. IHqlExpression * child = expr->queryChild(0);
  1434. if (expr->queryType()->getTypeCode() == child->queryType()->getTypeCode())
  1435. {
  1436. IHqlExpression * ret = doNormalizeAggregateExpr(selector, child, fields, assigns, extraSelectNeeded, false);
  1437. //This should be ret==child
  1438. if (ret == selector)
  1439. return ret;
  1440. HqlExprArray args;
  1441. args.append(*ret);
  1442. return expr->clone(args);
  1443. }
  1444. }
  1445. //fallthrough...
  1446. default:
  1447. {
  1448. HqlExprArray args;
  1449. unsigned max = expr->numChildren();
  1450. unsigned idx;
  1451. bool diff = false;
  1452. args.ensure(max);
  1453. for (idx = 0; idx < max; idx++)
  1454. {
  1455. IHqlExpression * child = expr->queryChild(idx);
  1456. IHqlExpression * changed = doNormalizeAggregateExpr(NULL, child, fields, assigns, extraSelectNeeded, false);
  1457. args.append(*changed);
  1458. if (child != changed)
  1459. diff = true;
  1460. }
  1461. if (diff)
  1462. return expr->clone(args);
  1463. return LINK(expr);
  1464. }
  1465. }
  1466. }
  1467. IHqlExpression * doNormalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts)
  1468. {
  1469. IHqlExpression * match = static_cast<IHqlExpression *>(expr->queryTransformExtra());
  1470. if (match)
  1471. return LINK(match);
  1472. IHqlExpression * ret = evalNormalizeAggregateExpr(selector, expr, fields, assigns, extraSelectNeeded, canOptimizeCasts);
  1473. expr->setTransformExtra(ret);
  1474. return ret;
  1475. }
  1476. IHqlExpression * normalizeAggregateExpr(IHqlExpression * selector, IHqlExpression * expr, HqlExprArray & fields, HqlExprArray & assigns, bool & extraSelectNeeded, bool canOptimizeCasts)
  1477. {
  1478. TransformMutexBlock block;
  1479. return doNormalizeAggregateExpr(selector, expr, fields, assigns, extraSelectNeeded, canOptimizeCasts);
  1480. }
  1481. //---------------------------------------------------------------------------
  1482. static void appendComponent(HqlExprArray & cpts, bool invert, IHqlExpression * expr)
  1483. {
  1484. if (invert)
  1485. cpts.append(*createValue(no_negate, expr->getType(), LINK(expr)));
  1486. else
  1487. cpts.append(*LINK(expr));
  1488. }
  1489. static void expandRowComponents(HqlExprArray & cpts, bool invert, IHqlExpression * select, IHqlExpression * record)
  1490. {
  1491. ForEachChild(i, record)
  1492. {
  1493. IHqlExpression * cur = record->queryChild(i);
  1494. switch (cur->getOperator())
  1495. {
  1496. case no_record:
  1497. expandRowComponents(cpts, invert, select, cur);
  1498. break;
  1499. case no_ifblock:
  1500. expandRowComponents(cpts, invert, select, cur->queryChild(1));
  1501. break;
  1502. case no_field:
  1503. {
  1504. OwnedHqlExpr childSelect = createSelectExpr(LINK(select), LINK(cur));
  1505. if (!childSelect->isDatarow())
  1506. appendComponent(cpts, invert, childSelect);
  1507. else
  1508. expandRowComponents(cpts, invert, childSelect, childSelect->queryRecord());
  1509. break;
  1510. }
  1511. }
  1512. }
  1513. }
  1514. static IHqlExpression * simplifySortlistComplexity(IHqlExpression * sortlist)
  1515. {
  1516. if (!sortlist)
  1517. return NULL;
  1518. //convert concat on fixed width strings to a list of fields.
  1519. bool same = true;
  1520. HqlExprArray cpts;
  1521. ForEachChild(idx, sortlist)
  1522. {
  1523. IHqlExpression * cpt = sortlist->queryChild(idx);
  1524. IHqlExpression * cur = cpt;
  1525. bool expand = false;
  1526. bool invert = false;
  1527. if (cpt->getOperator() == no_negate)
  1528. {
  1529. invert = true;
  1530. cur = cur->queryChild(0);
  1531. }
  1532. if (cur->getOperator() == no_concat)
  1533. {
  1534. HqlExprArray concats;
  1535. cur->unwindList(concats, no_concat);
  1536. expand = true;
  1537. ForEachItemIn(idxc, concats)
  1538. {
  1539. ITypeInfo * type = concats.item(idxc).queryType();
  1540. unsigned tc = type->getTypeCode();
  1541. if (!((tc == type_string || tc == type_data) && (type->getSize() != UNKNOWN_LENGTH)))
  1542. expand = false;
  1543. }
  1544. if (expand)
  1545. {
  1546. ForEachItemIn(idxc, concats)
  1547. appendComponent(cpts, invert, &concats.item(idxc));
  1548. }
  1549. }
  1550. else
  1551. {
  1552. #if 0
  1553. if (cur->getOperator() == no_select && cur->isDatarow() && !cur->hasProperty(newAtom))
  1554. {
  1555. expand = true;
  1556. expandRowComponents(cpts, invert, cur, cur->queryRecord());
  1557. }
  1558. #endif
  1559. }
  1560. if (!expand)
  1561. cpts.append(*LINK(cpt));
  1562. else
  1563. same = false;
  1564. }
  1565. if (!same)
  1566. return createSortList(cpts);
  1567. return NULL;
  1568. }
  1569. static IHqlExpression * normalizeIndexBuild(IHqlExpression * expr, bool sortIndexPayload, bool alwaysLocal, bool allowImplicitShuffle)
  1570. {
  1571. LinkedHqlExpr dataset = expr->queryChild(0);
  1572. IHqlExpression * normalizedDs = dataset->queryNormalizedSelector();
  1573. IHqlExpression * buildRecord = dataset->queryRecord();
  1574. // If any field types collate differently before and after translation to their hozed
  1575. // format, then we need to do the translation here, otherwise this
  1576. // sort may not be in the correct order. (ebcdic->ascii? integers are ok; unicode isn't!)
  1577. // First build the sort order we need....
  1578. HqlExprArray sorts;
  1579. gatherIndexBuildSortOrder(sorts, expr, sortIndexPayload);
  1580. OwnedHqlExpr sortOrder = createSortList(sorts);
  1581. OwnedHqlExpr newsort = simplifySortlistComplexity(sortOrder);
  1582. if (!newsort)
  1583. newsort.set(sortOrder);
  1584. ForEachChild(i1, expr)
  1585. {
  1586. IHqlExpression * cur = expr->queryChild(i1);
  1587. if (cur->getOperator() == no_distributer)
  1588. {
  1589. LinkedHqlExpr ds = dataset;
  1590. IHqlExpression * index = cur->queryChild(0);
  1591. if (!expr->hasProperty(sortedAtom))
  1592. {
  1593. if (!expr->hasProperty(localAtom))
  1594. {
  1595. HqlExprArray joinCondition;
  1596. IHqlExpression * indexRecord = index->queryChild(1);
  1597. assertex(indexRecord->numChildren() == buildRecord->numChildren());
  1598. unsigned numFields = firstPayloadField(index);
  1599. OwnedHqlExpr seq = createSelectorSequence();
  1600. OwnedHqlExpr left = createSelector(no_left, dataset, seq);
  1601. OwnedHqlExpr right = createSelector(no_right, index, seq);
  1602. OwnedHqlExpr cond;
  1603. unsigned idxLhs = 0;
  1604. unsigned idxRhs = 0;
  1605. for (unsigned i2=0; i2 < numFields; i2++)
  1606. {
  1607. IHqlExpression * lhs = createSelectExpr(LINK(left), LINK(queryNextRecordField(buildRecord, idxLhs)));
  1608. IHqlExpression * rhs = createSelectExpr(LINK(right), LINK(queryNextRecordField(indexRecord, idxRhs)));
  1609. IHqlExpression * test = createBoolExpr(no_eq, lhs, rhs);
  1610. extendConditionOwn(cond, no_and, test);
  1611. }
  1612. HqlExprArray args;
  1613. args.append(*ds.getClear());
  1614. args.append(*LINK(index));
  1615. args.append(*cond.getClear());
  1616. args.append(*LINK(seq));
  1617. ds.setown(createDataset(no_keyeddistribute, args));
  1618. ds.setown(cloneInheritedAnnotations(expr, ds));
  1619. }
  1620. ds.setown(createDataset(no_sort, ds.getClear(), createComma(LINK(newsort), createLocalAttribute())));
  1621. ds.setown(cloneInheritedAnnotations(expr, ds));
  1622. }
  1623. if (expr->hasProperty(mergeAtom))
  1624. {
  1625. LinkedHqlExpr sortedIndex = index;
  1626. if (!index->hasProperty(sortedAtom))
  1627. {
  1628. HqlExprArray args;
  1629. unwindChildren(args, index);
  1630. args.append(*createAttribute(sortedAtom));
  1631. sortedIndex.setown(index->clone(args));
  1632. }
  1633. HqlExprArray sorts;
  1634. unwindChildren(sorts, newsort);
  1635. OwnedHqlExpr sortAttr = createExprAttribute(sortedAtom, sorts);
  1636. HqlExprArray args;
  1637. args.append(*LINK(ds));
  1638. args.append(*sortedIndex.getClear());
  1639. args.append(*createLocalAttribute());
  1640. args.append(*replaceSelector(sortAttr, ds->queryNormalizedSelector(), queryActiveTableSelector()));
  1641. ds.setown(createDataset(no_merge, args));
  1642. ds.setown(cloneInheritedAnnotations(expr, ds));
  1643. }
  1644. HqlExprArray args;
  1645. unwindChildren(args, expr);
  1646. args.replace(*ds.getClear(), 0);
  1647. args.remove(i1);
  1648. args.append(*createAttribute(sortedAtom));
  1649. args.append(*createLocalAttribute());
  1650. args.append(*createAttribute(indexAtom, LINK(index->queryChild(3))));
  1651. return expr->clone(args);
  1652. }
  1653. }
  1654. IHqlExpression * distributed = expr->queryProperty(distributedAtom);
  1655. if (distributed && distributed->queryChild(0))
  1656. {
  1657. OwnedHqlExpr distribute = createDataset(no_distribute, LINK(dataset), LINK(distributed->queryChild(0)));
  1658. distribute.setown(cloneInheritedAnnotations(expr, distribute));
  1659. HqlExprArray args;
  1660. args.append(*distribute.getClear());
  1661. unwindChildren(args, expr, 1);
  1662. args.zap(*distributed);
  1663. return expr->clone(args);
  1664. }
  1665. if (!expr->hasProperty(sortedAtom))
  1666. {
  1667. if (dataset->queryType()->getTypeCode() == type_groupedtable)
  1668. {
  1669. while (dataset->getOperator() == no_group)
  1670. dataset.set(dataset->queryChild(0));
  1671. if (dataset->queryType()->getTypeCode() == type_groupedtable)
  1672. {
  1673. dataset.setown(createDataset(no_group, LINK(dataset), NULL));
  1674. dataset.setown(cloneInheritedAnnotations(expr, dataset));
  1675. }
  1676. }
  1677. OwnedHqlExpr sorted = ensureSorted(dataset, newsort, expr->hasProperty(localAtom), true, alwaysLocal, allowImplicitShuffle);
  1678. if (sorted == dataset)
  1679. return NULL;
  1680. sorted.setown(inheritAttribute(sorted, expr, skewAtom));
  1681. sorted.setown(inheritAttribute(sorted, expr, thresholdAtom));
  1682. HqlExprArray args;
  1683. args.append(*LINK(sorted));
  1684. unwindChildren(args, expr, 1);
  1685. args.append(*createAttribute(sortedAtom));
  1686. return expr->clone(args);
  1687. }
  1688. if (expr->hasProperty(dedupAtom))
  1689. {
  1690. IHqlExpression * ds = expr->queryChild(0);
  1691. OwnedHqlExpr seq = createSelectorSequence();
  1692. OwnedHqlExpr mappedSortList = replaceSelector(newsort, queryActiveTableSelector(), ds);
  1693. HqlExprArray dedupArgs;
  1694. dedupArgs.append(*LINK(expr->queryChild(0)));
  1695. unwindChildren(dedupArgs, mappedSortList);
  1696. dedupArgs.append(*createLocalAttribute());
  1697. dedupArgs.append(*LINK(seq));
  1698. OwnedHqlExpr dedup = createDataset(no_dedup, dedupArgs);
  1699. HqlExprArray buildArgs;
  1700. buildArgs.append(*cloneInheritedAnnotations(expr, dedup));
  1701. unwindChildren(buildArgs, expr, 1);
  1702. removeProperty(buildArgs, dedupAtom);
  1703. return expr->clone(buildArgs);
  1704. }
  1705. return NULL;
  1706. }
  1707. static HqlTransformerInfo thorHqlTransformerInfo("ThorHqlTransformer");
  1708. ThorHqlTransformer::ThorHqlTransformer(HqlCppTranslator & _translator, ClusterType _targetClusterType, IConstWorkUnit * wu)
  1709. : NewHqlTransformer(thorHqlTransformerInfo), translator(_translator), options(_translator.queryOptions())
  1710. {
  1711. targetClusterType = _targetClusterType;
  1712. topNlimit = options.topnLimit;
  1713. groupAllDistribute = isThorCluster(targetClusterType) && options.groupAllDistribute;
  1714. }
  1715. IHqlExpression * ThorHqlTransformer::createTransformed(IHqlExpression * expr)
  1716. {
  1717. OwnedHqlExpr transformed = PARENT::createTransformed(expr);
  1718. updateOrphanedSelectors(transformed, expr);
  1719. IHqlExpression * normalized = NULL;
  1720. switch (transformed->getOperator())
  1721. {
  1722. case no_group:
  1723. normalized = normalizeGroup(transformed);
  1724. break;
  1725. case no_join:
  1726. case no_selfjoin:
  1727. case no_denormalize:
  1728. case no_denormalizegroup:
  1729. normalized = normalizeJoinOrDenormalize(transformed);
  1730. break;
  1731. case no_cosort:
  1732. case no_sort:
  1733. case no_sorted:
  1734. case no_assertsorted:
  1735. normalized = normalizeSort(transformed);
  1736. break;
  1737. case no_shuffle:
  1738. normalized = normalizeShuffle(transformed);
  1739. break;
  1740. case no_cogroup:
  1741. normalized = normalizeCoGroup(transformed);
  1742. break;
  1743. case no_choosen:
  1744. normalized = normalizeChooseN(transformed);
  1745. break;
  1746. case no_aggregate:
  1747. normalized = normalizeTableGrouping(transformed);
  1748. break;
  1749. case no_newusertable:
  1750. normalized = normalizeTableGrouping(transformed);
  1751. if (!normalized)
  1752. normalized = normalizeTableToAggregate(expr, true);
  1753. break;
  1754. case no_newaggregate:
  1755. normalized = normalizePrefetchAggregate(transformed);
  1756. break;
  1757. case no_dedup:
  1758. normalized = normalizeDedup(transformed);
  1759. break;
  1760. case no_rollup:
  1761. normalized = normalizeRollup(transformed);
  1762. break;
  1763. case no_select:
  1764. normalized = normalizeSelect(transformed);
  1765. break;
  1766. case no_temptable:
  1767. normalized = normalizeTempTable(transformed);
  1768. break;
  1769. //MORE should do whole aggregate expression e.g., max(x)-min(x)
  1770. case NO_AGGREGATE:
  1771. normalized = normalizeScalarAggregate(transformed);
  1772. break;
  1773. case no_setresult:
  1774. normalized = convertSetResultToExtract(transformed);
  1775. break;
  1776. case no_projectrow:
  1777. {
  1778. IHqlExpression * ds = transformed->queryChild(0);
  1779. if (isAlwaysActiveRow(ds))
  1780. {
  1781. //Transform PROJECT(row, transform) to a ROW(transform') since more efficient
  1782. OwnedHqlExpr myLeft = createSelector(no_left, ds, querySelSeq(transformed));
  1783. OwnedHqlExpr replaced = replaceSelector(transformed->queryChild(1), myLeft, ds);
  1784. normalized = createRow(no_createrow, LINK(replaced));
  1785. }
  1786. break;
  1787. }
  1788. case no_debug_option_value:
  1789. //pick best engine etc. definitely done by now, so substitute any options that haven't been processed already
  1790. return getDebugValueExpr(translator.wu(), expr);
  1791. }
  1792. if (normalized)
  1793. {
  1794. transformed.setown(transform(normalized));
  1795. normalized->Release();
  1796. }
  1797. /*
  1798. //Has a minor impact on unnecessary local attributes
  1799. if (!translator.targetThor() && transformed->hasProperty(localAtom) && localChangesActivityAction(transformed))
  1800. return removeProperty(transformed, localAtom);
  1801. */
  1802. return transformed.getClear();
  1803. }
  1804. static IHqlExpression * convertDedupToGroupedDedup(IHqlExpression * expr, IHqlExpression * grouping, bool compareAll)
  1805. {
  1806. IHqlExpression * localAttr = expr->queryProperty(localAtom);
  1807. HqlExprArray groupArgs;
  1808. groupArgs.append(*LINK(expr->queryChild(0)));
  1809. groupArgs.append(*LINK(grouping));
  1810. if (compareAll)
  1811. groupArgs.append(*createAttribute(allAtom));
  1812. if (localAttr)
  1813. groupArgs.append(*LINK(localAttr));
  1814. //Ideally this would remove the equality conditions from the dedup, but ok since they are ignored later when generating
  1815. OwnedHqlExpr group = createDataset(no_group, groupArgs);
  1816. group.setown(cloneInheritedAnnotations(expr, group));
  1817. HqlExprArray dedupArgs;
  1818. dedupArgs.append(*LINK(group));
  1819. unwindChildren(dedupArgs, expr, 1);
  1820. removeProperty(dedupArgs, localAtom); //(since now a grouped dedup)
  1821. OwnedHqlExpr ungroup = createDataset(no_group, expr->clone(dedupArgs), NULL);
  1822. return cloneInheritedAnnotations(expr, ungroup);
  1823. }
  1824. IHqlExpression * ThorHqlTransformer::normalizeDedup(IHqlExpression * expr)
  1825. {
  1826. if (isGroupedActivity(expr))
  1827. {
  1828. //MORE: It should be possible to remove ,ALL if no conditions and
  1829. //the equalities (ignoring any grouping conditions) match the group sort order
  1830. return NULL;
  1831. }
  1832. // DEDUP, ALL, local: - pre sort the data, group, dedup and ungroup
  1833. // DEDUP, ALL, global - if just had a sort by any of the criteria then do it local
  1834. // DEDUP, not all, not grouped, group by criteria, dedup, degroup
  1835. DedupInfoExtractor info(expr);
  1836. if (info.equalities.ordinality() == 0)
  1837. return NULL;
  1838. IHqlExpression * dataset = expr->queryChild(0);
  1839. bool hasLocal = isLocalActivity(expr);
  1840. bool isLocal = hasLocal || !translator.targetThor();
  1841. bool isHashDedup = expr->hasProperty(hashAtom);
  1842. if (info.compareAllRows)
  1843. {
  1844. IHqlExpression * manyProp = expr->queryProperty(manyAtom);
  1845. if (!isLocal && manyProp)
  1846. {
  1847. //If lots of duplicates, then dedup all locally and then dedup all globally.
  1848. HqlExprArray localArgs;
  1849. unwindChildren(localArgs, expr);
  1850. localArgs.zap(*manyProp);
  1851. localArgs.append(*createLocalAttribute());
  1852. OwnedHqlExpr localDedup = expr->clone(localArgs);
  1853. HqlExprArray globalArgs;
  1854. globalArgs.append(*localDedup.getClear());
  1855. unwindChildren(globalArgs, expr, 1);
  1856. globalArgs.zap(*manyProp);
  1857. return expr->clone(globalArgs);
  1858. }
  1859. }
  1860. //If a dedup can be done locally then force it to be local
  1861. if (!isLocal)
  1862. {
  1863. OwnedHqlExpr newSort = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  1864. if (isPartitionedForGroup(dataset, newSort, info.compareAllRows))
  1865. {
  1866. OwnedHqlExpr ret = appendOwnedOperand(expr, createLocalAttribute());
  1867. //A global all join implies hash (historically) so preserve that semantic
  1868. if (info.compareAllRows && !isHashDedup)
  1869. return appendOwnedOperand(ret, createAttribute(hashAtom));
  1870. return ret.getClear();
  1871. }
  1872. }
  1873. //DEDUP,ALL
  1874. if (info.compareAllRows)
  1875. {
  1876. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  1877. bool checkLocal = isLocal || (options.supportsMergeDistribute && !isHashDedup);
  1878. //If the dataset is already sorted for deduping, (and no extra tests) then
  1879. //if local can just remove the ALL attribute, since the records are already adjacent.
  1880. //if global remove the all, but enclose the dedup in a group to avoid serial processing
  1881. //Ignore HASH if specified since this has to be more efficient.
  1882. if (info.conds.ordinality() == 0)
  1883. {
  1884. bool alreadySorted = isSortedForGroup(dataset, groupOrder, checkLocal);
  1885. if (alreadySorted)
  1886. {
  1887. OwnedHqlExpr noHash = removeProperty(expr, hashAtom);
  1888. OwnedHqlExpr noAll = removeProperty(noHash, allAtom);
  1889. if (isLocal)
  1890. return noAll.getClear();
  1891. return convertDedupToGroupedDedup(noAll, groupOrder, checkLocal && !isLocal);
  1892. }
  1893. }
  1894. if (!isHashDedup)
  1895. {
  1896. //If has post non equality condition, change it to a group all->dedup->ungroup
  1897. if (info.conds.ordinality())
  1898. return convertDedupToGroupedDedup(expr, groupOrder, true);
  1899. //If local and thor (since hash dedup may overflow) convert to sort, dedup(not all)
  1900. //Otherwise a hashdedup is likely to be more efficient - since it will be linear cf O(NlnN) for the sort
  1901. if (hasLocal && translator.targetThor())
  1902. {
  1903. HqlExprArray dedupArgs;
  1904. dedupArgs.append(*ensureSortedForGroup(dataset, groupOrder, true, false, options.implicitGroupShuffle));
  1905. unwindChildren(dedupArgs, expr, 1);
  1906. removeProperty(dedupArgs, allAtom);
  1907. return expr->clone(dedupArgs);
  1908. }
  1909. else
  1910. {
  1911. if (matchesConstantValue(info.numToKeep, 1) && !info.keepLeft)
  1912. return appendOwnedOperand(expr, createAttribute(hashAtom));
  1913. }
  1914. }
  1915. }
  1916. else
  1917. {
  1918. //Convert dedup(ds, exprs) to group(dedup(group(ds, exprs), exprs))
  1919. //To ensure that the activity isn't executed serially.
  1920. if (!isLocal && !areConstant(info.equalities))
  1921. {
  1922. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  1923. return convertDedupToGroupedDedup(expr, groupOrder, false);
  1924. }
  1925. }
  1926. return NULL;
  1927. }
  1928. IHqlExpression * ThorHqlTransformer::normalizeRollup(IHqlExpression * expr)
  1929. {
  1930. if (isGroupedActivity(expr))
  1931. return NULL;
  1932. IHqlExpression * dataset = expr->queryChild(0);
  1933. IHqlExpression * cond = expr->queryChild(1);
  1934. if (isThorCluster(targetClusterType) && !expr->queryProperty(localAtom) && isIndependentOfScope(expr))
  1935. {
  1936. HqlExprArray equalities;
  1937. OwnedHqlExpr extra;
  1938. if (cond->getOperator() == no_sortlist)
  1939. cond->unwindList(equalities, no_sortlist);
  1940. else if (!cond->isBoolean())
  1941. equalities.append(*LINK(cond));
  1942. else
  1943. {
  1944. HqlExprArray terms;
  1945. cond->unwindList(terms, no_and);
  1946. OwnedHqlExpr left = createSelector(no_left, dataset, querySelSeq(expr));
  1947. OwnedHqlExpr right = createSelector(no_right, dataset, querySelSeq(expr));
  1948. ForEachItemIn(i, terms)
  1949. {
  1950. IHqlExpression & cur = terms.item(i);
  1951. bool matched = false;
  1952. if (cur.getOperator() == no_eq)
  1953. {
  1954. OwnedHqlExpr mappedLeft = replaceSelector(cur.queryChild(0), left, dataset);
  1955. OwnedHqlExpr mappedRight = replaceSelector(cur.queryChild(1), right, dataset);
  1956. if (mappedLeft == mappedRight)
  1957. {
  1958. equalities.append(*LINK(mappedLeft));
  1959. matched = true;
  1960. }
  1961. }
  1962. if (!matched)
  1963. extendConditionOwn(extra, no_and, LINK(&cur));
  1964. }
  1965. }
  1966. //Don't create a group by constant - it will kill thor!
  1967. ForEachItemInRev(ie, equalities)
  1968. if (equalities.item(ie).isConstant())
  1969. equalities.remove(ie);
  1970. if (equalities.ordinality())
  1971. {
  1972. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), equalities);
  1973. if (isPartitionedForGroup(dataset, groupOrder, false))
  1974. return appendOwnedOperand(expr, createLocalAttribute());
  1975. HqlExprArray groupArgs, rollupArgs;
  1976. groupArgs.append(*LINK(dataset));
  1977. groupArgs.append(*LINK(groupOrder));
  1978. OwnedHqlExpr group = createDataset(no_group, groupArgs);
  1979. group.setown(cloneInheritedAnnotations(expr, group));
  1980. rollupArgs.append(*LINK(group));
  1981. if (extra)
  1982. rollupArgs.append(*extra.getClear());
  1983. else
  1984. rollupArgs.append(*createConstant(true));
  1985. unwindChildren(rollupArgs, expr, 2);
  1986. OwnedHqlExpr ungroup = createDataset(no_group, expr->clone(rollupArgs), NULL);
  1987. return cloneInheritedAnnotations(expr, ungroup);
  1988. }
  1989. }
  1990. return NULL;
  1991. }
  1992. IHqlExpression * ThorHqlTransformer::skipOverGroups(IHqlExpression * dataset, bool isLocal)
  1993. {
  1994. //if grouping a group, remove the initial group.
  1995. //Not completely sure about this - it may potentially cause extra splitters.
  1996. IHqlExpression * newDataset = dataset;
  1997. while (newDataset->getOperator() == no_group)
  1998. {
  1999. if (newDataset->hasProperty(allAtom))
  2000. break;
  2001. if (isLocal && queryRealChild(newDataset, 1))
  2002. {
  2003. //NOTE: local groups should not remove preceding non-local groups.
  2004. if (translator.targetThor() && !newDataset->hasProperty(localAtom))
  2005. break;
  2006. }
  2007. newDataset = newDataset->queryChild(0);
  2008. }
  2009. return newDataset;
  2010. }
  2011. IHqlExpression * ThorHqlTransformer::skipGroupsWithinGroup(IHqlExpression * expr, bool isLocal)
  2012. {
  2013. //if grouping a group, remove the initial group.
  2014. //Not completely sure about this - it may potentially cause extra splitters.
  2015. IHqlExpression * dataset = expr->queryChild(0);
  2016. if (dataset->getOperator() == no_group)
  2017. {
  2018. IHqlExpression * newDataset = skipOverGroups(dataset, isLocal);
  2019. if (newDataset == dataset)
  2020. return NULL;
  2021. //if we end up with the original grouping then probably have ungroup(group(x,y))
  2022. //so no need to do this group either
  2023. if (queryGrouping(newDataset) == queryGrouping(expr))
  2024. return LINK(newDataset);
  2025. return replaceChild(expr, 0, newDataset);
  2026. }
  2027. return NULL;
  2028. }
  2029. IHqlExpression * ThorHqlTransformer::normalizeGroup(IHqlExpression * expr)
  2030. {
  2031. assertex(expr->getOperator() == no_group);
  2032. IHqlExpression * sortlist = queryRealChild(expr, 1);
  2033. IHqlExpression * dataset = expr->queryChild(0);
  2034. if (!sortlist)
  2035. return skipGroupsWithinGroup(expr, false);
  2036. OwnedHqlExpr newsort = simplifySortlistComplexity(sortlist);
  2037. if (newsort)
  2038. return replaceChild(expr, 1, newsort);
  2039. bool hasLocal = expr->hasProperty(localAtom);
  2040. bool isLocal = hasLocal || !translator.targetThor();
  2041. bool wantSorted = expr->hasProperty(sortedAtom);
  2042. bool hasAll = expr->hasProperty(allAtom);
  2043. // First check if a global group can be done locally - applicable to all and non-all versions.
  2044. if (!isLocal)
  2045. {
  2046. if (!wantSorted && isPartitionedForGroup(dataset, sortlist, hasAll))
  2047. return appendLocalAttribute(expr);
  2048. }
  2049. if (!hasAll)
  2050. {
  2051. //if grouping a group, remove the initial group.
  2052. //Not completely sure about this - it may potentially cause extra splitters.
  2053. return skipGroupsWithinGroup(expr, isLocal);
  2054. }
  2055. //First check to see if the dataset is already sorted by the group criteria, or more.
  2056. //The the data could be globally sorted, but not distributed, and this is likely to be more efficient than redistributing...
  2057. OwnedHqlExpr sorted = ensureSortedForGroup(dataset, sortlist, hasLocal, !translator.targetThor(), options.implicitGroupShuffle);
  2058. if (sorted == dataset)
  2059. return removeProperty(expr, allAtom);
  2060. sorted.setown(cloneInheritedAnnotations(expr, sorted));
  2061. sorted.setown(inheritAttribute(sorted, expr, skewAtom));
  2062. sorted.setown(inheritAttribute(sorted, expr, thresholdAtom));
  2063. if (!isLocal)
  2064. {
  2065. //Options for ensuring distributed and locally sorted (in order)
  2066. // DISTRIBUTE,MERGE - since lightweight and streaming.
  2067. // DISTRIBUTE,LOCAL SORT
  2068. // SORT
  2069. if (!wantSorted)
  2070. {
  2071. //is it best to hash on all the grouping fields, or just some of them? Do all for the moment.
  2072. OwnedHqlExpr hashed = createValue(no_hash32, LINK(unsignedType), LINK(sortlist), createAttribute(internalAtom));
  2073. if (options.supportsMergeDistribute && isSortedForGroup(dataset, sortlist, true))
  2074. {
  2075. //Dataset is locally sorted, so can use the merge distribute to remove the subsequent local sort.
  2076. //changing a heavyweight global sort into a lightweight distribute,merge
  2077. OwnedHqlExpr sortOrder = getExistingSortOrder(dataset, true, true);
  2078. OwnedHqlExpr mergeAttr = createExprAttribute(mergeAtom, replaceSelector(sortOrder, queryActiveTableSelector(), dataset));
  2079. sorted.setown(createDatasetF(no_distribute, LINK(dataset), LINK(hashed), mergeAttr.getClear(), NULL));
  2080. sorted.setown(cloneInheritedAnnotations(expr, sorted));
  2081. }
  2082. else
  2083. {
  2084. if (groupAllDistribute || expr->hasProperty(unsortedAtom))
  2085. {
  2086. OwnedHqlExpr distributed = createDataset(no_distribute, LINK(dataset), LINK(hashed));
  2087. distributed.setown(cloneInheritedAnnotations(expr, distributed));
  2088. sorted.setown(createDataset(no_sort, LINK(distributed), createComma(LINK(sortlist), createLocalAttribute())));
  2089. sorted.setown(cloneInheritedAnnotations(expr, sorted));
  2090. }
  2091. }
  2092. }
  2093. #ifdef _DEBUG
  2094. assertex(!sortlist->isPure() || isPartitionedForGroup(sorted, sortlist, true)); // sanity check
  2095. #endif
  2096. }
  2097. //Do a local group after the sort because we know they can't overlap...
  2098. OwnedHqlExpr ret = createDatasetF(no_group, sorted.getClear(), LINK(sortlist), createLocalAttribute(), NULL);
  2099. return expr->cloneAllAnnotations(ret);
  2100. }
  2101. IHqlExpression * ThorHqlTransformer::normalizeCoGroup(IHqlExpression * expr)
  2102. {
  2103. IHqlExpression * grouping = queryPropertyChild(expr, groupAtom, 0);
  2104. OwnedHqlExpr newsort = simplifySortlistComplexity(grouping);
  2105. if (newsort)
  2106. {
  2107. OwnedHqlExpr newGroup = createExprAttribute(groupAtom, newsort.getClear());
  2108. return replaceOwnedProperty(expr, newGroup.getClear());
  2109. }
  2110. HqlExprArray inputs;
  2111. //Gather the inputs and ensure they aren't grouped.
  2112. ForEachChild(i, expr)
  2113. {
  2114. IHqlExpression * cur = expr->queryChild(i);
  2115. if (!cur->isAttribute())
  2116. {
  2117. if (isGrouped(cur))
  2118. {
  2119. OwnedHqlExpr ungroup = createDataset(no_group, LINK(cur));
  2120. inputs.append(*cloneInheritedAnnotations(expr, ungroup));
  2121. }
  2122. else
  2123. inputs.append(*LINK(cur));
  2124. }
  2125. }
  2126. bool hasLocal = expr->hasProperty(localAtom);
  2127. bool alwaysLocal = !translator.targetThor();
  2128. bool isLocal = hasLocal || alwaysLocal;
  2129. OwnedHqlExpr localFlag = !alwaysLocal ? createLocalAttribute() : NULL;
  2130. OwnedHqlExpr bestSortOrder;
  2131. //Choose the best existing sort order (for the moment assume the shortest - although
  2132. //even better would be to pick the shortest most frequent
  2133. ForEachItemIn(iBest, inputs)
  2134. {
  2135. if (isSortedForGroup(&inputs.item(iBest), grouping, true))
  2136. {
  2137. OwnedHqlExpr localOrder = getExistingSortOrder(&inputs.item(iBest), true, true);
  2138. if (!bestSortOrder || (localOrder->numChildren() < bestSortOrder->numChildren()))
  2139. bestSortOrder.set(localOrder);
  2140. }
  2141. }
  2142. if (!isLocal)
  2143. {
  2144. //Ensure all the inputs are co-distributed (use an existing distribution if possible)
  2145. //Even better would be to pick the most frequent
  2146. OwnedHqlExpr distribution;
  2147. ForEachItemIn(i, inputs)
  2148. {
  2149. IHqlExpression & cur = inputs.item(i);
  2150. if (isPartitionedForGroup(&cur, grouping, true))
  2151. {
  2152. IHqlExpression * curDistribution = queryDistribution(&cur);
  2153. if (!isSortDistribution(curDistribution))
  2154. {
  2155. distribution.set(curDistribution);
  2156. break;
  2157. }
  2158. }
  2159. }
  2160. if (!distribution)
  2161. distribution.setown(createValue(no_hash32, LINK(unsignedType), LINK(grouping), createAttribute(internalAtom)));
  2162. ForEachItemIn(iReplace, inputs)
  2163. {
  2164. IHqlExpression & cur = inputs.item(iReplace);
  2165. if (queryDistribution(&cur) != distribution)
  2166. {
  2167. OwnedHqlExpr mappedDistribution = replaceSelector(distribution, queryActiveTableSelector(), &cur);
  2168. OwnedHqlExpr mergeAttr;
  2169. if (bestSortOrder && isAlreadySorted(&cur, bestSortOrder, true, true))
  2170. mergeAttr.setown(createExprAttribute(mergeAtom, replaceSelector(bestSortOrder, queryActiveTableSelector(), &cur)));
  2171. OwnedHqlExpr distributedInput = createDatasetF(no_distribute, LINK(&cur), LINK(mappedDistribution), mergeAttr.getClear(), NULL);
  2172. distributedInput.setown(cloneInheritedAnnotations(expr, distributedInput));
  2173. inputs.replace(*distributedInput.getClear(), iReplace);
  2174. }
  2175. }
  2176. }
  2177. OwnedHqlExpr merged;
  2178. if (bestSortOrder)
  2179. {
  2180. //If some of the datasets are sorted then sort the remaining inputs by the same order and merge
  2181. HqlExprArray sortedInputs;
  2182. ForEachItemIn(i, inputs)
  2183. {
  2184. IHqlExpression & cur = inputs.item(i);
  2185. OwnedHqlExpr mappedOrder = replaceSelector(bestSortOrder, queryActiveTableSelector(), &cur);
  2186. sortedInputs.append(*ensureSorted(&cur, mappedOrder, true, true, alwaysLocal, options.implicitShuffle));
  2187. }
  2188. HqlExprArray sortedArgs;
  2189. unwindChildren(sortedArgs, bestSortOrder);
  2190. sortedInputs.append(*createExprAttribute(sortedAtom, sortedArgs));
  2191. if (localFlag)
  2192. sortedInputs.append(*LINK(localFlag));
  2193. merged.setown(createDataset(no_merge, sortedInputs));
  2194. }
  2195. else
  2196. {
  2197. //otherwise append the datasets and then sort them all
  2198. OwnedHqlExpr appended = createDataset(no_addfiles, inputs);
  2199. appended.setown(cloneInheritedAnnotations(expr, appended));
  2200. OwnedHqlExpr mappedOrder = replaceSelector(grouping, queryActiveTableSelector(), appended);
  2201. merged.setown(createDatasetF(no_sort, LINK(appended), mappedOrder.getClear(), LINK(localFlag), NULL));
  2202. }
  2203. //Now group by the grouping condition
  2204. merged.setown(cloneInheritedAnnotations(expr, merged));
  2205. OwnedHqlExpr mappedGrouping = replaceSelector(grouping, queryActiveTableSelector(), merged);
  2206. OwnedHqlExpr grouped = createDataset(no_group, LINK(merged), mappedGrouping.getClear());
  2207. return expr->cloneAllAnnotations(grouped);
  2208. }
  2209. static IHqlExpression * getNonThorSortedJoinInput(IHqlExpression * joinExpr, IHqlExpression * dataset, HqlExprArray & sorts, bool implicitShuffle)
  2210. {
  2211. if (!sorts.length())
  2212. return LINK(dataset);
  2213. LinkedHqlExpr expr = dataset;
  2214. if (isGrouped(expr))
  2215. {
  2216. expr.setown(createDataset(no_group, LINK(expr), NULL));
  2217. expr.setown(cloneInheritedAnnotations(joinExpr, expr));
  2218. }
  2219. // if already sorted or grouped, use it!
  2220. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  2221. groupOrder.setown(replaceSelector(groupOrder, queryActiveTableSelector(), expr->queryNormalizedSelector()));
  2222. //not used for thor, so sort can be local
  2223. OwnedHqlExpr table = ensureSorted(expr, groupOrder, false, true, true, implicitShuffle);
  2224. if (table != expr)
  2225. table.setown(cloneInheritedAnnotations(joinExpr, table));
  2226. OwnedHqlExpr group = createDatasetF(no_group, table.getClear(), LINK(groupOrder), NULL);
  2227. return cloneInheritedAnnotations(joinExpr, group);
  2228. }
  2229. static bool sameOrGrouped(IHqlExpression * newLeft, IHqlExpression * oldLeft)
  2230. {
  2231. if (newLeft->queryBody() == oldLeft->queryBody())
  2232. return true;
  2233. if (newLeft->getOperator() != no_group)
  2234. return false;
  2235. newLeft = newLeft->queryChild(0);
  2236. return (newLeft->queryBody() == oldLeft->queryBody());
  2237. }
  2238. bool canReorderMatchExistingLocalSort(HqlExprArray & newElements1, HqlExprArray & newElements2, IHqlExpression * ds1, Shared<IHqlExpression> & ds2, const HqlExprArray & elements1, HqlExprArray & elements2, bool canShuffle, bool isLocal, bool alwaysLocal)
  2239. {
  2240. newElements1.kill();
  2241. newElements2.kill();
  2242. if (reorderMatchExistingLocalSort(newElements1, newElements2, ds1, elements1, elements2))
  2243. {
  2244. if (isAlreadySorted(ds2, newElements2, isLocal||alwaysLocal, true))
  2245. return true;
  2246. if (canShuffle && isWorthShuffling(ds2, newElements2, isLocal||alwaysLocal, true))
  2247. {
  2248. OwnedHqlExpr shuffled = getShuffleSort(ds2, newElements2, isLocal, true, alwaysLocal);
  2249. if (shuffled)
  2250. {
  2251. ds2.swap(shuffled);
  2252. return true;
  2253. }
  2254. }
  2255. }
  2256. return false;
  2257. }
  2258. IHqlExpression * ThorHqlTransformer::normalizeJoinOrDenormalize(IHqlExpression * expr)
  2259. {
  2260. IHqlExpression * leftDs = expr->queryChild(0);
  2261. IHqlExpression * rightDs = queryJoinRhs(expr);
  2262. IHqlExpression * seq = querySelSeq(expr);
  2263. node_operator op = expr->getOperator();
  2264. if (op == no_join)
  2265. {
  2266. if (isSelfJoin(expr))
  2267. {
  2268. HqlExprArray children;
  2269. unwindChildren(children, expr);
  2270. children.replace(*createAttribute(_selfJoinPlaceholder_Atom), 1); // replace the 1st dataset with an attribute so parameters are still in the same place.
  2271. OwnedHqlExpr ret = createDataset(no_selfjoin, children);
  2272. return expr->cloneAllAnnotations(ret);
  2273. }
  2274. }
  2275. bool hasLocal = isLocalActivity(expr);
  2276. bool alwaysLocal = !translator.targetThor();
  2277. bool isLocal = hasLocal || alwaysLocal;
  2278. //hash,local doesn't make sense (hash is only used for distribution) => remove hash
  2279. //but also prevent it being converted to a lookup join??
  2280. if (isLocal && expr->hasProperty(hashAtom))
  2281. {
  2282. HqlExprArray args;
  2283. unwindChildren(args, expr);
  2284. removeProperty(args, hashAtom);
  2285. // args.append(*createAttribute(_normalized_Atom));
  2286. return expr->clone(args);
  2287. }
  2288. //Check to see if this join should be done as a keyed join...
  2289. if (!expr->hasProperty(lookupAtom) && !expr->hasProperty(allAtom))
  2290. {
  2291. if (rightDs->getOperator() == no_filter)
  2292. {
  2293. bool moveRhsFilter = false;
  2294. if (expr->hasProperty(keyedAtom) && queryPropertyChild(expr, keyedAtom, 0))
  2295. {
  2296. //Full keyed join - ensure the filter is moved from the rhs to the condition.
  2297. moveRhsFilter = true;
  2298. }
  2299. else if (options.spotPotentialKeyedJoins && (rightDs != leftDs))
  2300. {
  2301. //This can turn some non keyed joins into keyed joins
  2302. IHqlExpression * cur = rightDs;
  2303. while (cur->getOperator() == no_filter)
  2304. cur = cur->queryChild(0);
  2305. if (cur->getOperator() == no_newkeyindex)
  2306. moveRhsFilter = true;
  2307. }
  2308. if (moveRhsFilter)
  2309. {
  2310. //Transform join(a, b(x), c) to join(a, b, c and evaluate(right, x))
  2311. HqlExprAttr extraFilter;
  2312. OwnedHqlExpr right = createSelector(no_right, rightDs, seq);
  2313. IHqlExpression * cur = rightDs;
  2314. while (cur->getOperator() == no_filter)
  2315. {
  2316. unsigned max = cur->numChildren();
  2317. for (unsigned i = 1; i < max; i++)
  2318. {
  2319. IHqlExpression * filter = cur->queryChild(i);
  2320. if (!filter->isAttribute())
  2321. {
  2322. IHqlExpression * newFilter = replaceSelector(filter, rightDs, right);
  2323. extendConditionOwn(extraFilter, no_and, newFilter);
  2324. }
  2325. }
  2326. cur = cur->queryChild(0);
  2327. }
  2328. HqlExprArray args;
  2329. unwindChildren(args, expr);
  2330. args.replace(*LINK(cur), 1);
  2331. args.replace(*createValue(no_and, makeBoolType(), LINK(expr->queryChild(2)), extraFilter.getClear()), 2);
  2332. return expr->clone(args);
  2333. }
  2334. }
  2335. }
  2336. //Tag a keyed join as ordered in the platforms that ensure it does remain ordered. Extend if the others do.
  2337. if (isKeyedJoin(expr))
  2338. {
  2339. if (translator.targetRoxie() && !expr->hasProperty(_ordered_Atom))
  2340. return appendOwnedOperand(expr, createAttribute(_ordered_Atom));
  2341. return NULL;
  2342. }
  2343. HqlExprArray leftSorts, rightSorts, slidingMatches;
  2344. bool isLimitedSubstringJoin;
  2345. OwnedHqlExpr fuzzyMatch = findJoinSortOrders(expr, leftSorts, rightSorts, isLimitedSubstringJoin, canBeSlidingJoin(expr) ? &slidingMatches : NULL);
  2346. //If the data is already distributed so the data is on the correct machines then perform the join locally.
  2347. //Should be equally applicable to lookup, hash, all and normal joins.
  2348. if (!isLocal && !isLimitedSubstringJoin && leftSorts.ordinality())
  2349. {
  2350. if (isDistributedCoLocally(leftDs, rightDs, leftSorts, rightSorts))
  2351. return appendOwnedOperand(expr, createLocalAttribute());
  2352. //MORE: If left side (assumed to be the largest) is already distributed, it would be more efficient
  2353. //to redistribute the rhs by a matching hash function (or use cosort), and then join locally.
  2354. //Be careful about the persist scaling factors though.
  2355. if (!isPersistDistribution(queryDistribution(leftDs)) && isPartitionedForGroup(leftDs, leftSorts, true))
  2356. {
  2357. DBGLOG("MORE: Potential for distributed join optimization");
  2358. //MORE: May need a flag to stop this - to prevent issues with skew.
  2359. }
  2360. }
  2361. if (expr->hasProperty(allAtom))
  2362. return NULL;
  2363. if (expr->hasProperty(lookupAtom))
  2364. return NULL;
  2365. //Try and convert local joins to a lightweight join that doesn't require any sorting of the inputs.
  2366. //Improves resourcing for thor, and prevents lookup conversion for hthor/roxie
  2367. //Worthwhile even for lookup joins
  2368. if (translator.targetThor() &&
  2369. options.spotLocalMerge && !isLimitedSubstringJoin &&
  2370. ((op == no_join) || (op == no_selfjoin)) && isLocal && !expr->hasProperty(_lightweight_Atom))
  2371. {
  2372. if (isAlreadySorted(leftDs, leftSorts, true, true) &&
  2373. isAlreadySorted(rightDs, rightSorts, true, true))
  2374. {
  2375. //If this is a lookup join without a many then we need to make sure only the first match is retained.
  2376. return appendOwnedOperand(expr, createAttribute(_lightweight_Atom));
  2377. }
  2378. //Check for a local join where we can reorder the condition so both sides match the existing sort orders.
  2379. //could special case self-join to do less work, but probably not worth the effort.
  2380. HqlExprArray sortedLeft, sortedRight;
  2381. if (!isLimitedSubstringJoin)
  2382. {
  2383. //Since the distribution and order of global joins is not defined this could probably be used for non-local as well.
  2384. LinkedHqlExpr newLeftDs = leftDs;
  2385. LinkedHqlExpr newRightDs = rightDs;
  2386. bool canShuffle = options.shuffleLocalJoinConditions;
  2387. bool reordered = canReorderMatchExistingLocalSort(sortedLeft, sortedRight, newLeftDs, newRightDs,
  2388. leftSorts, rightSorts, canShuffle, isLocal, alwaysLocal);
  2389. //If allowed to shuffle then try the otherway around
  2390. if (!reordered && canShuffle)
  2391. reordered = canReorderMatchExistingLocalSort(sortedRight, sortedLeft, newRightDs, newLeftDs,
  2392. rightSorts, leftSorts, canShuffle, isLocal, alwaysLocal);
  2393. if (reordered)
  2394. {
  2395. //Recreate the join condition in the correct order to match the existing sorts...
  2396. HqlExprAttr newcond;
  2397. OwnedHqlExpr leftSelector = createSelector(no_left, newLeftDs, seq);
  2398. OwnedHqlExpr rightSelector = createSelector(no_right, newRightDs, seq);
  2399. ForEachItemIn(i, sortedLeft)
  2400. {
  2401. OwnedHqlExpr lc = replaceSelector(&sortedLeft.item(i), queryActiveTableSelector(), leftSelector);
  2402. OwnedHqlExpr rc = replaceSelector(&sortedRight.item(i), queryActiveTableSelector(), rightSelector);
  2403. extendConditionOwn(newcond, no_and, createValue(no_eq, makeBoolType(), lc.getClear(), rc.getClear()));
  2404. }
  2405. extendConditionOwn(newcond, no_and, fuzzyMatch.getClear());
  2406. HqlExprArray args;
  2407. args.append(*newLeftDs.getClear());
  2408. args.append(*newRightDs.getClear());
  2409. args.append(*newcond.getClear());
  2410. unwindChildren(args, expr, 3);
  2411. args.append(*createAttribute(_lightweight_Atom));
  2412. return expr->clone(args);
  2413. }
  2414. }
  2415. }
  2416. //Sort,Sort->join is O(NlnN) lookup join using a hash table is O(N) =>convert for hthor/roxie
  2417. if (!isThorCluster(targetClusterType) && !expr->hasProperty(_normalized_Atom))
  2418. {
  2419. bool createLookup = false;
  2420. if ((op == no_join) && options.convertJoinToLookup)
  2421. {
  2422. if ((targetClusterType == RoxieCluster) || hasFewRows(rightDs))
  2423. if (!isFullJoin(expr) && !isRightJoin(expr) && !expr->hasProperty(partitionRightAtom))
  2424. createLookup = !expr->hasProperty(_lightweight_Atom);
  2425. }
  2426. if (isLimitedSubstringJoin)
  2427. createLookup = false; //doesn't support it yet
  2428. else if (createLookup && leftSorts.ordinality() && rightSorts.ordinality())
  2429. {
  2430. //Check this isn't going to generate a between join - if it is that takes precedence.
  2431. if ((slidingMatches.ordinality() != 0) && (leftSorts.ordinality() == slidingMatches.ordinality()))
  2432. createLookup = false;
  2433. }
  2434. if (createLookup)
  2435. {
  2436. IHqlExpression * lhs = expr->queryChild(0);
  2437. HqlExprArray args;
  2438. if (isGrouped(lhs))
  2439. {
  2440. OwnedHqlExpr ungroup = createDataset(no_group, LINK(lhs));
  2441. args.append(*cloneInheritedAnnotations(expr, ungroup));
  2442. }
  2443. else
  2444. args.append(*LINK(lhs));
  2445. unwindChildren(args, expr, 1);
  2446. args.append(*createAttribute(manyAtom));
  2447. args.append(*createAttribute(lookupAtom));
  2448. return expr->clone(args);
  2449. }
  2450. OwnedHqlExpr newLeft = getNonThorSortedJoinInput(expr, leftDs, leftSorts, options.implicitShuffle);
  2451. OwnedHqlExpr newRight = getNonThorSortedJoinInput(expr, rightDs, rightSorts, options.implicitShuffle);
  2452. try
  2453. {
  2454. if ((leftDs != newLeft) || (rightDs != newRight))
  2455. {
  2456. HqlExprArray args;
  2457. args.append(*newLeft.getClear());
  2458. args.append(*newRight.getClear());
  2459. unwindChildren(args, expr, 2);
  2460. args.append(*createAttribute(_normalized_Atom));
  2461. return expr->clone(args);
  2462. }
  2463. }
  2464. catch (IException * e)
  2465. {
  2466. //Couldn't work out the sort orders - shouldn't be fatal because may constant fold later.
  2467. EXCLOG(e, "Transform");
  2468. e->Release();
  2469. }
  2470. }
  2471. //Convert hash selfjoin to self-join(distribute)
  2472. if ((op == no_selfjoin) && expr->hasProperty(hashAtom))
  2473. {
  2474. assertex(!isLocal);
  2475. if (isLimitedSubstringJoin)
  2476. {
  2477. leftSorts.pop();
  2478. rightSorts.pop();
  2479. }
  2480. if (leftSorts.ordinality())
  2481. {
  2482. OwnedHqlExpr sortlist = createValueSafe(no_sortlist, makeSortListType(NULL), leftSorts);
  2483. OwnedHqlExpr distribute;
  2484. //Only likely to catch this partition test if isLimitedSubstringJoin true, otherwise caught above
  2485. if (!isPartitionedForGroup(leftDs, sortlist, true))
  2486. {
  2487. //could use a more optimal hash function since comparing against self, so fields are same type
  2488. OwnedHqlExpr activeDist = createValue(no_hash32, LINK(unsignedType), LINK(sortlist), createAttribute(internalAtom));
  2489. //OwnedHqlExpr activeDist = createValue(no_hash, LINK(unsignedType), LINK(sortlist));
  2490. OwnedHqlExpr dist = replaceSelector(activeDist, queryActiveTableSelector(), leftDs);
  2491. distribute.setown(createDataset(no_distribute, LINK(leftDs), LINK(dist)));
  2492. distribute.setown(cloneInheritedAnnotations(expr, distribute));
  2493. }
  2494. else
  2495. distribute.set(leftDs);
  2496. HqlExprArray args;
  2497. args.append(*LINK(distribute));
  2498. unwindChildren(args, expr, 1);
  2499. removeProperty(args, hashAtom);
  2500. args.append(*createLocalAttribute());
  2501. return expr->clone(args);
  2502. }
  2503. }
  2504. if (isThorCluster(targetClusterType) && isLocal && options.implicitJoinShuffle)
  2505. {
  2506. IHqlExpression * noSortAttr = expr->queryProperty(noSortAtom);
  2507. OwnedHqlExpr newLeft;
  2508. OwnedHqlExpr newRight;
  2509. if (!userPreventsSort(noSortAttr, no_left))
  2510. newLeft.setown(getShuffleSort(leftDs, leftSorts, isLocal, true, alwaysLocal));
  2511. if (!userPreventsSort(noSortAttr, no_right))
  2512. newRight.setown(getShuffleSort(rightDs, rightSorts, isLocal, true, alwaysLocal));
  2513. if (newLeft || newRight)
  2514. {
  2515. HqlExprArray args;
  2516. if (newLeft)
  2517. args.append(*newLeft.getClear());
  2518. else
  2519. args.append(*LINK(leftDs));
  2520. if (newRight)
  2521. args.append(*newRight.getClear());
  2522. else
  2523. args.append(*LINK(rightDs));
  2524. unwindChildren(args, expr, 2);
  2525. return expr->clone(args);
  2526. }
  2527. }
  2528. return NULL;
  2529. }
  2530. IHqlExpression * ThorHqlTransformer::normalizeScalarAggregate(IHqlExpression * expr)
  2531. {
  2532. OwnedHqlExpr project = convertScalarAggregateToDataset(expr);
  2533. if (!project)
  2534. throwUnexpected();
  2535. IHqlExpression * field = project->queryRecord()->queryChild(0);
  2536. OwnedHqlExpr ret = createNewSelectExpr(project.getClear(), LINK(field));
  2537. return expr->cloneAllAnnotations(ret);
  2538. }
  2539. IHqlExpression * ThorHqlTransformer::normalizeSelect(IHqlExpression * expr)
  2540. {
  2541. return NULL;
  2542. /*
  2543. 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
  2544. However the following isn't good enough since the fields from a.b also need to be accessible. We would
  2545. need to introduce a field in the result $parent$, and also assign that across. Subsequent references to
  2546. a.b.xyz would need to be converted to in.parent.xyz. It will generate very inefficient code, so not going
  2547. to go this way at the moment.
  2548. */
  2549. if (!isNewSelector(expr) || !expr->isDataset())
  2550. return NULL;
  2551. IHqlExpression * ds = expr->queryChild(0);
  2552. if (!ds->isDataset())
  2553. return NULL;
  2554. //If we are a no_select of a no_select that is also new, insert an implicit denormalized
  2555. HqlExprArray args;
  2556. args.append(*LINK(ds));
  2557. OwnedHqlExpr selSeq = createSelectorSequence();
  2558. HqlExprArray selectArgs;
  2559. unwindChildren(selectArgs, expr);
  2560. selectArgs.replace(*createSelector(no_left, ds, selSeq), 0);
  2561. removeProperty(selectArgs, newAtom);
  2562. args.append(*expr->clone(selectArgs));
  2563. //Create a transform self := right;
  2564. OwnedHqlExpr right = createSelector(no_right, expr, selSeq);
  2565. OwnedHqlExpr assign = createAssign(getSelf(expr), LINK(right));
  2566. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(LINK(expr->queryRecordType())), LINK(assign));
  2567. args.append(*LINK(transform));
  2568. args.append(*LINK(selSeq));
  2569. args.append(*createAttribute(_internal_Atom));
  2570. return createDataset(no_normalize, args);
  2571. }
  2572. IHqlExpression * ThorHqlTransformer::normalizeSort(IHqlExpression * expr)
  2573. {
  2574. IHqlExpression * dataset = expr->queryChild(0);
  2575. IHqlExpression * sortlist = expr->queryChild(1);
  2576. OwnedHqlExpr newsort = simplifySortlistComplexity(sortlist);
  2577. if (newsort)
  2578. {
  2579. if (newsort == sortlist)
  2580. {
  2581. dbglogExpr(sortlist);
  2582. throwUnexpected();
  2583. }
  2584. HqlExprArray args;
  2585. unwindChildren(args, expr);
  2586. args.replace(*newsort.getClear(), 1);
  2587. return expr->clone(args);
  2588. }
  2589. node_operator op = expr->getOperator();
  2590. if (translator.targetThor())
  2591. {
  2592. if ((op == no_sort) && !isGrouped(expr) && !expr->hasProperty(localAtom))
  2593. {
  2594. //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
  2595. if (queryDistribution(expr) == queryDistribution(dataset))
  2596. return appendLocalAttribute(expr);
  2597. }
  2598. }
  2599. if (op == no_sorted)
  2600. {
  2601. IHqlExpression * normalized = normalizeSortSteppedIndex(expr, sortedAtom);
  2602. if (normalized)
  2603. return normalized;
  2604. }
  2605. bool isLocal = expr->hasProperty(localAtom);
  2606. bool alwaysLocal = !translator.targetThor();
  2607. if ((op != no_assertsorted) && isAlreadySorted(dataset, sortlist, isLocal||alwaysLocal, false))
  2608. return LINK(dataset);
  2609. if (op == no_sorted)
  2610. return normalizeSortSteppedIndex(expr, sortedAtom);
  2611. //NOTE: We can't convert a global sort to a shuffle because that will change the distribution
  2612. if (options.implicitShuffle && (isLocal || alwaysLocal) && (op != no_assertsorted))
  2613. {
  2614. OwnedHqlExpr shuffled = getShuffleSort(dataset, sortlist, isLocal, false, alwaysLocal);
  2615. if (shuffled)
  2616. return dataset->cloneAllAnnotations(shuffled);
  2617. }
  2618. return NULL;
  2619. }
  2620. IHqlExpression * ThorHqlTransformer::normalizeShuffle(IHqlExpression * expr)
  2621. {
  2622. IHqlExpression * dataset = expr->queryChild(0);
  2623. IHqlExpression * sortlist = expr->queryChild(1);
  2624. IHqlExpression * grouping = expr->queryChild(2);
  2625. OwnedHqlExpr newsort = simplifySortlistComplexity(sortlist);
  2626. OwnedHqlExpr newgrouping = simplifySortlistComplexity(grouping);
  2627. if (newsort || newgrouping)
  2628. {
  2629. HqlExprArray args;
  2630. unwindChildren(args, expr);
  2631. if (newsort)
  2632. args.replace(*newsort.getClear(), 1);
  2633. if (newgrouping)
  2634. args.replace(*newgrouping.getClear(), 2);
  2635. return expr->clone(args);
  2636. }
  2637. if (translator.targetThor() && !expr->hasProperty(localAtom))
  2638. return convertShuffleToGroupedSort(expr);
  2639. return NULL;
  2640. }
  2641. IHqlExpression * ThorHqlTransformer::normalizeSortSteppedIndex(IHqlExpression * expr, _ATOM attrName)
  2642. {
  2643. node_operator op = expr->getOperator();
  2644. if (op == no_assertsorted)
  2645. return NULL;
  2646. IHqlExpression * dataset = expr->queryChild(0);
  2647. node_operator datasetOp = dataset->getOperator();
  2648. if ((datasetOp == no_keyindex) || (datasetOp == no_newkeyindex))
  2649. {
  2650. IHqlExpression * indexRecord = dataset->queryRecord();
  2651. if (!dataset->hasProperty(attrName))
  2652. {
  2653. HqlExprArray selects;
  2654. IHqlExpression * sortList = expr->queryChild(1);
  2655. if (sortList)
  2656. {
  2657. OwnedHqlExpr mapped = replaceSelector(sortList, dataset->queryNormalizedSelector(), queryActiveTableSelector());
  2658. unwindChildren(selects, mapped);
  2659. }
  2660. HqlExprArray args;
  2661. unwindChildren(args, dataset);
  2662. args.append(*createExprAttribute(attrName, selects));
  2663. return dataset->clone(args);
  2664. }
  2665. }
  2666. return NULL;
  2667. }
  2668. IHqlExpression * ThorHqlTransformer::normalizeTempTable(IHqlExpression * expr)
  2669. {
  2670. #if 0
  2671. //This would be a great improvement to the generated code, but the xml storage formats are different + it doesn't cope with ALL.
  2672. IHqlExpression * values = expr->queryChild(0);
  2673. ITypeInfo * valuesType = values->queryType();
  2674. if ((values->getOperator() == no_getresult) && (valuesType->getTypeCode() == type_set))
  2675. {
  2676. IHqlExpression * record = expr->queryChild(1);
  2677. if ((record->numChildren() == 1) && (valuesType->queryChildType() == record->queryChild(0)->queryType()))
  2678. {
  2679. HqlExprArray args;
  2680. args.append(*LINK(record));
  2681. args.append(*createAttribute(sequenceAtom, LINK(values->queryChild(0))));
  2682. if (values->queryChild(1))
  2683. args.append(*createAttribute(nameAtom, LINK(values->queryChild(1))));
  2684. return createDataset(no_workunit_dataset, args);
  2685. }
  2686. }
  2687. #endif
  2688. return NULL;
  2689. }
  2690. IHqlExpression * ThorHqlTransformer::normalizeChooseN(IHqlExpression * expr)
  2691. {
  2692. OwnedHqlExpr first = foldHqlExpression(queryRealChild(expr, 2));
  2693. if (first)
  2694. {
  2695. if (matchesConstantValue(first, 1))
  2696. {
  2697. HqlExprArray args;
  2698. unwindChildren(args, expr);
  2699. args.remove(2);
  2700. return expr->clone(args);
  2701. }
  2702. }
  2703. if (!options.spotTopN) return NULL;
  2704. return queryConvertChoosenNSort(expr, topNlimit);
  2705. }
  2706. static IHqlExpression * extractPrefetchFields(HqlExprArray & fields, HqlExprArray & values, IHqlExpression * ds, IHqlExpression * expr)
  2707. {
  2708. switch (expr->getOperator())
  2709. {
  2710. case no_newtransform:
  2711. case no_transform:
  2712. case no_assignall:
  2713. case NO_AGGREGATEGROUP:
  2714. case no_sortlist:
  2715. {
  2716. HqlExprArray args;
  2717. ForEachChild(i, expr)
  2718. args.append(*extractPrefetchFields(fields, values, ds, expr->queryChild(i)));
  2719. return expr->clone(args);
  2720. }
  2721. case no_assign:
  2722. {
  2723. HqlExprArray args;
  2724. args.append(*LINK(expr->queryChild(0)));
  2725. args.append(*extractPrefetchFields(fields, values, ds, expr->queryChild(1)));
  2726. return expr->clone(args);
  2727. }
  2728. case no_attr:
  2729. case no_attr_expr:
  2730. case no_attr_link:
  2731. case no_record:
  2732. case no_field:
  2733. return LINK(expr);
  2734. }
  2735. unsigned match = values.find(*expr);
  2736. if (match == NotFound)
  2737. {
  2738. //What about preserving link counting on datasets?
  2739. match = fields.ordinality();
  2740. StringBuffer name;
  2741. name.append("_f").append(match).append("_");
  2742. IHqlExpression * field = createField(createIdentifierAtom(name.str()), expr->getType(), NULL);
  2743. fields.append(*field);
  2744. values.append(*LINK(expr));
  2745. }
  2746. return createSelectExpr(getActiveTableSelector(), LINK(&fields.item(match)));
  2747. }
  2748. IHqlExpression * ThorHqlTransformer::normalizePrefetchAggregate(IHqlExpression * expr)
  2749. {
  2750. //This optimization may be worth doing even if there is no prefetch attribute if the value being summed is very complicated!
  2751. IHqlExpression * prefetch = expr->queryProperty(prefetchAtom);
  2752. if (!prefetch)
  2753. return NULL;
  2754. //Create a prefetch project for all parameters to count/sum/grouping expressions
  2755. //and then aggregate those values.
  2756. IHqlExpression * ds = expr->queryChild(0);
  2757. HqlExprArray tempArgs, fields, values;
  2758. ForEachChildFrom(i, expr, 2)
  2759. {
  2760. IHqlExpression * cur = expr->queryChild(i);
  2761. if (cur != prefetch)
  2762. tempArgs.append(*extractPrefetchFields(fields, values, ds, cur));
  2763. }
  2764. OwnedHqlExpr newRecord = createRecord(fields);
  2765. OwnedHqlExpr self = createSelector(no_self, newRecord, NULL);
  2766. HqlExprArray assigns;
  2767. ForEachItemIn(iv, fields)
  2768. {
  2769. IHqlExpression * tgt = createSelectExpr(LINK(self), &OLINK(fields.item(iv)));
  2770. assigns.append(*createAssign(tgt, &OLINK(values.item(iv))));
  2771. }
  2772. HqlExprArray args;
  2773. args.append(*LINK(ds));
  2774. args.append(*LINK(newRecord));
  2775. args.append(*createValue(no_newtransform, makeTransformType(newRecord->getType()), assigns));
  2776. args.append(*LINK(prefetch));
  2777. OwnedHqlExpr project = createDataset(no_newusertable, args);
  2778. project.setown(cloneInheritedAnnotations(expr, project));
  2779. args.kill();
  2780. args.append(*LINK(project));
  2781. args.append(*LINK(expr->queryChild(1)));
  2782. ForEachItemIn(i2, tempArgs)
  2783. args.append(*replaceSelector(&tempArgs.item(i2), queryActiveTableSelector(), project->queryNormalizedSelector()));
  2784. return expr->clone(args);
  2785. }
  2786. static IHqlExpression * convertAggregateGroupingToGroupedAggregate(IHqlExpression * expr, IHqlExpression* groupBy)
  2787. {
  2788. IHqlExpression * dataset = expr->queryChild(0);
  2789. HqlExprArray groupArgs;
  2790. groupArgs.append(*LINK(dataset));
  2791. groupArgs.append(*LINK(groupBy));
  2792. groupArgs.append(*createAttribute(allAtom));
  2793. unwindChildren(groupArgs, expr, 4);
  2794. OwnedHqlExpr result = createDataset(no_group, groupArgs);
  2795. result.setown(cloneInheritedAnnotations(expr, result));
  2796. HqlExprArray args;
  2797. unwindChildren(args, expr);
  2798. args.replace(*result.getClear(), 0);
  2799. args.remove(3); // no longer grouped.
  2800. args.append(*createAttribute(aggregateAtom));
  2801. return expr->clone(args);
  2802. }
  2803. IHqlExpression * ThorHqlTransformer::getMergeTransform(IHqlExpression * dataset, IHqlExpression * transform)
  2804. {
  2805. HqlExprArray args;
  2806. ForEachChild(i, transform)
  2807. {
  2808. IHqlExpression * cur = transform->queryChild(i);
  2809. switch (cur->getOperator())
  2810. {
  2811. case no_assignall:
  2812. args.append(*getMergeTransform(dataset, cur));
  2813. break;
  2814. case no_assign:
  2815. {
  2816. IHqlExpression * lhs = cur->queryChild(0);
  2817. IHqlExpression * lhsField = lhs->queryChild(1);
  2818. IHqlExpression * rhs = cur->queryChild(1);
  2819. OwnedHqlExpr selected = createSelectExpr(LINK(dataset), LINK(lhsField));
  2820. OwnedHqlExpr newRhs;
  2821. node_operator rhsOp = rhs->getOperator();
  2822. switch (rhsOp)
  2823. {
  2824. case no_countgroup:
  2825. case no_sumgroup:
  2826. newRhs.setown(createValue(no_sumgroup, selected->getType(), LINK(selected)));
  2827. break;
  2828. case no_maxgroup:
  2829. case no_mingroup:
  2830. newRhs.setown(createValue(rhsOp, selected->getType(), LINK(selected)));
  2831. break;
  2832. case no_existsgroup:
  2833. newRhs.setown(createValue(no_existsgroup, selected->getType(), LINK(selected)));
  2834. break;
  2835. case no_vargroup:
  2836. case no_covargroup:
  2837. case no_corrgroup:
  2838. case no_avegroup:
  2839. throwUnexpected();
  2840. default:
  2841. newRhs.set(selected);
  2842. break;
  2843. }
  2844. args.append(*createAssign(LINK(lhs), newRhs.getClear()));
  2845. break;
  2846. }
  2847. default:
  2848. args.append(*LINK(cur));
  2849. break;
  2850. }
  2851. }
  2852. return transform->clone(args);
  2853. }
  2854. //Convert table(x { count(group), sum(group, x) }, gr) to
  2855. //sort(x, gr, local) -> group(gr) -> aggregate -> distribute(merge) -> group(local) -> aggregate'
  2856. IHqlExpression * ThorHqlTransformer::normalizeMergeAggregate(IHqlExpression * expr)
  2857. {
  2858. IHqlExpression * dataset = expr->queryChild(0);
  2859. IHqlExpression * groupBy = expr->queryChild(3);
  2860. //If locally distributed then don't do anything
  2861. OwnedHqlExpr noMerge = removeProperty(expr, mergeAtom);
  2862. if (!translator.targetThor() || expr->hasProperty(localAtom) || isPartitionedForGroup(dataset, groupBy, true))
  2863. return noMerge.getClear();
  2864. //Convert the aggregation (so no covariance/ave and other computed fields)
  2865. OwnedHqlExpr normalized = normalizeTableToAggregate(noMerge, true);
  2866. IHqlExpression * aggregate = normalized;
  2867. if (aggregate->getOperator() != no_newaggregate)
  2868. aggregate = aggregate->queryChild(0);
  2869. assertex(aggregate->getOperator() == no_newaggregate);
  2870. HqlExprArray localAggregateArgs;
  2871. unwindChildren(localAggregateArgs, aggregate);
  2872. removeProperty(localAggregateArgs, hashAtom);
  2873. removeProperty(localAggregateArgs, mergeAtom);
  2874. localAggregateArgs.append(*createLocalAttribute());
  2875. localAggregateArgs.append(*createAttribute(sortedAtom));
  2876. //Local aggregate and force a local sort order to be used
  2877. OwnedHqlExpr localAggregate = aggregate->clone(localAggregateArgs);
  2878. OwnedHqlExpr localGroupedAggregate = convertAggregateGroupingToGroupedAggregate(localAggregate, groupBy);
  2879. //Ensure the group,all is transformed to a local sort, local group
  2880. OwnedHqlExpr transformedFirstAggregate = transform(localGroupedAggregate);
  2881. //Use distribute(,MERGE) to move rows globally, and remain sorted
  2882. //Note grouping fields need to be mapped using the fields projected by the aggregate
  2883. TableProjectMapper mapper(transformedFirstAggregate);
  2884. bool groupCanBeMapped = false;
  2885. OwnedHqlExpr mappedGrouping = mapper.collapseFields(groupBy, dataset, transformedFirstAggregate, &groupCanBeMapped);
  2886. assertex(groupCanBeMapped);
  2887. OwnedHqlExpr sortOrder = getExistingSortOrder(transformedFirstAggregate, true, true);
  2888. OwnedHqlExpr mergeAttr = createExprAttribute(mergeAtom, replaceSelector(sortOrder, queryActiveTableSelector(), transformedFirstAggregate));
  2889. OwnedHqlExpr hashed = createValue(no_hash32, LINK(unsignedType), LINK(mappedGrouping), createAttribute(internalAtom));
  2890. OwnedHqlExpr redistributed = createDatasetF(no_distribute, LINK(transformedFirstAggregate), LINK(hashed), mergeAttr.getClear(), NULL);
  2891. redistributed.setown(cloneInheritedAnnotations(expr, redistributed));
  2892. OwnedHqlExpr grouped = createDatasetF(no_group, LINK(redistributed), LINK(mappedGrouping), createLocalAttribute(), NULL);
  2893. grouped.setown(cloneInheritedAnnotations(expr, grouped));
  2894. HqlExprArray args;
  2895. args.append(*LINK(grouped));
  2896. args.append(*LINK(localAggregate->queryChild(1)));
  2897. args.append(*getMergeTransform(grouped->queryNormalizedSelector(), localAggregate->queryChild(2)));
  2898. unwindChildren(args, localAggregate, 4);
  2899. OwnedHqlExpr newAggregate = localAggregate->clone(args);
  2900. if (aggregate == normalized)
  2901. return newAggregate.getClear();
  2902. return replaceChildDataset(normalized, newAggregate, 0);
  2903. }
  2904. IHqlExpression * ThorHqlTransformer::normalizeTableToAggregate(IHqlExpression * expr, bool canOptimizeCasts)
  2905. {
  2906. IHqlExpression * dataset = expr->queryChild(0);
  2907. IHqlExpression * record = expr->queryChild(1);
  2908. IHqlExpression * transform = expr->queryChild(2);
  2909. IHqlExpression * groupBy = expr->queryChild(3);
  2910. if (!isAggregateDataset(expr))
  2911. return NULL;
  2912. //MORE: Should fail if asked to group by variable length field, or do max/min on variable length field.
  2913. HqlExprArray aggregateFields;
  2914. HqlExprArray aggregateAssigns;
  2915. HqlExprArray extraAssigns;
  2916. IHqlExpression * maxLength = queryRecordProperty(record, maxLengthAtom);
  2917. if (maxLength)
  2918. aggregateFields.append(*LINK(maxLength));
  2919. bool extraSelectNeeded = false;
  2920. OwnedHqlExpr self = getSelf(expr);
  2921. ForEachChild(idx, transform)
  2922. {
  2923. IHqlExpression * assign=transform->queryChild(idx);
  2924. IHqlExpression * cur = assign->queryChild(0);
  2925. IHqlExpression * src = assign->queryChild(1);
  2926. IHqlExpression * mapped = normalizeAggregateExpr(cur, src, aggregateFields, aggregateAssigns, extraSelectNeeded, canOptimizeCasts);
  2927. if (mapped == src)
  2928. {
  2929. mapped->Release();
  2930. mapped = replaceSelector(cur, self, queryActiveTableSelector());
  2931. // Not an aggregate - must be an expression that is used in the grouping
  2932. aggregateFields.append(*LINK(cur->queryChild(1)));
  2933. aggregateAssigns.append(*createAssign(LINK(mapped), LINK(src)));
  2934. }
  2935. // Add expression to calculate the fields to the second projection
  2936. extraAssigns.append(*createAssign(LINK(cur), mapped));
  2937. }
  2938. //Now add any grouping fields.......
  2939. IHqlExpression * newGroupBy = NULL;
  2940. if (groupBy && !groupBy->isAttribute())
  2941. {
  2942. unsigned numGroupBy = groupBy->numChildren();
  2943. HqlExprArray newGroupElement;
  2944. for (unsigned idx = 0; idx < numGroupBy; idx++)
  2945. {
  2946. IHqlExpression * curGroup = groupBy->queryChild(idx);
  2947. bool matched = false;
  2948. ForEachItemIn(idxa, aggregateAssigns)
  2949. {
  2950. IHqlExpression * rhs = aggregateAssigns.item(idxa).queryChild(1);
  2951. if (rhs->getOperator() == no_activerow)
  2952. rhs = rhs->queryChild(0);
  2953. if (rhs == curGroup)
  2954. {
  2955. matched = true;
  2956. break;
  2957. }
  2958. }
  2959. if (!matched)
  2960. {
  2961. StringBuffer temp;
  2962. temp.append("_agg_").append(aggregateAssigns.ordinality());
  2963. IHqlExpression * targetField = createField(createIdentifierAtom(temp.str()), curGroup->getType(), NULL);
  2964. aggregateFields.append(*targetField);
  2965. aggregateAssigns.append(*createAssign(createSelectExpr(getActiveTableSelector(), LINK(targetField)), LINK(curGroup)));
  2966. extraSelectNeeded = true;
  2967. }
  2968. newGroupElement.append(*LINK(curGroup));
  2969. }
  2970. newGroupBy = createSortList(newGroupElement);
  2971. }
  2972. IHqlExpression * aggregateRecord = extraSelectNeeded ? translator.createRecordInheritMaxLength(aggregateFields, record) : LINK(record);
  2973. OwnedHqlExpr aggregateSelf = getSelf(aggregateRecord);
  2974. replaceAssignSelector(aggregateAssigns, aggregateSelf);
  2975. IHqlExpression * aggregateTransform = createValue(no_newtransform, makeTransformType(aggregateRecord->getType()), aggregateAssigns);
  2976. HqlExprArray aggregateAttrs;
  2977. unwindAttributes(aggregateAttrs, expr);
  2978. removeProperty(aggregateAttrs, aggregateAtom);
  2979. removeProperty(aggregateAttrs, fewAtom);
  2980. if (!expr->hasProperty(localAtom) && newGroupBy && !isGrouped(dataset) && isPartitionedForGroup(dataset, newGroupBy, true))
  2981. aggregateAttrs.append(*createLocalAttribute());
  2982. OwnedHqlExpr ret = createDataset(no_newaggregate, LINK(dataset), createComma(aggregateRecord, aggregateTransform, newGroupBy, createComma(aggregateAttrs)));
  2983. if (extraSelectNeeded)
  2984. ret.setown(cloneInheritedAnnotations(expr, ret));
  2985. else
  2986. ret.setown(expr->cloneAllAnnotations(ret));
  2987. if (expr->hasProperty(mergeAtom))
  2988. ret.setown(normalizeMergeAggregate(ret));
  2989. if (extraSelectNeeded)
  2990. {
  2991. replaceAssignSelector(extraAssigns, ret);
  2992. IHqlExpression * projectTransform = createValue(no_newtransform, makeTransformType(record->getType()), extraAssigns);
  2993. ret.setown(createDataset(no_newusertable, ret.getClear(), createComma(LINK(record), projectTransform)));
  2994. ret.setown(expr->cloneAllAnnotations(ret));
  2995. }
  2996. return ret.getClear();
  2997. }
  2998. IHqlExpression * ThorHqlTransformer::normalizeTableGrouping(IHqlExpression * expr)
  2999. {
  3000. //Transform table(x,y,z) to table(group(x,z),y)
  3001. IHqlExpression * dataset = expr->queryChild(0);
  3002. LinkedHqlExpr group = queryRealChild(expr, 3);
  3003. if (group)
  3004. {
  3005. if (expr->hasProperty(mergeAtom))
  3006. return normalizeMergeAggregate(expr);
  3007. bool useHashAggregate = expr->hasProperty(fewAtom);
  3008. if (expr->getOperator() == no_aggregate)
  3009. {
  3010. OwnedHqlExpr selector = createSelector(no_left, dataset->queryRecord(), querySelSeq(expr));
  3011. group.setown(replaceSelector(group, selector, dataset));
  3012. //Cannot use a hash aggregate if we don't know the mapping from input to output fields...
  3013. if (!isKnownTransform(expr->queryChild(2)))
  3014. useHashAggregate = false;
  3015. }
  3016. if (useHashAggregate && group->isConstant() && !translator.targetThor())
  3017. return removeProperty(expr, fewAtom);
  3018. if (!expr->hasProperty(manyAtom) && !expr->hasProperty(sortedAtom))
  3019. {
  3020. if (isSmallGrouping(group))
  3021. {
  3022. OwnedHqlExpr newsort = simplifySortlistComplexity(group);
  3023. if (!newsort)
  3024. newsort.set(group);
  3025. LinkedHqlExpr ds = dataset;
  3026. if (ds->queryType()->queryGroupInfo())
  3027. {
  3028. ds.setown(createDataset(no_group, ds.getClear(), NULL));
  3029. ds.setown(cloneInheritedAnnotations(expr, ds));
  3030. }
  3031. OwnedHqlExpr sorted = ensureSortedForGroup(ds, newsort, expr->hasProperty(localAtom), !translator.targetThor(), options.implicitGroupShuffle);
  3032. //For thor a global grouped aggregate would transfer elements between nodes so it is still likely to
  3033. //be more efficient to do a hash aggregate. Even better would be to check the distribution
  3034. if ((sorted != ds) ||
  3035. (translator.targetThor() && !expr->hasProperty(localAtom) && !isPartitionedForGroup(ds, newsort, true)))
  3036. useHashAggregate = true;
  3037. }
  3038. //Default to a hash aggregate for child queries/normalized sources
  3039. IHqlExpression * rootDs = queryExpression(dataset->queryDataset()->queryRootTable());
  3040. if (rootDs && rootDs->getOperator() == no_select)
  3041. useHashAggregate = true;
  3042. }
  3043. if (!expr->hasProperty(aggregateAtom) && !useHashAggregate)
  3044. return convertAggregateGroupingToGroupedAggregate(expr, group);
  3045. }
  3046. return NULL;
  3047. }
  3048. void HqlCppTranslator::convertLogicalToActivities(WorkflowArray & workflow)
  3049. {
  3050. {
  3051. unsigned time = msTick();
  3052. ThorHqlTransformer transformer(*this, targetClusterType, wu());
  3053. ForEachItemIn(idx, workflow)
  3054. {
  3055. HqlExprArray & exprs = workflow.item(idx).queryExprs();
  3056. HqlExprArray transformed;
  3057. transformer.transformRoot(exprs, transformed);
  3058. replaceArray(exprs, transformed);
  3059. }
  3060. DEBUG_TIMER("EclServer: tree transform: convert logical", msTick()-time);
  3061. }
  3062. if (queryOptions().normalizeLocations)
  3063. normalizeAnnotations(*this, workflow);
  3064. }
  3065. //------------------------------------------------------------------------
  3066. CompoundSourceInfo::CompoundSourceInfo(IHqlExpression * _original) : NewTransformInfo(_original)
  3067. {
  3068. sourceOp = no_none;
  3069. mode = no_none;
  3070. splitCount = 0;
  3071. reset();
  3072. }
  3073. void CompoundSourceInfo::reset()
  3074. {
  3075. forceCompound = false;
  3076. isBoundary = false;
  3077. isPreloaded = false;
  3078. isLimited = false;
  3079. hasChoosen = false;
  3080. hasSkipLimit = false;
  3081. isCloned = false;
  3082. isFiltered = false;
  3083. isPostFiltered = false;
  3084. isCreateRowLimited = false;
  3085. }
  3086. bool CompoundSourceInfo::canMergeLimit(IHqlExpression * expr, ClusterType targetClusterType) const
  3087. {
  3088. if (isAggregate() || isChooseNAllLimit(expr->queryChild(1)) || !isBinary())
  3089. return false;
  3090. node_operator op = expr->getOperator();
  3091. switch (op)
  3092. {
  3093. case no_limit:
  3094. //Can't merge a limit into a choosen() because the limit will be applied first
  3095. if (isLimited || hasChoosen)
  3096. return false;
  3097. //Don't merge skip and onfail limits into activities that can't implement them completely
  3098. if (targetClusterType != RoxieCluster)
  3099. {
  3100. if (expr->hasProperty(skipAtom) || expr->hasProperty(onFailAtom))
  3101. return false;
  3102. }
  3103. else
  3104. {
  3105. //Can always limit a count/aggregate with a skip limit - just resets count to 0
  3106. if (expr->hasProperty(skipAtom))
  3107. return true;
  3108. }
  3109. break;
  3110. case no_choosen:
  3111. if (hasChoosen)
  3112. return false;
  3113. break;
  3114. }
  3115. switch (sourceOp)
  3116. {
  3117. case no_compound_diskread:
  3118. case no_compound_disknormalize:
  3119. case no_compound_indexread:
  3120. case no_compound_indexnormalize:
  3121. return true;
  3122. }
  3123. return false;
  3124. }
  3125. void CompoundSourceInfo::ensureCompound()
  3126. {
  3127. if (sourceOp != no_none)
  3128. {
  3129. forceCompound = true;
  3130. #if 0
  3131. //MORE: We should really remove the sharing for entries that are going to become compound activities.
  3132. //However, that isn't just for this case - should be iterative
  3133. //e.g. while (spotMoreCompoundActivities())....
  3134. IHqlExpression * search = original;
  3135. loop
  3136. {
  3137. CompoundSourceInfo * extra = queryExtra(search);
  3138. if (extra->sharedCount-- > 1)
  3139. break;
  3140. search = search->queryChild(0);
  3141. }
  3142. #endif
  3143. }
  3144. }
  3145. bool CompoundSourceInfo::inherit(const CompoundSourceInfo & other, node_operator newSourceOp)
  3146. {
  3147. isLimited = other.isLimited;
  3148. hasSkipLimit = other.hasSkipLimit;
  3149. hasChoosen = other.hasChoosen;
  3150. isFiltered = other.isFiltered;
  3151. isPostFiltered = other.isPostFiltered;
  3152. isPreloaded = other.isPreloaded;
  3153. isCreateRowLimited = other.isCreateRowLimited;
  3154. mode = other.mode;
  3155. uid.set(other.uid);
  3156. if (other.sourceOp == no_none)
  3157. return false;
  3158. if (newSourceOp == no_none)
  3159. {
  3160. if (other.isCloned)
  3161. return false;
  3162. newSourceOp = other.sourceOp;
  3163. }
  3164. sourceOp = newSourceOp;
  3165. return true;
  3166. }
  3167. bool CompoundSourceInfo::isAggregate() const
  3168. {
  3169. switch (sourceOp)
  3170. {
  3171. case no_compound_diskaggregate:
  3172. case no_compound_diskcount:
  3173. case no_compound_diskgroupaggregate:
  3174. case no_compound_indexaggregate:
  3175. case no_compound_indexcount:
  3176. case no_compound_indexgroupaggregate:
  3177. case no_compound_childaggregate:
  3178. case no_compound_childcount:
  3179. case no_compound_childgroupaggregate:
  3180. return true;
  3181. }
  3182. return false;
  3183. }
  3184. //This doesn't try to restrict creating the compound nodes to the inner level, but will also create them for nested children.
  3185. //This shouldn't cause any problems, since compound operators within compounds are ignored, and it means that this transformer
  3186. //doesn't have to cope with being scope dependent.
  3187. //Calling the transformer again later on child queries should extend the compound activities if appropriate.
  3188. static HqlTransformerInfo compoundSourceTransformerInfo("CompoundSourceTransformer");
  3189. CompoundSourceTransformer::CompoundSourceTransformer(HqlCppTranslator & _translator, unsigned _flags)
  3190. : NewHqlTransformer(compoundSourceTransformerInfo), translator(_translator)
  3191. {
  3192. targetClusterType = translator.getTargetClusterType();
  3193. flags = _flags;
  3194. insideCompound = false;
  3195. candidate = false;
  3196. }
  3197. void CompoundSourceTransformer::analyseGatherInfo(IHqlExpression * expr)
  3198. {
  3199. CompoundSourceInfo * extra = queryBodyExtra(expr);
  3200. node_operator op = expr->getOperator();
  3201. bool wasInsideCompound = insideCompound;
  3202. if (!insideCompound)
  3203. extra->noteUsage();
  3204. if (!expr->isDataset())
  3205. insideCompound = false;
  3206. switch (op)
  3207. {
  3208. case no_fetch:
  3209. {
  3210. unsigned max = expr->numChildren();
  3211. for (unsigned i =1; i < max; i++)
  3212. analyseExpr(expr->queryChild(i));
  3213. break;
  3214. }
  3215. case no_keyed:
  3216. case no_record:
  3217. case no_attr:
  3218. case no_attr_expr:
  3219. break;
  3220. case no_keyedlimit:
  3221. case no_compound_diskread:
  3222. case no_compound_disknormalize:
  3223. case no_compound_diskaggregate:
  3224. case no_compound_diskcount:
  3225. case no_compound_diskgroupaggregate:
  3226. case no_compound_indexread:
  3227. case no_compound_indexnormalize:
  3228. case no_compound_indexaggregate:
  3229. case no_compound_indexcount:
  3230. case no_compound_indexgroupaggregate:
  3231. case no_compound_childread:
  3232. case no_compound_childnormalize:
  3233. case no_compound_childaggregate:
  3234. case no_compound_childcount:
  3235. case no_compound_childgroupaggregate:
  3236. case no_compound_selectnew:
  3237. case no_compound_inline:
  3238. case no_preload:
  3239. insideCompound = true;
  3240. NewHqlTransformer::analyseExpr(expr);
  3241. break;
  3242. case no_filter:
  3243. if (filterIsKeyed(expr))
  3244. insideCompound = true;
  3245. NewHqlTransformer::analyseExpr(expr);
  3246. break;
  3247. case no_hqlproject:
  3248. case no_newusertable:
  3249. case no_aggregate:
  3250. case no_newaggregate:
  3251. if (expr->hasProperty(keyedAtom))
  3252. insideCompound = true;
  3253. NewHqlTransformer::analyseExpr(expr);
  3254. break;
  3255. case no_join:
  3256. if (isKeyedJoin(expr) && !expr->hasProperty(_complexKeyed_Atom))
  3257. {
  3258. analyseExpr(expr->queryChild(0));
  3259. doAnalyseChildren(expr, 2);
  3260. }
  3261. else
  3262. NewHqlTransformer::analyseExpr(expr);
  3263. break;
  3264. default:
  3265. NewHqlTransformer::analyseExpr(expr);
  3266. break;
  3267. }
  3268. switch (op)
  3269. {
  3270. case no_newkeyindex:
  3271. extra->sourceOp = no_compound_indexread;
  3272. extra->uid.set(expr->queryProperty(_uid_Atom));
  3273. extra->mode = no_thor;
  3274. break;
  3275. case no_table:
  3276. {
  3277. IHqlExpression * mode = expr->queryChild(2);
  3278. if (!mode)
  3279. break;
  3280. switch (mode->getOperator())
  3281. {
  3282. case no_thor:
  3283. case no_flat:
  3284. if ((flags & CSFcompoundSpill) || !expr->hasProperty(_spill_Atom))
  3285. {
  3286. extra->sourceOp = no_compound_diskread;
  3287. extra->isPreloaded = expr->hasProperty(preloadAtom);
  3288. extra->uid.set(expr->queryProperty(_uid_Atom));
  3289. extra->mode = no_thor;
  3290. }
  3291. break;
  3292. case no_csv:
  3293. if (translator.queryOptions().enableCompoundCsvRead)
  3294. {
  3295. extra->sourceOp = no_compound_diskread;
  3296. extra->isPreloaded = expr->hasProperty(preloadAtom);
  3297. extra->uid.set(expr->queryProperty(_uid_Atom));
  3298. extra->mode = mode->getOperator();
  3299. }
  3300. break;
  3301. }
  3302. break;
  3303. }
  3304. case no_hqlproject:
  3305. {
  3306. if (!expr->hasProperty(prefetchAtom))
  3307. {
  3308. IHqlExpression * transform = expr->queryChild(1);
  3309. IHqlExpression * counter = queryPropertyChild(expr, _countProject_Atom, 0);
  3310. if (!counter || !transformContainsCounter(transform, counter))
  3311. {
  3312. IHqlExpression * dataset = expr->queryChild(0);
  3313. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3314. //Skips in datasets don't work very well at the moment - pure() is a bit strict really.
  3315. if ((dataset->isPure() || expr->hasProperty(keyedAtom)) && !parentExtra->isAggregate())
  3316. {
  3317. extra->inherit(*parentExtra);
  3318. if (expr->hasProperty(keyedAtom))
  3319. extra->ensureCompound();
  3320. if (!isPureActivity(expr))
  3321. {
  3322. extra->isFiltered = true;
  3323. extra->isPostFiltered = true;
  3324. }
  3325. }
  3326. }
  3327. }
  3328. break;
  3329. }
  3330. case no_keyedlimit:
  3331. {
  3332. IHqlExpression * dataset = expr->queryChild(0);
  3333. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3334. if (!parentExtra->isAggregate() && parentExtra->isBinary())
  3335. {
  3336. extra->inherit(*parentExtra);
  3337. extra->ensureCompound();
  3338. }
  3339. break;
  3340. }
  3341. case no_inlinetable:
  3342. case no_temptable:
  3343. case no_datasetfromrow:
  3344. extra->sourceOp = no_compound_inline;
  3345. extra->mode = no_inlinetable;
  3346. break;
  3347. case no_workunit_dataset:
  3348. // extra->sourceOp = no_compound_childread;
  3349. break;
  3350. case no_getgraphresult:
  3351. case no_externalcall:
  3352. // if (expr->isDataset())
  3353. // extra->sourceOp = no_compound_childread;
  3354. break;
  3355. case no_compound_diskread:
  3356. case no_compound_disknormalize:
  3357. case no_compound_diskaggregate:
  3358. case no_compound_diskcount:
  3359. case no_compound_diskgroupaggregate:
  3360. case no_compound_indexread:
  3361. case no_compound_indexnormalize:
  3362. case no_compound_indexaggregate:
  3363. case no_compound_indexcount:
  3364. case no_compound_indexgroupaggregate:
  3365. case no_compound_childread:
  3366. case no_compound_childnormalize:
  3367. case no_compound_childaggregate:
  3368. case no_compound_childcount:
  3369. case no_compound_childgroupaggregate:
  3370. case no_compound_selectnew:
  3371. case no_compound_inline:
  3372. {
  3373. IHqlExpression * dataset = expr->queryChild(0);
  3374. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3375. extra->inherit(*parentExtra, op);
  3376. extra->uid.set(expr->queryProperty(_uid_Atom));
  3377. break;
  3378. }
  3379. case no_select:
  3380. if (expr->isDataset())
  3381. {
  3382. if (expr->hasProperty(newAtom))
  3383. {
  3384. IHqlExpression * dataset = expr->queryChild(0);
  3385. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3386. if (!parentExtra->isAggregate() && !parentExtra->hasAnyLimit() && parentExtra->isBinary())
  3387. {
  3388. node_operator newOp = no_none;
  3389. switch (parentExtra->sourceOp)
  3390. {
  3391. case no_compound_diskread:
  3392. case no_compound_disknormalize:
  3393. if (flags & CSFnewdisk)
  3394. newOp = no_compound_disknormalize;
  3395. break;
  3396. case no_compound_indexread:
  3397. case no_compound_indexnormalize:
  3398. if (flags & CSFnewindex)
  3399. newOp = no_compound_indexnormalize;
  3400. break;
  3401. case no_compound_childread:
  3402. case no_compound_childnormalize:
  3403. if (flags & CSFnewchild)
  3404. newOp = no_compound_childnormalize;
  3405. break;
  3406. }
  3407. if (newOp)
  3408. {
  3409. if (extra->inherit(*parentExtra))
  3410. {
  3411. extra->sourceOp = newOp;
  3412. extra->ensureCompound();
  3413. }
  3414. }
  3415. }
  3416. if ((flags & CSFnewchild) && (extra->sourceOp == no_none))
  3417. {
  3418. extra->reset();
  3419. extra->sourceOp = no_compound_selectnew;
  3420. extra->ensureCompound();
  3421. }
  3422. }
  3423. else
  3424. {
  3425. if ((flags & CSFnewchild) && !isTargetSelector(expr)) // latter is optimization - still works without this
  3426. {
  3427. extra->sourceOp = no_compound_childread;
  3428. }
  3429. }
  3430. }
  3431. break;
  3432. case no_choosen:
  3433. {
  3434. IHqlExpression * arg2 = expr->queryChild(2);
  3435. if (arg2 && !arg2->isPure())
  3436. break;
  3437. //fall through
  3438. }
  3439. case no_limit:
  3440. {
  3441. IHqlExpression * dataset = expr->queryChild(0);
  3442. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3443. bool cloneRequired = needToCloneLimit(expr, parentExtra->sourceOp);
  3444. if (cloneRequired && !expr->queryChild(1)->isPure())
  3445. break;
  3446. if (parentExtra->canMergeLimit(expr, targetClusterType) && !isGrouped(expr) && parentExtra->isBinary())
  3447. {
  3448. if (extra->inherit(*parentExtra))
  3449. {
  3450. if (op == no_choosen)
  3451. {
  3452. extra->hasChoosen = true;
  3453. }
  3454. else
  3455. {
  3456. extra->isLimited = true;
  3457. if (expr->hasProperty(skipAtom))
  3458. extra->hasSkipLimit = true;
  3459. }
  3460. if (expr->hasProperty(onFailAtom))
  3461. extra->isCreateRowLimited = true;
  3462. extra->isCloned = cloneRequired;
  3463. }
  3464. }
  3465. break;
  3466. }
  3467. case no_aggregate:
  3468. case no_newusertable:
  3469. case no_newaggregate:
  3470. {
  3471. IHqlExpression * dataset = expr->queryChild(0);
  3472. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3473. if (isAggregateDataset(expr))
  3474. {
  3475. //Don't yet have csv/xml variants!
  3476. if (!parentExtra->isBinary())
  3477. break;
  3478. IHqlExpression * root = queryRoot(dataset);
  3479. if (!root || isGrouped(root) || expr->hasProperty(localAtom))
  3480. break;
  3481. bool isSimpleCountExists = isSimpleCountExistsAggregate(expr, true, false);
  3482. if (parentExtra->isCreateRowLimited)
  3483. break;
  3484. if (parentExtra->hasAnyLimit() && !isSimpleCountExists)
  3485. break;
  3486. node_operator newOp = no_none;
  3487. node_operator parentOp = parentExtra->sourceOp;
  3488. if (queryRealChild(expr, 3))
  3489. {
  3490. //Grouped aggregate
  3491. switch (parentOp)
  3492. {
  3493. case no_compound_diskread:
  3494. case no_compound_disknormalize:
  3495. if (flags & CSFnewdisk)
  3496. newOp = no_compound_diskgroupaggregate;
  3497. break;
  3498. case no_compound_indexread:
  3499. case no_compound_indexnormalize:
  3500. if (flags & CSFnewindex)
  3501. newOp = no_compound_indexgroupaggregate;
  3502. break;
  3503. case no_compound_childread:
  3504. case no_compound_childnormalize:
  3505. if (flags & CSFnewchild)
  3506. newOp = no_compound_childgroupaggregate;
  3507. break;
  3508. }
  3509. }
  3510. else
  3511. {
  3512. switch (parentOp)
  3513. {
  3514. case no_compound_diskread:
  3515. case no_compound_disknormalize:
  3516. if (flags & CSFnewdisk)
  3517. {
  3518. newOp = no_compound_diskaggregate;
  3519. if (isSimpleCountExists && !parentExtra->isFiltered && (parentOp == no_compound_diskread))
  3520. {
  3521. IHqlExpression * root = queryRoot(expr);
  3522. if (root)
  3523. {
  3524. ColumnToOffsetMap * map = translator.queryRecordOffsetMap(root->queryRecord());
  3525. if (map->isFixedWidth())
  3526. extra->forceCompound = true;
  3527. }
  3528. }
  3529. }
  3530. break;
  3531. case no_compound_indexread:
  3532. case no_compound_indexnormalize:
  3533. //Don't create counts for (non-keyed) skip limits - little benefit, and could cause problems
  3534. //correctly returning the counts - e.g. especially for exists()
  3535. if ((flags & CSFnewindex) && !parentExtra->hasSkipLimit)
  3536. {
  3537. newOp = no_compound_indexaggregate;
  3538. //Force counts on indexes to become a new compound activity
  3539. //otherwise if(count(x) > n, f(x), g()) will always cause x to be read and spilt.
  3540. //The commented out test would do a better job, but not all keyed filters have an explicit keyed() so it is insufficient
  3541. //
  3542. //Really this should become a count if there are no index reads with the same level of conditionality, or if all accesses
  3543. //are counts.
  3544. //That can be logged as a future enhancement.....
  3545. // if (isSimpleCountExists && !parentExtra->isPostFiltered && (parentOp == no_compound_indexread))
  3546. if (isSimpleCountExists && (parentOp == no_compound_indexread))
  3547. {
  3548. //A skip limit will require everything to be read anyway - so no point splitting in two
  3549. if (!parentExtra->hasSkipLimit)
  3550. extra->forceCompound = true;
  3551. }
  3552. }
  3553. break;
  3554. case no_compound_childread:
  3555. case no_compound_childnormalize:
  3556. if (flags & CSFnewchild)
  3557. newOp = no_compound_childaggregate;
  3558. break;
  3559. case no_compound_inline:
  3560. if (flags & CSFnewinline)
  3561. newOp = no_compound_inline;
  3562. break;
  3563. }
  3564. }
  3565. if (newOp)
  3566. {
  3567. //NB: When creating a limited aggregate, it is ok if the input indicates it is cloned
  3568. //because the new compound count operation will take it into account.
  3569. extra->inherit(*parentExtra, newOp);
  3570. }
  3571. }
  3572. else
  3573. {
  3574. if (!parentExtra->isAggregate())
  3575. extra->inherit(*queryBodyExtra(dataset));
  3576. }
  3577. if (expr->hasProperty(keyedAtom))
  3578. extra->ensureCompound();
  3579. }
  3580. break;
  3581. case no_filter:
  3582. {
  3583. IHqlExpression * dataset = expr->queryChild(0);
  3584. CompoundSourceInfo * parentExtra = queryBodyExtra(dataset);
  3585. if (!parentExtra->hasAnyLimit() && !parentExtra->isAggregate())
  3586. {
  3587. if (extra->inherit(*parentExtra))
  3588. {
  3589. extra->isFiltered = true;
  3590. if (filterIsKeyed(expr))
  3591. extra->ensureCompound();
  3592. if (filterIsUnkeyed(expr))
  3593. extra->isPostFiltered = true;
  3594. }
  3595. }
  3596. }
  3597. break;
  3598. case no_preload:
  3599. {
  3600. IHqlExpression * dataset = expr->queryChild(0);
  3601. extra->inherit(*queryBodyExtra(dataset));
  3602. extra->isPreloaded = true;
  3603. break;
  3604. }
  3605. case no_sorted:
  3606. case no_preservemeta:
  3607. case no_distributed:
  3608. case no_grouped:
  3609. case no_stepped:
  3610. case no_section:
  3611. case no_sectioninput:
  3612. case no_dataset_alias:
  3613. {
  3614. IHqlExpression * dataset = expr->queryChild(0);
  3615. extra->inherit(*queryBodyExtra(dataset));
  3616. break;
  3617. }
  3618. case no_usertable:
  3619. case no_selectfields:
  3620. UNIMPLEMENTED;
  3621. break;
  3622. case no_addfiles:
  3623. if (canProcessInline(NULL, expr) && (flags & CSFnewinline))
  3624. extra->sourceOp = no_compound_inline;
  3625. break;
  3626. }
  3627. insideCompound = wasInsideCompound;
  3628. }
  3629. void CompoundSourceTransformer::analyseMarkBoundaries(IHqlExpression * expr)
  3630. {
  3631. //This code means that child-query compounds inside a compound aren't yet spotted, they are spotted later.
  3632. if (createCompoundSource(expr))
  3633. {
  3634. queryBodyExtra(expr)->isBoundary = true;
  3635. candidate = true;
  3636. return;
  3637. }
  3638. else if (isCompoundSource(expr))
  3639. return;
  3640. //Might cause problems if Some items are references (e.g., keyed, fetch(0), keyedjoin(1) and don't want translating.
  3641. NewHqlTransformer::analyseExpr(expr);
  3642. }
  3643. void CompoundSourceTransformer::analyseExpr(IHqlExpression * expr)
  3644. {
  3645. if (alreadyVisited(expr->queryBody()))
  3646. {
  3647. if ((pass == 0) && !insideCompound)
  3648. {
  3649. if (!queryBodyExtra(expr)->isNoteUsageFirst())
  3650. return;
  3651. }
  3652. else
  3653. return;
  3654. }
  3655. if (expr->isConstant())
  3656. return;
  3657. switch (pass)
  3658. {
  3659. case 0:
  3660. analyseGatherInfo(expr);
  3661. break;
  3662. case 1:
  3663. analyseMarkBoundaries(expr);
  3664. break;
  3665. default:
  3666. throwUnexpected();
  3667. break;
  3668. }
  3669. }
  3670. bool CompoundSourceTransformer::childrenAreShared(IHqlExpression * expr)
  3671. {
  3672. if (isCompoundSource(expr))
  3673. return false;
  3674. unsigned numChildren = getNumChildTables(expr);
  3675. for (unsigned i=0; i < numChildren; i++)
  3676. {
  3677. IHqlExpression * cur = expr->queryChild(i);
  3678. if (queryBodyExtra(cur)->isShared() || childrenAreShared(cur))
  3679. return true;
  3680. }
  3681. return false;
  3682. }
  3683. bool CompoundSourceTransformer::createCompoundSource(IHqlExpression * expr)
  3684. {
  3685. CompoundSourceInfo * extra = queryBodyExtra(expr);
  3686. if (extra->sourceOp == no_none)
  3687. return false;
  3688. if (extra->forceCompound)
  3689. return true;
  3690. if (isSourceActivity(expr))
  3691. return false;
  3692. if (expr->getOperator() == no_preservemeta)
  3693. return false;
  3694. if (extra->isPreloaded)
  3695. return (flags & CSFpreload) != 0;
  3696. switch (extra->sourceOp)
  3697. {
  3698. case no_compound_diskread:
  3699. case no_compound_diskaggregate:
  3700. case no_compound_diskcount:
  3701. case no_compound_diskgroupaggregate:
  3702. return ((flags & CSFignoreShared) || !childrenAreShared(expr));
  3703. case no_compound_disknormalize:
  3704. return true;
  3705. case no_compound_indexaggregate:
  3706. case no_compound_indexcount:
  3707. case no_compound_indexgroupaggregate:
  3708. case no_compound_indexread:
  3709. //MORE: Should stop at sufficiently shared children - e.g.,
  3710. //* if the children are aggregates, when we get that far.
  3711. //* if child actions don't change the filter significantly (e.g, just projects, or no seg monitors)
  3712. {
  3713. if (!(flags & CSFindex))
  3714. return false;
  3715. CompoundSourceInfo * parentExtra = queryBodyExtra(expr->queryChild(0));
  3716. return ((flags & CSFignoreShared) || !childrenAreShared(expr) || !parentExtra->isFiltered);
  3717. }
  3718. case no_compound_indexnormalize:
  3719. return ((flags & CSFindex) != 0);
  3720. case no_compound_inline:
  3721. if (!(flags & CSFnewinline))
  3722. return false;
  3723. return !childrenAreShared(expr);
  3724. case no_compound_childread:
  3725. case no_compound_childnormalize:
  3726. case no_compound_childaggregate:
  3727. case no_compound_childcount:
  3728. case no_compound_childgroupaggregate:
  3729. case no_compound_selectnew:
  3730. return true;
  3731. }
  3732. UNIMPLEMENTED;
  3733. return false;
  3734. }
  3735. IHqlExpression * CompoundSourceTransformer::createTransformed(IHqlExpression * expr)
  3736. {
  3737. if (expr->isConstant())
  3738. return LINK(expr);
  3739. OwnedHqlExpr ret = queryTransformAnnotation(expr);
  3740. if (ret)
  3741. return ret.getClear();
  3742. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  3743. CompoundSourceInfo * extra = queryBodyExtra(expr);
  3744. if (extra->isBoundary)
  3745. {
  3746. HqlExprAttr def = transformed;
  3747. if (extra->isCloned)
  3748. transformed.setown(appendLocalAttribute(transformed));
  3749. transformed.setown(createDataset(extra->sourceOp, LINK(transformed), LINK(extra->uid)));
  3750. if (extra->isCloned)
  3751. {
  3752. HqlExprArray args;
  3753. unwindChildren(args, def);
  3754. args.replace(*transformed.getClear(), 0);
  3755. transformed.setown(def->clone(args));
  3756. }
  3757. }
  3758. return transformed.getClear();
  3759. }
  3760. ANewTransformInfo * CompoundSourceTransformer::createTransformInfo(IHqlExpression * expr)
  3761. {
  3762. return CREATE_NEWTRANSFORMINFO(CompoundSourceInfo, expr);
  3763. }
  3764. bool CompoundSourceTransformer::needToCloneLimit(IHqlExpression * expr, node_operator sourceOp)
  3765. {
  3766. node_operator op = expr->getOperator();
  3767. switch (op)
  3768. {
  3769. case no_choosen:
  3770. if (queryRealChild(expr, 2))
  3771. return true;
  3772. break;
  3773. case no_limit:
  3774. if (expr->hasProperty(skipAtom) && (targetClusterType != RoxieCluster))
  3775. return true;
  3776. break;
  3777. }
  3778. switch (targetClusterType)
  3779. {
  3780. case RoxieCluster:
  3781. return false;
  3782. case HThorCluster:
  3783. return (sourceOp != no_compound_indexread) || (op != no_limit);
  3784. case ThorCluster:
  3785. case ThorLCRCluster:
  3786. return true;
  3787. default:
  3788. UNIMPLEMENTED;
  3789. }
  3790. }
  3791. IHqlExpression * CompoundSourceTransformer::process(IHqlExpression * expr)
  3792. {
  3793. analyse(expr, 0);
  3794. analyse(expr, 1);
  3795. if (candidate)
  3796. return transformRoot(expr);
  3797. return LINK(expr);
  3798. }
  3799. //---------------------------------------------------------------------------
  3800. IHqlExpression * getMergedFetch(IHqlExpression * expr)
  3801. {
  3802. IHqlExpression * child = expr->queryChild(0);
  3803. if (isLimitedDataset(child))
  3804. return LINK(expr);
  3805. HqlExprArray args;
  3806. if (child->getOperator() == no_compound_fetch)
  3807. return swapDatasets(expr);
  3808. if (child->getOperator() != no_fetch)
  3809. return LINK(expr);
  3810. args.append(*LINK(expr));
  3811. return createDataset(no_compound_fetch, args);
  3812. }
  3813. static HqlTransformerInfo compoundActivityTransformerInfo("CompoundActivityTransformer");
  3814. CompoundActivityTransformer::CompoundActivityTransformer(ClusterType _targetClusterType) : NewHqlTransformer(compoundActivityTransformerInfo)
  3815. {
  3816. targetClusterType = _targetClusterType;
  3817. }
  3818. IHqlExpression * CompoundActivityTransformer::createTransformed(IHqlExpression * expr)
  3819. {
  3820. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  3821. updateOrphanedSelectors(transformed, expr);
  3822. switch (transformed->getOperator())
  3823. {
  3824. case no_filter:
  3825. return getMergedFetch(transformed);
  3826. case no_limit:
  3827. {
  3828. if (transformed->hasProperty(onFailAtom))
  3829. break;
  3830. LinkedHqlExpr dataset = transformed->queryChild(0);
  3831. if (dataset->hasProperty(limitAtom) || transformed->hasProperty(skipAtom))
  3832. break;
  3833. switch (dataset->getOperator())
  3834. {
  3835. case no_join:
  3836. case no_denormalize:
  3837. case no_denormalizegroup:
  3838. if (isKeyedJoin(dataset))
  3839. break;
  3840. return transformed.getClear();
  3841. default:
  3842. return transformed.getClear();
  3843. }
  3844. if (!isThorCluster(targetClusterType))
  3845. return mergeLimitIntoDataset(dataset, transformed);
  3846. HqlExprArray args;
  3847. unwindChildren(args, transformed);
  3848. args.replace(*mergeLimitIntoDataset(dataset, transformed), 0);
  3849. return transformed->clone(args);
  3850. }
  3851. }
  3852. return transformed.getClear();
  3853. }
  3854. //------------------------------------------------------------------------
  3855. static HqlTransformerInfo optimizeActivityTransformerInfo("OptimizeActivityTransformer");
  3856. OptimizeActivityTransformer::OptimizeActivityTransformer(bool _optimizeCountCompare, bool _optimizeNonEmpty)
  3857. : NewHqlTransformer(optimizeActivityTransformerInfo)
  3858. {
  3859. optimizeCountCompare = _optimizeCountCompare; optimizeNonEmpty = _optimizeNonEmpty;
  3860. }
  3861. void OptimizeActivityTransformer::analyseExpr(IHqlExpression * expr)
  3862. {
  3863. expr = expr->queryBody();
  3864. queryBodyExtra(expr)->noteUsed();
  3865. if (alreadyVisited(expr))
  3866. return;
  3867. NewHqlTransformer::analyseExpr(expr);
  3868. }
  3869. //either a simple count, or isCountAggregate is guaranteed to be true - so structure is well defined
  3870. IHqlExpression * OptimizeActivityTransformer::insertChoosen(IHqlExpression * lhs, IHqlExpression * limit, __int64 limitDelta)
  3871. {
  3872. if (isShared(lhs))
  3873. return NULL;
  3874. IHqlExpression * ds = lhs->queryChild(0);
  3875. HqlExprArray args;
  3876. switch (lhs->getOperator())
  3877. {
  3878. case no_choosen:
  3879. return NULL;
  3880. case no_count:
  3881. case no_newaggregate:
  3882. {
  3883. //count on a child dataset is better if not limited...
  3884. node_operator dsOp = ds->getOperator();
  3885. if ((dsOp == no_select) || (dsOp == no_choosen) || (dsOp == no_rows))
  3886. return NULL;
  3887. args.append(*createDataset(no_choosen, LINK(ds), adjustValue(limit, limitDelta)));
  3888. break;
  3889. }
  3890. case no_implicitcast:
  3891. case no_cast:
  3892. case no_compound_childaggregate:
  3893. case no_compound_diskaggregate:
  3894. case no_compound_indexaggregate:
  3895. case no_select:
  3896. {
  3897. IHqlExpression * newDs = insertChoosen(ds, limit, limitDelta);
  3898. if (!newDs)
  3899. return NULL;
  3900. args.append(*newDs);
  3901. break;
  3902. }
  3903. default:
  3904. throwUnexpectedOp(lhs->getOperator());
  3905. }
  3906. unwindChildren(args, lhs, 1);
  3907. return lhs->clone(args);
  3908. }
  3909. static bool looksLikeSimpleCount(IHqlExpression * expr)
  3910. {
  3911. if ((expr->getOperator() == no_select) && expr->hasProperty(newAtom))
  3912. {
  3913. IHqlExpression * ds = expr->queryChild(0);
  3914. return isSimpleCountAggregate(ds, false);
  3915. }
  3916. return (expr->getOperator() == no_count);
  3917. }
  3918. IHqlExpression * OptimizeActivityTransformer::optimizeCompare(IHqlExpression * lhs, IHqlExpression * rhs, node_operator op)
  3919. {
  3920. if (isShared(lhs))
  3921. return NULL;
  3922. if (!isIndependentOfScope(rhs))
  3923. return NULL;
  3924. if (!looksLikeSimpleCount(lhs))
  3925. return NULL;
  3926. // count(x) op count(y) - not clear if a choosen should be added to either, so assume neither for the moment,
  3927. // (we definitely don't want it added to both, which happens without the second test.)
  3928. if (looksLikeSimpleCount(rhs))
  3929. return NULL;
  3930. //Convert count(x) >= 1 to exists(x) (and other varients)
  3931. node_operator existOp = no_none;
  3932. switch (op)
  3933. {
  3934. case no_ne:
  3935. case no_gt:
  3936. if (matchesConstantValue(rhs, 0))
  3937. existOp = no_exists;
  3938. break;
  3939. case no_eq:
  3940. case no_le:
  3941. if (matchesConstantValue(rhs, 0))
  3942. existOp = no_not;
  3943. break;
  3944. case no_lt:
  3945. if (matchesConstantValue(rhs, 1))
  3946. existOp = no_not;
  3947. break;
  3948. case no_ge:
  3949. if (matchesConstantValue(rhs, 1))
  3950. existOp = no_exists;
  3951. break;
  3952. }
  3953. if (existOp != no_none)
  3954. {
  3955. if (lhs->getOperator() == no_count)
  3956. {
  3957. IHqlExpression * ds = lhs->queryChild(0);
  3958. OwnedHqlExpr ret = createValue(no_exists, makeBoolType(), LINK(ds));
  3959. if (existOp == no_not)
  3960. return createValue(no_not, makeBoolType(), ret.getClear());
  3961. return ret.getClear();
  3962. }
  3963. }
  3964. unsigned choosenDelta =0;
  3965. switch (op)
  3966. {
  3967. case no_eq:
  3968. //count(x) == n -> count(choosen(x,n+1)) == n
  3969. choosenDelta = 1;
  3970. break;
  3971. case no_ne:
  3972. //count(x) != 0 -> count(choosen(x,n+1)) != n
  3973. choosenDelta = 1;
  3974. break;
  3975. case no_lt:
  3976. //count(x) < n -> count(choosen(x,n)) < n
  3977. break;
  3978. case no_le:
  3979. //count(x) <= n -> count(choosen(x,n+1)) <= n
  3980. choosenDelta = 1;
  3981. break;
  3982. case no_gt:
  3983. //count(x) > n -> count(choosen(x,n+1)) > n
  3984. choosenDelta = 1;
  3985. break;
  3986. case no_ge:
  3987. //count(x) >= n -> count(choosen(x,n)) >= n
  3988. break;
  3989. }
  3990. IHqlExpression * newLhs = insertChoosen(lhs, rhs, choosenDelta);
  3991. if (!newLhs)
  3992. return NULL;
  3993. return createValue(op, makeBoolType(), newLhs, LINK(rhs));
  3994. }
  3995. static IHqlExpression * queryNormalizedAggregateParameter(IHqlExpression * expr)
  3996. {
  3997. loop
  3998. {
  3999. switch (expr->getOperator())
  4000. {
  4001. case no_choosen:
  4002. if (queryRealChild(expr, 2))
  4003. return expr;
  4004. break;
  4005. case no_sort:
  4006. case no_shuffle:
  4007. case no_distribute:
  4008. break;
  4009. default:
  4010. return expr;
  4011. }
  4012. expr = expr->queryChild(0);
  4013. }
  4014. }
  4015. static bool aggregateMatchesDataset(IHqlExpression * agg, IHqlExpression * ds)
  4016. {
  4017. return queryNormalizedAggregateParameter(agg)->queryBody() == queryNormalizedAggregateParameter(ds)->queryBody();
  4018. }
  4019. static bool isCheckExistsAtleast(IHqlExpression * cond, IHqlExpression * ds, __int64 minMinElements, __int64 maxMinElements)
  4020. {
  4021. if (maxMinElements <= 0)
  4022. return false;
  4023. switch (cond->getOperator())
  4024. {
  4025. case no_exists:
  4026. if (aggregateMatchesDataset(cond->queryChild(0), ds))
  4027. return true;
  4028. break;
  4029. case no_ne:
  4030. {
  4031. IHqlExpression * condLhs = cond->queryChild(0);
  4032. if ((condLhs->getOperator() == no_count) && isZero(cond->queryChild(1)))
  4033. {
  4034. if (aggregateMatchesDataset(condLhs->queryChild(0), ds))
  4035. return true;
  4036. }
  4037. break;
  4038. }
  4039. case no_gt:
  4040. minMinElements--;
  4041. maxMinElements--;
  4042. //fallthrough
  4043. case no_ge:
  4044. {
  4045. IHqlExpression * condLhs = cond->queryChild(0);
  4046. if (condLhs->getOperator() == no_count)
  4047. {
  4048. IHqlExpression * limit = cond->queryChild(1);
  4049. if (limit->queryValue())
  4050. {
  4051. __int64 limitVal = limit->queryValue()->getIntValue();
  4052. if ((limitVal <= maxMinElements) && (limitVal >= minMinElements))
  4053. {
  4054. if (aggregateMatchesDataset(condLhs->queryChild(0), ds))
  4055. return true;
  4056. }
  4057. }
  4058. }
  4059. }
  4060. break;
  4061. }
  4062. return false;
  4063. }
  4064. //is "value" of the form ds[n].x and other the same as the null expression for that field?
  4065. //if so we may be able to remove a condition
  4066. IHqlExpression * queryNullDsSelect(__int64 & selectIndex, IHqlExpression * value, IHqlExpression * other)
  4067. {
  4068. if (isCast(value))
  4069. value = value->queryChild(0);
  4070. if (value->getOperator() != no_select)
  4071. return NULL;
  4072. bool isNew;
  4073. IHqlExpression * ds = querySelectorDataset(value, isNew);
  4074. if (!isNew || ds->getOperator() != no_selectnth)
  4075. return NULL;
  4076. IValue * index = ds->queryChild(1)->queryValue();
  4077. if (!index)
  4078. return NULL;
  4079. if (!isNullExpr(other, value->queryType()))
  4080. return NULL;
  4081. selectIndex = index->getIntValue();
  4082. return ds->queryChild(0);
  4083. }
  4084. IHqlExpression * OptimizeActivityTransformer::createTransformed(IHqlExpression * expr)
  4085. {
  4086. OwnedHqlExpr transformed = doCreateTransformed(expr);
  4087. if (transformed)
  4088. {
  4089. assertex(transformed != expr);
  4090. queryBodyExtra(transformed)->inherit(queryBodyExtra(expr));
  4091. return transform(transformed);
  4092. }
  4093. transformed.setown(NewHqlTransformer::createTransformed(expr));
  4094. if (transformed != expr)
  4095. queryBodyExtra(transformed)->inherit(queryBodyExtra(expr));
  4096. return transformed.getClear();
  4097. }
  4098. IHqlExpression * OptimizeActivityTransformer::doCreateTransformed(IHqlExpression * expr)
  4099. {
  4100. node_operator op = expr->getOperator();
  4101. switch (op)
  4102. {
  4103. case no_if:
  4104. {
  4105. IHqlExpression * cond = expr->queryChild(0);
  4106. IHqlExpression * lhs = expr->queryChild(1);
  4107. //convert if(exists(x)|count(x)>0, x, y) to nonempty(x, y);
  4108. //must happen before the count(x)>n optimization below....
  4109. if (optimizeNonEmpty && expr->isDataset() && !canProcessInline(NULL, expr))
  4110. {
  4111. if (isCheckExistsAtleast(cond, lhs, 1, 1))
  4112. {
  4113. HqlExprArray args;
  4114. args.append(*transform(lhs));
  4115. args.append(*transform(expr->queryChild(2)));
  4116. OwnedHqlExpr ret = createDataset(no_nonempty, args);
  4117. return expr->cloneAllAnnotations(ret);
  4118. }
  4119. }
  4120. __int64 selectIndex = 0;
  4121. IHqlExpression * ds = queryNullDsSelect(selectIndex, expr->queryChild(1), expr->queryChild(2));
  4122. if (ds)
  4123. {
  4124. if (isCheckExistsAtleast(cond, ds, 1, selectIndex))
  4125. return LINK(lhs);
  4126. }
  4127. break;
  4128. }
  4129. case no_selectnth:
  4130. {
  4131. IHqlExpression * ds = expr->queryChild(0);
  4132. if ((ds->getOperator() != no_sort) || isShared(ds))
  4133. break;
  4134. IHqlExpression * index = expr->queryChild(1);
  4135. if (getIntValue(index, 99999) > 100)
  4136. break;
  4137. OwnedHqlExpr transformedDs = transform(ds);
  4138. OwnedHqlExpr transformedIndex = transform(index);
  4139. HqlExprArray args;
  4140. unwindChildren(args, transformedDs);
  4141. args.add(*LINK(transformedIndex), 2);
  4142. OwnedHqlExpr topn = createDataset(no_topn, args);
  4143. args.kill();
  4144. args.append(*ds->cloneAllAnnotations(topn));
  4145. args.append(*LINK(transformedIndex));
  4146. unwindChildren(args, expr, 2);
  4147. return expr->clone(args);
  4148. }
  4149. case no_eq:
  4150. case no_ne:
  4151. case no_le:
  4152. case no_lt:
  4153. case no_ge:
  4154. case no_gt:
  4155. //MORE Would still be worth doing for thor i) if a no_select non-new, ii) if the lhs was an aggregate on
  4156. //a compound_disk_aggregate iii) possibly others.
  4157. if (optimizeCountCompare)
  4158. {
  4159. IHqlExpression * lhs = expr->queryChild(0);
  4160. IHqlExpression * rhs = expr->queryChild(1);
  4161. OwnedHqlExpr ret = optimizeCompare(lhs, rhs, op);
  4162. if (!ret)
  4163. ret.setown(optimizeCompare(rhs, lhs, getReverseOp(op)));
  4164. if (ret)
  4165. return ret.getClear();
  4166. }
  4167. break;
  4168. }
  4169. return NULL;
  4170. }
  4171. void optimizeActivities(HqlExprArray & exprs, bool optimizeCountCompare, bool optimizeNonEmpty)
  4172. {
  4173. OptimizeActivityTransformer transformer(optimizeCountCompare, optimizeNonEmpty);
  4174. HqlExprArray results;
  4175. transformer.analyseArray(exprs, 0);
  4176. transformer.transformRoot(exprs, results);
  4177. replaceArray(exprs, results);
  4178. }
  4179. IHqlExpression * optimizeActivities(IHqlExpression * expr, bool optimizeCountCompare, bool optimizeNonEmpty)
  4180. {
  4181. OptimizeActivityTransformer transformer(optimizeCountCompare, optimizeNonEmpty);
  4182. HqlExprArray results;
  4183. transformer.analyse(expr, 0);
  4184. return transformer.transformRoot(expr);
  4185. }
  4186. void optimizeActivities(WorkflowArray & array, bool optimizeCountCompare, bool optimizeNonEmpty)
  4187. {
  4188. ForEachItemIn(idx, array)
  4189. optimizeActivities(array.item(idx).queryExprs(), optimizeCountCompare, optimizeNonEmpty);
  4190. }
  4191. IHqlExpression * GlobalAttributeInfo::queryAlias(IHqlExpression * value)
  4192. {
  4193. if (!aliasName)
  4194. {
  4195. if (storedName)
  4196. aliasName.set(storedName);
  4197. else
  4198. aliasName.setown(createNextStringValue(value, storedPrefix));
  4199. }
  4200. return aliasName;
  4201. }
  4202. IHqlExpression * GlobalAttributeInfo::queryFilename(IHqlExpression * value, IConstWorkUnit * wu, bool isRoxie)
  4203. {
  4204. if (!cachedFilename)
  4205. {
  4206. if (storedName)
  4207. cachedFilename.set(storedName);
  4208. else
  4209. cachedFilename.setown(createNextStringValue(value, filePrefix));
  4210. if (persistOp != no_persist)
  4211. {
  4212. StringBuffer prefix("~");
  4213. if (storedName)
  4214. {
  4215. if (persistOp == no_stored)
  4216. prefix.append("spill::stored");
  4217. else if (persistOp == no_checkpoint)
  4218. prefix.append("spill::checkpoint");
  4219. }
  4220. if (persistOp == no_once)
  4221. prefix.append("once::");
  4222. bool wuidIsConstant = isRoxie || !wu->getCloneable();
  4223. if (wuidIsConstant)
  4224. {
  4225. StringBuffer s;
  4226. cachedFilename->queryValue()->getStringValue(s.append(prefix));
  4227. cachedFilename.setown(createConstant(s.str()));
  4228. }
  4229. else
  4230. {
  4231. ITypeInfo * type = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  4232. OwnedHqlExpr filename = createValue(no_concat, type, createConstant(prefix), cachedFilename.getClear());
  4233. cachedFilename.setown(foldHqlExpression(filename));
  4234. }
  4235. }
  4236. }
  4237. return cachedFilename;
  4238. }
  4239. IHqlExpression * GlobalAttributeInfo::createSetValue(IHqlExpression * value, IHqlExpression * name)
  4240. {
  4241. HqlExprArray args;
  4242. args.append(*LINK(value));
  4243. args.append(*createAttribute(sequenceAtom, LINK(sequence)));
  4244. args.append(*createAttribute(namedAtom, LINK(name)));
  4245. if (extraSetAttr)
  4246. extraSetAttr->unwindList(args, no_comma);
  4247. if (cluster)
  4248. args.append(*createAttribute(clusterAtom, LINK(cluster)));
  4249. if (setOp == no_setresult)
  4250. return createSetResult(args);
  4251. return createValue(setOp, makeVoidType(), args);
  4252. }
  4253. IHqlExpression * GlobalAttributeInfo::getStoredKey()
  4254. {
  4255. return createAttribute(nameAtom, LINK(sequence), lowerCaseHqlExpr(storedName));
  4256. }
  4257. void GlobalAttributeInfo::extractCluster(IHqlExpression * expr, bool isRoxie)
  4258. {
  4259. extractGlobal(expr, isRoxie);
  4260. setCluster(queryRealChild(expr, 1));
  4261. }
  4262. void GlobalAttributeInfo::setCluster(IHqlExpression * expr)
  4263. {
  4264. if (expr && !isBlankString(expr))
  4265. cluster.set(expr);
  4266. }
  4267. void GlobalAttributeInfo::extractGlobal(IHqlExpression * expr, bool isRoxie)
  4268. {
  4269. few = isRoxie || spillToWorkunitNotFile(expr);
  4270. if (expr->hasProperty(fewAtom))
  4271. few = true;
  4272. else if (expr->hasProperty(manyAtom) && !isRoxie)
  4273. few = false;
  4274. setOp = no_setresult;
  4275. sequence.setown(getLocalSequenceNumber());
  4276. persistOp = no_global;
  4277. }
  4278. void GlobalAttributeInfo::extractStoredInfo(IHqlExpression * expr, IHqlExpression * originalValue, bool isRoxie)
  4279. {
  4280. node_operator op = expr->getOperator();
  4281. few = expr->hasProperty(fewAtom) || (isRoxie);// && !expr->hasProperty(manyAtom));
  4282. switch (op)
  4283. {
  4284. case no_stored:
  4285. setOp = no_ensureresult;
  4286. storedName.set(expr->queryChild(0));
  4287. sequence.setown(getStoredSequenceNumber());
  4288. few = true;
  4289. break;
  4290. case no_checkpoint:
  4291. setOp = no_ensureresult;
  4292. storedName.set(expr->queryChild(0));
  4293. sequence.setown(getLocalSequenceNumber());
  4294. extraSetAttr.setown(createAttribute(checkpointAtom));
  4295. break;
  4296. case no_persist:
  4297. setOp = no_ensureresult;
  4298. storedName.set(expr->queryChild(0));
  4299. sequence.setown(getGlobalSequenceNumber());
  4300. extraSetAttr.setown(createAttribute(_workflowPersist_Atom, LINK(originalValue)));
  4301. setCluster(queryRealChild(expr, 1));
  4302. few = expr->hasProperty(fewAtom); // PERSISTs need a consistent format.
  4303. extraOutputAttr.setown(createComma(LINK(expr->queryProperty(expireAtom)), LINK(expr->queryProperty(clusterAtom))));
  4304. break;
  4305. case no_global:
  4306. throwUnexpected();
  4307. case no_independent:
  4308. setOp = no_setresult;
  4309. storedName.clear();
  4310. sequence.setown(getLocalSequenceNumber());
  4311. extraSetAttr.setown(createAttribute(_workflow_Atom));
  4312. setCluster(queryRealChild(expr, 0));
  4313. op = no_global;
  4314. break;
  4315. case no_once:
  4316. setOp = no_setresult;
  4317. storedName.clear();
  4318. sequence.setown(getOnceSequenceNumber());
  4319. extraSetAttr.setown(createAttribute(_workflow_Atom));
  4320. break;
  4321. case no_success:
  4322. case no_failure:
  4323. case no_recovery:
  4324. if(setOp == no_none)
  4325. {
  4326. storedName.clear();
  4327. setOp = no_setresult;
  4328. sequence.setown(getLocalSequenceNumber());
  4329. }
  4330. break;
  4331. default:
  4332. return;
  4333. }
  4334. persistOp = op;
  4335. }
  4336. void GlobalAttributeInfo::splitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie)
  4337. {
  4338. doSplitGlobalDefinition(type, value, wu, setOutput, getOutput, isRoxie);
  4339. }
  4340. void GlobalAttributeInfo::doSplitGlobalDefinition(ITypeInfo * type, IHqlExpression * value, IConstWorkUnit * wu, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput, bool isRoxie)
  4341. {
  4342. OwnedHqlExpr targetName;
  4343. if (storedName)
  4344. targetName.set(storedName);
  4345. else
  4346. targetName.setown(createNextStringValue(value));
  4347. ITypeInfo * valueType = value->queryType();
  4348. if (value->isDataset())
  4349. {
  4350. IHqlExpression * groupOrder = (IHqlExpression *)valueType->queryGroupInfo();
  4351. if (few)
  4352. {
  4353. splitSmallDataset(value, setOutput, getOutput);
  4354. return;
  4355. }
  4356. LinkedHqlExpr filename = queryFilename(value, wu, isRoxie);
  4357. HqlExprArray args;
  4358. args.append(*LINK(value));
  4359. args.append(*LINK(filename));
  4360. //NB: Also update the dataset node at the end...
  4361. if (valueType->getTypeCode() == type_groupedtable)
  4362. args.append(*createAttribute(groupedAtom));
  4363. else
  4364. assertex(groupOrder == NULL);
  4365. bool compressFile = true;
  4366. switch (persistOp)
  4367. {
  4368. case no_persist:
  4369. {
  4370. args.append(*createAttribute(_workflowPersist_Atom));
  4371. args.append(*createAttribute(sequenceAtom, getGlobalSequenceNumber()));
  4372. //add a flag to help get the resourcing right - may need to hash distribute on different size thor
  4373. IHqlExpression * distribution = queryDistribution(valueType);
  4374. if (distribution && !distribution->isAttribute())
  4375. args.append(*createAttribute(distributedAtom));
  4376. break;
  4377. }
  4378. case no_stored:
  4379. args.append(*createAttribute(ownedAtom));
  4380. args.append(*createAttribute(sequenceAtom, getStoredSequenceNumber()));
  4381. break;
  4382. case no_checkpoint:
  4383. args.append(*createAttribute(ownedAtom));
  4384. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  4385. break;
  4386. case no_once:
  4387. args.append(*createAttribute(ownedAtom));
  4388. args.append(*createAttribute(sequenceAtom, getOnceSequenceNumber()));
  4389. break;
  4390. case no_global:
  4391. //May extend over several different graphs
  4392. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  4393. args.append(*createAttribute(ownedAtom));
  4394. args.append(*createAttribute(jobTempAtom));
  4395. break;
  4396. default:
  4397. //global, independent, success, failure, etc. etc.
  4398. args.append(*createAttribute(ownedAtom));
  4399. args.append(*createAttribute(jobTempAtom));
  4400. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  4401. break;
  4402. }
  4403. if (compressFile)
  4404. args.append(*createAttribute(__compressed__Atom));
  4405. args.append(*createAttribute(overwriteAtom));
  4406. if (extraOutputAttr)
  4407. extraOutputAttr->unwindList(args, no_comma);
  4408. OwnedHqlExpr output = createValue(no_output, makeVoidType(), args);
  4409. // if (persistOp == no_independent)
  4410. if (setOp == no_setresult)
  4411. setOutput.set(output);
  4412. else
  4413. setOutput.setown(createSetValue(output, queryAlias(value)));
  4414. if(getOutput)
  4415. {
  4416. IHqlExpression * record = value->queryRecord();
  4417. args.kill();
  4418. args.append(*LINK(filename));
  4419. args.append(*LINK(record));
  4420. args.append(*createValue(no_thor));
  4421. args.append(*createAttribute(_noVirtual_Atom)); // don't interpret virtual fields in spilled output
  4422. if (persistOp == no_persist)
  4423. args.append(*createAttribute(_workflowPersist_Atom));
  4424. if (groupOrder)
  4425. args.append(*createAttribute(groupedAtom));
  4426. if (compressFile)
  4427. args.append(*createAttribute(__compressed__Atom));
  4428. if (hasSingleRow(value))
  4429. args.append(*createAttribute(rowAtom));
  4430. if (output->hasProperty(jobTempAtom))
  4431. args.append(*createAttribute(jobTempAtom));
  4432. if (persistOp != no_stored)
  4433. {
  4434. IHqlExpression * recordCountAttr = queryRecordCountInfo(value);
  4435. if (recordCountAttr)
  4436. args.append(*LINK(recordCountAttr));
  4437. }
  4438. OwnedHqlExpr getValue = createDataset(no_table, args);
  4439. //getValue.setown(cloneInheritedAnnotations(value, getValue));
  4440. if (persistOp != no_stored)
  4441. getValue.setown(preserveTableInfo(getValue, value, false, (persistOp == no_persist) ? filename : NULL));
  4442. //Note: getValue->queryType() != valueType because the dataset used for field resolution has changed...
  4443. getOutput->setown(getValue.getClear());
  4444. }
  4445. }
  4446. else if (type->getTypeCode() == type_void)
  4447. {
  4448. switch (persistOp)
  4449. {
  4450. case no_stored:
  4451. case no_checkpoint:
  4452. case no_once:
  4453. case no_persist:
  4454. setOutput.setown(createSetValue(value, queryAlias(value)));
  4455. break;
  4456. default:
  4457. setOutput.set(value);
  4458. break;
  4459. }
  4460. if(getOutput) getOutput->setown(createValue(no_null, makeVoidType(), createAttribute(_internal_Atom, LINK(sequence), LINK(queryAlias(value)))));
  4461. }
  4462. else
  4463. {
  4464. ITypeInfo * ct = type->queryChildType();
  4465. if (type->getTypeCode() == type_set)
  4466. extraSetAttr.setown(createComma(extraSetAttr.getClear(), createAttribute(_original_Atom, createValue(no_implicitcast, LINK(type), LINK(value)))));
  4467. setOutput.setown(createSetValue(value, queryAlias(value)));
  4468. if(getOutput) getOutput->setown(createGetResultFromSetResult(setOutput, type));
  4469. }
  4470. }
  4471. void GlobalAttributeInfo::createSmallOutput(IHqlExpression * value, SharedHqlExpr & setOutput)
  4472. {
  4473. if (value->getOperator() == no_temptable)
  4474. {
  4475. IHqlExpression * values = value->queryChild(0);
  4476. if ((values->getOperator() == no_null) ||
  4477. ((values->getOperator() == no_list) && (values->numChildren() == 0)))
  4478. {
  4479. OwnedHqlExpr newNull = createDataset(no_null, LINK(value->queryRecord()));
  4480. setOutput.setown(createSetValue(newNull, queryAlias(value)));
  4481. return;
  4482. }
  4483. else if (values->getOperator() == no_all)
  4484. {
  4485. OwnedHqlExpr newAll = createDataset(no_all, LINK(value->queryRecord()));
  4486. setOutput.setown(createSetValue(newAll, queryAlias(value)));
  4487. return;
  4488. }
  4489. }
  4490. // else if (value->getOperator() == no_null)
  4491. // {
  4492. // setOutput.setown(createSetValue(value, queryAlias()));
  4493. // return;
  4494. // }
  4495. HqlExprArray args;
  4496. args.append(*LINK(value));
  4497. args.append(*createAttribute(sequenceAtom, LINK(sequence)));
  4498. args.append(*createAttribute(namedAtom, LINK(queryAlias(value))));
  4499. if (isGrouped(value))
  4500. args.append(*createAttribute(groupedAtom));
  4501. setOutput.setown(createValue(no_output, makeVoidType(), args));
  4502. if (setOp != no_setresult)
  4503. {
  4504. extraSetAttr.setown(createComma(LINK(extraSetAttr), createAttribute(noSetAtom)));
  4505. setOutput.setown(createSetValue(setOutput, queryAlias(value)));
  4506. }
  4507. }
  4508. void GlobalAttributeInfo::checkFew(HqlCppTranslator & translator, IHqlExpression * value)
  4509. {
  4510. // if (few && isGrouped(value))
  4511. // translator.WARNINGAT(queryLocation(value), HQLWRN_GroupedGlobalFew);
  4512. }
  4513. void GlobalAttributeInfo::splitSmallDataset(IHqlExpression * value, SharedHqlExpr & setOutput, OwnedHqlExpr * getOutput)
  4514. {
  4515. createSmallOutput(value, setOutput);
  4516. if(getOutput)
  4517. {
  4518. IHqlExpression * record = value->queryRecord();
  4519. HqlExprArray args;
  4520. args.append(*LINK(record));
  4521. args.append(*createAttribute(nameAtom, LINK(queryAlias(value))));
  4522. args.append(*createAttribute(sequenceAtom, LINK(sequence)));
  4523. if (isGrouped(value))
  4524. args.append(*createAttribute(groupedAtom));
  4525. if (persistOp != no_stored)
  4526. {
  4527. IHqlExpression * recordCountAttr = queryRecordCountInfo(value);
  4528. if (recordCountAttr)
  4529. args.append(*LINK(recordCountAttr));
  4530. }
  4531. OwnedHqlExpr wuRead = createDataset(no_workunit_dataset, args);
  4532. //wuRead.setown(cloneInheritedAnnotations(value, wuRead));
  4533. if (persistOp != no_stored)
  4534. getOutput->setown(preserveTableInfo(wuRead, value, true, NULL));
  4535. else
  4536. getOutput->set(wuRead);
  4537. }
  4538. }
  4539. //------------------------------------------------------------------------
  4540. static bool isStored(IHqlExpression * set)
  4541. {
  4542. switch (set->getOperator())
  4543. {
  4544. case no_setresult:
  4545. case no_ensureresult:
  4546. case no_output:
  4547. return matchesConstantValue(queryPropertyChild(set, sequenceAtom, 0), ResultSequenceStored);
  4548. }
  4549. return false;
  4550. }
  4551. static bool isTrivialStored(IHqlExpression * set)
  4552. {
  4553. switch (set->getOperator())
  4554. {
  4555. case no_setresult:
  4556. case no_ensureresult:
  4557. if (matchesConstantValue(queryPropertyChild(set, sequenceAtom, 0), ResultSequenceStored))
  4558. {
  4559. IHqlExpression * value = set->queryChild(0);
  4560. loop
  4561. {
  4562. switch (value->getOperator())
  4563. {
  4564. case no_constant:
  4565. case no_all:
  4566. case no_null:
  4567. return true;
  4568. case no_list:
  4569. return (value->numChildren() == 0);
  4570. case no_cast:
  4571. case no_implicitcast:
  4572. value = value->queryChild(0);
  4573. break;
  4574. case no_output:
  4575. return isTrivialInlineOutput(value);
  4576. default:
  4577. return false;
  4578. }
  4579. }
  4580. }
  4581. break;
  4582. case no_output:
  4583. return isTrivialInlineOutput(set);
  4584. }
  4585. return false;
  4586. }
  4587. inline bool isWorkflowAction(IHqlExpression * expr)
  4588. {
  4589. return expr && (expr->getOperator() == no_workflow_action);
  4590. }
  4591. void cloneDependencies(UnsignedArray & tgt, const UnsignedArray & src)
  4592. {
  4593. ForEachItemIn(i, src)
  4594. tgt.append(src.item(i));
  4595. }
  4596. inline bool addDependency(UnsignedArray & tgt, unsigned wfid)
  4597. {
  4598. if (!tgt.contains(wfid))
  4599. {
  4600. tgt.append(wfid);
  4601. return true;
  4602. }
  4603. return false;
  4604. }
  4605. void inheritDependencies(UnsignedArray & tgt, const UnsignedArray & src)
  4606. {
  4607. ForEachItemIn(i, src)
  4608. addDependency(tgt, src.item(i));
  4609. }
  4610. bool hasSameDependencies(UnsignedArray const & d1, UnsignedArray const & d2)
  4611. {
  4612. if (d1.ordinality() != d2.ordinality())
  4613. return false;
  4614. ForEachItemIn(i, d2)
  4615. {
  4616. if (d1.find(d2.item(i)) == NotFound)
  4617. return false;
  4618. }
  4619. return true;
  4620. }
  4621. bool hasExtraDependencies(UnsignedArray const & p, UnsignedArray const & n, UnsignedArray const & ignore)
  4622. {
  4623. if (n.ordinality() > p.ordinality() + ignore.ordinality())
  4624. return true;
  4625. ForEachItemIn(i, n)
  4626. {
  4627. unsigned cur = n.item(i);
  4628. if (!p.contains(cur) && !ignore.contains(cur))
  4629. return true;
  4630. }
  4631. return false;
  4632. }
  4633. void diffDependencies(UnsignedArray & target, UnsignedArray const & d1, UnsignedArray const & d2)
  4634. {
  4635. ForEachItemIn(i, d1)
  4636. {
  4637. unsigned cur = d1.item(i);
  4638. if (d2.find(cur) == NotFound)
  4639. addDependency(target, cur);
  4640. }
  4641. ForEachItemIn(j, d2)
  4642. {
  4643. unsigned cur = d2.item(j);
  4644. if (d1.find(cur) == NotFound)
  4645. addDependency(target, cur);
  4646. }
  4647. }
  4648. void intersectDependencies(UnsignedArray & target, UnsignedArray const & d1, UnsignedArray const & d2)
  4649. {
  4650. ForEachItemIn(i, d1)
  4651. {
  4652. unsigned cur = d1.item(i);
  4653. if (d2.find(cur) != NotFound)
  4654. addDependency(target, cur);
  4655. }
  4656. }
  4657. //------------------------------------------------------------------------
  4658. static HqlTransformerInfo workflowTransformerInfo("WorkflowTransformer");
  4659. WorkflowTransformer::WorkflowTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  4660. : NewHqlTransformer(workflowTransformerInfo), wu(_wu), translator(_translator), wfidCount(0)
  4661. {
  4662. trivialStoredWfid = 0;
  4663. nextInternalFunctionId = 0;
  4664. onceWfid = 0;
  4665. combineAllStored = translator.queryOptions().combineAllStored;
  4666. combineTrivialStored = translator.queryOptions().combineTrivialStored;
  4667. isRootAction = true;
  4668. isRoxie = (translator.getTargetClusterType() == RoxieCluster);
  4669. workflowOut = NULL;
  4670. isConditional = false;
  4671. insideStored = false;
  4672. }
  4673. //-- Helper routines --
  4674. IWorkflowItem * WorkflowTransformer::addWorkflowToWorkunit(unsigned wfid, WFType type, WFMode mode, UnsignedArray const & dependencies, ContingencyData const & conts, IHqlExpression * cluster)
  4675. {
  4676. Owned<IWorkflowItem> wf(wu->addWorkflowItem(wfid, type, mode, conts.success, conts.failure, conts.recovery, conts.retries, conts.contingencyFor));
  4677. if (cluster)
  4678. {
  4679. StringBuffer clusterText;
  4680. getStringValue(clusterText, cluster);
  4681. wf->setCluster(clusterText);
  4682. }
  4683. ForEachItemIn(idx, dependencies)
  4684. wf->addDependency(dependencies.item(idx));
  4685. return wf.getClear();
  4686. }
  4687. void WorkflowTransformer::setWorkflowSchedule(IWorkflowItem * wf, const ScheduleData & sched)
  4688. {
  4689. if(sched.now)
  4690. {
  4691. wf->setScheduledNow();
  4692. }
  4693. else
  4694. {
  4695. wu->incEventScheduledCount();
  4696. wf->setScheduledOn(sched.eventName.str(), sched.eventText.str());
  4697. if(sched.counting)
  4698. {
  4699. wf->setScheduleCount(sched.count);
  4700. if (sched.count == 0)
  4701. wf->setState(WFStateDone);
  4702. }
  4703. }
  4704. int priority = sched.priority;
  4705. if(priority > 100) priority = 100;
  4706. if(priority < 0) priority = 0;
  4707. wf->setSchedulePriority(priority);
  4708. }
  4709. void WorkflowTransformer::setWorkflowPersist(IWorkflowItem * wf, char const * persistName, unsigned persistWfid)
  4710. {
  4711. wf->setPersistInfo(persistName, persistWfid);
  4712. }
  4713. WorkflowItem * WorkflowTransformer::createWorkflowItem(IHqlExpression * expr, unsigned wfid, unsigned persistWfid)
  4714. {
  4715. WorkflowItem * item = new WorkflowItem(wfid);
  4716. expr->unwindList(item->queryExprs(), no_comma);
  4717. gatherIndirectDependencies(item->dependencies, expr);
  4718. return item;
  4719. }
  4720. IWorkflowItem * WorkflowTransformer::lookupWorkflowItem(unsigned wfid)
  4721. {
  4722. Owned<IWorkflowItemIterator> iter = wu->updateWorkflowItems();
  4723. ForEach(*iter)
  4724. {
  4725. Owned<IWorkflowItem> cur = iter->get();
  4726. if (cur->queryWfid() == wfid)
  4727. return cur.getClear();
  4728. }
  4729. return NULL;
  4730. }
  4731. bool WorkflowTransformer::hasStoredDependencies(IHqlExpression * expr)
  4732. {
  4733. return false;
  4734. }
  4735. void WorkflowTransformer::inheritDependencies(IHqlExpression * expr)
  4736. {
  4737. ForEachChild(i, expr)
  4738. copyDependencies(queryBodyExtra(expr->queryChild(i)), queryBodyExtra(expr));
  4739. }
  4740. void WorkflowTransformer::copyDependencies(WorkflowTransformInfo * source, WorkflowTransformInfo * dest)
  4741. {
  4742. if(!source) return;
  4743. UnsignedArray const & dependencies = source->queryDependencies();
  4744. ForEachItemIn(idx, dependencies)
  4745. dest->addDependency(dependencies.item(idx));
  4746. }
  4747. void WorkflowTransformer::copySetValueDependencies(WorkflowTransformInfo * source, IHqlExpression * expr)
  4748. {
  4749. node_operator op = expr->getOperator();
  4750. if (op == no_compound || op==no_actionlist)
  4751. {
  4752. copySetValueDependencies(source, expr->queryChild(expr->numChildren()-1));
  4753. inheritDependencies(expr);
  4754. }
  4755. else
  4756. copyDependencies(source, queryBodyExtra(expr));
  4757. }
  4758. unsigned WorkflowTransformer::ensureWorkflowAction(IHqlExpression * expr)
  4759. {
  4760. if (isWorkflowAction(expr))
  4761. return (unsigned)getIntValue(expr->queryChild(0));
  4762. unsigned wfid = ++wfidCount;
  4763. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(expr), rootCluster);
  4764. workflowOut->append(*createWorkflowItem(expr, wfid));
  4765. return wfid;
  4766. }
  4767. //-- first pass - extracting workflow
  4768. unsigned WorkflowTransformer::splitValue(IHqlExpression * value)
  4769. {
  4770. GlobalAttributeInfo info("spill::wf", "wf");
  4771. info.sequence.setown(getLocalSequenceNumber());
  4772. info.setOp = no_setresult;
  4773. info.persistOp = no_global;
  4774. OwnedHqlExpr setValue;
  4775. info.checkFew(translator, value);
  4776. info.splitGlobalDefinition(value->queryType(), value, wu, setValue, 0, (translator.getTargetClusterType() == RoxieCluster));
  4777. inheritDependencies(setValue);
  4778. unsigned wfid = ++wfidCount;
  4779. workflowOut->append(*createWorkflowItem(setValue, wfid));
  4780. return wfid;
  4781. }
  4782. IHqlExpression * WorkflowTransformer::extractWorkflow(IHqlExpression * untransformed, IHqlExpression * expr)
  4783. {
  4784. GlobalAttributeInfo info("spill::wf", "wf");
  4785. info.sequence.setown(getLocalSequenceNumber());
  4786. OwnedHqlExpr scheduleActions;
  4787. IHqlExpression * value = expr->queryChild(0);
  4788. HqlExprArray actions;
  4789. unwindChildren(actions, expr, 1);
  4790. IHqlExpression * original = queryProperty(_original_Atom, actions);
  4791. if (original) original = original->queryChild(0);
  4792. //First check for duplicate expressions, and cope with the weird case where they are identical except for the annotations.
  4793. //Do it before wfid is allocated to make life simpler
  4794. ForEachItemIn(iCheck, actions)
  4795. {
  4796. IHqlExpression & cur = actions.item(iCheck);
  4797. node_operator curOp = cur.getOperator();
  4798. switch (curOp)
  4799. {
  4800. case no_persist:
  4801. case no_checkpoint:
  4802. case no_stored:
  4803. info.extractStoredInfo(&cur, original, isRoxie);
  4804. OwnedHqlExpr id = info.getStoredKey();
  4805. unsigned match = alreadyProcessed.find(*id);
  4806. if (match == NotFound)
  4807. break;
  4808. //Compare the definitions - not the expressions, otherwise the original attribute can create false negatives
  4809. IHqlExpression * prevValue = alreadyProcessedExpr.item(match).queryChild(0);
  4810. if(prevValue->queryBody() != value->queryBody())
  4811. {
  4812. StringBuffer s;
  4813. getStoredDescription(s, info.sequence, info.storedName, true);
  4814. if(prevValue->queryType() != value->queryBody()->queryType())
  4815. {
  4816. #ifdef _DEBUG
  4817. debugFindFirstDifference(alreadyProcessedExpr.item(match).queryBody(), expr->queryBody());
  4818. #endif
  4819. if (curOp == no_stored)
  4820. throwError1(HQLERR_DuplicateStoredDiffType, s.str());
  4821. else
  4822. throwError1(HQLERR_DuplicateDefinitionDiffType, s.str());
  4823. }
  4824. else if (translator.queryOptions().allowStoredDuplicate) // only here as a temporary workaround
  4825. translator.reportWarning(queryActiveLocation(expr), HQLERR_DuplicateDefinition, HQLERR_DuplicateDefinition_Text, s.str());
  4826. else
  4827. {
  4828. if (queryLocationIndependent(prevValue) != queryLocationIndependent(value))
  4829. {
  4830. #ifdef _DEBUG
  4831. debugFindFirstDifference(prevValue->queryBody(), value->queryBody());
  4832. debugFindFirstDifference(queryLocationIndependent(prevValue), queryLocationIndependent(value));
  4833. #endif
  4834. if (curOp == no_stored)
  4835. throwError1(HQLERR_DuplicateStoredDefinition, s.str());
  4836. else
  4837. throwError1(HQLERR_DuplicateDefinition, s.str());
  4838. }
  4839. }
  4840. }
  4841. //If the body was essentially the same, call transform on the previous value - so
  4842. return transform(&alreadyProcessedUntransformed.item(match));
  4843. }
  4844. }
  4845. ContingencyData conts;
  4846. ScheduleData sched;
  4847. unsigned wfid = ++wfidCount;
  4848. unsigned schedWfid = 0;
  4849. ForEachItemIn(idx, actions)
  4850. {
  4851. IHqlExpression & cur = actions.item(idx);
  4852. node_operator curOp = cur.getOperator();
  4853. switch (curOp)
  4854. {
  4855. case no_persist:
  4856. if (isRoxie && translator.getCheckRoxieRestrictions())
  4857. {
  4858. StringBuffer s;
  4859. IHqlExpression * name = cur.queryChild(0);
  4860. OwnedHqlExpr seq = getGlobalSequenceNumber();
  4861. getStoredDescription(s, seq, name, true);
  4862. throwError1(HQLERR_NotSupportInRoxie, s.str());
  4863. }
  4864. //fall through
  4865. case no_checkpoint:
  4866. case no_stored:
  4867. {
  4868. info.extractStoredInfo(&cur, original, isRoxie);
  4869. OwnedHqlExpr id = info.getStoredKey();
  4870. alreadyProcessed.append(*id.getClear());
  4871. alreadyProcessedExpr.append(*LINK(expr));
  4872. alreadyProcessedUntransformed.append(*LINK(untransformed));
  4873. }
  4874. break;
  4875. case no_independent:
  4876. case no_once:
  4877. info.extractStoredInfo(&cur, original, isRoxie);
  4878. break;
  4879. case no_success:
  4880. {
  4881. OwnedHqlExpr successExpr = transformSequentialEtc(cur.queryChild(0));
  4882. conts.success = splitValue(successExpr);
  4883. Owned<IWorkflowItem> wf = addWorkflowContingencyToWorkunit(conts.success, WFTypeSuccess, WFModeNormal, queryDirectDependencies(successExpr), NULL, wfid);
  4884. info.extractStoredInfo(&cur, original, isRoxie);
  4885. break;
  4886. }
  4887. case no_failure:
  4888. {
  4889. OwnedHqlExpr failureExpr = transformSequentialEtc(cur.queryChild(0));
  4890. conts.failure = splitValue(failureExpr);
  4891. Owned<IWorkflowItem> wf = addWorkflowContingencyToWorkunit(conts.failure, WFTypeFailure, WFModeNormal, queryDirectDependencies(failureExpr), NULL, wfid);
  4892. info.extractStoredInfo(&cur, original, isRoxie);
  4893. break;
  4894. }
  4895. case no_recovery:
  4896. {
  4897. conts.recovery = splitValue(cur.queryChild(0));
  4898. conts.retries = (unsigned)getIntValue(cur.queryChild(1), 0);
  4899. Owned<IWorkflowItem> wf = addWorkflowContingencyToWorkunit(conts.recovery, WFTypeRecovery, WFModeNormal, queryDirectDependencies(cur.queryChild(0)), NULL, wfid);
  4900. info.extractStoredInfo(&cur, original, isRoxie);
  4901. break;
  4902. }
  4903. case no_attr:
  4904. assertex(cur.queryName() == _original_Atom);
  4905. break;
  4906. case no_when:
  4907. {
  4908. OwnedHqlExpr folded = foldHqlExpression(&cur);
  4909. IHqlExpression * event = folded->queryChild(0);
  4910. IHqlExpression * eventFilter = event->queryChild(1);
  4911. sched.now = false;
  4912. event->queryChild(0)->queryValue()->getStringValue(sched.eventName);
  4913. if (eventFilter)
  4914. eventFilter->queryValue()->getStringValue(sched.eventText);
  4915. else
  4916. sched.eventText.append("*");
  4917. if(cur.numChildren()>1)
  4918. {
  4919. sched.counting = true;
  4920. sched.count = (unsigned)getIntValue(folded->queryChild(1));
  4921. }
  4922. sched.independent = true;
  4923. }
  4924. break;
  4925. case no_priority:
  4926. {
  4927. sched.priority = (int)getIntValue(cur.queryChild(0));
  4928. sched.independent = true;
  4929. break;
  4930. }
  4931. default:
  4932. throwUnexpectedOp(curOp);
  4933. }
  4934. }
  4935. OwnedHqlExpr setValue;
  4936. OwnedHqlExpr getValue;
  4937. bool done = false;
  4938. if (info.setOp != no_none)
  4939. {
  4940. assertex(!sched.independent); // should have been enforced by the tree normalization
  4941. ITypeInfo * type = expr->queryType();
  4942. info.checkFew(translator, expr);
  4943. info.splitGlobalDefinition(type, value, wu, setValue, &getValue, isRoxie);
  4944. copySetValueDependencies(queryBodyExtra(value), setValue);
  4945. }
  4946. else
  4947. {
  4948. assertex(sched.independent);
  4949. getValue.set(value);
  4950. done = true;
  4951. schedWfid = wfid;
  4952. }
  4953. if(!sched.independent && !conts.success && !conts.failure && !conts.recovery)
  4954. {
  4955. bool combine = false;
  4956. if (combineAllStored && !hasNonTrivialDependencies(setValue))
  4957. {
  4958. switch (getResultSequenceValue(setValue))
  4959. {
  4960. case ResultSequenceStored:
  4961. combine = true;
  4962. break;
  4963. case ResultSequenceInternal:
  4964. combine = insideStored;
  4965. break;
  4966. }
  4967. }
  4968. if (info.persistOp == no_once)
  4969. {
  4970. //MORE: Error if refers to stored or persist
  4971. if (queryDirectDependencies(setValue).ordinality())
  4972. translator.ERRORAT(queryLocation(untransformed), HQLERR_OnceCannotAccessStored);
  4973. if (onceWfid == 0)
  4974. {
  4975. onceWfid = wfid;
  4976. }
  4977. else
  4978. {
  4979. wfid = onceWfid;
  4980. wfidCount--;
  4981. }
  4982. if (!onceExprs.contains(*setValue))
  4983. onceExprs.append(*LINK(setValue));
  4984. done = true;
  4985. }
  4986. if (combineTrivialStored && isTrivialStored(setValue))
  4987. combine = true;
  4988. if (combine)
  4989. {
  4990. if (trivialStoredWfid == 0)
  4991. {
  4992. trivialStoredWfid = wfid;
  4993. storedWfids.append(wfid);
  4994. }
  4995. else
  4996. {
  4997. wfid = trivialStoredWfid;
  4998. wfidCount--;
  4999. }
  5000. if (trivialStoredExprs.find(*setValue) == NotFound)
  5001. trivialStoredExprs.append(*LINK(setValue));
  5002. done = true;
  5003. }
  5004. }
  5005. if (!done)
  5006. {
  5007. if (info.persistOp == no_stored)
  5008. storedWfids.append(wfid);
  5009. //If you really want side effects within a no_persist to be processed in the correct sequence
  5010. //you need to use persist(failure(independent, f(independent))
  5011. //It generally makes worse code (and incorrect in jbellow.xhql) if they are expanded.
  5012. //because there is no ensure result in the expected wfid.
  5013. if ((info.persistOp != no_persist) && expr->isAction())
  5014. setValue.setown(transformSequentialEtc(setValue));
  5015. if(info.persistOp == no_persist)
  5016. {
  5017. StringBuffer persistName;
  5018. info.storedName->queryValue()->getStringValue(persistName);
  5019. unsigned persistWfid = ++wfidCount;
  5020. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModePersist, queryDirectDependencies(setValue), conts, info.queryCluster());
  5021. setWorkflowPersist(wf, persistName.str(), persistWfid);
  5022. Owned<IWorkflowItem> wfPersist = addWorkflowToWorkunit(persistWfid, WFTypeNormal, WFModeNormal, NULL);
  5023. DependenciesUsed dependencies(false);
  5024. gatherDependencies(setValue, dependencies, GatherAll);
  5025. dependencies.removeInternalReads();
  5026. HqlExprArray checkArgs;
  5027. checkArgs.append(*createExprAttribute(_files_Atom, dependencies.tablesRead));
  5028. if (dependencies.resultsRead.ordinality())
  5029. checkArgs.append(*createExprAttribute(_results_Atom, dependencies.resultsRead));
  5030. checkArgs.append(*createAttribute(_original_Atom, LINK(original)));
  5031. checkArgs.append(*createAttribute(namedAtom, LINK(info.storedName)));
  5032. if (expr->isDataset())
  5033. checkArgs.append(*createAttribute(fileAtom));
  5034. OwnedHqlExpr check = createValue(no_persist_check, makeVoidType(), checkArgs);
  5035. workflowOut->append(*createWorkflowItem(check, persistWfid));
  5036. workflowOut->append(*createWorkflowItem(setValue, wfid, persistWfid));
  5037. }
  5038. else
  5039. {
  5040. if (info.queryCluster())
  5041. {
  5042. OwnedHqlExpr cluster = createValue(no_cluster, makeVoidType(), LINK(setValue), LINK(info.queryCluster()));
  5043. inheritDependencies(cluster);
  5044. setValue.set(cluster);
  5045. }
  5046. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(setValue), conts, info.queryCluster());
  5047. workflowOut->append(*createWorkflowItem(setValue, wfid));
  5048. }
  5049. }
  5050. if(sched.independent)
  5051. {
  5052. if (schedWfid == 0)
  5053. schedWfid = ++wfidCount;
  5054. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(schedWfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(getValue), info.queryCluster());
  5055. setWorkflowSchedule(wf, sched);
  5056. workflowOut->append(*createWorkflowItem(getValue, schedWfid));
  5057. getValue.setown(createValue(no_null, makeVoidType()));
  5058. }
  5059. else
  5060. queryBodyExtra(getValue.get())->addDependency(wfid);
  5061. return getValue.getClear();
  5062. }
  5063. IHqlExpression * WorkflowTransformer::extractCommonWorkflow(IHqlExpression * expr, IHqlExpression * transformed)
  5064. {
  5065. if (!transformed->queryDataset())
  5066. return LINK(transformed);
  5067. WorkflowTransformInfo * extra = queryBodyExtra(expr);
  5068. if (!extra->isCommonUpCandidate() || !isWorthHoisting(transformed, false))
  5069. return LINK(transformed);
  5070. if (isContextDependent(transformed) || !isIndependentOfScope(transformed))
  5071. return LINK(transformed);
  5072. StringBuffer s;
  5073. IHqlExpression * location = activeLocations.ordinality() ? &activeLocations.tos() : NULL;
  5074. if (!translator.queryOptions().performWorkflowCse)
  5075. {
  5076. s.appendf("AutoWorkflow: Try adding ': INDEPENDENT' to %s ", getOpString(expr->getOperator()));
  5077. if (expr->queryName())
  5078. s.append("[").append(expr->queryName()).append("] ");
  5079. s.append(" to common up code between workflow items");
  5080. DBGLOG("%s", s.str());
  5081. translator.addWorkunitException(ExceptionSeverityInformation, HQLWRN_TryAddingIndependent, s.str(), location);
  5082. if (!translator.queryOptions().performWorkflowCse)
  5083. return LINK(transformed);
  5084. }
  5085. //This code would need a lot more work for it to be enabled by default.
  5086. // e.g., ensure it really is worth commoning up, the expressions aren't to be evaluated on different clusters etc. etc.
  5087. unsigned wfid = ++wfidCount;
  5088. s.appendf("AutoWorkflow: Spotted %s ", getOpString(expr->getOperator()));
  5089. if (expr->queryName())
  5090. s.append("[").append(expr->queryName()).append("] ");
  5091. s.append(" to common up between workflow items [").append(wfid).append("]");
  5092. DBGLOG("%s", s.str());
  5093. translator.addWorkunitException(ExceptionSeverityInformation, 0, s.str(), location);
  5094. GlobalAttributeInfo info("spill::wfa", "wfa");
  5095. info.extractGlobal(transformed, isRoxie); // should really be a slightly different unction
  5096. OwnedHqlExpr setValue;
  5097. OwnedHqlExpr getValue;
  5098. ContingencyData conts;
  5099. WorkflowTransformInfo * transformedExtra = queryBodyExtra(transformed);
  5100. info.splitGlobalDefinition(transformed->queryType(), transformed, wu, setValue, &getValue, isRoxie);
  5101. copySetValueDependencies(transformedExtra, setValue);
  5102. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(setValue), conts, NULL);
  5103. workflowOut->append(*createWorkflowItem(setValue, wfid));
  5104. queryBodyExtra(getValue.get())->addDependency(wfid);
  5105. return getValue.getClear();
  5106. }
  5107. IHqlExpression * WorkflowTransformer::transformInternalFunction(IHqlExpression * newFuncDef)
  5108. {
  5109. IHqlExpression * body = newFuncDef->queryChild(0);
  5110. if (body->getOperator() != no_outofline)
  5111. return LINK(newFuncDef);
  5112. IHqlExpression * ecl = body->queryChild(0);
  5113. StringBuffer funcname;
  5114. funcname.append("user").append(++nextInternalFunctionId);
  5115. if (translator.queryOptions().debugGeneratedCpp)
  5116. funcname.append("_").append(newFuncDef->queryName()).toLowerCase();
  5117. OwnedHqlExpr funcNameExpr = createConstant(funcname);
  5118. IHqlExpression * formals = newFuncDef->queryChild(1);
  5119. OwnedHqlExpr newFormals = mapInternalFunctionParameters(formals);
  5120. HqlExprArray bodyArgs;
  5121. bodyArgs.append(*replaceParameters(ecl, formals, newFormals));
  5122. unwindChildren(bodyArgs, body, 1);
  5123. bodyArgs.append(*createLocalAttribute());
  5124. bodyArgs.append(*createExprAttribute(entrypointAtom, LINK(funcNameExpr)));
  5125. OwnedHqlExpr newBody = body->clone(bodyArgs);
  5126. inheritDependencies(newBody);
  5127. HqlExprArray funcdefArgs;
  5128. funcdefArgs.append(*LINK(newBody));
  5129. funcdefArgs.append(*LINK(newFormals));
  5130. unwindChildren(funcdefArgs, newFuncDef, 2);
  5131. OwnedHqlExpr namedFuncDef = newFuncDef->clone(funcdefArgs);
  5132. inheritDependencies(namedFuncDef);
  5133. if (ecl->getOperator() == no_cppbody)
  5134. return namedFuncDef.getClear();
  5135. WorkflowItem * item = new WorkflowItem(namedFuncDef);
  5136. workflowOut->append(*item);
  5137. return createExternalFuncdefFromInternal(namedFuncDef);
  5138. }
  5139. IHqlExpression * WorkflowTransformer::transformInternalCall(IHqlExpression * transformed)
  5140. {
  5141. IHqlExpression * funcDef = transformed->queryDefinition();
  5142. Owned<IHqlExpression> newFuncDef = transform(funcDef);
  5143. HqlExprArray paramters;
  5144. unwindChildren(paramters, transformed);
  5145. OwnedHqlExpr rebound = createReboundFunction(newFuncDef, paramters);
  5146. inheritDependencies(rebound);
  5147. return rebound.getClear();
  5148. }
  5149. IHqlExpression * WorkflowTransformer::createTransformed(IHqlExpression * expr)
  5150. {
  5151. //Could short-circuit if doesn't contain workflow, but it also modifies outputs/buildindex...
  5152. //Force record to be transformed - so any stored values in record (ifblock!!) are hoisted.
  5153. node_operator op = expr->getOperator();
  5154. if (op == no_param)
  5155. return LINK(expr);
  5156. if (op == no_transform || op == no_newtransform)
  5157. ::Release(transform(expr->queryRecord()));
  5158. IHqlExpression * body = expr->queryBody(true);
  5159. if (expr != body)
  5160. {
  5161. switch (expr->getAnnotationKind())
  5162. {
  5163. case annotate_location:
  5164. case annotate_symbol:
  5165. activeLocations.append(*expr);
  5166. break;
  5167. }
  5168. OwnedHqlExpr transformedBody = transform(body);
  5169. switch (expr->getAnnotationKind())
  5170. {
  5171. case annotate_location:
  5172. case annotate_symbol:
  5173. activeLocations.pop();
  5174. break;
  5175. }
  5176. OwnedHqlExpr transformed = (transformedBody == body) ? LINK(expr) : expr->cloneAnnotation(transformedBody);
  5177. //more: this really shouldn't be needed
  5178. inheritDependencies(transformed);
  5179. return transformed.getClear();
  5180. }
  5181. bool wasInsideStored = insideStored;
  5182. if ((op == no_colon) && queryOperatorInList(no_stored, expr->queryChild(1)))
  5183. insideStored = true;
  5184. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  5185. insideStored = wasInsideStored;
  5186. inheritDependencies(transformed);
  5187. switch (op)
  5188. {
  5189. #if 0
  5190. //MORE: Workflow in user functions doesn't work for roxie at the moment
  5191. case no_call:
  5192. transformed.setown(transformCall(transformed));
  5193. inheritDependencies(transformed);
  5194. copyDependencies(queryBodyExtra(transformed->queryExternalDefinition()), queryBodyExtra(transformed));
  5195. break;
  5196. case no_externalcall:
  5197. transformed.setown(transformExternalCall(transformed));
  5198. inheritDependencies(transformed);
  5199. copyDependencies(queryExtra(transformed->queryExternalDefinition()), queryExtra(transformed));
  5200. break;
  5201. #endif
  5202. case no_colon:
  5203. if (translator.insideLibrary())
  5204. {
  5205. SCMStringBuffer libraryName;
  5206. StringBuffer colonText(" (");
  5207. getOutputLibraryName(libraryName, wu);
  5208. getExprECL(expr, colonText);
  5209. colonText.append(")");
  5210. throwError2(HQLERR_LibraryCannotContainWorkflow, libraryName.str(), colonText.str());
  5211. }
  5212. transformed.setown(extractWorkflow(expr, transformed));
  5213. break;
  5214. case no_output:
  5215. case no_buildindex:
  5216. {
  5217. IHqlExpression * updateAttr = transformed->queryProperty(updateAtom);
  5218. if (updateAttr)
  5219. {
  5220. DependenciesUsed dependencies(false);
  5221. gatherDependencies(transformed->queryChild(0), dependencies, GatherAll);
  5222. dependencies.removeInternalReads();
  5223. bool canEvaluateFilenames = true;
  5224. HqlExprArray updateArgs;
  5225. unwindChildren(updateArgs, updateAttr);
  5226. if (dependencies.tablesRead.ordinality())
  5227. {
  5228. OwnedHqlExpr attr = createExprAttribute(_files_Atom, dependencies.tablesRead);
  5229. if (!isIndependentOfScope(attr) || isContextDependent(attr))
  5230. {
  5231. if (!updateAttr->hasProperty(alwaysAtom))
  5232. throwError(HQLERR_InputsAreTooComplexToUpdate);
  5233. canEvaluateFilenames = false;
  5234. }
  5235. else
  5236. updateArgs.append(*attr.getClear());
  5237. }
  5238. if (dependencies.resultsRead.ordinality())
  5239. updateArgs.append(*createExprAttribute(_results_Atom, dependencies.resultsRead));
  5240. HqlExprArray args;
  5241. unwindChildren(args, transformed);
  5242. args.zap(*updateAttr);
  5243. if (canEvaluateFilenames)
  5244. args.append(*createExprAttribute(updateAtom, updateArgs));
  5245. transformed.setown(transformed->clone(args));
  5246. inheritDependencies(transformed);
  5247. }
  5248. break;
  5249. }
  5250. case no_funcdef:
  5251. transformed.setown(transformInternalFunction(transformed));
  5252. break;
  5253. case no_call:
  5254. transformed.setown(transformInternalCall(transformed));
  5255. break;
  5256. }
  5257. return extractCommonWorkflow(expr, transformed);
  5258. }
  5259. //-- second pass - sort out sequential etc.
  5260. /*
  5261. This is very tricky... The problem is we only want to create workflow actions for sequential/parallel and conditions if they
  5262. are necessary. In particular.
  5263. o workflow items are only executed once per invocation
  5264. o create them for sequential if the dependencies haven't already been evaluated
  5265. o create them for conditions if the non-intersection of the dependencies for the branches haven't already been evaluated
  5266. o create if a workflow action has been created for a child action.
  5267. o can't rely on createTransform() updating the dependencies so-far because the transform() may be cached.
  5268. o Need to be careful that dependencies done so far are set up correctly before each call to transform()
  5269. */
  5270. UnsignedArray const & WorkflowTransformer::queryDependencies(unsigned wfid)
  5271. {
  5272. if (wfid == trivialStoredWfid)
  5273. return emptyDependencies;
  5274. ForEachItemIn(i, *workflowOut)
  5275. {
  5276. WorkflowItem & cur = workflowOut->item(i);
  5277. if (cur.wfid == wfid)
  5278. return cur.dependencies;
  5279. }
  5280. throwUnexpected();
  5281. }
  5282. void WorkflowTransformer::gatherIndirectDependencies(UnsignedArray & result, IHqlExpression * expr)
  5283. {
  5284. if (isWorkflowAction(expr))
  5285. {
  5286. unsigned wfid = (unsigned)getIntValue(expr->queryChild(0));
  5287. ::inheritDependencies(result, queryDependencies(wfid));
  5288. }
  5289. else
  5290. {
  5291. const UnsignedArray & direct = queryBodyExtra(expr)->queryDependencies();
  5292. ForEachItemIn(i, direct)
  5293. {
  5294. unsigned wfid = direct.item(i);
  5295. if (addDependency(result, wfid))
  5296. ::inheritDependencies(result, queryDependencies(wfid));
  5297. }
  5298. }
  5299. }
  5300. bool WorkflowTransformer::hasNonTrivialDependencies(IHqlExpression * expr)
  5301. {
  5302. UnsignedArray const & dependencies = queryDirectDependencies(expr);
  5303. ForEachItemIn(i, dependencies)
  5304. {
  5305. unsigned cur = dependencies.item(i);
  5306. if ((cur != trivialStoredWfid) && (cur != onceWfid))
  5307. return true;
  5308. }
  5309. return false;
  5310. }
  5311. UnsignedArray const & WorkflowTransformer::queryDirectDependencies(IHqlExpression * expr)
  5312. {
  5313. return queryBodyExtra(expr)->queryDependencies();
  5314. }
  5315. void WorkflowTransformer::cacheWorkflowDependencies(unsigned wfid, UnsignedArray & extra)
  5316. {
  5317. WorkflowItem * item = new WorkflowItem(wfid);
  5318. ForEachItemIn(i, extra)
  5319. {
  5320. unsigned wfid = extra.item(i);
  5321. item->dependencies.append(wfid);
  5322. ::inheritDependencies(item->dependencies, queryDependencies(wfid));
  5323. }
  5324. workflowOut->append(*item);
  5325. }
  5326. IHqlExpression * WorkflowTransformer::createWorkflowAction(unsigned wfid)
  5327. {
  5328. //NB: Needs to include wfid as an argument otherwise inherited dependencies get messed up
  5329. OwnedHqlExpr transformed = createValue(no_workflow_action, makeVoidType(), getSizetConstant(wfid));
  5330. queryBodyExtra(transformed)->addDependency(wfid);
  5331. return transformed.getClear();
  5332. }
  5333. void WorkflowTransformer::ensureWorkflowAction(UnsignedArray & dependencies, IHqlExpression * expr)
  5334. {
  5335. unsigned wfid = ensureWorkflowAction(expr);
  5336. addDependency(dependencies, wfid);
  5337. }
  5338. //Create a sequential workflow action if any of the branches contains a workflow action
  5339. IHqlExpression * WorkflowTransformer::createCompoundWorkflow(IHqlExpression * expr)
  5340. {
  5341. HqlExprArray pendingBranches;
  5342. UnsignedArray childWfid;
  5343. ForEachChild(i, expr)
  5344. {
  5345. IHqlExpression * cur = expr->queryChild(i);
  5346. unsigned mark = markDependencies();
  5347. OwnedHqlExpr transformed = transformRootAction(cur);
  5348. restoreDependencies(mark);
  5349. if (isWorkflowAction(transformed))
  5350. {
  5351. if (pendingBranches.ordinality())
  5352. {
  5353. OwnedHqlExpr branch = createActionList(pendingBranches);
  5354. inheritDependencies(branch);
  5355. ensureWorkflowAction(childWfid, branch);
  5356. pendingBranches.kill();
  5357. }
  5358. ensureWorkflowAction(childWfid, transformed);
  5359. }
  5360. else
  5361. {
  5362. pendingBranches.append(*LINK(transformed));
  5363. }
  5364. gatherIndirectDependencies(cumulativeDependencies, transformed);
  5365. }
  5366. if (childWfid.ordinality())
  5367. {
  5368. if (pendingBranches.ordinality())
  5369. {
  5370. OwnedHqlExpr branch = createActionList(pendingBranches);
  5371. inheritDependencies(branch);
  5372. ensureWorkflowAction(childWfid, branch);
  5373. }
  5374. unsigned wfid = ++wfidCount;
  5375. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeSequential, childWfid, rootCluster);
  5376. cacheWorkflowDependencies(wfid, childWfid);
  5377. return createWorkflowAction(wfid);
  5378. }
  5379. return LINK(expr);
  5380. }
  5381. //Create a sequential workflow action if any of the branches introduce new dependencies/or creates a workflow item (e.g., wait!)
  5382. IHqlExpression * WorkflowTransformer::createSequentialWorkflow(IHqlExpression * expr)
  5383. {
  5384. OwnedHqlExpr nextBranch;
  5385. UnsignedArray childWfid;
  5386. ForEachChild(i, expr)
  5387. {
  5388. IHqlExpression * cur = expr->queryChild(i);
  5389. unsigned mark = markDependencies();
  5390. OwnedHqlExpr transformed = transformRootAction(cur);
  5391. restoreDependencies(mark);
  5392. UnsignedArray dependencies;
  5393. gatherIndirectDependencies(dependencies, transformed);
  5394. if (hasExtraDependencies(cumulativeDependencies, dependencies, storedWfids) || isWorkflowAction(transformed))
  5395. {
  5396. if (nextBranch)
  5397. {
  5398. ensureWorkflowAction(childWfid, nextBranch);
  5399. nextBranch.clear();
  5400. }
  5401. ::inheritDependencies(cumulativeDependencies, dependencies);
  5402. if (isWorkflowAction(transformed))
  5403. ensureWorkflowAction(childWfid, transformed);
  5404. else
  5405. nextBranch.set(transformed);
  5406. }
  5407. else
  5408. {
  5409. if (nextBranch)
  5410. nextBranch.setown(createValue(expr->getOperator(), nextBranch.getClear(), LINK(transformed)));
  5411. else
  5412. nextBranch.set(transformed);
  5413. inheritDependencies(nextBranch);
  5414. }
  5415. }
  5416. if (childWfid.ordinality())
  5417. {
  5418. if (nextBranch)
  5419. ensureWorkflowAction(childWfid, nextBranch);
  5420. unsigned wfid = ++wfidCount;
  5421. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeSequential, childWfid, rootCluster);
  5422. cacheWorkflowDependencies(wfid, childWfid);
  5423. return createWorkflowAction(wfid);
  5424. }
  5425. return LINK(expr);
  5426. }
  5427. // Create a parallel workflow action if any of the child actions are workflow actions
  5428. IHqlExpression * WorkflowTransformer::createParallelWorkflow(IHqlExpression * expr)
  5429. {
  5430. HqlExprArray branches;
  5431. UnsignedArray childWfid;
  5432. unsigned mark = markDependencies();
  5433. ForEachChild(i, expr)
  5434. {
  5435. IHqlExpression * cur = expr->queryChild(i);
  5436. OwnedHqlExpr transformed = transformRootAction(cur);
  5437. if (isWorkflowAction(transformed))
  5438. ensureWorkflowAction(childWfid, transformed);
  5439. else
  5440. branches.append(*LINK(transformed));
  5441. restoreDependencies(mark);
  5442. }
  5443. if (childWfid.ordinality())
  5444. {
  5445. if (branches.ordinality())
  5446. {
  5447. OwnedHqlExpr branch = createActionList(branches);
  5448. inheritDependencies(branch);
  5449. ensureWorkflowAction(childWfid, branch);
  5450. }
  5451. unsigned wfid = ++wfidCount;
  5452. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeParallel, childWfid, rootCluster);
  5453. cacheWorkflowDependencies(wfid, childWfid);
  5454. return createWorkflowAction(wfid);
  5455. }
  5456. return LINK(expr);
  5457. }
  5458. IHqlExpression * WorkflowTransformer::createIfWorkflow(IHqlExpression * expr)
  5459. {
  5460. IHqlExpression * cond = expr->queryChild(0);
  5461. IHqlExpression * trueExpr = expr->queryChild(1);
  5462. IHqlExpression * falseExpr = expr->queryChild(2);
  5463. OwnedHqlExpr newCond = LINK(cond);
  5464. gatherIndirectDependencies(cumulativeDependencies, cond);
  5465. //more: inherit dependencies?
  5466. UnsignedArray trueDepends, falseDepends;
  5467. unsigned mark = markDependencies();
  5468. OwnedHqlExpr newTrueExpr = transformRootAction(trueExpr);
  5469. restoreDependencies(mark);
  5470. OwnedHqlExpr newFalseExpr = falseExpr ? transformRootAction(falseExpr) : NULL;
  5471. restoreDependencies(mark);
  5472. //Need to turn a conditional action into a conditional workflow item if
  5473. //i) it has a workflow action as a child.
  5474. //ii) the true/false branches are dependent on something that hasn't already been evaluated
  5475. // (and isn't shared between both branches)
  5476. bool needToCreateWorkflow = false;
  5477. if (hasDependencies(newTrueExpr) || (newFalseExpr && hasDependencies(newFalseExpr)))
  5478. {
  5479. needToCreateWorkflow = isWorkflowAction(newTrueExpr) || isWorkflowAction(newFalseExpr);
  5480. if (!needToCreateWorkflow)
  5481. {
  5482. //Failures are assumed to be exceptional, so don't worry about extra dependencies
  5483. if (!isFailAction(newTrueExpr) && !isFailAction(newFalseExpr))
  5484. {
  5485. UnsignedArray newTrueDepends;
  5486. gatherIndirectDependencies(newTrueDepends, newTrueExpr);
  5487. if (!falseExpr)
  5488. needToCreateWorkflow = hasExtraDependencies(cumulativeDependencies, newTrueDepends, storedWfids);
  5489. else
  5490. {
  5491. UnsignedArray newFalseDepends;
  5492. gatherIndirectDependencies(newFalseDepends, newFalseExpr);
  5493. UnsignedArray diff;
  5494. diffDependencies(diff, newTrueDepends, newFalseDepends);
  5495. needToCreateWorkflow = hasExtraDependencies(cumulativeDependencies, diff, storedWfids);
  5496. }
  5497. }
  5498. }
  5499. if (needToCreateWorkflow)
  5500. {
  5501. //Represent as wfid(cond-wfid, true-wfid, false-wfid)
  5502. UnsignedArray dependencies;
  5503. OwnedHqlExpr setCondExpr = createValue(no_setworkflow_cond, makeVoidType(), LINK(cond));
  5504. inheritDependencies(setCondExpr);
  5505. ensureWorkflowAction(dependencies, setCondExpr);
  5506. ensureWorkflowAction(dependencies, newTrueExpr);
  5507. if (newFalseExpr)
  5508. ensureWorkflowAction(dependencies, newFalseExpr);
  5509. unsigned wfid = ++wfidCount;
  5510. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeCondition, dependencies, rootCluster);
  5511. WorkflowItem * item = new WorkflowItem(wfid);
  5512. cloneDependencies(item->dependencies, dependencies);
  5513. if (falseExpr)
  5514. {
  5515. UnsignedArray newTrueDepends;
  5516. UnsignedArray newFalseDepends;
  5517. gatherIndirectDependencies(newTrueDepends, newTrueExpr);
  5518. gatherIndirectDependencies(newFalseDepends, newFalseExpr);
  5519. intersectDependencies(item->dependencies, newTrueDepends, newFalseDepends);
  5520. }
  5521. workflowOut->append(*item);
  5522. return createWorkflowAction(wfid);
  5523. }
  5524. }
  5525. return LINK(expr);
  5526. }
  5527. IHqlExpression * WorkflowTransformer::createWaitWorkflow(IHqlExpression * expr)
  5528. {
  5529. //First create a EndWait workflow item which has a when clause of the wait criteria
  5530. OwnedHqlExpr folded = foldHqlExpression(expr);
  5531. IHqlExpression * event = folded->queryChild(0);
  5532. IHqlExpression * eventFilter = event->queryChild(1);
  5533. ScheduleData sched;
  5534. sched.now = false;
  5535. getStringValue(sched.eventName, event->queryChild(0));
  5536. if (eventFilter)
  5537. getStringValue(sched.eventText, eventFilter);
  5538. else
  5539. sched.eventText.append("*");
  5540. sched.counting = true;
  5541. sched.count = 0;
  5542. sched.independent = true;
  5543. unsigned endWaitWfid = ++wfidCount;
  5544. UnsignedArray noDependencies;
  5545. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(endWaitWfid, WFTypeNormal, WFModeWait, noDependencies, rootCluster);
  5546. setWorkflowSchedule(wf, sched);
  5547. OwnedHqlExpr doNothing = createValue(no_null, makeVoidType());
  5548. workflowOut->append(*createWorkflowItem(doNothing, endWaitWfid));
  5549. //Now create a wait entry, with the EndWait as the dependency
  5550. UnsignedArray dependencies;
  5551. dependencies.append(endWaitWfid);
  5552. unsigned beginWaitWfid = ++wfidCount;
  5553. Owned<IWorkflowItem> wfWait = addWorkflowToWorkunit(beginWaitWfid, WFTypeNormal, WFModeBeginWait, dependencies, rootCluster);
  5554. cacheWorkflowDependencies(beginWaitWfid, dependencies);
  5555. return createWorkflowAction(beginWaitWfid);
  5556. }
  5557. IHqlExpression * WorkflowTransformer::transformRootAction(IHqlExpression * expr)
  5558. {
  5559. node_operator op = expr->getOperator();
  5560. switch (op)
  5561. {
  5562. case no_compound:
  5563. if (expr->isAction())
  5564. return createCompoundWorkflow(expr);
  5565. break;
  5566. case no_parallel:
  5567. return createParallelWorkflow(expr);
  5568. case no_sequential:
  5569. return createSequentialWorkflow(expr);
  5570. case no_actionlist:
  5571. return createCompoundWorkflow(expr);
  5572. case no_if:
  5573. if (expr->isAction())
  5574. return createIfWorkflow(expr);
  5575. break;
  5576. case no_wait:
  5577. return createWaitWorkflow(expr);
  5578. case no_ensureresult:
  5579. {
  5580. IHqlExpression * value = expr->queryChild(0);
  5581. if (!value->isAction())
  5582. break;
  5583. OwnedHqlExpr transformed = transformRootAction(value);
  5584. if (value == transformed)
  5585. break;
  5586. HqlExprArray args;
  5587. args.append(*transformed.getClear());
  5588. unwindChildren(args, expr, 1);
  5589. OwnedHqlExpr ret = expr->clone(args);
  5590. inheritDependencies(ret);
  5591. return ret.getClear();
  5592. }
  5593. }
  5594. return LINK(expr);
  5595. }
  5596. IHqlExpression * WorkflowTransformer::transformSequentialEtc(IHqlExpression * expr)
  5597. {
  5598. unsigned mark = markDependencies();
  5599. //Ignore differences in access to trivial stored variables.
  5600. if (trivialStoredWfid)
  5601. cumulativeDependencies.append(trivialStoredWfid);
  5602. if (onceWfid)
  5603. cumulativeDependencies.append(onceWfid);
  5604. OwnedHqlExpr ret = transformRootAction(expr);
  5605. restoreDependencies(mark);
  5606. return ret.getClear();
  5607. }
  5608. void WorkflowTransformer::percolateScheduledIds(WorkflowArray & workflow)
  5609. {
  5610. ForEachItemIn(i, workflow)
  5611. {
  5612. WorkflowItem & cur = workflow.item(i);
  5613. Owned<IWorkflowItem> wf = lookupWorkflowItem(cur.queryWfid());
  5614. if (wf && wf->isScheduledNow())
  5615. {
  5616. ForEachItemIn(i2, cur.dependencies)
  5617. {
  5618. Owned<IWorkflowItem> child = lookupWorkflowItem(cur.dependencies.item(i2));
  5619. if (child->queryMode() == WFModeWait)
  5620. child->setScheduledWfid(cur.queryWfid());
  5621. }
  5622. }
  5623. }
  5624. }
  5625. ///- workflow processing
  5626. void WorkflowTransformer::analyseExpr(IHqlExpression * expr)
  5627. {
  5628. WorkflowTransformInfo * extra = queryBodyExtra(expr);
  5629. if (extra->noteWorkflow(activeWfid, isConditional))
  5630. return;
  5631. switch (expr->getOperator())
  5632. {
  5633. case no_allnodes:
  5634. //MORE: Do I need to recurse and explicitly disable hoisting?
  5635. return;
  5636. case no_if:
  5637. {
  5638. bool wasConditional = isConditional;
  5639. analyseExpr(expr->queryChild(0));
  5640. isConditional = true;
  5641. analyseExpr(expr->queryChild(1));
  5642. if (expr->queryChild(2))
  5643. analyseExpr(expr->queryChild(2));
  5644. isConditional = wasConditional;
  5645. return;
  5646. }
  5647. case no_colon:
  5648. {
  5649. if (!isIndependentOfScope(expr->queryChild(0)))
  5650. {
  5651. StringBuffer s;
  5652. if (expr->queryName())
  5653. s.appendf(" '%s'", expr->queryName()->str());
  5654. //MORE: Better if we also kept nested track of locations
  5655. translator.WARNINGAT1(queryActiveLocation(expr), HQLWRN_WorkflowSeemsToBeDependent, s.str());
  5656. }
  5657. unsigned prevWfid = activeWfid;
  5658. activeWfid = ++wfidCount;
  5659. analyseExpr(expr->queryChild(0));
  5660. activeWfid = prevWfid;
  5661. return;
  5662. }
  5663. }
  5664. NewHqlTransformer::analyseExpr(expr);
  5665. }
  5666. void WorkflowTransformer::analyseAll(const HqlExprArray & in)
  5667. {
  5668. activeWfid = ++wfidCount;
  5669. analyseArray(in, 0);
  5670. wfidCount = 0;
  5671. }
  5672. void WorkflowTransformer::transformRoot(const HqlExprArray & in, WorkflowArray & out)
  5673. {
  5674. wfidCount = 0;
  5675. workflowOut = &out;
  5676. HqlExprArray transformed;
  5677. WorkflowTransformInfo globalInfo(NULL);
  5678. ForEachItemIn(idx, in)
  5679. {
  5680. OwnedHqlExpr ret = transform(&in.item(idx));
  5681. copyDependencies(queryBodyExtra(ret), &globalInfo);
  5682. //ignore results that do nothing, but still collect the dependencies...
  5683. if (ret->getOperator() != no_null)
  5684. transformed.append(*ret.getClear());
  5685. }
  5686. if (onceExprs.length())
  5687. {
  5688. //By definition they don't have any dependencies, so no need to call inheritDependencies.
  5689. OwnedHqlExpr onceExpr = createActionList(onceExprs);
  5690. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(onceWfid, WFTypeNormal, WFModeOnce, queryDirectDependencies(onceExpr), NULL);
  5691. wf->setScheduledNow();
  5692. out.append(*createWorkflowItem(onceExpr, onceWfid));
  5693. }
  5694. if (trivialStoredExprs.length())
  5695. {
  5696. //By definition they don't have any dependencies, so no need to call inheritDependencies.
  5697. OwnedHqlExpr trivialStoredExpr = createActionList(trivialStoredExprs);
  5698. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(trivialStoredWfid, WFTypeNormal, WFModeNormal, queryDirectDependencies(trivialStoredExpr), NULL);
  5699. out.append(*createWorkflowItem(trivialStoredExpr, trivialStoredWfid));
  5700. }
  5701. if (transformed.ordinality())
  5702. {
  5703. //Handle sequential etc.
  5704. OwnedHqlExpr combined = createActionList(transformed);
  5705. OwnedHqlExpr result = transformSequentialEtc(combined);
  5706. transformed.kill();
  5707. transformed.append(*result.getClear());
  5708. }
  5709. UnsignedArray const & dependencies = globalInfo.queryDependencies();
  5710. if(transformed.ordinality() || dependencies.ordinality())
  5711. {
  5712. if ((transformed.ordinality() == 0) && (dependencies.ordinality() == 1))
  5713. {
  5714. Owned<IWorkflowItem> wf = lookupWorkflowItem(dependencies.item(0));
  5715. wf->setScheduledNow();
  5716. }
  5717. else
  5718. {
  5719. Owned<IHqlExpression> combinedItems = createComma(transformed);
  5720. if (!combinedItems)
  5721. combinedItems.setown(createValue(no_null, makeVoidType()));
  5722. unsigned wfid;
  5723. if (!isWorkflowAction(combinedItems))
  5724. {
  5725. wfid = ++wfidCount;
  5726. ScheduleData sched;
  5727. Owned<IWorkflowItem> wf = addWorkflowToWorkunit(wfid, WFTypeNormal, WFModeNormal, dependencies, NULL);
  5728. setWorkflowSchedule(wf, sched);
  5729. out.append(*createWorkflowItem(combinedItems, wfid));
  5730. }
  5731. else
  5732. wfid = ensureWorkflowAction(combinedItems);
  5733. Owned<IWorkflowItem> wf = lookupWorkflowItem(wfid);
  5734. wf->setScheduledNow();
  5735. }
  5736. }
  5737. workflowOut = NULL;
  5738. percolateScheduledIds(out);
  5739. }
  5740. void extractWorkflow(HqlCppTranslator & translator, HqlExprArray & exprs, WorkflowArray & out)
  5741. {
  5742. WorkflowTransformer transformer(translator.wu(), translator);
  5743. if (translator.queryOptions().performWorkflowCse || translator.queryOptions().notifyWorkflowCse)
  5744. transformer.analyseAll(exprs);
  5745. transformer.transformRoot(exprs, out);
  5746. }
  5747. //------------------------------------------------------------------------
  5748. enum { SIKnone, SIKhole, SIKagent, SIKthor };
  5749. class StatementInfo : public CInterface
  5750. {
  5751. public:
  5752. StatementInfo(IHqlExpression * _expr);
  5753. void calcDependencies();
  5754. bool canSwapOrder(StatementInfo & other)
  5755. {
  5756. return queryDependencies().canSwapOrder(other.queryDependencies());
  5757. }
  5758. inline bool isConditional() { return expr->getOperator() == no_if; }
  5759. inline bool isThorQuery() { return category == SIKthor; }
  5760. DependenciesUsed & queryDependencies()
  5761. {
  5762. if (!hasDependencies)
  5763. {
  5764. calcDependencies();
  5765. hasDependencies = true;
  5766. }
  5767. return dependencies;
  5768. }
  5769. public:
  5770. HqlExprAttr expr;
  5771. protected:
  5772. DependenciesUsed dependencies;
  5773. bool hasDependencies;
  5774. unsigned category;
  5775. };
  5776. StatementInfo::StatementInfo(IHqlExpression * _expr) : dependencies(true)
  5777. {
  5778. expr.set(_expr);
  5779. if (expr->getOperator() == no_thor)
  5780. category = SIKthor;
  5781. else
  5782. category = SIKagent;
  5783. hasDependencies = false;
  5784. }
  5785. void StatementInfo::calcDependencies()
  5786. {
  5787. gatherDependencies(expr, dependencies, GatherAll);
  5788. }
  5789. void groupThorGraphs(HqlExprArray & in)
  5790. {
  5791. //Gather information about the statements...
  5792. bool hadThor = false;
  5793. bool lastWasThor = false;
  5794. bool couldImprove = false;
  5795. CIArrayOf<StatementInfo> stmts;
  5796. ForEachItemIn(idx, in)
  5797. {
  5798. StatementInfo & cur = *new StatementInfo(&in.item(idx));
  5799. stmts.append(cur);
  5800. if (cur.isThorQuery())
  5801. {
  5802. if (hadThor && !lastWasThor)
  5803. couldImprove = true;
  5804. hadThor = true;
  5805. lastWasThor = true;
  5806. }
  5807. else
  5808. lastWasThor = false;
  5809. }
  5810. //If no thor queries are split by other queries, then may as well keep in the same order...
  5811. if (!couldImprove)
  5812. return;
  5813. //Need to work out the best order to generate the statements in. We want
  5814. //to move non thor queries to the front, so we do a insertion sort on them
  5815. CopyCIArrayOf<StatementInfo> sorted;
  5816. ForEachItemIn(idx1, stmts)
  5817. {
  5818. StatementInfo & cur = stmts.item(idx1);
  5819. bool curIsThor = cur.isThorQuery();
  5820. unsigned insertPos = sorted.ordinality();
  5821. ForEachItemInRev(idx2, sorted)
  5822. {
  5823. StatementInfo & compare = sorted.item(idx2);
  5824. if (compare.isThorQuery() == curIsThor)
  5825. {
  5826. insertPos = idx2+1;
  5827. break;
  5828. }
  5829. if (!compare.canSwapOrder(cur))
  5830. break;
  5831. }
  5832. sorted.add(cur, insertPos);
  5833. }
  5834. //Finally see if there is any merit in moving an initial block of thor queries down to
  5835. //merge with a subsequent one.
  5836. StatementInfo & first = sorted.item(0);
  5837. if (first.isThorQuery())
  5838. {
  5839. unsigned max = sorted.ordinality();
  5840. unsigned numToMove;
  5841. for (numToMove = 1; numToMove < max; numToMove++)
  5842. {
  5843. if (!(sorted.item(numToMove)).isThorQuery())
  5844. break;
  5845. }
  5846. for (unsigned i=numToMove; i < max; i++)
  5847. {
  5848. StatementInfo & compare = sorted.item(i);
  5849. if (compare.isThorQuery())
  5850. {
  5851. for (unsigned j=0; j < numToMove; j++)
  5852. sorted.rotateL(0, i-1);
  5853. break;
  5854. }
  5855. for (unsigned j=0; j < numToMove; j++)
  5856. {
  5857. if (!compare.canSwapOrder(sorted.item(j)))
  5858. {
  5859. i = max - 1;
  5860. break;
  5861. }
  5862. }
  5863. }
  5864. }
  5865. in.kill();
  5866. ForEachItemIn(idxSorted, sorted)
  5867. {
  5868. StatementInfo & cur = sorted.item(idxSorted);
  5869. in.append(*cur.expr.getLink());
  5870. }
  5871. }
  5872. //------------------------------------------------------------------------
  5873. //We will generate better code if conditional statements precede unconditional statements because globals can
  5874. //be commoned up better.
  5875. bool moveUnconditionalEarlier(HqlExprArray & in)
  5876. {
  5877. //Gather information about the statements...
  5878. unsigned numConditionals = 0;
  5879. unsigned firstConditional = NotFound;
  5880. bool couldImprove = false;
  5881. CIArrayOf<StatementInfo> stmts;
  5882. ForEachItemIn(idx, in)
  5883. {
  5884. StatementInfo & cur = *new StatementInfo(&in.item(idx));
  5885. stmts.append(cur);
  5886. if (cur.isConditional())
  5887. {
  5888. if (numConditionals == 0)
  5889. firstConditional = idx;
  5890. numConditionals++;
  5891. }
  5892. else if (numConditionals)
  5893. couldImprove = true;
  5894. }
  5895. //If no unconditionals follow a conditional, and no conditionals to be combined, then keep in the same order...
  5896. if (!couldImprove && numConditionals <= 1)
  5897. return false;
  5898. //For each block of unconditional statements which follow a conditional statement, see if they can be moved over the conditional statements.
  5899. //(copies with no overhead if couldImprove is false)
  5900. CopyCIArrayOf<StatementInfo> sorted;
  5901. unsigned max = stmts.ordinality();
  5902. for (unsigned idx1 = 0; idx1 < max;)
  5903. {
  5904. StatementInfo & cur = stmts.item(idx1);
  5905. bool isConditional = cur.isConditional();
  5906. unsigned cnt = 1;
  5907. if (isConditional || idx1 < firstConditional)
  5908. {
  5909. sorted.append(cur);
  5910. }
  5911. else
  5912. {
  5913. //calculate the number of contiguous unconditional statements
  5914. for (cnt=1; idx1+cnt < max; cnt++)
  5915. {
  5916. if (stmts.item(idx1+cnt).isConditional())
  5917. break;
  5918. }
  5919. unsigned movePosition = 0;
  5920. for (unsigned iBlock = 0; iBlock < cnt; iBlock++)
  5921. {
  5922. StatementInfo & curBlock = stmts.item(idx1+iBlock);
  5923. unsigned bestPosition = NotFound; // best position to add block.
  5924. unsigned prev = idx1;
  5925. while (prev-- > firstConditional)
  5926. {
  5927. StatementInfo & compare = sorted.item(prev);
  5928. if (!compare.canSwapOrder(curBlock))
  5929. break;
  5930. if (prev == firstConditional)
  5931. bestPosition = prev;
  5932. else if (compare.isConditional() && !sorted.item(prev-1).isConditional())
  5933. bestPosition = prev;
  5934. }
  5935. if (bestPosition == NotFound)
  5936. {
  5937. //can't move this element in the block => append the items to the list.
  5938. movePosition = sorted.ordinality();
  5939. break;
  5940. }
  5941. //Intersection of the best positions to provide earliest we can move the block
  5942. if (movePosition < bestPosition)
  5943. movePosition = bestPosition;
  5944. }
  5945. for (unsigned iBlock2 = 0; iBlock2 < cnt; iBlock2++)
  5946. sorted.add(stmts.item(idx1+iBlock2), movePosition+iBlock2);
  5947. }
  5948. idx1 += cnt;
  5949. }
  5950. //See if moving conditional statements could make some conditions next to each other
  5951. //Now see if any of the conditional statements can be combined.
  5952. //Finally replace the array
  5953. in.kill();
  5954. ForEachItemIn(idxSorted, sorted)
  5955. {
  5956. StatementInfo & cur = (StatementInfo &)sorted.item(idxSorted);
  5957. in.append(*cur.expr.getLink());
  5958. }
  5959. return true;
  5960. }
  5961. //------------------------------------------------------------------------
  5962. void mergeThorGraphs(HqlExprArray & exprs, bool resourceConditionalActions, bool resourceSequential);
  5963. IHqlExpression * mergeThorGraphs(IHqlExpression * expr, bool resourceConditionalActions, bool resourceSequential)
  5964. {
  5965. HqlExprArray args;
  5966. expr->unwindList(args, no_actionlist);
  5967. mergeThorGraphs(args, resourceConditionalActions, resourceSequential);
  5968. return createActionList(args);
  5969. }
  5970. void mergeThorGraphs(HqlExprArray & exprs, bool resourceConditionalActions, bool resourceSequential)
  5971. {
  5972. HqlExprArray thorActions;
  5973. HqlExprArray combined;
  5974. ForEachItemIn(idx, exprs)
  5975. {
  5976. IHqlExpression * original = &exprs.item(idx);
  5977. LinkedHqlExpr cur = original;
  5978. const node_operator op = cur->getOperator();
  5979. switch (op)
  5980. {
  5981. case no_compound:
  5982. {
  5983. OwnedHqlExpr replace = mergeThorGraphs(cur->queryChild(0), resourceConditionalActions, resourceSequential);
  5984. cur.setown(replaceChild(cur, 0, replace));
  5985. break;
  5986. }
  5987. case no_if:
  5988. if (cur->isAction())
  5989. {
  5990. IHqlExpression * left = cur->queryChild(1);
  5991. IHqlExpression * right = cur->queryChild(2);
  5992. OwnedHqlExpr newLeft = mergeThorGraphs(left, resourceConditionalActions, resourceSequential);
  5993. OwnedHqlExpr newRight = right ? mergeThorGraphs(right, resourceConditionalActions, resourceSequential) : NULL;
  5994. if (left != newLeft || right != newRight)
  5995. {
  5996. HqlExprArray args;
  5997. unwindChildren(args, cur);
  5998. //Not sure about this - the test condition may not be evaluatable inside thor
  5999. if (resourceConditionalActions && ((newLeft->getOperator() == no_thor) && (!newRight || newRight->getOperator() == no_thor)))
  6000. {
  6001. args.replace(*LINK(newLeft->queryChild(0)), 1);
  6002. if (newRight)
  6003. args.replace(*LINK(newRight->queryChild(0)), 2);
  6004. cur.setown(createValue(no_thor, makeVoidType(), cur->clone(args)));
  6005. }
  6006. else
  6007. {
  6008. args.replace(*LINK(newLeft), 1);
  6009. if (newRight)
  6010. args.replace(*LINK(newRight), 2);
  6011. cur.setown(cur->clone(args));
  6012. }
  6013. }
  6014. }
  6015. break;
  6016. case no_parallel:
  6017. if (false)
  6018. {
  6019. HqlExprArray args;
  6020. bool allThor = true;
  6021. ForEachChild(i, cur)
  6022. {
  6023. IHqlExpression * merged = mergeThorGraphs(cur->queryChild(i), resourceConditionalActions, resourceSequential);
  6024. args.append(*merged);
  6025. if (merged->getOperator() != no_thor)
  6026. allThor = false;
  6027. }
  6028. if (allThor)
  6029. {
  6030. ForEachItemIn(i, args)
  6031. args.replace(*LINK(args.item(i).queryChild(0)), i);
  6032. cur.setown(cur->clone(args));
  6033. cur.setown(createValue(no_thor, makeVoidType(), cur.getClear()));
  6034. }
  6035. else
  6036. cur.setown(cur->clone(args));
  6037. break;
  6038. }
  6039. //fall through
  6040. case no_actionlist:
  6041. {
  6042. HqlExprArray args;
  6043. cur->unwindList(args, op);
  6044. mergeThorGraphs(args, resourceConditionalActions, resourceSequential);
  6045. cur.setown(cur->clone(args));
  6046. break;
  6047. }
  6048. case no_sequential:
  6049. {
  6050. HqlExprArray args;
  6051. bool allThor = true;
  6052. ForEachChild(i, cur)
  6053. {
  6054. IHqlExpression * merged = mergeThorGraphs(cur->queryChild(i), resourceConditionalActions, resourceSequential);
  6055. args.append(*merged);
  6056. if (merged->getOperator() != no_thor)
  6057. allThor = false;
  6058. }
  6059. if (resourceSequential && allThor)
  6060. {
  6061. ForEachItemIn(i, args)
  6062. args.replace(*LINK(args.item(i).queryChild(0)), i);
  6063. cur.setown(cur->clone(args));
  6064. cur.setown(createValue(no_thor, makeVoidType(), cur.getClear()));
  6065. }
  6066. else
  6067. cur.setown(cur->clone(args));
  6068. break;
  6069. }
  6070. case no_ensureresult:
  6071. {
  6072. HqlExprArray args;
  6073. unwindChildren(args, cur);
  6074. args.replace(*mergeThorGraphs(cur->queryChild(0), resourceConditionalActions, resourceSequential), 0);
  6075. cur.setown(cloneOrLink(cur, args));
  6076. break;
  6077. }
  6078. }
  6079. if (cur->getOperator() == no_thor)
  6080. {
  6081. thorActions.append(*LINK(cur->queryChild(0)));
  6082. }
  6083. else
  6084. {
  6085. if (thorActions.ordinality())
  6086. {
  6087. combined.append(*createValue(no_thor, makeVoidType(), createActionList(thorActions)));
  6088. thorActions.kill();
  6089. }
  6090. combined.append(*cur.getClear());
  6091. }
  6092. }
  6093. if (thorActions.ordinality())
  6094. combined.append(*createValue(no_thor, makeVoidType(), createActionList(thorActions)));
  6095. replaceArray(exprs, combined);
  6096. }
  6097. void mergeThorGraphs(WorkflowArray & array, bool resourceConditionalActions, bool resourceSequential)
  6098. {
  6099. ForEachItemIn(idx4, array)
  6100. groupThorGraphs(array.item(idx4).queryExprs());
  6101. ForEachItemIn(idx2, array)
  6102. mergeThorGraphs(array.item(idx2).queryExprs(), resourceConditionalActions, resourceSequential);
  6103. }
  6104. //------------------------------------------------------------------------
  6105. //#define NEW_SCALAR_CODE
  6106. //I think NEW_SCALAR_CODE should be better - but in practice it seems to be worse.....
  6107. inline bool isTypeToHoist(ITypeInfo * type)
  6108. {
  6109. return isSingleValuedType(type);// || (type && type->getTypeCode() == type_set);
  6110. }
  6111. static HqlTransformerInfo scalarGlobalTransformerInfo("ScalarGlobalTransformer");
  6112. ScalarGlobalTransformer::ScalarGlobalTransformer(HqlCppTranslator & _translator)
  6113. : HoistingHqlTransformer(scalarGlobalTransformerInfo, CTFtraverseallnodes), translator(_translator)
  6114. {
  6115. okToHoist = true;
  6116. neverHoist = false;
  6117. }
  6118. void ScalarGlobalTransformer::analyseExpr(IHqlExpression * expr)
  6119. {
  6120. ScalarGlobalExtra * extra = queryBodyExtra(expr);
  6121. analyseThis(expr);
  6122. #ifdef NEW_SCALAR_CODE
  6123. if (++extra->numUses > 1)
  6124. {
  6125. if (!extra->candidate)
  6126. return;
  6127. if (extra->couldHoist || extra->alreadyGlobal)
  6128. return;
  6129. }
  6130. extra->candidate = !containsAnyDataset(expr) && !expr->isConstant() && !isContextDependent(expr);
  6131. extra->couldHoist = extra->candidate && isTypeToHoist(expr->queryType()) && canCreateTemporary(expr) && expr->isPure();
  6132. #else
  6133. if (++extra->numUses > 1)
  6134. {
  6135. if (!okToHoist)
  6136. {
  6137. if (!neverHoist || extra->neverHoist)
  6138. return;
  6139. }
  6140. if (extra->couldHoist)
  6141. {
  6142. if (extra->createGlobal)
  6143. return;
  6144. //Allow a global to be created inside a global marked from somewhere else.
  6145. if (containsAnyDataset(expr) || expr->isConstant() || isContextDependent(expr))
  6146. return;
  6147. }
  6148. }
  6149. extra->couldHoist = okToHoist;
  6150. if (!okToHoist && !neverHoist && !isTypeToHoist(expr->queryType()))
  6151. okToHoist = true;
  6152. #endif
  6153. extra->neverHoist = neverHoist;
  6154. doAnalyseExpr(expr);
  6155. okToHoist = extra->couldHoist;
  6156. neverHoist = extra->neverHoist;
  6157. }
  6158. void ScalarGlobalTransformer::doAnalyseExpr(IHqlExpression * expr)
  6159. {
  6160. switch (expr->getOperator())
  6161. {
  6162. case no_attr:
  6163. case no_constant:
  6164. case no_attr_link:
  6165. case no_null:
  6166. case no_all:
  6167. return;
  6168. case no_persist_check:
  6169. //No point spotting global within this since it will not create a subquery..
  6170. return;
  6171. case no_attr_expr:
  6172. {
  6173. _ATOM name = expr->queryName();
  6174. if ((name == _selectors_Atom) || (name == keyedAtom))
  6175. return;
  6176. analyseChildren(expr);
  6177. return;
  6178. }
  6179. case no_getresult:
  6180. case no_libraryinput:
  6181. queryBodyExtra(expr)->alreadyGlobal = true;
  6182. break;
  6183. case no_globalscope:
  6184. case no_setresult:
  6185. case no_ensureresult:
  6186. {
  6187. queryBodyExtra(expr)->alreadyGlobal = true; // don't tag again - even if opt flag is present
  6188. queryBodyExtra(expr->queryChild(0))->alreadyGlobal = true;
  6189. okToHoist = false;
  6190. break;
  6191. }
  6192. }
  6193. #ifndef NEW_SCALAR_CODE
  6194. // Commented line has problems with SELF used in HOLE definition, and explosion in thumphrey7 etc.
  6195. // if (okToHoist && isIndependentOfScope(expr) && !expr->isConstant() && !isContextDependent(expr) && expr->isPure())
  6196. if (okToHoist && !containsAnyDataset(expr) && !expr->isConstant() && !isContextDependent(expr) && expr->isPure())
  6197. {
  6198. ITypeInfo * type = expr->queryType();
  6199. if (isTypeToHoist(type))
  6200. {
  6201. if (canCreateTemporary(expr))
  6202. {
  6203. queryBodyExtra(expr)->createGlobal = true;
  6204. okToHoist = false;
  6205. }
  6206. }
  6207. }
  6208. #endif
  6209. HoistingHqlTransformer::doAnalyseExpr(expr);
  6210. }
  6211. /*
  6212. Try and decide what is trivial enough to serialise, and what should remain. It is more trial an error than particularly logical
  6213. o Better to store smaller objects because they will serialize smaller.
  6214. o If something is used more than once then probably worth serializing regardless - since calculation will be commoned up.
  6215. 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.
  6216. */
  6217. bool ScalarGlobalTransformer::isComplex(IHqlExpression * expr, bool checkGlobal)
  6218. {
  6219. ScalarGlobalExtra * extra = queryBodyExtra(expr);
  6220. if (checkGlobal)
  6221. {
  6222. //If something else has turned this into a global then no point.
  6223. if (extra->alreadyGlobal)
  6224. return false;
  6225. }
  6226. switch (expr->getOperator())
  6227. {
  6228. case no_constant:
  6229. case no_getresult:
  6230. case no_globalscope:
  6231. case no_workunit_dataset:
  6232. case no_libraryinput:
  6233. return false;
  6234. case no_cast:
  6235. case no_implicitcast:
  6236. //serialize if the cast reduces the size of the item, otherwise check argument.
  6237. if (expr->queryType()->getSize() <= expr->queryChild(0)->queryType()->getSize())
  6238. return true;
  6239. //If used a lot then save lots of duplicated work.
  6240. if (extra->numUses > 2)
  6241. return true;
  6242. break;
  6243. case no_eq:
  6244. case no_ne:
  6245. case no_lt:
  6246. case no_gt:
  6247. case no_le:
  6248. case no_ge:
  6249. //Accessed more than once-> probably worth commoning up
  6250. if (extra->numUses > 1)
  6251. return true;
  6252. break;
  6253. //f[1..length(trim(x))] = x is very common, and if the length(trim)) was serialized separately then
  6254. //the generated code would be worse.
  6255. case no_trim:
  6256. case no_charlen:
  6257. case no_sorted:
  6258. break;
  6259. case no_substring:
  6260. //single character substring - don't create separate items just for this, since likely to have many of them.
  6261. if (!expr->queryChild(1)->queryValue())
  6262. return true;
  6263. break;
  6264. default:
  6265. if (expr->isConstant())
  6266. return false;
  6267. return true;
  6268. }
  6269. ForEachChild(i, expr)
  6270. {
  6271. if (isComplex(expr->queryChild(i), true))
  6272. return true;
  6273. }
  6274. return false;
  6275. }
  6276. IHqlExpression * ScalarGlobalTransformer::createTransformed(IHqlExpression * expr)
  6277. {
  6278. IHqlExpression * ret = queryTransformAnnotation(expr);
  6279. if (ret)
  6280. return ret;
  6281. OwnedHqlExpr transformed = HoistingHqlTransformer::createTransformed(expr);
  6282. ScalarGlobalExtra * extra = queryBodyExtra(expr);
  6283. #ifdef NEW_SCALAR_CODE
  6284. if (extra->numUses > 1 && extra->couldHoist && !extra->alreadyGlobal && isComplex(expr, false))
  6285. #else
  6286. if (extra->createGlobal && !extra->alreadyGlobal && isComplex(expr, false))
  6287. #endif
  6288. {
  6289. #ifdef _DEBUG
  6290. translator.traceExpression("Mark as global", expr);
  6291. #endif
  6292. //mark as global, so isComplex() can take it into account.
  6293. extra->alreadyGlobal = true;
  6294. if (expr->getOperator() == no_createset)
  6295. transformed.setown(projectCreateSetDataset(transformed));
  6296. return createValue(no_globalscope, transformed->getType(), LINK(transformed));
  6297. }
  6298. return transformed.getClear();
  6299. }
  6300. //------------------------------------------------------------------------
  6301. static HqlTransformerInfo explicitGlobalTransformerInfo("ExplicitGlobalTransformer");
  6302. ExplicitGlobalTransformer::ExplicitGlobalTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  6303. : HoistingHqlTransformer(explicitGlobalTransformerInfo, CTFnoteifactions|CTFtraverseallnodes), translator(_translator)
  6304. {
  6305. wu = _wu;
  6306. isRoxie = (translator.getTargetClusterType() == RoxieCluster);
  6307. seenGlobalScope = false;
  6308. seenLocalGlobalScope = false;
  6309. }
  6310. void ExplicitGlobalTransformer::doAnalyseExpr(IHqlExpression * expr)
  6311. {
  6312. node_operator op = expr->getOperator();
  6313. switch (op)
  6314. {
  6315. case no_output:
  6316. if (!isIndependentOfScope(expr))
  6317. {
  6318. IHqlExpression * filename = queryRealChild(expr, 2);
  6319. if (!filename)
  6320. filename = expr->queryProperty(namedAtom);
  6321. StringBuffer s;
  6322. if (filename)
  6323. getExprECL(filename, s);
  6324. translator.WARNINGAT1(queryActiveLocation(expr), HQLWRN_OutputDependendOnScope, s.str());
  6325. #if 0
  6326. HqlExprCopyArray scopeUsed;
  6327. expr->gatherTablesUsed(NULL, &scopeUsed);
  6328. ForEachItemIn(i, scopeUsed)
  6329. dbglogExpr(&scopeUsed.item(i));
  6330. #endif
  6331. }
  6332. break;
  6333. case no_nothor:
  6334. if (expr->isAction())
  6335. break;
  6336. //fall through
  6337. case no_globalscope:
  6338. //Try and avoid transforms (especially nested ones) as much as possible.
  6339. seenGlobalScope = true;
  6340. //If local attribute is present on a global, then an independent transform may cause an extra
  6341. //transformation because it may become unconditional, when previously conditional
  6342. if (expr->hasProperty(localAtom))
  6343. seenLocalGlobalScope = true;
  6344. break;
  6345. }
  6346. HoistingHqlTransformer::doAnalyseExpr(expr);
  6347. }
  6348. IHqlExpression * ExplicitGlobalTransformer::createTransformed(IHqlExpression * expr)
  6349. {
  6350. if (expr->isConstant())
  6351. return LINK(expr);
  6352. IHqlExpression * ret = queryTransformAnnotation(expr);
  6353. if (ret)
  6354. return ret;
  6355. OwnedHqlExpr transformed = HoistingHqlTransformer::createTransformed(expr);
  6356. node_operator op = expr->getOperator();
  6357. switch (op)
  6358. {
  6359. case no_nothor:
  6360. if (transformed->isAction())
  6361. break;
  6362. //fall through
  6363. case no_globalscope:
  6364. {
  6365. if (!expr->hasProperty(localAtom) || isUsedUnconditionally(expr))
  6366. {
  6367. IHqlExpression * value = transformed->queryChild(0);
  6368. if (!isIndependentOfScope(value))
  6369. {
  6370. if (expr->hasProperty(optAtom))
  6371. return LINK(transformed->queryChild(0));
  6372. IHqlExpression * symbol = queryActiveSymbol();
  6373. StringBuffer s;
  6374. if (symbol && symbol->queryBody() == expr)
  6375. s.appendf(" '%s'", symbol->queryName()->str());
  6376. else
  6377. {
  6378. s.append(" ").append(getOpString(value->getOperator()));
  6379. if (symbol)
  6380. s.append(" in ").append(symbol->queryName());
  6381. }
  6382. translator.reportWarning(queryActiveLocation(expr), ECODETEXT(HQLWRN_GlobalDoesntSeemToBe), s.str());
  6383. }
  6384. if (value->getOperator() == no_createset)
  6385. {
  6386. OwnedHqlExpr createset = projectCreateSetDataset(value);
  6387. IHqlExpression * ds = createset->queryChild(0);
  6388. HqlExprArray outArgs, setArgs;
  6389. outArgs.append(*LINK(ds));
  6390. outArgs.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  6391. outArgs.append(*createAttribute(namedAtom, createNextStringValue(value)));
  6392. IHqlExpression * setResult = createValue(no_output, makeVoidType(), outArgs);
  6393. appendToTarget(*setResult);
  6394. transformed.setown(createGetResultFromSetResult(setResult, expr->queryType()));
  6395. }
  6396. else
  6397. {
  6398. GlobalAttributeInfo info("spill::global","gl");
  6399. info.extractGlobal(transformed, isRoxie || (op == no_nothor));
  6400. OwnedHqlExpr getResult, setResult;
  6401. info.checkFew(translator, transformed);
  6402. info.splitGlobalDefinition(transformed->queryType(), value, wu, setResult, &getResult, isRoxie);
  6403. if (op == no_nothor)
  6404. setResult.setown(createValue(no_nothor, makeVoidType(), LINK(setResult)));
  6405. IHqlExpression * cluster = queryRealChild(transformed, 1);
  6406. if (cluster && !isBlankString(cluster))
  6407. setResult.setown(createValue(no_cluster, makeVoidType(), LINK(setResult), LINK(cluster)));
  6408. appendToTarget(*setResult.getClear());
  6409. transformed.setown(getResult.getClear());
  6410. }
  6411. break;
  6412. }
  6413. }
  6414. }
  6415. return transformed.getClear();
  6416. }
  6417. //------------------------------------------------------------------------
  6418. IHqlDataset * queryRootDataset(IHqlExpression * dataset)
  6419. {
  6420. return dataset->queryDataset()->queryRootTable();
  6421. }
  6422. //roxie only executes outputs to temporaries if they are required, or if not all references are from within the graph
  6423. //therefore, there is no need to special case if actions. Thor on the other hand will cause it to be executed unnecessarily.
  6424. static HqlTransformerInfo newScopeMigrateTransformerInfo("NewScopeMigrateTransformer");
  6425. NewScopeMigrateTransformer::NewScopeMigrateTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  6426. : HoistingHqlTransformer(newScopeMigrateTransformerInfo, 0), translator(_translator)
  6427. {
  6428. wu = _wu;
  6429. isRoxie = translator.targetRoxie();
  6430. if (!isRoxie && !_translator.queryOptions().resourceConditionalActions)
  6431. setFlags(CTFnoteifactions);
  6432. minimizeWorkunitTemporaries = translator.queryOptions().minimizeWorkunitTemporaries;
  6433. #ifdef REMOVE_GLOBAL_ANNOTATION
  6434. activityDepth = 0; // should be 0 to actually have any effect - but causes problems...
  6435. #else
  6436. activityDepth = 999; // should be 0 to actually have any effect - but causes problems...
  6437. #endif
  6438. }
  6439. void NewScopeMigrateTransformer::analyseExpr(IHqlExpression * expr)
  6440. {
  6441. ScopeMigrateInfo * extra = queryBodyExtra(expr);
  6442. if (activityDepth > extra->maxActivityDepth)
  6443. {
  6444. if (extra->maxActivityDepth == 0)
  6445. extra->setUnvisited(); // so we walk children again
  6446. extra->maxActivityDepth = activityDepth;
  6447. }
  6448. unsigned savedActivityDepth = activityDepth;
  6449. node_operator op = expr->getOperator();
  6450. switch (op)
  6451. {
  6452. case NO_AGGREGATE:
  6453. case no_createset:
  6454. case NO_ACTION_REQUIRES_GRAPH:
  6455. case no_extractresult:
  6456. case no_distributer:
  6457. case no_within:
  6458. case no_notwithin:
  6459. case no_soapaction_ds:
  6460. case no_returnresult:
  6461. activityDepth++;
  6462. break;
  6463. case no_setresult:
  6464. if (expr->queryChild(0)->isDataset())
  6465. activityDepth++;
  6466. break;
  6467. case no_select:
  6468. if (expr->hasProperty(newAtom))
  6469. activityDepth++;
  6470. break;
  6471. }
  6472. HoistingHqlTransformer::analyseExpr(expr);
  6473. activityDepth = savedActivityDepth;
  6474. }
  6475. IHqlExpression * NewScopeMigrateTransformer::hoist(IHqlExpression * expr, IHqlExpression * hoisted)
  6476. {
  6477. if (minimizeWorkunitTemporaries)
  6478. return createWrapper(no_globalscope, LINK(hoisted));
  6479. IHqlExpression * setResult = createSetResult(hoisted);
  6480. IHqlExpression * seqAttr = setResult->queryProperty(sequenceAtom);
  6481. IHqlExpression * aliasAttr = setResult->queryProperty(namedAtom);
  6482. appendToTarget(*setResult);
  6483. return createGetResultFromSetResult(setResult);
  6484. }
  6485. IHqlExpression * NewScopeMigrateTransformer::createTransformed(IHqlExpression * expr)
  6486. {
  6487. if (expr->isConstant())
  6488. return LINK(expr);
  6489. IHqlExpression * ret = queryTransformAnnotation(expr);
  6490. if (ret)
  6491. return ret;
  6492. OwnedHqlExpr transformed = HoistingHqlTransformer::createTransformed(expr);
  6493. ScopeMigrateInfo * extra = queryBodyExtra(expr);
  6494. node_operator op = expr->getOperator();
  6495. switch (op)
  6496. {
  6497. case no_createset:
  6498. {
  6499. if (isUsedUnconditionally(expr))
  6500. {
  6501. if (isIndependentOfScope(transformed) && !isContextDependent(expr))
  6502. {
  6503. OwnedHqlExpr createset = projectCreateSetDataset(transformed);
  6504. if (minimizeWorkunitTemporaries)
  6505. return createWrapper(no_globalscope, LINK(createset));
  6506. //MORE: This is only temporary until child datasets come into existence, then it will need improving
  6507. //Save it as a temporary dataset in the wu, and retrieve it as a getresult(set)
  6508. IHqlExpression * ds = createset->queryChild(0);
  6509. HqlExprArray outArgs, setArgs;
  6510. outArgs.append(*LINK(ds));
  6511. outArgs.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  6512. outArgs.append(*createAttribute(namedAtom, createNextStringValue(expr)));
  6513. IHqlExpression * setResult = createValue(no_output, makeVoidType(), outArgs);
  6514. appendToTarget(*setResult);
  6515. transformed.setown(createGetResultFromSetResult(setResult, expr->queryType()));
  6516. }
  6517. }
  6518. break;
  6519. }
  6520. case no_select:
  6521. {
  6522. IHqlExpression * newAttr = transformed->queryProperty(newAtom);
  6523. if (newAttr)
  6524. {
  6525. if (isUsedUnconditionally(expr))
  6526. {
  6527. if (extra->maxActivityDepth != 0)
  6528. {
  6529. IHqlExpression * row = transformed->queryChild(0);
  6530. node_operator rowOp = row->getOperator();
  6531. if (rowOp == no_selectnth)
  6532. {
  6533. node_operator dsOp = row->queryChild(0)->getOperator();
  6534. if ((dsOp == no_workunit_dataset) || (dsOp == no_inlinetable))
  6535. break;
  6536. }
  6537. if (rowOp == no_createrow)
  6538. break;
  6539. if (!isInlineTrivialDataset(row) && !isContextDependent(row) && !transformed->isDataset())
  6540. {
  6541. if (isIndependentOfScope(row))
  6542. return hoist(expr, transformed);
  6543. }
  6544. }
  6545. }
  6546. }
  6547. }
  6548. break;
  6549. case NO_AGGREGATE:
  6550. {
  6551. if (isUsedUnconditionally(expr))
  6552. {
  6553. if (extra->maxActivityDepth != 0)
  6554. {
  6555. IHqlExpression * datasetExpr = transformed->queryChild(0);
  6556. IHqlDataset * rootDataset = queryRootDataset(datasetExpr);
  6557. if (!rootDataset)
  6558. {
  6559. //Something like a+b+c
  6560. rootDataset = datasetExpr->queryDataset()->queryTable();
  6561. if (!rootDataset)
  6562. break;
  6563. }
  6564. //Don't do anything with child datasets....
  6565. IHqlExpression * rootDatasetExpr = queryExpression(rootDataset);
  6566. node_operator rootOp = rootDatasetExpr->getOperator();
  6567. if ((rootOp == no_select) || (rootOp == no_field))
  6568. break;
  6569. if (isIndependentOfScope(datasetExpr) && !isContextDependent(expr))
  6570. {
  6571. return hoist(expr, transformed);
  6572. }
  6573. }
  6574. }
  6575. break;
  6576. }
  6577. }
  6578. return transformed.getClear();
  6579. }
  6580. void migrateExprToNaturalLevel(WorkflowArray & array, IWorkUnit * wu, HqlCppTranslator & translator)
  6581. {
  6582. const HqlCppOptions & options = translator.queryOptions();
  6583. ForEachItemIn(idx, array)
  6584. {
  6585. WorkflowItem & cur = array.item(idx);
  6586. HqlExprArray & exprs = cur.queryExprs();
  6587. if (translator.queryOptions().moveUnconditionalActions)
  6588. moveUnconditionalEarlier(exprs);
  6589. translator.checkNormalized(exprs);
  6590. if (options.hoistSimpleGlobal)
  6591. {
  6592. ScalarGlobalTransformer transformer(translator);
  6593. HqlExprArray results;
  6594. transformer.analyseArray(exprs, 0);
  6595. transformer.transformRoot(exprs, results);
  6596. replaceArray(exprs, results);
  6597. translator.checkNormalized(exprs);
  6598. }
  6599. translator.traceExpressions("m0", exprs);
  6600. if (options.workunitTemporaries)
  6601. {
  6602. ExplicitGlobalTransformer transformer(wu, translator);
  6603. transformer.analyseArray(exprs, 0);
  6604. if (transformer.needToTransform())
  6605. {
  6606. HqlExprArray results;
  6607. transformer.transformRoot(exprs, results);
  6608. replaceArray(exprs, results);
  6609. }
  6610. translator.checkNormalized(exprs);
  6611. }
  6612. translator.traceExpressions("m1", exprs);
  6613. if (options.allowScopeMigrate) // && !options.minimizeWorkunitTemporaries)
  6614. {
  6615. NewScopeMigrateTransformer transformer(wu, translator);
  6616. HqlExprArray results;
  6617. transformer.analyseArray(exprs, 0);
  6618. transformer.transformRoot(exprs, results);
  6619. replaceArray(exprs, results);
  6620. translator.checkNormalized(exprs);
  6621. }
  6622. translator.traceExpressions("m2", exprs);
  6623. }
  6624. }
  6625. void expandGlobalDatasets(WorkflowArray & array, IWorkUnit * wu, HqlCppTranslator & translator)
  6626. {
  6627. }
  6628. //---------------------------------------------------------------------------
  6629. bool AutoScopeMigrateInfo::addGraph(unsigned graph)
  6630. {
  6631. if (graph == lastGraph)
  6632. return false;
  6633. if (lastGraph)
  6634. manyGraphs = true;
  6635. lastGraph = graph;
  6636. return true;
  6637. }
  6638. bool AutoScopeMigrateInfo::doAutoHoist(IHqlExpression * transformed, bool minimizeWorkunitTemporaries)
  6639. {
  6640. if (useCount == 0)
  6641. return false;
  6642. node_operator op = original->getOperator();
  6643. switch (op)
  6644. {
  6645. case no_fail:
  6646. return false;
  6647. }
  6648. if (firstUseIsConditional && firstUseIsSequential)
  6649. return false;
  6650. if (firstUseIsSequential && !manyGraphs)
  6651. return false;
  6652. // The following *should* generate better code, but there are currently a couple of exceptions (cmaroney29, jholt20) which need investigation
  6653. // if (!manyGraphs)
  6654. // return false;
  6655. if (globalInsideChild && !minimizeWorkunitTemporaries)// && !transformed->isDataset() && !transformed->isDatarow())
  6656. return true;
  6657. if (!manyGraphs)
  6658. return false;
  6659. if (!original->isDataset())
  6660. {
  6661. switch (op)
  6662. {
  6663. case NO_AGGREGATE:
  6664. break;
  6665. default:
  6666. return false;
  6667. }
  6668. }
  6669. if (!isWorthHoisting(transformed, false))
  6670. return false;
  6671. if (isContextDependent(transformed))
  6672. return false;
  6673. return isIndependentOfScope(original);
  6674. }
  6675. static HqlTransformerInfo autoScopeMigrateTransformerInfo("AutoScopeMigrateTransformer");
  6676. AutoScopeMigrateTransformer::AutoScopeMigrateTransformer(IWorkUnit * _wu, HqlCppTranslator & _translator)
  6677. : NewHqlTransformer(autoScopeMigrateTransformerInfo), translator(_translator)
  6678. {
  6679. wu = _wu;
  6680. isRoxie = (translator.getTargetClusterType() == RoxieCluster);
  6681. isConditional = false;
  6682. isSequential = false;
  6683. hasCandidate = false;
  6684. activityDepth = 0;
  6685. curGraph = 1;
  6686. }
  6687. void AutoScopeMigrateTransformer::analyseExpr(IHqlExpression * expr)
  6688. {
  6689. AutoScopeMigrateInfo * extra = queryBodyExtra(expr);
  6690. if (isConditional)
  6691. extra->condUseCount++;
  6692. else
  6693. extra->useCount++;
  6694. bool newGraph = extra->addGraph(curGraph);
  6695. if (!newGraph)
  6696. return;
  6697. if (extra->doAutoHoist(expr, translator.queryOptions().minimizeWorkunitTemporaries))
  6698. {
  6699. hasCandidate = true;
  6700. return;
  6701. }
  6702. unsigned savedDepth = activityDepth;
  6703. doAnalyseExpr(expr);
  6704. activityDepth = savedDepth;
  6705. }
  6706. void AutoScopeMigrateTransformer::doAnalyseExpr(IHqlExpression * expr)
  6707. {
  6708. AutoScopeMigrateInfo * extra = queryBodyExtra(expr);
  6709. if (activityDepth && expr->isDataset())
  6710. {
  6711. if (isWorthHoisting(expr, true) && isIndependentOfScope(expr) && !isContextDependent(expr))
  6712. {
  6713. #ifdef _DEBUG
  6714. isWorthHoisting(expr, true);
  6715. #endif
  6716. extra->globalInsideChild = true;
  6717. hasCandidate = true;
  6718. activityDepth = 0;
  6719. }
  6720. }
  6721. extra->firstUseIsConditional = isConditional;
  6722. extra->firstUseIsSequential = isSequential;
  6723. switch (expr->getOperator())
  6724. {
  6725. case no_allnodes:
  6726. case no_keyedlimit:
  6727. case no_nothor:
  6728. return;
  6729. case no_sequential:
  6730. return;
  6731. case no_if:
  6732. {
  6733. if (expr->isAction())
  6734. {
  6735. bool wasConditional = isConditional;
  6736. analyseExpr(expr->queryChild(0));
  6737. isConditional = true;
  6738. analyseExpr(expr->queryChild(1));
  6739. if (expr->queryChild(2))
  6740. analyseExpr(expr->queryChild(2));
  6741. isConditional = wasConditional;
  6742. return;
  6743. }
  6744. break;
  6745. }
  6746. case no_newtransform:
  6747. case no_transform:
  6748. if (curGraph)
  6749. {
  6750. activityDepth++;
  6751. NewHqlTransformer::analyseExpr(expr);
  6752. activityDepth--;
  6753. return;
  6754. }
  6755. break;
  6756. case no_thor:
  6757. //ignore thor attribute on a dataset..
  6758. if (expr->queryType())
  6759. {
  6760. curGraph++;
  6761. NewHqlTransformer::analyseExpr(expr);
  6762. curGraph++; // don't restore - new pseudo graph to aid cse between global branches separated by graphs
  6763. return;
  6764. }
  6765. break;
  6766. }
  6767. NewHqlTransformer::analyseExpr(expr);
  6768. }
  6769. IHqlExpression * AutoScopeMigrateTransformer::createTransformed(IHqlExpression * expr)
  6770. {
  6771. switch (expr->getOperator())
  6772. {
  6773. case no_allnodes:
  6774. case no_keyedlimit:
  6775. case no_libraryscope:
  6776. case no_nothor:
  6777. case no_sequential:
  6778. return LINK(expr);
  6779. case no_thor:
  6780. {
  6781. IHqlExpression * actions = expr->queryChild(0);
  6782. if (actions)
  6783. {
  6784. //MORE: Simplify this???? or remove the special case all together?
  6785. //OwnedHqlExpr newActions = transform(actions);
  6786. HqlExprArray args;
  6787. unwindCommaCompound(args, actions);
  6788. ForEachItemIn(i, args)
  6789. graphActions.append(*transform(&args.item(i)));
  6790. OwnedHqlExpr newActions = createActionList(graphActions);
  6791. graphActions.kill();
  6792. if (actions == newActions)
  6793. return LINK(expr);
  6794. return createWrapper(no_thor, newActions.getClear());
  6795. }
  6796. break;
  6797. }
  6798. }
  6799. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  6800. updateOrphanedSelectors(transformed, expr);
  6801. AutoScopeMigrateInfo * extra = queryBodyExtra(expr);
  6802. if (extra->doAutoHoist(transformed, translator.queryOptions().minimizeWorkunitTemporaries))
  6803. {
  6804. StringBuffer s;
  6805. s.appendf("AutoGlobal: Spotted %s ", getOpString(expr->getOperator()));
  6806. if (expr->queryName())
  6807. s.append("[").append(expr->queryName()).append("] ");
  6808. s.append("as an item to hoist");
  6809. DBGLOG("%s", s.str());
  6810. GlobalAttributeInfo info("spill::auto","auto");
  6811. info.extractGlobal(transformed, isRoxie);
  6812. if (translator.targetThor() && extra->globalInsideChild)
  6813. info.preventDiskSpill();
  6814. OwnedHqlExpr getResult, setResult;
  6815. info.checkFew(translator, transformed);
  6816. info.splitGlobalDefinition(transformed->queryType(), transformed, wu, setResult, &getResult, isRoxie);
  6817. //If the first use is conditional, then hoist the expression globally (it can't have any dependents)
  6818. //else hoist it within the current graph, otherwise it can get hoisted before globals on datasets that
  6819. //it is dependent on.
  6820. if (extra->firstUseIsConditional)
  6821. globalTarget->append(*createWrapper(no_thor, setResult.getClear()));
  6822. else
  6823. graphActions.append(*setResult.getClear());
  6824. transformed.setown(getResult.getClear());
  6825. }
  6826. return transformed.getClear();
  6827. }
  6828. void AutoScopeMigrateTransformer::transformRoot(const HqlExprArray & in, HqlExprArray & out)
  6829. {
  6830. globalTarget = &out;
  6831. NewHqlTransformer::transformRoot(in, out);
  6832. globalTarget = NULL;
  6833. }
  6834. //---------------------------------------------------------------------------
  6835. static HqlTransformerInfo trivialGraphRemoverInfo("TrivialGraphRemover");
  6836. TrivialGraphRemover::TrivialGraphRemover() : NewHqlTransformer(trivialGraphRemoverInfo)
  6837. {
  6838. hasCandidate = false;
  6839. }
  6840. void TrivialGraphRemover::analyseExpr(IHqlExpression * expr)
  6841. {
  6842. if (hasCandidate || alreadyVisited(expr))
  6843. return;
  6844. if (expr->getOperator() == no_thor)
  6845. {
  6846. if (isTrivialGraph(expr->queryChild(0)))
  6847. hasCandidate = true;
  6848. return;
  6849. }
  6850. NewHqlTransformer::analyseExpr(expr);
  6851. }
  6852. IHqlExpression * TrivialGraphRemover::createTransformed(IHqlExpression * expr)
  6853. {
  6854. switch (expr->getOperator())
  6855. {
  6856. case no_thor:
  6857. {
  6858. IHqlExpression * child = expr->queryChild(0);
  6859. if (child && isTrivialGraph(child))
  6860. return LINK(child);
  6861. return LINK(expr);
  6862. }
  6863. }
  6864. return NewHqlTransformer::createTransformed(expr);
  6865. }
  6866. bool TrivialGraphRemover::isTrivialGraph(IHqlExpression * expr)
  6867. {
  6868. if (!expr)
  6869. return false;
  6870. if (expr->getOperator() == no_setresult)
  6871. {
  6872. IHqlExpression * value = expr->queryChild(0);
  6873. if (value->getOperator() != no_getresult)
  6874. return false;
  6875. return true;
  6876. }
  6877. else if (expr->getOperator() == no_output)
  6878. return isTrivialInlineOutput(expr);
  6879. else
  6880. return false;
  6881. }
  6882. void removeTrivialGraphs(WorkflowArray & workflow)
  6883. {
  6884. ForEachItemIn(idx, workflow)
  6885. {
  6886. WorkflowItem & cur = workflow.item(idx);
  6887. HqlExprArray & exprs = cur.queryExprs();
  6888. TrivialGraphRemover transformer;
  6889. transformer.analyseArray(exprs, 0);
  6890. if (transformer.worthTransforming())
  6891. {
  6892. HqlExprArray simplified;
  6893. transformer.transformRoot(exprs, simplified);
  6894. replaceArray(exprs, simplified);
  6895. }
  6896. }
  6897. }
  6898. //==============================================================================================================
  6899. class FilterCloner
  6900. {
  6901. public:
  6902. FilterCloner(IHqlExpression * _ds) { ds.set(_ds); matched = false; lockTransformMutex(); }
  6903. ~FilterCloner() { unlockTransformMutex(); }
  6904. void addMappings(IHqlExpression * expr, IHqlExpression * addDs);
  6905. IHqlExpression * inheritFilters(IHqlExpression * expr);
  6906. inline bool hasMappings() { return matched; }
  6907. protected:
  6908. void doAddMappings(IHqlExpression * expr);
  6909. bool isMatchingSelector(IHqlExpression * expr);
  6910. void setMapping(IHqlExpression * selector, IHqlExpression * value);
  6911. protected:
  6912. HqlExprAttr ds;
  6913. bool matched;
  6914. };
  6915. void FilterCloner::setMapping(IHqlExpression * selector, IHqlExpression * value)
  6916. {
  6917. selector->setTransformExtra(value);
  6918. matched = true;
  6919. }
  6920. void FilterCloner::doAddMappings(IHqlExpression * expr)
  6921. {
  6922. loop
  6923. {
  6924. switch (expr->getOperator())
  6925. {
  6926. case no_and:
  6927. doAddMappings(expr->queryChild(0));
  6928. expr = expr->queryChild(1);
  6929. continue;
  6930. case no_in:
  6931. case no_notin:
  6932. {
  6933. IHqlExpression * lhs = expr->queryChild(0);
  6934. IHqlExpression * rhs = expr->queryChild(1);
  6935. if (isMatchingSelector(lhs) && !containsActiveDataset(rhs))
  6936. setMapping(lhs, expr);
  6937. break;
  6938. }
  6939. case no_between:
  6940. case no_notbetween:
  6941. {
  6942. IHqlExpression * lhs = expr->queryChild(0);
  6943. if (isMatchingSelector(lhs) && !containsActiveDataset(expr->queryChild(1)) && !containsActiveDataset(expr->queryChild(2)))
  6944. setMapping(lhs, expr);
  6945. break;
  6946. }
  6947. case no_eq:
  6948. case no_ne:
  6949. case no_lt:
  6950. case no_gt:
  6951. case no_ge:
  6952. case no_le:
  6953. {
  6954. IHqlExpression * lhs = expr->queryChild(0);
  6955. IHqlExpression * rhs = expr->queryChild(1);
  6956. if (isMatchingSelector(lhs) && !containsActiveDataset(rhs))
  6957. setMapping(lhs, expr);
  6958. else if (isMatchingSelector(rhs) && !containsActiveDataset(lhs))
  6959. setMapping(rhs, expr);
  6960. break;
  6961. }
  6962. }
  6963. return;
  6964. }
  6965. }
  6966. void FilterCloner::addMappings(IHqlExpression * expr, IHqlExpression * addDs)
  6967. {
  6968. if (!expr) return;
  6969. OwnedHqlExpr replaced = replaceSelector(expr, addDs, ds);
  6970. doAddMappings(replaced);
  6971. }
  6972. bool FilterCloner::isMatchingSelector(IHqlExpression * expr)
  6973. {
  6974. return queryDatasetCursor(expr) == ds;
  6975. }
  6976. IHqlExpression * FilterCloner::inheritFilters(IHqlExpression * expr)
  6977. {
  6978. switch (expr->getOperator())
  6979. {
  6980. case no_and:
  6981. case no_assertkeyed:
  6982. case no_assertstepped:
  6983. {
  6984. HqlExprArray args;
  6985. ForEachChild(i, expr)
  6986. args.append(*inheritFilters(expr->queryChild(i)));
  6987. return cloneOrLink(expr, args);
  6988. }
  6989. case no_eq:
  6990. {
  6991. IHqlExpression * lhs = expr->queryChild(0);
  6992. IHqlExpression * rhs = expr->queryChild(1);
  6993. IHqlExpression * lhsExtra = (IHqlExpression *)lhs->queryTransformExtra();
  6994. if (lhsExtra)
  6995. {
  6996. DBGLOG("Inheriting filter condition");
  6997. IHqlExpression * cond = replaceExpression(lhsExtra, lhs, rhs);
  6998. return createValue(no_and, LINK(expr), cond);
  6999. }
  7000. IHqlExpression * rhsExtra = (IHqlExpression *)rhs->queryTransformExtra();
  7001. if (rhsExtra)
  7002. {
  7003. DBGLOG("Inheriting filter condition");
  7004. IHqlExpression * cond = replaceExpression(rhsExtra, rhs, lhs);
  7005. return createValue(no_and, LINK(expr), cond);
  7006. }
  7007. break;
  7008. }
  7009. case no_in:
  7010. case no_notin:
  7011. case no_between:
  7012. case no_notbetween:
  7013. {
  7014. IHqlExpression * lhs = expr->queryChild(0);
  7015. IHqlExpression * lhsExtra = (IHqlExpression *)lhs->queryTransformExtra();
  7016. if (lhsExtra)
  7017. {
  7018. DBGLOG("Inheriting filter condition");
  7019. return createValue(no_and, LINK(expr), LINK(lhsExtra));
  7020. }
  7021. break;
  7022. }
  7023. }
  7024. return LINK(expr);
  7025. }
  7026. static IHqlExpression * optimizeJoinFilter(IHqlExpression * expr)
  7027. {
  7028. //NB: Not a member function because we use a different transform mutex, and don't want to accidentally interfere with caller's use
  7029. IHqlExpression * index = expr->queryChild(1);
  7030. if (!index->hasProperty(filteredAtom) && !index->hasProperty(_filtered_Atom) && (index->getOperator() == no_newkeyindex))
  7031. return LINK(expr);
  7032. if (expr->hasProperty(keyedAtom))
  7033. return LINK(expr); //MORE!
  7034. OwnedHqlExpr rhs = createSelector(no_right, index, querySelSeq(expr));
  7035. FilterCloner processor(rhs);
  7036. while (index->getOperator() != no_newkeyindex)
  7037. {
  7038. switch (index->getOperator())
  7039. {
  7040. case no_filter:
  7041. //case no_filtered:
  7042. //MORE: This might be useful in the future
  7043. UNIMPLEMENTED;
  7044. }
  7045. index = index->queryChild(0);
  7046. }
  7047. processor.addMappings(queryPropertyChild(index, filteredAtom, 0), queryActiveTableSelector());
  7048. processor.addMappings(queryPropertyChild(index, _filtered_Atom, 0), queryActiveTableSelector());
  7049. if (!processor.hasMappings())
  7050. return LINK(expr);
  7051. HqlExprArray exprs;
  7052. expr->queryChild(2)->unwindList(exprs, no_and);
  7053. bool keyedExplicitly = false;
  7054. ForEachItemIn(i1, exprs)
  7055. {
  7056. IHqlExpression & cur = exprs.item(i1);
  7057. switch (cur.getOperator())
  7058. {
  7059. case no_assertkeyed:
  7060. case no_assertwild:
  7061. keyedExplicitly = true;
  7062. exprs.replace(*processor.inheritFilters(&cur), i1);
  7063. break;
  7064. }
  7065. }
  7066. if (!keyedExplicitly)
  7067. {
  7068. ForEachItemIn(i2, exprs)
  7069. {
  7070. IHqlExpression & cur = exprs.item(i2);
  7071. switch (cur.getOperator())
  7072. {
  7073. case no_assertkeyed:
  7074. case no_assertwild:
  7075. case no_attr:
  7076. case no_attr_link:
  7077. case no_attr_expr:
  7078. break;
  7079. default:
  7080. exprs.replace(*processor.inheritFilters(&cur), i2);
  7081. break;
  7082. }
  7083. }
  7084. }
  7085. HqlExprArray args;
  7086. unwindChildren(args, expr);
  7087. args.replace(*createBalanced(no_and, queryBoolType(), exprs), 2);
  7088. return expr->clone(args);
  7089. }
  7090. static HqlTransformerInfo filteredIndexOptimizerInfo("FilteredIndexOptimizer");
  7091. FilteredIndexOptimizer::FilteredIndexOptimizer(bool _processJoins, bool _processReads)
  7092. : NewHqlTransformer(filteredIndexOptimizerInfo)
  7093. {
  7094. processJoins = _processJoins;
  7095. processReads = _processReads;
  7096. }
  7097. IHqlExpression * FilteredIndexOptimizer::createTransformed(IHqlExpression * expr)
  7098. {
  7099. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  7100. if (processJoins && isKeyedJoin(transformed))
  7101. transformed.setown(optimizeJoinFilter(transformed));
  7102. if (processReads)
  7103. {
  7104. switch (transformed->getOperator())
  7105. {
  7106. case no_compound_indexread:
  7107. case no_compound_indexnormalize:
  7108. case no_compound_indexaggregate:
  7109. case no_compound_indexcount:
  7110. case no_compound_indexgroupaggregate:
  7111. //MORE:
  7112. break;
  7113. }
  7114. }
  7115. return transformed.getClear();
  7116. }
  7117. //==============================================================================================================
  7118. static HqlTransformerInfo localUploadTransformerInfo("LocalUploadTransformer");
  7119. LocalUploadTransformer::LocalUploadTransformer(IWorkUnit * _wu) : NewHqlTransformer(localUploadTransformerInfo)
  7120. {
  7121. wu = _wu;
  7122. }
  7123. IHqlExpression * LocalUploadTransformer::createTransformed(IHqlExpression * expr)
  7124. {
  7125. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  7126. if (transformed->hasProperty(localUploadAtom))
  7127. {
  7128. assertex(transformed->getOperator() == no_table);
  7129. IHqlExpression * filename = transformed->queryChild(0);
  7130. IHqlExpression * mode = transformed->queryChild(2);
  7131. assertex(filename->getOperator() == no_constant);
  7132. StringBuffer sourceName,localName;
  7133. filename->queryValue()->getStringValue(sourceName);
  7134. getUniqueId(localName.append("local"));
  7135. LocalFileUploadType uploadType = UploadTypeWUResult;
  7136. switch (mode->getOperator())
  7137. {
  7138. case no_csv:
  7139. uploadType = UploadTypeWUResultCsv;
  7140. break;
  7141. case no_xml:
  7142. uploadType = UploadTypeWUResultXml;
  7143. break;
  7144. }
  7145. wu->addLocalFileUpload(uploadType, sourceName, localName, NULL);
  7146. HqlExprArray args;
  7147. args.append(*LINK(expr->queryRecord()));
  7148. args.append(*createAttribute(nameAtom, createConstant(localName.str())));
  7149. args.append(*createAttribute(sequenceAtom, getStoredSequenceNumber()));
  7150. return createDataset(no_workunit_dataset, args);
  7151. }
  7152. return transformed.getClear();
  7153. }
  7154. //==============================================================================================================
  7155. /*
  7156. The following code converts expressions of the form a.b where a and b are datasets into a normalized form including
  7157. an explicit normalize activity. It follows the following rules:
  7158. 1) An filter/project/table on a.b logically has access to fields in a and a.b.
  7159. 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
  7160. subsequent operations.
  7161. 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.
  7162. This is done by converting f(a.b) to normalize(a, f(LEFT.b)) at the appropriate place.
  7163. These rules mean we maintain the HOLe semantics which allow computed fields to be implemented by projecting fields from the parent dataset,
  7164. but also mean that we avoid problems with parent datasets e.g., join(a.b, c.d)
  7165. To make this efficient we also need to implement the following in the code generator:
  7166. 1) aggregate-normalize(x).
  7167. 2) normalize-source.
  7168. 3) aggregate-normalize-source
  7169. 4) inline processing of normalize.
  7170. 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.
  7171. For the first version, it only generates normalizes around datasets - and assumes that parent fields don't need to be mapped into the denormalize.
  7172. This makes it simpler, but means that parse statements that take a record which could theoretically access parent dataset
  7173. fields won't work. The fix would require a new kind of child normalize that took a no_newtransform, and would require
  7174. analysis of which parent fields are used in the child's no_newtransform.
  7175. */
  7176. inline void getDatasetRange(IHqlExpression * expr, unsigned & first, unsigned & max)
  7177. {
  7178. first = 0;
  7179. switch (getChildDatasetType(expr))
  7180. {
  7181. case childdataset_many_noscope:
  7182. case childdataset_many:
  7183. max = expr->numChildren();
  7184. break;
  7185. case childdataset_if:
  7186. first = 1;
  7187. max = expr->numChildren();
  7188. break;
  7189. default:
  7190. max = getNumChildTables(expr);
  7191. break;
  7192. }
  7193. }
  7194. static HqlTransformerInfo nestedSelectorNormalizerInfo("NestedSelectorNormalizer");
  7195. NestedSelectorNormalizer::NestedSelectorNormalizer() : NewHqlTransformer(nestedSelectorNormalizerInfo)
  7196. {
  7197. spottedCandidate = false;
  7198. }
  7199. void NestedSelectorNormalizer::analyseExpr(IHqlExpression * expr)
  7200. {
  7201. if (alreadyVisited(expr))
  7202. return;
  7203. NewHqlTransformer::analyseExpr(expr);
  7204. if (expr->isDataset())
  7205. {
  7206. bool childrenAreDenormalized = false;
  7207. unsigned first, max;
  7208. getDatasetRange(expr, first, max);
  7209. for (unsigned i=0; i < max; i++)
  7210. {
  7211. if (queryBodyExtra(expr->queryChild(i))->isDenormalized)
  7212. childrenAreDenormalized = true;
  7213. }
  7214. NestedSelectorInfo * extra = queryBodyExtra(expr);
  7215. switch (expr->getOperator())
  7216. {
  7217. case no_select:
  7218. if (isNewSelector(expr))
  7219. {
  7220. childrenAreDenormalized = true;
  7221. spottedCandidate = true;
  7222. }
  7223. break;
  7224. case no_hqlproject:
  7225. case no_usertable:
  7226. break;
  7227. default:
  7228. //Follow test effectively checks whether parent dataset is active beyond this point
  7229. if (expr->queryBody() == expr->queryNormalizedSelector())
  7230. {
  7231. if (childrenAreDenormalized)
  7232. {
  7233. extra->insertDenormalize = true;
  7234. childrenAreDenormalized = false;
  7235. }
  7236. }
  7237. break;
  7238. }
  7239. extra->isDenormalized = childrenAreDenormalized;
  7240. }
  7241. }
  7242. static IHqlExpression * splitSelector(IHqlExpression * expr, SharedHqlExpr & oldDataset)
  7243. {
  7244. assertex(expr->getOperator() == no_select);
  7245. IHqlExpression * ds = expr->queryChild(0);
  7246. if (expr->hasProperty(newAtom))
  7247. {
  7248. oldDataset.set(ds);
  7249. OwnedHqlExpr left = createSelector(no_left, ds, querySelSeq(expr));
  7250. return createSelectExpr(left.getClear(), LINK(expr->queryChild(1)));
  7251. }
  7252. HqlExprArray args;
  7253. args.append(*splitSelector(ds, oldDataset));
  7254. unwindChildren(args, expr, 1);
  7255. return expr->clone(args);
  7256. }
  7257. IHqlExpression * NestedSelectorNormalizer::createNormalized(IHqlExpression * expr)
  7258. {
  7259. IHqlExpression * root = queryRoot(expr);
  7260. assertex(root && root->getOperator() == no_select && isNewSelector(root));
  7261. OwnedHqlExpr selSeq = createSelectorSequence();
  7262. OwnedHqlExpr oldDataset;
  7263. OwnedHqlExpr newSelector = splitSelector(root, oldDataset);
  7264. OwnedHqlExpr right = createSelector(no_right, expr, selSeq);
  7265. HqlExprArray args;
  7266. args.append(*LINK(oldDataset));
  7267. args.append(*replaceExpression(expr, root, newSelector));
  7268. args.append(*createTransformFromRow(right));
  7269. args.append(*LINK(selSeq));
  7270. OwnedHqlExpr ret = createDataset(no_normalize, args);
  7271. return expr->cloneAllAnnotations(ret);
  7272. }
  7273. IHqlExpression * NestedSelectorNormalizer::createTransformed(IHqlExpression * expr)
  7274. {
  7275. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  7276. NestedSelectorInfo * extra = queryBodyExtra(expr);
  7277. bool denormalizeInputs = false;
  7278. if (extra->insertDenormalize)
  7279. {
  7280. denormalizeInputs = true;
  7281. }
  7282. else
  7283. {
  7284. switch (expr->getOperator())
  7285. {
  7286. case NO_AGGREGATE:
  7287. case no_joined:
  7288. case no_buildindex:
  7289. case no_apply:
  7290. case no_distribution:
  7291. case no_distributer:
  7292. case no_within:
  7293. case no_notwithin:
  7294. case no_output:
  7295. case no_createset:
  7296. case no_soapaction_ds:
  7297. case no_newsoapaction_ds:
  7298. case no_returnresult:
  7299. case no_setgraphresult:
  7300. case no_setgraphloopresult:
  7301. case no_keydiff:
  7302. case no_rowdiff:
  7303. case no_extractresult:
  7304. // case no_setresult:
  7305. case no_blob2id:
  7306. case no_selectnth:
  7307. case no_keypatch:
  7308. case no_assign:
  7309. case no_lt:
  7310. case no_le:
  7311. case no_gt:
  7312. case no_ge:
  7313. case no_ne:
  7314. case no_eq:
  7315. case no_order:
  7316. case no_keyed:
  7317. case no_loopbody:
  7318. case no_rowvalue:
  7319. case no_setmeta:
  7320. case no_typetransfer:
  7321. case no_subgraph:
  7322. denormalizeInputs = true;
  7323. break;
  7324. }
  7325. }
  7326. if (denormalizeInputs)
  7327. {
  7328. bool same = true;
  7329. HqlExprArray args;
  7330. unwindChildren(args, transformed);
  7331. unsigned first, max;
  7332. getDatasetRange(expr, first, max);
  7333. for (unsigned i = first; i < max; i++)
  7334. {
  7335. if (queryBodyExtra(expr->queryChild(i))->isDenormalized)
  7336. {
  7337. args.replace(*createNormalized(&args.item(i)), i);
  7338. same = false;
  7339. }
  7340. }
  7341. if (!same)
  7342. return transformed->clone(args);
  7343. }
  7344. return transformed.getClear();
  7345. }
  7346. //==============================================================================================================
  7347. /*
  7348. Code to spot ambiguous LEFT dataset references....
  7349. */
  7350. static HqlTransformerInfo leftRightSelectorNormalizerInfo("LeftRightSelectorNormalizer");
  7351. LeftRightSelectorNormalizer::LeftRightSelectorNormalizer(bool _allowAmbiguity) : NewHqlTransformer(leftRightSelectorNormalizerInfo)
  7352. {
  7353. allowAmbiguity = _allowAmbiguity;
  7354. isAmbiguous = false;
  7355. }
  7356. void LeftRightSelectorNormalizer::checkAmbiguity(const HqlExprCopyArray & inScope, IHqlExpression * selector)
  7357. {
  7358. node_operator selectOp = selector->getOperator();
  7359. ForEachItemIn(i, inScope)
  7360. {
  7361. IHqlExpression & cur = inScope.item(i);
  7362. if ((&cur != selector) && (cur.getOperator() == selectOp) && (cur.queryRecord() == selector->queryRecord()))
  7363. {
  7364. isAmbiguous = true;
  7365. if (!allowAmbiguity)
  7366. {
  7367. StringBuffer ecl;
  7368. getExprECL(selector, ecl);
  7369. throwError1(HQLERR_AmbiguousLeftRight, ecl.str());
  7370. }
  7371. }
  7372. }
  7373. }
  7374. void LeftRightSelectorNormalizer::analyseExpr(IHqlExpression * expr)
  7375. {
  7376. if (alreadyVisited(expr))
  7377. return;
  7378. IHqlExpression * selSeq = querySelSeq(expr);
  7379. if (selSeq)
  7380. {
  7381. HqlExprCopyArray inScope;
  7382. switch (getChildDatasetType(expr))
  7383. {
  7384. case childdataset_none:
  7385. case childdataset_many_noscope:
  7386. case childdataset_many:
  7387. case childdataset_map:
  7388. case childdataset_dataset_noscope:
  7389. case childdataset_if:
  7390. case childdataset_case:
  7391. case childdataset_dataset:
  7392. case childdataset_evaluate:
  7393. break;
  7394. case childdataset_datasetleft:
  7395. case childdataset_left:
  7396. {
  7397. IHqlExpression * dataset = expr->queryChild(0);
  7398. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  7399. gatherChildTablesUsed(NULL, &inScope, expr, 1);
  7400. checkAmbiguity(inScope, left);
  7401. break;
  7402. }
  7403. case childdataset_leftright:
  7404. {
  7405. OwnedHqlExpr left = createSelector(no_left, expr->queryChild(0), selSeq);
  7406. OwnedHqlExpr right = createSelector(no_right, expr->queryChild(1), selSeq);
  7407. gatherChildTablesUsed(NULL, &inScope, expr, 2);
  7408. checkAmbiguity(inScope, left);
  7409. checkAmbiguity(inScope, right);
  7410. break;
  7411. }
  7412. case childdataset_same_left_right:
  7413. case childdataset_top_left_right:
  7414. case childdataset_nway_left_right:
  7415. {
  7416. IHqlExpression * dataset = expr->queryChild(0);
  7417. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  7418. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  7419. gatherChildTablesUsed(NULL, &inScope, expr, 1);
  7420. checkAmbiguity(inScope, left);
  7421. checkAmbiguity(inScope, right);
  7422. break;
  7423. }
  7424. default:
  7425. UNIMPLEMENTED;
  7426. }
  7427. }
  7428. NewHqlTransformer::analyseExpr(expr);
  7429. }
  7430. IHqlExpression * LeftRightSelectorNormalizer::createTransformed(IHqlExpression * expr)
  7431. {
  7432. if (expr->isAttribute() && expr->queryName() == _selectorSequence_Atom)
  7433. return createDummySelectorSequence();
  7434. return NewHqlTransformer::createTransformed(expr);
  7435. }
  7436. IHqlExpression * LeftRightSelectorNormalizer::createTransformedSelector(IHqlExpression * expr)
  7437. {
  7438. node_operator op = expr->getOperator();
  7439. switch (op)
  7440. {
  7441. case no_left:
  7442. case no_right:
  7443. return transform(expr);
  7444. }
  7445. return NewHqlTransformer::createTransformedSelector(expr);
  7446. }
  7447. //==============================================================================================================
  7448. static HqlTransformerInfo forceLocalTransformerInfo("ForceLocalTransformer");
  7449. ForceLocalTransformer::ForceLocalTransformer(ClusterType _targetClusterType) : NewHqlTransformer(forceLocalTransformerInfo)
  7450. {
  7451. targetClusterType = _targetClusterType;
  7452. insideForceLocal = false;
  7453. allNodesDepth = 0;
  7454. }
  7455. IHqlExpression * ForceLocalTransformer::createTransformed(IHqlExpression * expr)
  7456. {
  7457. node_operator op = expr->getOperator();
  7458. switch (expr->getOperator())
  7459. {
  7460. case no_forcelocal:
  7461. case no_forcenolocal:
  7462. {
  7463. bool wasLocal = insideForceLocal;
  7464. insideForceLocal = (op == no_forcelocal) && (targetClusterType != HThorCluster);
  7465. IHqlExpression * ret = transform(expr->queryChild(0));
  7466. insideForceLocal = wasLocal;
  7467. return ret;
  7468. }
  7469. case no_thisnode:
  7470. if ((targetClusterType != HThorCluster) && (allNodesDepth == 0))
  7471. throwError(HQLERR_ThisNodeNotInsideAllNodes);
  7472. //fall through
  7473. case no_allnodes:
  7474. {
  7475. if (targetClusterType != HThorCluster)
  7476. {
  7477. unsigned oldDepth = allNodesDepth;
  7478. if (op == no_allnodes)
  7479. allNodesDepth++;
  7480. else
  7481. allNodesDepth--;
  7482. IHqlExpression * ret = NewHqlTransformer::createTransformed(expr);
  7483. allNodesDepth = oldDepth;
  7484. return ret;
  7485. }
  7486. else
  7487. return transform(expr->queryChild(0));
  7488. }
  7489. case no_globalscope:
  7490. case no_colon:
  7491. {
  7492. bool wasLocal = insideForceLocal;
  7493. unsigned oldDepth = allNodesDepth;
  7494. insideForceLocal = false;
  7495. allNodesDepth = 0;
  7496. IHqlExpression * ret = NewHqlTransformer::createTransformed(expr);
  7497. insideForceLocal = wasLocal;
  7498. allNodesDepth = oldDepth;
  7499. return ret;
  7500. }
  7501. }
  7502. OwnedHqlExpr ret = NewHqlTransformer::createTransformed(expr);
  7503. if (!insideForceLocal || !localChangesActivity(expr) || expr->hasProperty(noLocalAtom))
  7504. return ret.getClear();
  7505. return appendLocalAttribute(ret);
  7506. }
  7507. ANewTransformInfo * ForceLocalTransformer::createTransformInfo(IHqlExpression * expr)
  7508. {
  7509. return CREATE_NEWTRANSFORMINFO(ForceLocalTransformInfo, expr);
  7510. }
  7511. IHqlExpression * ForceLocalTransformer::queryAlreadyTransformed(IHqlExpression * expr)
  7512. {
  7513. ForceLocalTransformInfo * extra = queryExtra(expr);
  7514. return extra->localTransformed[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())];
  7515. }
  7516. void ForceLocalTransformer::setTransformed(IHqlExpression * expr, IHqlExpression * transformed)
  7517. {
  7518. ForceLocalTransformInfo * extra = queryExtra(expr);
  7519. extra->localTransformed[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())].set(transformed);
  7520. }
  7521. IHqlExpression * ForceLocalTransformer::queryAlreadyTransformedSelector(IHqlExpression * expr)
  7522. {
  7523. ForceLocalTransformInfo * extra = queryExtra(expr);
  7524. return extra->localTransformedSelector[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())];
  7525. }
  7526. void ForceLocalTransformer::setTransformedSelector(IHqlExpression * expr, IHqlExpression * transformed)
  7527. {
  7528. ForceLocalTransformInfo * extra = queryExtra(expr);
  7529. extra->localTransformedSelector[boolToInt(insideForceLocal)][boolToInt(insideAllNodes())].set(transformed);
  7530. }
  7531. //---------------------------------------------------------------------------
  7532. /*
  7533. 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
  7534. 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
  7535. complicated transformation. However there are some exceptions:
  7536. a) weird field dataset syntax which dates back to hole days is no transformed.
  7537. b) add a project before a build index to ensure the code is more efficient. (It will be later moved over any intervening sorts).
  7538. c) ensure input and out from a pipe is serialized (so that sizeof(inputrow) returns a sensible value)
  7539. */
  7540. static HqlTransformerInfo hqlLinkedChildRowTransformerInfo("HqlLinkedChildRowTransformer");
  7541. HqlLinkedChildRowTransformer::HqlLinkedChildRowTransformer(bool _implicitLinkedChildRows) : QuickHqlTransformer(hqlLinkedChildRowTransformerInfo, NULL)
  7542. {
  7543. implicitLinkedChildRows = _implicitLinkedChildRows;
  7544. }
  7545. IHqlExpression * HqlLinkedChildRowTransformer::ensureInputSerialized(IHqlExpression * expr)
  7546. {
  7547. LinkedHqlExpr dataset = expr->queryChild(0);
  7548. IHqlExpression * record = dataset->queryRecord();
  7549. OwnedHqlExpr serializedRecord = getSerializedForm(record);
  7550. //If the dataset requires serialization, it is much more efficient to serialize before the sort, than to serialize after.
  7551. if (record == serializedRecord)
  7552. return LINK(expr);
  7553. OwnedHqlExpr selSeq = createSelectorSequence();
  7554. //The expression/transform has references to the in-memory selector, but the selector provided to transform will be serialised.
  7555. //so create a mapping <unserialized> := f(serialized)
  7556. //and then use it to expand references to the unserialized format
  7557. IHqlExpression * selector = dataset->queryNormalizedSelector();
  7558. OwnedHqlExpr mapTransform = createRecordMappingTransform(no_transform, serializedRecord, selector);
  7559. OwnedHqlExpr newDataset = createDatasetF(no_newusertable, LINK(dataset), LINK(serializedRecord), LINK(mapTransform), LINK(selSeq), NULL);
  7560. NewProjectMapper2 mapper;
  7561. mapper.setMapping(mapTransform);
  7562. HqlExprArray oldArgs, expandedArgs, newArgs;
  7563. newArgs.append(*LINK(newDataset));
  7564. unwindChildren(oldArgs, expr, 1);
  7565. mapper.expandFields(expandedArgs, oldArgs, dataset, newDataset, selector);
  7566. //Finally replace any remaining selectors - so that sizeof(ds) gets mapped correctly. Obscure..... but could possibly be used in a pipe,repeat
  7567. ForEachItemIn(i, expandedArgs)
  7568. newArgs.append(*replaceSelector(&expandedArgs.item(i), selector, newDataset->queryNormalizedSelector()));
  7569. return expr->clone(newArgs);
  7570. }
  7571. IHqlExpression * HqlLinkedChildRowTransformer::transformBuildIndex(IHqlExpression * expr)
  7572. {
  7573. return ensureInputSerialized(expr);
  7574. }
  7575. IHqlExpression * HqlLinkedChildRowTransformer::transformPipeThrough(IHqlExpression * expr)
  7576. {
  7577. //serialize input to pipe through, so that if they happen to use sizeof(ds) on the input it will give the
  7578. //non serialized format. No major need to ensure output is not serialized.
  7579. return ensureInputSerialized(expr);
  7580. }
  7581. IHqlExpression * HqlLinkedChildRowTransformer::createTransformedBody(IHqlExpression * expr)
  7582. {
  7583. switch (expr->getOperator())
  7584. {
  7585. case no_field:
  7586. {
  7587. ITypeInfo * type = expr->queryType();
  7588. switch (type->getTypeCode())
  7589. {
  7590. case type_dictionary:
  7591. case type_table:
  7592. case type_groupedtable:
  7593. if (expr->hasProperty(embeddedAtom))
  7594. {
  7595. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  7596. return removeProperty(transformed, embeddedAtom);
  7597. }
  7598. if (implicitLinkedChildRows && !expr->hasProperty(_linkCounted_Atom))
  7599. {
  7600. //Don't use link counted rows for weird HOLe style dataset attributes
  7601. if (expr->hasProperty(countAtom) || expr->hasProperty(sizeofAtom))
  7602. break;
  7603. //add the attribute first so a no linked field doesn't contain a record that requires it
  7604. OwnedHqlExpr modified = appendOwnedOperand(expr, getLinkCountedAttr());
  7605. return transform(modified);
  7606. }
  7607. break;
  7608. }
  7609. break;
  7610. }
  7611. case no_buildindex:
  7612. {
  7613. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  7614. return transformBuildIndex(transformed);
  7615. }
  7616. case no_pipe:
  7617. if (expr->queryRecord())
  7618. {
  7619. return QuickHqlTransformer::createTransformedBody(expr);
  7620. }
  7621. case no_output:
  7622. //would this be a good idea for output to file? output to pipe?
  7623. if (false)
  7624. {
  7625. IHqlExpression * filename = queryRealChild(expr, 2);
  7626. if (filename)
  7627. {
  7628. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformedBody(expr);
  7629. return ensureInputSerialized(transformed);
  7630. }
  7631. }
  7632. break;
  7633. }
  7634. return QuickHqlTransformer::createTransformedBody(expr);
  7635. }
  7636. //---------------------------------------------------------------------------
  7637. HqlScopeTaggerInfo::HqlScopeTaggerInfo(IHqlExpression * _expr) : MergingTransformInfo(_expr)
  7638. {
  7639. if (!onlyTransformOnce() && isIndependentOfScope(_expr))
  7640. {
  7641. //If the node doesn't have any active selectors then it isn't going to be context dependent
  7642. setOnlyTransformOnce(true);
  7643. }
  7644. }
  7645. ANewTransformInfo * HqlScopeTagger::createTransformInfo(IHqlExpression * expr)
  7646. {
  7647. return CREATE_NEWTRANSFORMINFO(HqlScopeTaggerInfo, expr);
  7648. }
  7649. /*
  7650. Details of the scope tagging.
  7651. no_select
  7652. if the lhs dataset is in scope then no flags are attached. if the lhs is not in scope, then a newAtom attribute is
  7653. attached to select node. That may contain the following attributes:
  7654. global - is an outer level activity
  7655. noTable - no other tables are active at this point e.g., global[1].field;
  7656. relatedTable - I think this could be deprecated in favour of the flag above.
  7657. Datasets
  7658. In other situations where a dataset/datarow is ambiguous whether it is new or in scope then a no_activerow
  7659. is inserted to indicate it is in scope.
  7660. Note:
  7661. new attributes aren't created for subfield e.g, myDataset.level1.level2.
  7662. This means that if (myDataset.level1) is expanded to some expression then a newAtom will be need to be created on the new select
  7663. */
  7664. static HqlTransformerInfo hqlScopeTaggerInfo("HqlScopeTagger");
  7665. HqlScopeTagger::HqlScopeTagger(IErrorReceiver * _errors)
  7666. : ScopedDependentTransformer(hqlScopeTaggerInfo), errors(_errors)
  7667. {
  7668. }
  7669. bool HqlScopeTagger::isValidNormalizeSelector(IHqlExpression * expr)
  7670. {
  7671. loop
  7672. {
  7673. switch (expr->getOperator())
  7674. {
  7675. case no_filter:
  7676. break;
  7677. case no_usertable:
  7678. if (isAggregateDataset(expr))
  7679. return false;
  7680. return true;
  7681. case no_hqlproject:
  7682. if (isCountProject(expr))
  7683. return false;
  7684. return true;
  7685. case no_select:
  7686. {
  7687. IHqlExpression * ds = expr->queryChild(0);
  7688. if (isDatasetActive(ds))
  7689. return true;
  7690. //Not really sure what the following should do. Avoid a.b.c[1].d.e
  7691. if (ds->isDatarow() && (ds->getOperator() != no_select))
  7692. return false;
  7693. break;
  7694. }
  7695. case no_table:
  7696. return (queryTableMode(expr) == no_flat);
  7697. case no_keyindex:
  7698. case no_newkeyindex:
  7699. case no_rows:
  7700. return true;
  7701. default:
  7702. return false;
  7703. }
  7704. expr = expr->queryChild(0);
  7705. }
  7706. }
  7707. static const char * getECL(IHqlExpression * expr, StringBuffer & s)
  7708. {
  7709. toUserECL(s, expr, false);
  7710. if (s.length() > 2)
  7711. s.setLength(s.length()-2);
  7712. return s.str();
  7713. }
  7714. void HqlScopeTagger::checkActiveRow(IHqlExpression * expr)
  7715. {
  7716. if (!isDatasetActive(expr))
  7717. {
  7718. StringBuffer exprText;
  7719. getECL(expr, exprText);
  7720. elideString(exprText, 20);
  7721. VStringBuffer msg("ROW(%s) - dataset argument is not in scope. Did you mean dataset[1]?", exprText.str());
  7722. reportError(msg);
  7723. }
  7724. }
  7725. void HqlScopeTagger::reportSelectorError(IHqlExpression * selector, IHqlExpression * expr)
  7726. {
  7727. ScopeInfo * scope = innerScope;
  7728. if (innerScope && innerScope->isEmpty() && scopeStack.ordinality() > 1)
  7729. scope = &scopeStack.item(scopeStack.ordinality()-2);
  7730. StringBuffer exprText, datasetName, scopeName;
  7731. StringBuffer msg;
  7732. if (scope && scope->dataset)
  7733. {
  7734. IHqlExpression * topScope = scope->dataset;
  7735. msg.appendf("%s - Table %s is not related to %s",
  7736. getECL(expr, exprText),
  7737. getExprIdentifier(datasetName, selector).str(), getExprIdentifier(scopeName, topScope).str());
  7738. }
  7739. else if (scope && scope->left)
  7740. {
  7741. msg.appendf("%s - no active row for Table %s inside transform (use LEFT?)",
  7742. getECL(expr, exprText),
  7743. getExprIdentifier(datasetName, selector).str());
  7744. }
  7745. else
  7746. {
  7747. msg.appendf("%s - no specified row for Table %s", getECL(expr, exprText),
  7748. getExprIdentifier(datasetName, selector).str());
  7749. }
  7750. reportError(msg);
  7751. }
  7752. IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
  7753. {
  7754. IHqlExpression * ds = expr->queryChild(0);
  7755. if (isDatasetActive(ds))
  7756. {
  7757. if (!innerScope && scopeStack.ordinality() == 0)
  7758. {
  7759. ds = queryDatasetCursor(ds);
  7760. switch (ds->getOperator())
  7761. {
  7762. case no_left:
  7763. case no_right:
  7764. StringBuffer exprText, datasetName;
  7765. VStringBuffer msg("%s - %s not in scope, possibly passed into a global/workflow definition", getECL(expr, exprText), getExprIdentifier(datasetName, ds).str());
  7766. reportError(msg);
  7767. break;
  7768. }
  7769. }
  7770. return Parent::createTransformed(expr); // this will call transformSelector() on lhs since new is not present
  7771. }
  7772. IHqlExpression * cursor = queryDatasetCursor(ds);
  7773. if (cursor->isDataset())
  7774. {
  7775. if (expr->isDataset())
  7776. {
  7777. if (!isValidNormalizeSelector(cursor))
  7778. {
  7779. StringBuffer exprText;
  7780. VStringBuffer msg("dataset %s may not be supported without using NORMALIZE", getECL(expr, exprText));
  7781. reportError(msg, true);
  7782. }
  7783. }
  7784. else
  7785. {
  7786. if (!isDatasetARow(ds))
  7787. reportSelectorError(ds, expr);
  7788. }
  7789. }
  7790. pushScope();
  7791. OwnedHqlExpr newDs = transformNewDataset(ds, false);
  7792. popScope();
  7793. IHqlExpression * field = expr->queryChild(1);
  7794. if (ds->isDataset())
  7795. {
  7796. if (!expr->isDataset() && !expr->isDatarow())
  7797. {
  7798. //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
  7799. return createSelectExpr(newDs.getClear(), LINK(field));
  7800. }
  7801. }
  7802. //MORE: What about child datasets - should really be tagged as
  7803. //if (!isNewDataset && field->isDataset() && !containsSelf(ds) && !isDatasetActive(ds)) isNew = true;
  7804. return createNewSelectExpr(newDs.getClear(), LINK(field));
  7805. }
  7806. IHqlExpression * HqlScopeTagger::transformSelectorsAttr(IHqlExpression * expr)
  7807. {
  7808. HqlExprArray args;
  7809. HqlExprArray transformedArgs;
  7810. unwindChildren(args, expr);
  7811. ForEachItemIn(i, args)
  7812. {
  7813. IHqlExpression & cur = args.item(i);
  7814. assertex(cur.getOperator() == no_select);
  7815. //Only retain selectors for datasets which are in scope.
  7816. if (isDatasetActive(cur.queryChild(0)))
  7817. transformedArgs.append(*transformSelector(&cur));
  7818. }
  7819. return expr->clone(transformedArgs);
  7820. }
  7821. IHqlExpression * HqlScopeTagger::transformNewDataset(IHqlExpression * expr, bool isActiveOk)
  7822. {
  7823. node_operator op = expr->getOperator();
  7824. switch (op)
  7825. {
  7826. case no_activerow:
  7827. {
  7828. IHqlExpression * arg0 = expr->queryChild(0);
  7829. checkActiveRow(arg0);
  7830. OwnedHqlExpr transformedArg = transformSelector(arg0);
  7831. return ensureActiveRow(transformedArg);
  7832. }
  7833. }
  7834. OwnedHqlExpr transformed = transform(expr);
  7835. switch (op)
  7836. {
  7837. //MORE: I'm still not quite sure the active tagging of rows is right to have these as exceptions...
  7838. case no_left:
  7839. case no_right:
  7840. case no_matchattr:
  7841. return transformed.getClear();
  7842. case no_select:
  7843. if (isDatasetActive(expr))
  7844. {
  7845. IHqlExpression * ds = expr->queryChild(0);
  7846. if (!isAlwaysActiveRow(ds))
  7847. {
  7848. StringBuffer exprText;
  7849. VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
  7850. reportError(msg, false);
  7851. }
  7852. }
  7853. return transformed.getClear();
  7854. }
  7855. if (isDatasetActive(expr))
  7856. {
  7857. if (!isActiveOk)
  7858. {
  7859. StringBuffer exprText;
  7860. VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
  7861. reportError(msg);
  7862. }
  7863. return ensureActiveRow(transformed->queryNormalizedSelector());
  7864. }
  7865. switch (op)
  7866. {
  7867. case no_if:
  7868. {
  7869. HqlExprArray args;
  7870. args.append(*transform(expr->queryChild(0)));
  7871. args.append(*transformNewDataset(expr->queryChild(1), false));
  7872. if (expr->queryChild(2))
  7873. args.append(*transformNewDataset(expr->queryChild(2), false));
  7874. return expr->clone(args);
  7875. }
  7876. case no_addfiles:
  7877. case no_projectrow:
  7878. return transformAmbiguousChildren(expr);
  7879. case no_case:
  7880. case no_map:
  7881. throwUnexpected(); // should have been converted to no_if by now...
  7882. default:
  7883. return transformed.getClear();
  7884. }
  7885. }
  7886. IHqlExpression * HqlScopeTagger::transformAmbiguous(IHqlExpression * expr, bool isActiveOk)
  7887. {
  7888. ITypeInfo * type = expr->queryType();
  7889. type_t tc = type_void;
  7890. if (type)
  7891. tc = type->getTypeCode();
  7892. switch (tc)
  7893. {
  7894. case type_void:
  7895. return transformAmbiguousChildren(expr);
  7896. case type_table:
  7897. case type_groupedtable:
  7898. {
  7899. pushScope();
  7900. OwnedHqlExpr ret = transformNewDataset(expr, isActiveOk);
  7901. popScope();
  7902. return ret.getClear();
  7903. }
  7904. }
  7905. return transform(expr);
  7906. }
  7907. IHqlExpression * HqlScopeTagger::transformAmbiguousChildren(IHqlExpression * expr)
  7908. {
  7909. unsigned max = expr->numChildren();
  7910. if (max == 0)
  7911. return LINK(expr);
  7912. bool same = true;
  7913. HqlExprArray args;
  7914. args.ensure(max);
  7915. for(unsigned i=0; i < max; i++)
  7916. {
  7917. IHqlExpression * cur = expr->queryChild(i);
  7918. IHqlExpression * tr = transformAmbiguous(cur, false);
  7919. args.append(*tr);
  7920. if (cur != tr)
  7921. same = false;
  7922. }
  7923. if (same)
  7924. return LINK(expr);
  7925. return expr->clone(args);
  7926. }
  7927. IHqlExpression * HqlScopeTagger::transformSizeof(IHqlExpression * expr)
  7928. {
  7929. IHqlExpression * arg = expr->queryChild(0)->queryNormalizedSelector();
  7930. //Sizeof (dataset.somefield(<new>)) - convert to sizeof(record.somefield), so the argument doesn't get hoisted incorrectly, and don't get a scope error
  7931. OwnedHqlExpr newArg;
  7932. if (arg->getOperator() == no_select)
  7933. {
  7934. IHqlExpression * ds = arg->queryChild(0);
  7935. IHqlExpression * cursor = queryDatasetCursor(ds);
  7936. if (!isDatasetActive(cursor) && cursor->isDataset())
  7937. newArg.setown(createSelectExpr(LINK(ds->queryRecord()), LINK(arg->queryChild(1))));
  7938. }
  7939. if (!newArg)
  7940. newArg.setown(transformAmbiguous(arg, true));
  7941. HqlExprArray args;
  7942. args.append(*newArg.getClear());
  7943. return completeTransform(expr, args);
  7944. }
  7945. IHqlExpression * HqlScopeTagger::transformWithin(IHqlExpression * dataset, IHqlExpression * scope)
  7946. {
  7947. while (dataset->getOperator() == no_related)
  7948. dataset = dataset->queryChild(0);
  7949. if (dataset->getOperator() != no_select)
  7950. {
  7951. StringBuffer exprText;
  7952. VStringBuffer msg("%s - dataset filtered by WITHIN is too complex", getECL(dataset, exprText));
  7953. reportError(msg);
  7954. return transform(dataset);
  7955. }
  7956. IHqlExpression * ds = dataset->queryChild(0);
  7957. IHqlExpression * field = dataset->queryChild(1);
  7958. if (ds->queryNormalizedSelector() == scope)
  7959. {
  7960. OwnedHqlExpr newDs = transform(ds);
  7961. return createSelectExpr(newDs.getClear(), LINK(field));
  7962. }
  7963. OwnedHqlExpr newDs = transformWithin(ds, scope);
  7964. return createNewSelectExpr(newDs.getClear(), LINK(field));
  7965. }
  7966. IHqlExpression * HqlScopeTagger::transformRelated(IHqlExpression * expr)
  7967. {
  7968. IHqlExpression * ds = expr->queryChild(0);
  7969. IHqlExpression * scope = expr->queryChild(1);
  7970. if (!isDatasetActive(scope))
  7971. {
  7972. StringBuffer exprText;
  7973. VStringBuffer msg("dataset \"%s\" used in WITHIN is not in scope", getECL(scope, exprText));
  7974. reportError(msg);
  7975. }
  7976. //Check the ds is a table
  7977. IHqlDataset * scopeDs = scope->queryDataset();
  7978. if (scopeDs != scopeDs->queryTable())
  7979. {
  7980. StringBuffer exprText;
  7981. VStringBuffer msg("dataset \"%s\" used as parameter to WITHIN is too complex", getECL(expr, exprText));
  7982. reportError(msg);
  7983. }
  7984. return transformWithin(ds, scope->queryNormalizedSelector());
  7985. }
  7986. IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
  7987. {
  7988. IHqlExpression * body = expr->queryBody(true);
  7989. if (expr != body)
  7990. {
  7991. switch (expr->getAnnotationKind())
  7992. {
  7993. case annotate_meta:
  7994. collector.processMetaAnnotation(expr);
  7995. break;
  7996. case annotate_symbol:
  7997. {
  7998. WarningProcessor::OnWarningState saved;
  7999. collector.pushSymbol(saved, expr);
  8000. OwnedHqlExpr transformedBody = transform(body);
  8001. collector.popSymbol(saved);
  8002. if (body == transformedBody)
  8003. return LINK(expr);
  8004. return expr->cloneAnnotation(transformedBody);
  8005. }
  8006. break;
  8007. case annotate_location:
  8008. {
  8009. break;
  8010. }
  8011. }
  8012. OwnedHqlExpr transformedBody = transform(body);
  8013. if (body == transformedBody)
  8014. return LINK(expr);
  8015. return expr->cloneAnnotation(transformedBody);
  8016. }
  8017. collector.checkForGlobalOnWarning(expr);
  8018. switch (expr->getOperator())
  8019. {
  8020. case no_left:
  8021. case no_right:
  8022. case no_self:
  8023. case no_top:
  8024. return LINK(expr);
  8025. case no_activerow:
  8026. checkActiveRow(expr->queryChild(0));
  8027. break;
  8028. case no_select:
  8029. return transformSelect(expr);
  8030. case no_call:
  8031. case no_externalcall:
  8032. case no_rowvalue:
  8033. // case no_addfiles:
  8034. // case no_libraryscopeinstance:??
  8035. return transformAmbiguousChildren(expr);
  8036. case no_offsetof:
  8037. case no_sizeof:
  8038. return transformSizeof(expr);
  8039. case no_attr_expr:
  8040. if (expr->queryName() == _selectors_Atom)
  8041. return transformSelectorsAttr(expr);
  8042. return transformAmbiguousChildren(expr);
  8043. case no_datasetfromrow:
  8044. {
  8045. IHqlExpression * ds = expr->queryChild(0);
  8046. if (ds->isDataset() && !isDatasetActive(ds))
  8047. {
  8048. StringBuffer exprText;
  8049. VStringBuffer msg("dataset %s mistakenly interpreted as a datarow, possibly due to missing dataset() in parameter type", getECL(ds, exprText));
  8050. reportError(msg);
  8051. }
  8052. return transformAmbiguousChildren(expr);
  8053. }
  8054. case no_temptable:
  8055. if (expr->queryChild(0)->isDatarow())
  8056. return transformAmbiguousChildren(expr);
  8057. break;
  8058. case no_related:
  8059. return transformRelated(expr);
  8060. case no_eq:
  8061. case no_ne:
  8062. case no_lt:
  8063. case no_le:
  8064. case no_gt:
  8065. case no_ge:
  8066. case no_order:
  8067. //MORE: Should check this doesn't make the comparison invalid.
  8068. return transformAmbiguousChildren(expr);
  8069. case no_assign:
  8070. {
  8071. IHqlExpression * lhs = expr->queryChild(0);
  8072. IHqlExpression * rhs = expr->queryChild(1);
  8073. OwnedHqlExpr newRhs = transformAmbiguous(rhs, false);
  8074. if (lhs->isDatarow() && newRhs->isDataset())
  8075. {
  8076. StringBuffer exprText;
  8077. VStringBuffer msg("dataset expression (%s) assigned to field '%s' with type row", getECL(rhs, exprText), lhs->queryChild(1)->queryName()->str());
  8078. reportError(msg.str());
  8079. }
  8080. if (rhs == newRhs)
  8081. return LINK(expr);
  8082. HqlExprArray children;
  8083. children.append(*LINK(expr->queryChild(0)));
  8084. children.append(*newRhs.getClear());
  8085. return completeTransform(expr, children);
  8086. }
  8087. break;
  8088. case no_evaluate:
  8089. throwUnexpected();
  8090. case no_projectrow:
  8091. {
  8092. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  8093. if (transformed->queryChild(0)->isDataset())
  8094. reportError("PROJECT() row argument resolved to a dataset. Missing DATASET() from parameter type?");
  8095. return transformed.getClear();
  8096. }
  8097. case no_merge:
  8098. {
  8099. HqlExprArray children;
  8100. transformChildren(expr, children);
  8101. IHqlExpression * sorted = queryProperty(sortedAtom, children);
  8102. if (!sorted || queryProperty(_implicitSorted_Atom, children))
  8103. {
  8104. IHqlExpression * dataset = &children.item(0);
  8105. removeProperty(children, _implicitSorted_Atom);
  8106. if (sorted)
  8107. children.zap(*sorted);
  8108. HqlExprArray sorts;
  8109. OwnedHqlExpr order = getExistingSortOrder(dataset, expr->hasProperty(localAtom), true);
  8110. if (order)
  8111. unwindChildren(sorts, order);
  8112. ForEachItemInRev(i, sorts)
  8113. {
  8114. if (sorts.item(i).isAttribute())
  8115. {
  8116. reportError(HQLWRN_MergeBadSortOrder_Text, true);
  8117. sorts.remove(i);
  8118. }
  8119. }
  8120. children.append(*createExprAttribute(sortedAtom, sorts));
  8121. }
  8122. return expr->clone(children);
  8123. }
  8124. }
  8125. return Parent::createTransformed(expr);
  8126. }
  8127. void HqlScopeTagger::reportWarnings()
  8128. {
  8129. if (errors)
  8130. collector.report(*errors);
  8131. }
  8132. void HqlScopeTagger::reportError(const char * msg, bool warning)
  8133. {
  8134. IHqlExpression * location = collector.queryActiveSymbol();
  8135. //Make this an error when we are confident...
  8136. int startLine= location ? location->getStartLine() : 0;
  8137. int startColumn = location ? location->getStartColumn() : 0;
  8138. ISourcePath * sourcePath = location ? location->querySourcePath() : NULL;
  8139. Owned<IECLError> err = createECLError(!warning, ERR_ASSERT_WRONGSCOPING, msg, sourcePath->str(), startLine, startColumn, 0);
  8140. collector.report(NULL, errors, err); // will throw immediately if it is an error.
  8141. }
  8142. //---------------------------------------------------------------------------------------------------------------------
  8143. SharedTableInfo * ImplicitAliasTransformInfo::uses(IHqlExpression * tableBody) const
  8144. {
  8145. ForEachItemIn(i, sharedTables)
  8146. {
  8147. SharedTableInfo & cur = sharedTables.item(i);
  8148. if (cur.dataset == tableBody)
  8149. return &cur;
  8150. }
  8151. return NULL;
  8152. }
  8153. void ImplicitAliasTransformInfo::add(SharedTableInfo * table)
  8154. {
  8155. sharedTables.append(*LINK(table));
  8156. }
  8157. void ImplicitAliasTransformInfo::addAmbiguity(SharedTableInfo * table)
  8158. {
  8159. containsAmbiguity = true;
  8160. merge(table);
  8161. }
  8162. void ImplicitAliasTransformInfo::merge(SharedTableInfo * table)
  8163. {
  8164. ForEachItemIn(i, sharedTables)
  8165. {
  8166. SharedTableInfo & cur = sharedTables.item(i);
  8167. if (cur.dataset == table->dataset)
  8168. {
  8169. if (cur.depth < table->depth)
  8170. sharedTables.replace(*LINK(table), i);
  8171. return;
  8172. }
  8173. }
  8174. add(table);
  8175. }
  8176. void ImplicitAliasTransformInfo::inherit(const ImplicitAliasTransformInfo * other)
  8177. {
  8178. ForEachItemIn(i, other->sharedTables)
  8179. merge(&other->sharedTables.item(i));
  8180. }
  8181. static HqlTransformerInfo implicitAliasTransformerInfo("ImplicitAliasTransformer");
  8182. ImplicitAliasTransformer::ImplicitAliasTransformer() : NewHqlTransformer(implicitAliasTransformerInfo)
  8183. {
  8184. seenShared = true;
  8185. seenAmbiguity = false;
  8186. }
  8187. void ImplicitAliasTransformer::analyseExpr(IHqlExpression * _expr)
  8188. {
  8189. IHqlExpression * body = _expr->queryBody();
  8190. if (alreadyVisited(body))
  8191. {
  8192. if ((pass == 0) && body->isDataset())
  8193. {
  8194. switch (body->getOperator())
  8195. {
  8196. case no_rows:
  8197. break;
  8198. default:
  8199. seenShared = true;
  8200. queryExtra(body)->shared.setown(new SharedTableInfo(body, 0));
  8201. break;
  8202. }
  8203. }
  8204. return;
  8205. }
  8206. NewHqlTransformer::analyseExpr(body);
  8207. if (pass == 0)
  8208. return;
  8209. ImplicitAliasTransformInfo * extra = queryExtra(body);
  8210. if (extra->shared)
  8211. extra->add(extra->shared);
  8212. switch (body->getOperator())
  8213. {
  8214. case no_activerow:
  8215. case no_filepos:
  8216. case no_file_logicalname:
  8217. case no_offsetof:
  8218. case no_joined:
  8219. case no_colon:
  8220. case no_globalscope:
  8221. case no_attr:
  8222. return;
  8223. case no_select:
  8224. {
  8225. bool isNew;
  8226. IHqlExpression * ds = querySelectorDataset(body, isNew);
  8227. if (isNew)
  8228. {
  8229. ImplicitAliasTransformInfo * dsExtra = queryExtra(ds->queryBody());
  8230. extra->inherit(dsExtra);
  8231. }
  8232. return;
  8233. }
  8234. }
  8235. IHqlExpression * dataset = NULL;
  8236. switch (getChildDatasetType(body))
  8237. {
  8238. case childdataset_none:
  8239. case childdataset_many_noscope:
  8240. case childdataset_many:
  8241. case childdataset_map:
  8242. case childdataset_dataset_noscope:
  8243. case childdataset_if:
  8244. case childdataset_case:
  8245. case childdataset_evaluate:
  8246. case childdataset_left:
  8247. case childdataset_leftright:
  8248. case childdataset_same_left_right:
  8249. case childdataset_nway_left_right:
  8250. break;
  8251. case childdataset_dataset:
  8252. case childdataset_datasetleft:
  8253. case childdataset_top_left_right:
  8254. dataset = body->queryChild(0)->queryBody();
  8255. break;
  8256. default:
  8257. UNIMPLEMENTED;
  8258. }
  8259. ForEachChild(i, body)
  8260. {
  8261. IHqlExpression * cur = body->queryChild(i);
  8262. ImplicitAliasTransformInfo * childExtra = queryExtra(cur->queryBody());
  8263. //If this is one of the arguments to an operation which has an active top dataset,
  8264. //check to see if any of the contained expressions reference this item
  8265. if (dataset && (i != 0))
  8266. {
  8267. SharedTableInfo * match = childExtra->uses(dataset);
  8268. if (match)
  8269. {
  8270. seenAmbiguity = true;
  8271. SharedTableInfo * nested = createAmbiguityInfo(match->dataset, match->depth+1);
  8272. extra->addAmbiguity(nested);
  8273. }
  8274. // dbglogExpr(_expr);
  8275. // DBGLOG("Implicit nested table ambiguity spotted in expression");
  8276. }
  8277. extra->inherit(childExtra);
  8278. }
  8279. }
  8280. SharedTableInfo * ImplicitAliasTransformer::createAmbiguityInfo(IHqlExpression * dataset, unsigned depth)
  8281. {
  8282. ForEachItemIn(i, ambiguousTables)
  8283. {
  8284. SharedTableInfo & cur = ambiguousTables.item(i);
  8285. if ((cur.dataset == dataset) && (depth == cur.depth))
  8286. return &cur;
  8287. }
  8288. ambiguousTables.append(*new SharedTableInfo(dataset, depth));
  8289. return &ambiguousTables.tos();
  8290. }
  8291. ANewTransformInfo * ImplicitAliasTransformer::createTransformInfo(IHqlExpression * expr)
  8292. {
  8293. return CREATE_NEWTRANSFORMINFO(ImplicitAliasTransformInfo, expr);
  8294. }
  8295. IHqlExpression * ImplicitAliasTransformer::createTransformed(IHqlExpression * expr)
  8296. {
  8297. IHqlExpression * body = expr->queryBody();
  8298. if (expr != body)
  8299. {
  8300. OwnedHqlExpr newBody = transform(body);
  8301. return expr->cloneAllAnnotations(newBody);
  8302. }
  8303. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  8304. updateOrphanedSelectors(transformed, expr);
  8305. ImplicitAliasTransformInfo * extra = queryExtra(body);
  8306. if (!extra->containsAmbiguity)
  8307. return transformed.getClear();
  8308. SharedTableInfo * match = extra->uses(body->queryChild(0)->queryBody());
  8309. assertex(match && match->depth != 0);
  8310. if (!match->uid)
  8311. match->uid.setown(createUniqueId());
  8312. OwnedHqlExpr aliased;
  8313. IHqlExpression * dataset = transformed->queryChild(0)->queryBody();
  8314. IHqlExpression * uid = match->uid;
  8315. aliased.setown(createDataset(no_dataset_alias, LINK(dataset), LINK(uid)));
  8316. //Replace dataset with an aliased variety, and remap all the selectors
  8317. HqlExprArray args;
  8318. args.append(*LINK(aliased));
  8319. replaceSelectors(args, transformed, 1, dataset->queryNormalizedSelector(), aliased->queryNormalizedSelector());
  8320. return transformed->clone(args);
  8321. }
  8322. void ImplicitAliasTransformer::process(HqlExprArray & exprs)
  8323. {
  8324. analyseArray(exprs, 0);
  8325. if (!seenShared)
  8326. return;
  8327. analyseArray(exprs, 1);
  8328. if (hasAmbiguity())
  8329. {
  8330. // DBGLOG("Implicit nested dataset ambiguity spotted in expression");
  8331. HqlExprArray transformed;
  8332. transformRoot(exprs, transformed);
  8333. replaceArray(exprs, transformed);
  8334. }
  8335. }
  8336. //---------------------------------------------------------------------------------------------------------------------
  8337. SharedTableInfo * LeftRightTransformInfo::uses(IHqlExpression * tableBody) const
  8338. {
  8339. ForEachItemIn(i, sharedTables)
  8340. {
  8341. SharedTableInfo & cur = sharedTables.item(i);
  8342. if (cur.dataset == tableBody)
  8343. return &cur;
  8344. }
  8345. return NULL;
  8346. }
  8347. void LeftRightTransformInfo::add(SharedTableInfo * table)
  8348. {
  8349. sharedTables.append(*LINK(table));
  8350. }
  8351. bool LeftRightTransformInfo::noteUsed(IHqlExpression * seq)
  8352. {
  8353. if (!seqs.contains(*seq))
  8354. seqs.append(*seq);
  8355. if (seqs.ordinality() > 1)
  8356. {
  8357. shared.setown(new SharedTableInfo(original, 0));
  8358. return true;
  8359. }
  8360. return false;
  8361. }
  8362. void LeftRightTransformInfo::addAmbiguity(SharedTableInfo * table)
  8363. {
  8364. containsAmbiguity = true;
  8365. merge(table);
  8366. }
  8367. void LeftRightTransformInfo::merge(SharedTableInfo * table)
  8368. {
  8369. ForEachItemIn(i, sharedTables)
  8370. {
  8371. SharedTableInfo & cur = sharedTables.item(i);
  8372. if (cur.dataset == table->dataset)
  8373. {
  8374. if (cur.depth < table->depth)
  8375. sharedTables.replace(*LINK(table), i);
  8376. return;
  8377. }
  8378. }
  8379. add(table);
  8380. }
  8381. void LeftRightTransformInfo::inherit(const LeftRightTransformInfo * other)
  8382. {
  8383. ForEachItemIn(i, other->sharedTables)
  8384. merge(&other->sharedTables.item(i));
  8385. }
  8386. static HqlTransformerInfo LeftRightTransformerInfo("LeftRightTransformer");
  8387. LeftRightTransformer::LeftRightTransformer() : NewHqlTransformer(LeftRightTransformerInfo)
  8388. {
  8389. seenShared = true;
  8390. }
  8391. void LeftRightTransformer::analyseExpr(IHqlExpression * _expr)
  8392. {
  8393. IHqlExpression * body = _expr->queryBody();
  8394. if (alreadyVisited(body))
  8395. return;
  8396. NewHqlTransformer::analyseExpr(body);
  8397. if (pass == 0)
  8398. {
  8399. //First pass gathers a list of selectors that are potentially ambiguous if the sequence was removed
  8400. IHqlExpression * left = NULL;
  8401. IHqlExpression * right = NULL;
  8402. switch (getChildDatasetType(body))
  8403. {
  8404. case childdataset_left:
  8405. case childdataset_datasetleft:
  8406. left = body->queryChild(0);
  8407. break;
  8408. case childdataset_same_left_right:
  8409. case childdataset_nway_left_right:
  8410. case childdataset_top_left_right:
  8411. left = body->queryChild(0);
  8412. right = body->queryChild(0);
  8413. break;
  8414. case childdataset_leftright:
  8415. left = body->queryChild(0);
  8416. right = body->queryChild(1);
  8417. break;
  8418. }
  8419. if (left)
  8420. {
  8421. LeftRightTransformInfo * extra = queryExtra(body);
  8422. IHqlExpression * selSeq = querySelSeq(body);
  8423. OwnedHqlExpr seq = createDummySelectorSequence();
  8424. extra->rawLeft.setown(createSelector(no_left, left, seq));
  8425. incUsage(extra->rawLeft, selSeq);
  8426. if (right)
  8427. {
  8428. //no_left is used deliberately in the following to avoid complications where right matches
  8429. //but left doesn't, causing the depths to be messed up.
  8430. extra->rawRight.setown(createSelector(no_left, right, seq));
  8431. if (extra->rawLeft != extra->rawRight)
  8432. incUsage(extra->rawRight, selSeq);
  8433. else
  8434. extra->rawRight.clear();
  8435. }
  8436. }
  8437. }
  8438. else
  8439. {
  8440. //Second pass - for each expression, gather a list of selectors that would actually be ambiguous.
  8441. LeftRightTransformInfo * extra = queryExtra(body);
  8442. IHqlExpression * rawLeft = extra->rawLeft;
  8443. IHqlExpression * rawRight = extra->rawRight;
  8444. //If LEFT is potentially ambiguous, then add it to the list of selectors used by this expression
  8445. if (rawLeft)
  8446. {
  8447. LeftRightTransformInfo * leftExtra = queryExtra(rawLeft);
  8448. if (leftExtra->shared)
  8449. extra->add(leftExtra->shared);
  8450. }
  8451. //Ditto for right
  8452. if (rawRight)
  8453. {
  8454. LeftRightTransformInfo * rightExtra = queryExtra(rawRight);
  8455. if (rightExtra->shared)
  8456. extra->add(rightExtra->shared);
  8457. }
  8458. switch (body->getOperator())
  8459. {
  8460. case no_activerow:
  8461. case no_filepos:
  8462. case no_file_logicalname:
  8463. case no_offsetof:
  8464. case no_joined:
  8465. case no_colon:
  8466. case no_globalscope:
  8467. case no_attr:
  8468. return;
  8469. case no_select:
  8470. {
  8471. bool isNew;
  8472. IHqlExpression * ds = querySelectorDataset(body, isNew);
  8473. if (isNew)
  8474. {
  8475. LeftRightTransformInfo * dsExtra = queryExtra(ds->queryBody());
  8476. extra->inherit(dsExtra);
  8477. }
  8478. return;
  8479. }
  8480. }
  8481. ForEachChild(i, body)
  8482. {
  8483. IHqlExpression * cur = body->queryChild(i);
  8484. LeftRightTransformInfo * childExtra = queryExtra(cur->queryBody());
  8485. //If this is one of the arguments to an operation which has an active top dataset,
  8486. //check to see if any of the contained expressions reference this item
  8487. if ((i != 0) && rawLeft)
  8488. {
  8489. SharedTableInfo * matchLeft = childExtra->uses(rawLeft);
  8490. SharedTableInfo * matchRight = rawRight ? childExtra->uses(rawRight) : NULL;
  8491. if (matchLeft || matchRight)
  8492. {
  8493. unsigned leftDepth = matchLeft ? matchLeft->depth : 0;
  8494. unsigned rightDepth = matchRight ? matchRight->depth : 0;
  8495. unsigned depth = leftDepth > rightDepth ? leftDepth : rightDepth;
  8496. SharedTableInfo * nested = createAmbiguityInfo(rawLeft, depth+1);
  8497. extra->addAmbiguity(nested);
  8498. if (rawRight)
  8499. {
  8500. SharedTableInfo * nested = createAmbiguityInfo(rawRight, depth+1);
  8501. extra->addAmbiguity(nested);
  8502. }
  8503. }
  8504. }
  8505. extra->inherit(childExtra);
  8506. }
  8507. }
  8508. }
  8509. void LeftRightTransformer::incUsage(IHqlExpression * expr, IHqlExpression * seq)
  8510. {
  8511. //MORE: Needs to keep track of the sequences that were used with it, so know if needs disambiguating.
  8512. LeftRightTransformInfo * extra = queryExtra(expr);
  8513. if (extra->noteUsed(seq))
  8514. seenShared = true;
  8515. }
  8516. SharedTableInfo * LeftRightTransformer::createAmbiguityInfo(IHqlExpression * dataset, unsigned depth)
  8517. {
  8518. ForEachItemIn(i, ambiguousTables)
  8519. {
  8520. SharedTableInfo & cur = ambiguousTables.item(i);
  8521. if ((cur.dataset == dataset) && (depth == cur.depth))
  8522. return &cur;
  8523. }
  8524. ambiguousTables.append(*new SharedTableInfo(dataset, depth));
  8525. return &ambiguousTables.tos();
  8526. }
  8527. ANewTransformInfo * LeftRightTransformer::createTransformInfo(IHqlExpression * expr)
  8528. {
  8529. return CREATE_NEWTRANSFORMINFO(LeftRightTransformInfo, expr);
  8530. }
  8531. IHqlExpression * LeftRightTransformer::createTransformed(IHqlExpression * expr)
  8532. {
  8533. IHqlExpression * body = expr->queryBody();
  8534. if (expr != body)
  8535. {
  8536. OwnedHqlExpr newBody = transform(body);
  8537. return expr->cloneAllAnnotations(newBody);
  8538. }
  8539. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  8540. updateOrphanedSelectors(transformed, expr);
  8541. LeftRightTransformInfo * extra = queryExtra(body);
  8542. SharedTableInfo * matchLeft = extra->rawLeft ? extra->uses(extra->rawLeft) : NULL;
  8543. if (matchLeft)
  8544. {
  8545. childDatasetType dsType = getChildDatasetType(expr);
  8546. IHqlExpression * left = transformed->queryChild(0);
  8547. IHqlExpression * right = hasRight(dsType) ? (hasSameLeftRight(dsType) ? left : transformed->queryChild(1)) : NULL;
  8548. IHqlExpression * oldSelSeq = querySelSeq(expr);
  8549. OwnedHqlExpr newSelSeq = createSelectorSequence(matchLeft->depth);
  8550. OwnedHqlExpr oldLeft = createSelector(no_left, left, oldSelSeq);
  8551. OwnedHqlExpr newLeft = createSelector(no_left, left, newSelSeq);
  8552. //Replace dataset with an aliased variety, and remap all the selectors
  8553. HqlExprArray mapped;
  8554. replaceSelectors(mapped, transformed, 1, oldLeft, newLeft);
  8555. if (right)
  8556. {
  8557. OwnedHqlExpr oldRight = createSelector(no_right, right, oldSelSeq);
  8558. OwnedHqlExpr newRight = createSelector(no_right, right, newSelSeq);
  8559. unsigned firstArg = (hasSameLeftRight(dsType) ? 0 : 1);
  8560. replaceSelectors(mapped, firstArg, oldRight, newRight);
  8561. }
  8562. HqlExprArray args;
  8563. args.append(*LINK(left));
  8564. appendArray(args, mapped);
  8565. args.zap(*oldSelSeq);
  8566. args.append(*LINK(newSelSeq));
  8567. transformed.setown(transformed->clone(args));
  8568. }
  8569. return transformed.getClear();
  8570. }
  8571. void LeftRightTransformer::process(HqlExprArray & exprs)
  8572. {
  8573. analyseArray(exprs, 0);
  8574. if (!seenShared)
  8575. return;
  8576. analyseArray(exprs, 1);
  8577. HqlExprArray transformed;
  8578. transformRoot(exprs, transformed);
  8579. replaceArray(exprs, transformed);
  8580. }
  8581. //---------------------------------------------------------------------------------------------------------------------
  8582. /*
  8583. Common up expressions so that all references to the same expression have identical symbols, annotations.
  8584. Generally it improves the code a lot - especially when macros are used. However there are occasional problems....
  8585. a) ut.CleanCompany(ds.x) and ut.cleanCompany(left.x).
  8586. 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
  8587. then test to see if something is sorted it can incorrectly mismatch (see busheader.xhql dnb_combined_append)
  8588. */
  8589. static void unwindAnnotations(HqlExprCopyArray & unwound, IHqlExpression * expr)
  8590. {
  8591. if (expr->getAnnotationKind() == annotate_none)
  8592. return;
  8593. unwindAnnotations(unwound, expr->queryBody(true));
  8594. unwound.append(*expr);
  8595. }
  8596. IHqlExpression * AnnotationTransformInfo::cloneAnnotations(IHqlExpression * newBody)
  8597. {
  8598. if (annotations.ordinality() == 0)
  8599. return LINK(newBody);
  8600. return annotations.item(0).cloneAllAnnotations(newBody);
  8601. LinkedHqlExpr ret = newBody;
  8602. #if 1
  8603. ForEachItemIn(i, annotations)
  8604. ret.setown(annotations.item(i).cloneAllAnnotations(ret));
  8605. #else
  8606. //Code saved once we start removing duplicate annotations (e.g., locations)
  8607. HqlExprCopyArray toApply;
  8608. ForEachItemIn(i, annotations)
  8609. unwindAnnotations(toApply, &annotations.item(i));
  8610. ForEachItemIn(i2, toApply)
  8611. {
  8612. IHqlExpression & curAnnotate = toApply.item(i2);
  8613. ret.setown(curAnnotate.cloneAnnotation(ret));
  8614. }
  8615. #endif
  8616. return ret.getClear();
  8617. }
  8618. void AnnotationTransformInfo::noteAnnotation(IHqlExpression * annotation)
  8619. {
  8620. //MORE: Need more intelligence to see if this is a subset of what we already have..
  8621. annotations.append(*annotation);
  8622. }
  8623. static HqlTransformerInfo annotationNormalizerInfo("AnnotationNormalizerTransformer");
  8624. AnnotationNormalizerTransformer::AnnotationNormalizerTransformer()
  8625. : NewHqlTransformer(annotationNormalizerInfo)
  8626. {
  8627. }
  8628. ANewTransformInfo * AnnotationNormalizerTransformer::createTransformInfo(IHqlExpression * expr)
  8629. {
  8630. return CREATE_NEWTRANSFORMINFO(AnnotationTransformInfo, expr);
  8631. }
  8632. void AnnotationNormalizerTransformer::analyseExpr(IHqlExpression * expr)
  8633. {
  8634. if (alreadyVisited(expr))
  8635. return;
  8636. IHqlExpression * body = expr->queryBody();
  8637. if (expr != body)
  8638. {
  8639. queryCommonExtra(body)->noteAnnotation(expr);
  8640. //Note: expr already tested if expr == body...
  8641. if (alreadyVisited(body))
  8642. return;
  8643. }
  8644. node_operator op = body->getOperator();
  8645. switch (op)
  8646. {
  8647. case no_attr_expr:
  8648. analyseChildren(body);
  8649. return;
  8650. }
  8651. NewHqlTransformer::analyseExpr(body);
  8652. }
  8653. IHqlExpression * AnnotationNormalizerTransformer::createTransformed(IHqlExpression * expr)
  8654. {
  8655. node_operator op = expr->getOperator();
  8656. IHqlExpression * body = expr->queryBody();
  8657. switch (op)
  8658. {
  8659. case no_list:
  8660. {
  8661. if (body->numChildren() == 0)
  8662. return LINK(body);
  8663. break;
  8664. }
  8665. case no_constant:
  8666. // case no_null:
  8667. {
  8668. //AnnotationTransformInfo * extra = queryCommonExtra(body);
  8669. //Don't common up the location information for this, otherwise it gets silly! Possibly worth removing altogether if ambiguous?
  8670. //MORE: This should probably depend on whether there is more than one annotation on the constant.
  8671. return LINK(body);
  8672. }
  8673. }
  8674. if (expr != body)
  8675. return transform(body);
  8676. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  8677. return queryCommonExtra(body)->cloneAnnotations(transformed);
  8678. }
  8679. AnnotationTransformInfo * AnnotationNormalizerTransformer::queryCommonExtra(IHqlExpression * expr)
  8680. {
  8681. return static_cast<AnnotationTransformInfo *>(queryTransformExtra(queryLocationIndependent(expr)));
  8682. }
  8683. void normalizeAnnotations(HqlCppTranslator & translator, HqlExprArray & exprs)
  8684. {
  8685. //First iterate through the expressions and call queryLocationIndependent() to avoid nested transforms (which are less efficient)
  8686. ForEachItemIn(iInit, exprs)
  8687. queryLocationIndependent(&exprs.item(iInit));
  8688. translator.traceExpressions("before annotation normalize", exprs);
  8689. unsigned time = msTick();
  8690. AnnotationNormalizerTransformer normalizer;
  8691. HqlExprArray transformed;
  8692. normalizer.analyseArray(exprs, 0);
  8693. normalizer.transformRoot(exprs, transformed);
  8694. replaceArray(exprs, transformed);
  8695. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.annotations", msTick()-time);
  8696. }
  8697. void normalizeAnnotations(HqlCppTranslator & translator, WorkflowArray & workflow)
  8698. {
  8699. ForEachItemIn(i, workflow)
  8700. normalizeAnnotations(translator, workflow.item(i).queryExprs());
  8701. }
  8702. //---------------------------------------------------------------------------
  8703. static HqlTransformerInfo containsCompoundTransformerInfo("ContainsCompoundTransformer");
  8704. ContainsCompoundTransformer::ContainsCompoundTransformer()
  8705. : QuickHqlTransformer(containsCompoundTransformerInfo, NULL)
  8706. {
  8707. containsCompound = false;
  8708. }
  8709. //NB: This cannot be short circuited, because it is also gathering information about whether or
  8710. void ContainsCompoundTransformer::doAnalyseBody(IHqlExpression * expr)
  8711. {
  8712. if (containsCompound)
  8713. return;
  8714. switch (expr->getOperator())
  8715. {
  8716. case no_compound:
  8717. if (!expr->isAction())
  8718. {
  8719. containsCompound = true;
  8720. return;
  8721. }
  8722. break;
  8723. case no_colon:
  8724. case no_cluster:
  8725. case no_sequential:
  8726. case no_allnodes:
  8727. case no_thisnode:
  8728. //Need to recursively handle these
  8729. containsCompound = true;
  8730. return;
  8731. case no_record:
  8732. case no_field:
  8733. case no_attr:
  8734. case no_attr_link:
  8735. case no_left:
  8736. case no_right:
  8737. case no_self:
  8738. case no_top:
  8739. case no_workunit_dataset:
  8740. case no_assertwild:
  8741. case no_getresult:
  8742. case no_getgraphresult:
  8743. case no_activerow:
  8744. case no_newkeyindex:
  8745. return;
  8746. case no_list:
  8747. if (expr->isConstant())
  8748. return;
  8749. break;
  8750. case no_select:
  8751. // if (expr->hasProperty(newAtom))
  8752. analyse(expr->queryChild(0));
  8753. return;
  8754. case no_assign:
  8755. analyse(expr->queryChild(1));
  8756. return;
  8757. }
  8758. QuickHqlTransformer::doAnalyseBody(expr);
  8759. }
  8760. bool containsCompound(const HqlExprArray & exprs)
  8761. {
  8762. ContainsCompoundTransformer spotter;
  8763. spotter.analyseArray(exprs);
  8764. return spotter.containsCompound;
  8765. }
  8766. bool containsCompound(IHqlExpression * expr)
  8767. {
  8768. ContainsCompoundTransformer spotter;
  8769. spotter.analyse(expr);
  8770. return spotter.containsCompound;
  8771. }
  8772. static HqlTransformerInfo nestedCompoundTransformerInfo("NestedCompoundTransformer");
  8773. NestedCompoundTransformer::NestedCompoundTransformer(HqlCppTranslator & _translator)
  8774. : HoistingHqlTransformer(nestedCompoundTransformerInfo, CTFnoteifactions), translator(_translator), translatorOptions(_translator.queryOptions())
  8775. {
  8776. }
  8777. //For the moment allow simple external calls in scalar setting
  8778. //to make logging much easier...
  8779. static bool isSimpleSideeffect(IHqlExpression * expr)
  8780. {
  8781. switch (expr->getOperator())
  8782. {
  8783. case no_externalcall:
  8784. case no_attr:
  8785. case no_attr_expr:
  8786. case no_attr_link:
  8787. return true;
  8788. case no_comma:
  8789. case no_compound:
  8790. case no_parallel:
  8791. {
  8792. ForEachChild(i, expr)
  8793. {
  8794. if (!isSimpleSideeffect(expr->queryChild(i)))
  8795. return false;
  8796. }
  8797. return true;
  8798. }
  8799. case no_if:
  8800. {
  8801. ForEachChildFrom(i, expr, 1)
  8802. {
  8803. if (!isSimpleSideeffect(expr->queryChild(i)))
  8804. return false;
  8805. }
  8806. return true;
  8807. }
  8808. }
  8809. return false;
  8810. }
  8811. static bool isCalloutSideeffect(IHqlExpression * expr)
  8812. {
  8813. if (!expr->queryType()->isScalar())
  8814. return false;
  8815. return isSimpleSideeffect(expr->queryChild(0));
  8816. }
  8817. IHqlExpression * NestedCompoundTransformer::createTransformed(IHqlExpression * expr)
  8818. {
  8819. if (expr->isConstant())
  8820. return LINK(expr);
  8821. IHqlExpression * ret = queryTransformAnnotation(expr);
  8822. if (ret)
  8823. return ret;
  8824. node_operator op = expr->getOperator();
  8825. switch (op)
  8826. {
  8827. case no_compound:
  8828. if (isUsedUnconditionally(expr) && !expr->isAction() && !isCalloutSideeffect(expr))
  8829. {
  8830. IHqlExpression * sideEffect = expr->queryChild(0);
  8831. IHqlExpression * value = expr->queryChild(1);
  8832. if (!isIndependentOfScope(sideEffect))
  8833. {
  8834. StringBuffer s;
  8835. if (sideEffect->queryName())
  8836. s.appendf(" '%s'", sideEffect->queryName()->str());
  8837. else if (value->queryName())
  8838. s.appendf(" '%s'", value->queryName()->str());
  8839. else
  8840. s.append(" ").append(getOpString(sideEffect->getOperator()));
  8841. IHqlExpression * location = queryLocation(sideEffect);
  8842. if (!location)
  8843. location = queryLocation(value);
  8844. if (!location)
  8845. location = queryActiveLocation();
  8846. if (!isSimpleSideeffect(sideEffect))
  8847. {
  8848. //MORE: This should be an error, but there are still occasional false positives e.g., OUTPUT(ds1.childds)
  8849. //so needs to stay a warning.
  8850. // translator.ERRORAT1(location, HQLERR_GlobalSideEffectDependent, s.str());
  8851. translator.WARNINGAT1(location, HQLWRN_GlobalSideEffectDependent, s.str());
  8852. }
  8853. break;
  8854. }
  8855. if (!translatorOptions.workunitTemporaries)
  8856. {
  8857. StringBuffer s;
  8858. if (expr->queryName())
  8859. s.append(expr->queryName()).append(": ");
  8860. getExprECL(sideEffect, s);
  8861. throwError1(HQLERR_LibrariesCannotContainSideEffects, s.str());
  8862. }
  8863. appendToTarget(*transform(sideEffect));
  8864. return transform(value);
  8865. }
  8866. break;
  8867. }
  8868. return HoistingHqlTransformer::createTransformed(expr);
  8869. }
  8870. //---------------------------------------------------------------------------
  8871. class LocationInfo : public CInterface
  8872. {
  8873. public:
  8874. HqlExprArray matches;
  8875. };
  8876. static HqlTransformerInfo duplicateCodeSpotterInfo("DuplicateCodeSpotter");
  8877. class DuplicateCodeSpotter : public QuickHqlTransformer
  8878. {
  8879. public:
  8880. DuplicateCodeSpotter() : QuickHqlTransformer(duplicateCodeSpotterInfo, NULL) {}
  8881. inline bool checkExpr(IHqlExpression * expr)
  8882. {
  8883. if (!expr->isDataset())
  8884. return false;
  8885. switch (expr->getOperator())
  8886. {
  8887. case no_join:
  8888. break;
  8889. default:
  8890. return false;
  8891. }
  8892. if (expr->queryName() != createIdentifierAtom("ds_raw"))
  8893. return false;
  8894. return true;
  8895. }
  8896. virtual void doAnalyse(IHqlExpression * expr)
  8897. {
  8898. if (checkExpr(expr))
  8899. {
  8900. IHqlExpression * location = queryLocation(expr);
  8901. if (location)
  8902. {
  8903. OwnedHqlExpr attr = createLocationAttr(location->querySourcePath(), location->getStartLine(), location->getStartColumn(), 0);
  8904. Linked<LocationInfo> info;
  8905. Shared<LocationInfo> * match = map.getValue(attr);
  8906. if (match)
  8907. info.set(*match);
  8908. else
  8909. {
  8910. info.setown(new LocationInfo);
  8911. map.setValue(attr, info);
  8912. }
  8913. IHqlExpression * body = expr->queryBody();
  8914. if (!info->matches.contains(*body))
  8915. {
  8916. ForEachItemIn(i, info->matches)
  8917. {
  8918. debugFindFirstDifference(body, &info->matches.item(i));
  8919. }
  8920. info->matches.append(*LINK(body));
  8921. }
  8922. }
  8923. }
  8924. QuickHqlTransformer::doAnalyse(expr);
  8925. }
  8926. MapOwnedToOwned<IHqlExpression, LocationInfo> map;
  8927. };
  8928. void spotPotentialDuplicateCode(HqlExprArray & exprs)
  8929. {
  8930. DuplicateCodeSpotter spotter;
  8931. spotter.analyseArray(exprs);
  8932. }
  8933. //---------------------------------------------------------------------------
  8934. static bool isUniqueAttributeName(_ATOM name)
  8935. {
  8936. const char * nameText = name->str();
  8937. unsigned len = strlen(nameText);
  8938. if (len > 3)
  8939. {
  8940. if ((nameText[len-2] == '_') && (nameText[len-1] == '_') && isdigit((unsigned char)nameText[len-3]))
  8941. return true;
  8942. }
  8943. return false;
  8944. }
  8945. static _ATOM simplifyUniqueAttributeName(_ATOM name)
  8946. {
  8947. //Rename all attributes __x__1234__ to __x__
  8948. const char * nameText = name->str();
  8949. unsigned len = strlen(nameText);
  8950. if (len > 3)
  8951. {
  8952. if ((nameText[len-2] == '_') && (nameText[len-1] == '_') && isdigit((unsigned char)nameText[len-3]))
  8953. {
  8954. len -= 3;
  8955. while (len && isdigit((unsigned char)nameText[len-1]))
  8956. len--;
  8957. if (len)
  8958. {
  8959. StringAttr truncName;
  8960. truncName.set(nameText, len);
  8961. return createIdentifierAtom(truncName);
  8962. }
  8963. }
  8964. }
  8965. return NULL;
  8966. }
  8967. static bool exprIsSelfConstant(IHqlExpression * expr)
  8968. {
  8969. if (expr->isConstant())
  8970. return true;
  8971. switch (expr->getOperator())
  8972. {
  8973. case no_select:
  8974. {
  8975. IHqlExpression * selector = expr->queryChild(0);
  8976. while (selector->getOperator() == no_select)
  8977. selector = selector->queryChild(0);
  8978. return (selector->getOperator() == no_selfref);
  8979. }
  8980. }
  8981. if (expr->isDataset() && (getNumChildTables(expr) == 0))
  8982. return false;
  8983. ForEachChild(i, expr)
  8984. {
  8985. IHqlExpression * cur = expr->queryChild(i);
  8986. if (!exprIsSelfConstant(cur))
  8987. return false;
  8988. }
  8989. return true;
  8990. }
  8991. static _ATOM queryPatUseModule(IHqlExpression * expr)
  8992. {
  8993. IHqlExpression * moduleAttr = expr->queryProperty(moduleAtom);
  8994. if (moduleAttr)
  8995. return moduleAttr->queryChild(0)->queryBody()->queryName();
  8996. return NULL;
  8997. }
  8998. static _ATOM queryPatUseName(IHqlExpression * expr)
  8999. {
  9000. IHqlExpression * nameAttr = expr->queryProperty(nameAtom);
  9001. return nameAttr->queryChild(0)->queryBody()->queryName();
  9002. }
  9003. void HqlTreeNormalizerInfo::noteSymbol(IHqlExpression * _symbol)
  9004. {
  9005. if (!symbol || isUniqueAttributeName(symbol->queryName()))
  9006. symbol = _symbol;
  9007. }
  9008. static HqlTransformerInfo hqlTreeNormalizerInfo("HqlTreeNormalizer");
  9009. HqlTreeNormalizer::HqlTreeNormalizer(HqlCppTranslator & _translator) : NewHqlTransformer(hqlTreeNormalizerInfo), translator(_translator)
  9010. {
  9011. seenForceLocal = false;
  9012. seenLocalUpload = false;
  9013. const HqlCppOptions & translatorOptions = translator.queryOptions();
  9014. options.removeAsserts = !translatorOptions.checkAsserts;
  9015. options.commonUniqueNameAttributes = translatorOptions.commonUniqueNameAttributes;
  9016. options.simplifySelectorSequence = !translatorOptions.preserveUniqueSelector && !translatorOptions.detectAmbiguousSelector && !translatorOptions.allowAmbiguousSelector;
  9017. options.sortIndexPayload = translatorOptions.sortIndexPayload;
  9018. options.allowSections = translatorOptions.allowSections;
  9019. options.normalizeExplicitCasts = translatorOptions.normalizeExplicitCasts;
  9020. options.ensureRecordsHaveSymbols = translatorOptions.ensureRecordsHaveSymbols;
  9021. options.outputRowsAsDatasets = translator.targetRoxie();
  9022. options.constantFoldNormalize = translatorOptions.constantFoldNormalize;
  9023. options.allowActivityForKeyedJoin = translatorOptions.allowActivityForKeyedJoin;
  9024. options.implicitShuffle = translatorOptions.implicitBuildIndexShuffle;
  9025. errors = translator.queryErrors();
  9026. nextSequenceValue = 1;
  9027. }
  9028. ANewTransformInfo * HqlTreeNormalizer::createTransformInfo(IHqlExpression * expr)
  9029. {
  9030. return CREATE_NEWTRANSFORMINFO(HqlTreeNormalizerInfo, expr);
  9031. }
  9032. HqlTreeNormalizerInfo * HqlTreeNormalizer::queryCommonExtra(IHqlExpression * expr)
  9033. {
  9034. return static_cast<HqlTreeNormalizerInfo *>(queryTransformExtra(queryLocationIndependent(expr)));
  9035. }
  9036. void HqlTreeNormalizer::convertRecordToAssigns(HqlExprArray & assigns, IHqlExpression * oldRecord, IHqlExpression * targetSelector, bool canOmit, bool convertTempTable)
  9037. {
  9038. ForEachChild(idx, oldRecord)
  9039. {
  9040. IHqlExpression * oldField = oldRecord->queryChild(idx);
  9041. OwnedHqlExpr newField = transform(oldField);
  9042. switch (oldField->getOperator())
  9043. {
  9044. case no_ifblock:
  9045. convertRecordToAssigns(assigns, oldField->queryChild(1), targetSelector, canOmit, convertTempTable);
  9046. break;
  9047. case no_record:
  9048. convertRecordToAssigns(assigns, oldField, targetSelector, canOmit, convertTempTable);
  9049. break;
  9050. case no_field:
  9051. {
  9052. IHqlExpression * oldFieldRecord = oldField->queryRecord();
  9053. IHqlExpression * value = queryRealChild(oldField, 0);
  9054. OwnedHqlExpr newTargetSelector = createSelectExpr(LINK(targetSelector), LINK(newField));
  9055. if (oldFieldRecord && !oldField->isDataset() && !value)
  9056. {
  9057. if (convertTempTable)
  9058. convertRecordToAssigns(assigns, oldFieldRecord, newTargetSelector, canOmit, convertTempTable);
  9059. else
  9060. {
  9061. IHqlExpression * newRecord = newField->queryRecord();
  9062. OwnedHqlExpr newSelf = getSelf(newRecord);
  9063. HqlExprArray newAssigns;
  9064. convertRecordToAssigns(newAssigns, oldFieldRecord, newSelf, canOmit, convertTempTable);
  9065. IHqlExpression * transform = createValue(no_newtransform, makeTransformType(newRecord->getType()), newAssigns);
  9066. IHqlExpression * newValue = createRow(no_createrow, transform);
  9067. assigns.append(*createAssign(LINK(newTargetSelector), newValue));
  9068. }
  9069. }
  9070. else
  9071. {
  9072. assertex(value || canOmit);
  9073. if (value && (!convertTempTable || exprIsSelfConstant(value)))
  9074. assigns.append(*createAssign(LINK(newTargetSelector), transform(value)));
  9075. if (oldFieldRecord && convertTempTable)
  9076. assigns.append(*createExprAttribute(defaultAtom, createExprAttribute(defaultAtom, LINK(newTargetSelector)), convertRecordToAssigns(oldFieldRecord, canOmit, convertTempTable)));
  9077. }
  9078. break;
  9079. }
  9080. case no_attr:
  9081. case no_attr_link:
  9082. case no_attr_expr:
  9083. break;
  9084. default:
  9085. UNIMPLEMENTED;
  9086. }
  9087. }
  9088. }
  9089. IHqlExpression * HqlTreeNormalizer::convertRecordToAssigns(IHqlExpression * oldRecord, bool canOmit, bool convertTempTable)
  9090. {
  9091. OwnedHqlExpr newRecord = transform(oldRecord);
  9092. HqlExprArray assigns;
  9093. OwnedHqlExpr self = getSelf(newRecord);
  9094. convertRecordToAssigns(assigns, oldRecord, self, canOmit, convertTempTable);
  9095. return createValue(no_transform, makeTransformType(newRecord->getType()), assigns);
  9096. }
  9097. // Problems occur if a record used in a select fields is also used for some other linked purpose.
  9098. // Thankfully the only one so far is BUILDINDEX(index)
  9099. IHqlExpression * HqlTreeNormalizer::convertSelectToProject(IHqlExpression * newRecord, IHqlExpression * expr)
  9100. {
  9101. OwnedHqlExpr newDataset = transform(expr->queryChild(0));
  9102. IHqlExpression * oldRecord = expr->queryChild(1);
  9103. if (oldRecord->getOperator() == no_null)
  9104. return newDataset.getClear();
  9105. HqlExprArray assigns;
  9106. OwnedHqlExpr self = getSelf(newRecord);
  9107. convertRecordToAssigns(assigns, oldRecord, self, false, false);
  9108. OwnedHqlExpr newTransform = createValue(no_newtransform, makeTransformType(LINK(newRecord->queryRecordType())), assigns);
  9109. newTransform.setown(newRecord->cloneAllAnnotations(newTransform));
  9110. HqlExprArray args;
  9111. args.append(*newDataset.getClear());
  9112. args.append(*LINK(newRecord));
  9113. args.append(*newTransform.getClear());
  9114. unsigned numChildren = expr->numChildren();
  9115. for (unsigned idx = 2; idx < numChildren; idx++)
  9116. args.append(*transform(expr->queryChild(idx)));
  9117. OwnedHqlExpr project = createDataset(no_newusertable, args);
  9118. return expr->cloneAllAnnotations(project);
  9119. }
  9120. IHqlExpression * HqlTreeNormalizer::removeDefaultsFromExpr(IHqlExpression * expr, unsigned recordChildIndex, node_operator newOp)
  9121. {
  9122. IHqlExpression * oldRecord = expr->queryChild(recordChildIndex);
  9123. OwnedHqlExpr newRecord = transform(oldRecord);
  9124. IHqlExpression * ds = expr->queryChild(0);
  9125. HqlExprArray assigns;
  9126. OwnedHqlExpr self = getSelf(newRecord);
  9127. convertRecordToAssigns(assigns, oldRecord, self, false, false);
  9128. IHqlExpression * newTransform = createValue(no_newtransform, makeTransformType(LINK(newRecord->queryRecordType())), assigns);
  9129. HqlExprArray args;
  9130. args.append(*transform(expr->queryChild(0)));
  9131. for (unsigned i= 1; i < recordChildIndex; i++)
  9132. args.append(*transform(expr->queryChild(i)));
  9133. args.append(*LINK(newRecord));
  9134. args.append(*newTransform);
  9135. unsigned numChildren = expr->numChildren();
  9136. for (unsigned idx = recordChildIndex+1; idx < numChildren; idx++)
  9137. args.append(*transform(expr->queryChild(idx)));
  9138. OwnedHqlExpr project;
  9139. if (expr->isDataset())
  9140. project.setown(createDataset(newOp, args));
  9141. else if (expr->isDatarow())
  9142. project.setown(createRow(newOp, args));
  9143. else
  9144. project.setown(createValue(newOp, makeVoidType(), args));
  9145. return expr->cloneAllAnnotations(project);
  9146. }
  9147. ITypeInfo * HqlTreeNormalizer::transformType(ITypeInfo * type)
  9148. {
  9149. switch (type->queryModifier())
  9150. {
  9151. case typemod_original:
  9152. {
  9153. switch (type->getTypeCode())
  9154. {
  9155. case type_record:
  9156. case type_transform:
  9157. case type_row:
  9158. case type_table:
  9159. case type_groupedtable:
  9160. //Strip all original annotations - they cause branches to not be commoned up
  9161. return transformType(type->queryTypeBase());
  9162. }
  9163. //But keep annotations used for typedef information, they should probably work differently
  9164. break;
  9165. }
  9166. case typemod_none:
  9167. {
  9168. //Ensure all records with the same format get the same original modifier
  9169. Owned<ITypeInfo> transformedType = NewHqlTransformer::transformType(type);
  9170. if (type->getTypeCode() == type_record)
  9171. {
  9172. IHqlExpression * record = queryExpression(type);
  9173. if (record && record->getOperator() == no_record)
  9174. {
  9175. OwnedHqlExpr transformedRecord = transform(record);
  9176. if (transformedRecord->queryBody() != transformedRecord)
  9177. return makeOriginalModifier(LINK(transformedType), LINK(transformedRecord));
  9178. }
  9179. }
  9180. return transformedType.getClear();
  9181. }
  9182. break;
  9183. }
  9184. return NewHqlTransformer::transformType(type);
  9185. }
  9186. bool isVoidOrDatasetOrList(IHqlExpression * expr)
  9187. {
  9188. ITypeInfo * type = expr->queryType();
  9189. switch (type->getTypeCode())
  9190. {
  9191. case type_void:
  9192. case type_table:
  9193. case type_row:
  9194. case type_groupedtable:
  9195. case type_set:
  9196. return true;
  9197. default:
  9198. return false;
  9199. }
  9200. }
  9201. inline IHqlExpression * createColon(IHqlExpression * l, HqlExprArray & actions)
  9202. {
  9203. HqlExprArray args;
  9204. args.append(*l);
  9205. ForEachItemIn(i, actions)
  9206. args.append(OLINK(actions.item(i)));
  9207. return createWrapper(no_colon, args);
  9208. }
  9209. void HqlTreeNormalizer::analyseExpr(IHqlExpression * expr)
  9210. {
  9211. IHqlExpression * body = expr->queryBody();
  9212. node_operator op = body->getOperator();
  9213. if ((op == no_record) && (expr != body))
  9214. {
  9215. IHqlExpression * symbol = queryNamedSymbol(expr);
  9216. if (symbol)
  9217. queryCommonExtra(body)->noteSymbol(expr);
  9218. }
  9219. if (alreadyVisited(body))
  9220. return;
  9221. //Record a list of all USE(name[,name]) so we know what needs fixing up, and all patterns with explicit defines already
  9222. switch (op)
  9223. {
  9224. case no_pat_use:
  9225. if (body->hasProperty(nameAtom))
  9226. forwardReferences.append(*LINK(body));
  9227. break;
  9228. case no_pat_instance:
  9229. if (body->queryChild(0)->getOperator() == no_define)
  9230. defines.append(*LINK(body));
  9231. break;
  9232. case no_libraryscopeinstance:
  9233. analyseExpr(body->queryDefinition());
  9234. break;
  9235. case no_transform:
  9236. case no_call:
  9237. case no_externalcall:
  9238. {
  9239. IHqlExpression * record = queryOriginalRecord(body->queryType());
  9240. if (record)
  9241. analyseExpr(record);
  9242. break;
  9243. }
  9244. case no_attr_expr:
  9245. case no_record:
  9246. case no_ifblock:
  9247. case no_select:
  9248. analyseChildren(body);
  9249. return;
  9250. case no_field:
  9251. {
  9252. IHqlExpression * record = queryOriginalRecord(body->queryType());
  9253. if (record)
  9254. analyseExpr(record);
  9255. analyseChildren(body);
  9256. break;
  9257. }
  9258. }
  9259. Parent::analyseExpr(body);
  9260. }
  9261. IHqlExpression * HqlTreeNormalizer::makeRecursiveName(_ATOM searchModule, _ATOM searchName)
  9262. {
  9263. //If this symbol is already has a user define, use that instead of creating our own,
  9264. //because I don't cope very well with multiple defines on the same pattern instance.
  9265. ForEachItemIn(i, defines)
  9266. {
  9267. IHqlExpression & cur = defines.item(i);
  9268. IHqlExpression * moduleExpr = cur.queryChild(2);
  9269. _ATOM module = moduleExpr ? moduleExpr->queryBody()->queryName() : NULL;
  9270. _ATOM name = cur.queryChild(1)->queryBody()->queryName();
  9271. if (name == searchName && module == searchModule)
  9272. return LINK(cur.queryChild(0)->queryChild(1));
  9273. }
  9274. StringBuffer s;
  9275. s.append("$").append(searchModule).append(".").append(searchName);
  9276. return createConstant(s.str());
  9277. }
  9278. IHqlExpression * HqlTreeNormalizer::queryTransformPatternDefine(IHqlExpression * expr)
  9279. {
  9280. if (expr->queryChild(0)->getOperator() == no_define)
  9281. return NULL;
  9282. IHqlExpression * moduleExpr = expr->queryChild(2);
  9283. _ATOM module = moduleExpr ? moduleExpr->queryBody()->queryName() : NULL;
  9284. _ATOM name = expr->queryChild(1)->queryBody()->queryName();
  9285. ForEachItemIn(i, forwardReferences)
  9286. {
  9287. IHqlExpression * cur = &forwardReferences.item(i);
  9288. if ((name == queryPatUseName(cur)) && (module == queryPatUseModule(cur)))
  9289. {
  9290. IHqlExpression * base = transform(expr->queryChild(0));
  9291. HqlExprArray args;
  9292. args.append(*createValue(no_define, base->getType(), base, makeRecursiveName(module, name)));
  9293. unwindChildren(args, expr, 1);
  9294. return expr->clone(args);
  9295. }
  9296. }
  9297. return NULL;
  9298. }
  9299. IHqlExpression * HqlTreeNormalizer::transformActionList(IHqlExpression * expr)
  9300. {
  9301. HqlExprArray args;
  9302. ForEachChild(i, expr)
  9303. {
  9304. IHqlExpression * cur = expr->queryChild(i);
  9305. if (cur->getOperator() != no_setmeta)
  9306. {
  9307. OwnedHqlExpr transformed = transform(cur);
  9308. if ((transformed->getOperator() != no_null) || !transformed->isAction())
  9309. args.append(*transformed.getClear());
  9310. }
  9311. }
  9312. return createActionList(args);
  9313. }
  9314. IHqlExpression * HqlTreeNormalizer::transformCase(IHqlExpression * expr)
  9315. {
  9316. unsigned max = numRealChildren(expr);
  9317. OwnedHqlExpr testVar = transform(expr->queryChild(0));
  9318. OwnedHqlExpr elseExpr = transform(expr->queryChild(max-1));
  9319. for (unsigned idx = max-2; idx != 0; idx--)
  9320. {
  9321. IHqlExpression * cur = expr->queryChild(idx);
  9322. IHqlExpression * curValue = cur->queryChild(0);
  9323. Owned<ITypeInfo> type = ::getPromotedECLType(testVar->queryType(), curValue->queryType());
  9324. OwnedHqlExpr castCurValue = ensureExprType(curValue, type);
  9325. OwnedHqlExpr test = createBoolExpr(no_eq, ensureExprType(testVar, type), transform(castCurValue));
  9326. OwnedHqlExpr trueExpr = transform(cur->queryChild(1));
  9327. elseExpr.setown(createIf(test.getClear(), trueExpr.getClear(), elseExpr.getClear()));
  9328. }
  9329. return elseExpr.getClear();
  9330. }
  9331. IHqlExpression * HqlTreeNormalizer::transformEvaluate(IHqlExpression * expr)
  9332. {
  9333. //Evaluate causes chaos - so translate it to a different form.
  9334. //following cases supported so far:
  9335. //EVALUATE(LEFT/RIGHT, g()) -> g(LEFT)
  9336. //EVAlUATE(x, field) -> x.field;
  9337. //EVALUATE(t[n], e) -> table(t,{f1 := e})[n].f1;
  9338. IHqlExpression * ds = expr->queryChild(0);
  9339. IHqlExpression * attr = expr->queryChild(1);
  9340. OwnedHqlExpr transformed;
  9341. OwnedHqlExpr activeTable = getActiveTableSelector();
  9342. if ((attr->getOperator() == no_select) && (attr->queryChild(0) == activeTable))
  9343. {
  9344. //EVAlUATE(x, field) -> x.field;
  9345. transformed.setown(createSelectExpr(LINK(ds), LINK(attr->queryChild(1))));
  9346. }
  9347. else if (attr->isConstant())
  9348. transformed.set(attr);
  9349. else
  9350. {
  9351. switch (ds->getOperator())
  9352. {
  9353. case no_left:
  9354. case no_right:
  9355. //EVALUATE(LEFT/RIGHT, g()) -> g(LEFT)
  9356. //May change too many datasets?
  9357. transformed.setown(replaceSelector(attr, activeTable, ds));
  9358. break;
  9359. case no_select:
  9360. //EVALUATE(x.y, g()) -> EVALUATE(x, g(y))
  9361. //May change too many datasets?
  9362. transformed.setown(createValue(no_evaluate, attr->getType(), LINK(ds->queryChild(0)), replaceSelector(attr, activeTable, ds->queryChild(1))));
  9363. break;
  9364. case no_selectnth:
  9365. {
  9366. IHqlExpression * baseDs = ds->queryChild(0);
  9367. if ((attr->getOperator() == no_select) && (attr->queryChild(0)->queryNormalizedSelector() == baseDs->queryNormalizedSelector()))
  9368. {
  9369. //Special case a select same as field...
  9370. transformed.setown(createSelectExpr(LINK(ds), LINK(attr->queryChild(1))));
  9371. }
  9372. else
  9373. {
  9374. //EVALUATE(t[n], e) -> table(t,{f1 := e})[n].f1;
  9375. OwnedHqlExpr field = createField(valueAtom, expr->getType(), NULL);
  9376. IHqlExpression * aggregateRecord = createRecord(field);
  9377. IHqlExpression * newAttr = replaceSelector(attr, activeTable, baseDs);
  9378. IHqlExpression * assign = createAssign(createSelectExpr(getSelf(aggregateRecord), LINK(field)), newAttr);
  9379. IHqlExpression * transform = createValue(no_newtransform, makeTransformType(aggregateRecord->getType()), assign);
  9380. IHqlExpression * project = createDataset(no_newusertable, LINK(baseDs), createComma(aggregateRecord, transform));
  9381. project = createRow(no_selectnth, project, LINK(ds->queryChild(1)));
  9382. transformed.setown(createSelectExpr(project, LINK(field)));
  9383. }
  9384. break;
  9385. }
  9386. default:
  9387. UNIMPLEMENTED;
  9388. }
  9389. }
  9390. return transform(transformed);
  9391. }
  9392. IHqlExpression * HqlTreeNormalizer::transformMap(IHqlExpression * expr)
  9393. {
  9394. unsigned max = numRealChildren(expr);
  9395. OwnedHqlExpr elseExpr = transform(expr->queryChild(max-1));
  9396. for (unsigned idx = max-1; idx-- != 0; idx)
  9397. {
  9398. IHqlExpression * cur = expr->queryChild(idx);
  9399. elseExpr.setown(createIf(transform(cur->queryChild(0)), transform(cur->queryChild(1)), elseExpr.getClear()));
  9400. }
  9401. return elseExpr.getClear();
  9402. }
  9403. class AbortingErrorReceiver : extends CInterface, implements IErrorReceiver
  9404. {
  9405. public:
  9406. AbortingErrorReceiver(IErrorReceiver * _errors)
  9407. {
  9408. errors = _errors ? _errors : &defaultReporter;
  9409. }
  9410. IMPLEMENT_IINTERFACE
  9411. virtual void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos)
  9412. {
  9413. errors->reportError(errNo, msg, filename, lineno, column, pos);
  9414. throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
  9415. }
  9416. virtual void report(IECLError* error)
  9417. {
  9418. errors->report(error);
  9419. throw MakeStringException(HQLERR_ErrorAlreadyReported, "%s", "");
  9420. }
  9421. virtual void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
  9422. {
  9423. errors->reportWarning(warnNo, msg, filename, lineno, column, pos);
  9424. }
  9425. virtual size32_t errCount()
  9426. {
  9427. return errors->errCount();
  9428. }
  9429. virtual size32_t warnCount()
  9430. {
  9431. return errors->warnCount();
  9432. }
  9433. protected:
  9434. IErrorReceiver * errors;
  9435. ThrowingErrorReceiver defaultReporter;
  9436. };
  9437. IHqlExpression * HqlTreeNormalizer::transformTempRow(IHqlExpression * expr)
  9438. {
  9439. ECLlocation dummyLocation(0, 0, 0, NULL);
  9440. AbortingErrorReceiver errorReporter(errors);
  9441. OwnedHqlExpr createRow = convertTempRowToCreateRow(&errorReporter, dummyLocation, expr);
  9442. return transform(createRow);
  9443. }
  9444. IHqlExpression * HqlTreeNormalizer::transformTempTable(IHqlExpression * expr)
  9445. {
  9446. ECLlocation dummyLocation(0, 0, 0, NULL);
  9447. AbortingErrorReceiver errorReporter(errors);
  9448. OwnedHqlExpr inlineTable = convertTempTableToInlineTable(&errorReporter, dummyLocation, expr);
  9449. if (expr != inlineTable)
  9450. return transform(inlineTable);
  9451. IHqlExpression * oldValues = expr->queryChild(0);
  9452. IHqlExpression * oldRecord = expr->queryChild(1);
  9453. OwnedHqlExpr values = normalizeListCasts(oldValues);
  9454. OwnedHqlExpr newRecord = transform(oldRecord);
  9455. node_operator valueOp = values->getOperator();
  9456. if ((valueOp != no_recordlist) && (valueOp != no_list))
  9457. {
  9458. if (queryRealChild(expr, 2))
  9459. return Parent::createTransformed(expr);
  9460. HqlExprArray children;
  9461. children.append(*transform(oldValues));
  9462. children.append(*LINK(newRecord));
  9463. children.append(*convertRecordToAssigns(oldRecord, true, true));
  9464. return expr->clone(children);
  9465. }
  9466. //should have already been handled by convertTempTableToInlineTable();
  9467. throwUnexpected();
  9468. }
  9469. IHqlExpression * HqlTreeNormalizer::transformNewKeyIndex(IHqlExpression * expr)
  9470. {
  9471. IHqlExpression * ds = expr->queryChild(0);
  9472. //If dataset is already null, then do standard
  9473. if (ds->getOperator() == no_null)
  9474. return completeTransform(expr);
  9475. //Before we do anything replace the dataset with a null dataset. This ensures we do the minimum transformation on the rest of the tree
  9476. OwnedHqlExpr newDs = createDataset(no_null, LINK(ds->queryRecord()));
  9477. HqlExprArray args;
  9478. args.append(*ds->cloneAllAnnotations(newDs));
  9479. args.append(*LINK(expr->queryChild(1)));
  9480. args.append(*quickFullReplaceExpression(expr->queryChild(2), ds->queryNormalizedSelector(), newDs));
  9481. unwindChildren(args, expr, 3);
  9482. OwnedHqlExpr ret = expr->clone(args);
  9483. return transform(ret);
  9484. }
  9485. IHqlExpression * HqlTreeNormalizer::transformKeyIndex(IHqlExpression * expr)
  9486. {
  9487. //Before we do anything replace the dataset with a null dataset. This ensures we do the minimum transformation on the rest of the tree
  9488. IHqlExpression * ds = expr->queryChild(0);
  9489. OwnedHqlExpr newDs = createDataset(no_null, LINK(ds->queryRecord()));
  9490. HqlExprArray args;
  9491. args.append(*ds->cloneAllAnnotations(newDs));
  9492. args.append(*quickFullReplaceExpression(expr->queryChild(1), ds->queryNormalizedSelector(), newDs));
  9493. unwindChildren(args, expr, 2);
  9494. OwnedHqlExpr normalized = expr->clone(args);
  9495. //Now convert from the no_keyindex format to the no_newkeyindex format.
  9496. //force the 1st argument to be processed..
  9497. OwnedHqlExpr transformed = completeTransform(normalized);
  9498. HqlExprArray assigns;
  9499. OwnedHqlExpr self = getSelf(transformed);
  9500. convertRecordToAssigns(assigns, normalized->queryChild(1), self, true, false); // fpos may not have a value...
  9501. args.kill();
  9502. unwindChildren(args, transformed);
  9503. args.add(*createValue(no_newtransform, makeTransformType(transformed->queryChild(1)->getType()), assigns), 2);
  9504. OwnedHqlExpr ret = createDataset(no_newkeyindex, args);
  9505. //MORE: This would be the place to add a FILTERED() attribute derived from any filters applied to the dataset
  9506. return expr->cloneAllAnnotations(ret);
  9507. }
  9508. IHqlExpression * HqlTreeNormalizer::transformMerge(IHqlExpression * expr)
  9509. {
  9510. HqlExprArray children;
  9511. transformChildren(expr, children);
  9512. HqlExprArray args;
  9513. reorderAttributesToEnd(args, children);
  9514. return expr->clone(args);
  9515. }
  9516. IHqlExpression * HqlTreeNormalizer::transformPatNamedUse(IHqlExpression * expr)
  9517. {
  9518. OwnedHqlExpr define = makeRecursiveName(queryPatUseModule(expr), queryPatUseName(expr));
  9519. HqlExprArray args;
  9520. ForEachChild(i, expr)
  9521. {
  9522. IHqlExpression * cur = queryRealChild(expr, i);
  9523. if (cur)
  9524. args.append(*LINK(cur));
  9525. }
  9526. args.append(*define.getClear());
  9527. return expr->clone(args);
  9528. }
  9529. IHqlExpression * HqlTreeNormalizer::transformPatCheckIn(IHqlExpression * expr)
  9530. {
  9531. OwnedHqlExpr set = transform(expr->queryChild(1));
  9532. //because this is a check pattern, we are free to remove any instance tags - they can't be used for matching.
  9533. while (set->getOperator() == no_pat_instance)
  9534. set.set(set->queryChild(0));
  9535. if (set->getOperator() == no_pat_set)
  9536. {
  9537. IHqlExpression * notAttr = expr->queryProperty(notAtom);
  9538. if (!notAttr)
  9539. return LINK(set);
  9540. HqlExprArray args;
  9541. unwindChildren(args, set);
  9542. if (args.find(*notAttr) == NotFound)
  9543. args.append(*LINK(notAttr));
  9544. else
  9545. args.zap(*notAttr);
  9546. return set->clone(args);
  9547. }
  9548. HqlExprArray values, newValues;
  9549. set->unwindList(values, no_pat_or);
  9550. ForEachItemIn(idx, values)
  9551. {
  9552. IHqlExpression * cur = &values.item(idx);
  9553. while (cur->getOperator() == no_pat_instance)
  9554. cur = cur->queryChild(0);
  9555. if (cur->getOperator() != no_pat_const)
  9556. return NULL;
  9557. IValue * value = cur->queryChild(0)->queryValue();
  9558. if (!value)
  9559. return NULL;
  9560. ITypeInfo * type = value->queryType();
  9561. if (type->getStringLen() != 1)
  9562. return NULL;
  9563. switch (type->getTypeCode())
  9564. {
  9565. case type_string:
  9566. newValues.append(*createConstant((int)*(const byte *)value->queryValue()));
  9567. break;
  9568. case type_unicode:
  9569. newValues.append(*createConstant((int)*(const UChar *)value->queryValue()));
  9570. break;
  9571. case type_utf8:
  9572. newValues.append(*createConstant((int)rtlUtf8Char((const char *)value->queryValue())));
  9573. break;
  9574. default:
  9575. return NULL;
  9576. }
  9577. }
  9578. if (expr->hasProperty(notAtom))
  9579. newValues.append(*createAttribute(notAtom));
  9580. return createValue(no_pat_set, makePatternType(), newValues);
  9581. }
  9582. IHqlExpression * HqlTreeNormalizer::transformTable(IHqlExpression * untransformed)
  9583. {
  9584. //Convert DATASET('xx', rec, PIPE('z'))
  9585. //DATASET('xx', rec, THOR) | PIPE('z')
  9586. OwnedHqlExpr transformed = completeTransform(untransformed);
  9587. IHqlExpression * mode = transformed->queryChild(2);
  9588. if (mode->getOperator() != no_pipe)
  9589. return transformed.getClear();
  9590. IHqlExpression * filename = transformed->queryChild(0);
  9591. StringBuffer s;
  9592. if (getStringValue(s, filename, NULL).length() == 0)
  9593. return transformed.getClear();
  9594. OwnedHqlExpr modeThor = createValue(no_thor);
  9595. IHqlExpression * diskRead = replaceChild(transformed, 2, modeThor);
  9596. HqlExprArray args;
  9597. args.append(*diskRead);
  9598. unwindChildren(args, mode);
  9599. return createDataset(no_pipe, args);
  9600. }
  9601. IHqlExpression * HqlTreeNormalizer::optimizeAssignSkip(HqlExprArray & children, IHqlExpression * expr, IHqlExpression * cond, unsigned depth)
  9602. {
  9603. if (!containsSkip(expr))
  9604. return LINK(expr);
  9605. switch (expr->getOperator())
  9606. {
  9607. case no_skip:
  9608. children.append(*createValue(no_skip, makeVoidType(), LINK(cond)));
  9609. return NULL;
  9610. case no_cast:
  9611. case no_implicitcast:
  9612. {
  9613. bool same= true;
  9614. HqlExprArray args;
  9615. ForEachChild(i, expr)
  9616. {
  9617. IHqlExpression * cur = expr->queryChild(i);
  9618. IHqlExpression * ret = optimizeAssignSkip(children, cur, cond, depth);
  9619. if (!ret)
  9620. return NULL;
  9621. args.append(*ret);
  9622. if (cur != ret)
  9623. same = false;
  9624. }
  9625. if (same)
  9626. return LINK(expr);
  9627. return expr->clone(args);
  9628. }
  9629. //could try and handle map/case/choose, but less common, and more complicated.
  9630. case no_if:
  9631. {
  9632. //For the moment only hoist SKIPS within a single level of IF() conditions.
  9633. //Multi level rarely occur, and don't significantly improve the code
  9634. if (depth != 0)
  9635. return LINK(expr);
  9636. IHqlExpression * thisCond = expr->queryChild(0);
  9637. IHqlExpression * left = expr->queryChild(1);
  9638. IHqlExpression * right = expr->queryChild(2);
  9639. if (!right)
  9640. return LINK(expr);
  9641. OwnedHqlExpr leftCond = extendConditionOwn(no_and, LINK(cond), LINK(thisCond));
  9642. OwnedHqlExpr inverseCond = createValue(no_not, makeBoolType(), LINK(thisCond));
  9643. OwnedHqlExpr rightCond = extendConditionOwn(no_and, LINK(cond), LINK(inverseCond));
  9644. OwnedHqlExpr newLeft = optimizeAssignSkip(children, left, leftCond, depth+1);
  9645. OwnedHqlExpr newRight = optimizeAssignSkip(children, right, rightCond, depth+1);
  9646. if (!newLeft && !newRight)
  9647. return NULL;
  9648. //if cond is true, then it will skip => no need to check the condition
  9649. if (!newLeft)
  9650. return LINK(newRight);
  9651. if (!newRight)
  9652. return LINK(newLeft);
  9653. if (left == newLeft && right == newRight)
  9654. return LINK(expr);
  9655. HqlExprArray args;
  9656. unwindChildren(args, expr);
  9657. args.replace(*newLeft.getClear(), 1);
  9658. args.replace(*newRight.getClear(), 2);
  9659. return expr->clone(args);
  9660. }
  9661. default:
  9662. return LINK(expr);
  9663. }
  9664. }
  9665. bool HqlTreeNormalizer::transformTransform(HqlExprArray & children, IHqlExpression * expr)
  9666. {
  9667. bool same = true;
  9668. ForEachChild(i, expr)
  9669. {
  9670. IHqlExpression * cur = expr->queryChild(i);
  9671. switch (cur->getOperator())
  9672. {
  9673. case no_assignall:
  9674. transformTransform(children, cur);
  9675. same = false; // assign all is removed and assigns expanded in its place
  9676. break;
  9677. case no_assign:
  9678. {
  9679. OwnedHqlExpr assign = transform(cur);
  9680. if (cur->getInfoFlags() & HEFcontainsSkip)
  9681. {
  9682. IHqlExpression * rhs = assign->queryChild(1);
  9683. OwnedHqlExpr newRhs = optimizeAssignSkip(children, rhs, NULL, 0);
  9684. if (rhs != newRhs)
  9685. {
  9686. IHqlExpression * lhs = assign->queryChild(0);
  9687. if (!newRhs)
  9688. newRhs.setown(createNullExpr(rhs));
  9689. assign.setown(createAssign(LINK(lhs), newRhs.getClear()));
  9690. }
  9691. }
  9692. if (assign != cur)
  9693. same = false;
  9694. children.append(*assign.getClear());
  9695. break;
  9696. }
  9697. default:
  9698. {
  9699. IHqlExpression * next = transform(cur);
  9700. children.append(*next);
  9701. if (next != cur)
  9702. same = false;
  9703. }
  9704. break;
  9705. }
  9706. }
  9707. return same;
  9708. }
  9709. IHqlExpression * HqlTreeNormalizer::transformTransform(IHqlExpression * expr)
  9710. {
  9711. HqlExprArray children;
  9712. IHqlExpression * oldRecord = queryOriginalRecord(expr);
  9713. OwnedHqlExpr newRecord = transform(oldRecord);
  9714. bool same = transformTransform(children, expr);
  9715. if ((oldRecord != newRecord) || !same)
  9716. {
  9717. ITypeInfo * newRecordType = createRecordType(newRecord);
  9718. OwnedHqlExpr ret = createValue(expr->getOperator(), makeTransformType(newRecordType), children);
  9719. return expr->cloneAllAnnotations(ret);
  9720. }
  9721. return LINK(expr);
  9722. }
  9723. IHqlExpression * HqlTreeNormalizer::transformIfAssert(node_operator newOp, IHqlExpression * expr)
  9724. {
  9725. unsigned max = expr->numChildren();
  9726. HqlExprArray children;
  9727. bool same = transformChildren(expr, children);
  9728. if (expr->hasProperty(assertAtom) && !options.removeAsserts)
  9729. {
  9730. OwnedHqlExpr ret = createDataset(newOp, children);
  9731. return expr->cloneAllAnnotations(ret);
  9732. }
  9733. if (!same)
  9734. return expr->clone(children);
  9735. return LINK(expr);
  9736. }
  9737. IHqlExpression * HqlTreeNormalizer::transformExecuteWhen(IHqlExpression * expr)
  9738. {
  9739. OwnedHqlExpr transformedAction = transform(expr->queryChild(1));
  9740. if ((transformedAction->getOperator() == no_setmeta) ||
  9741. ((transformedAction->getOperator() == no_null) && transformedAction->isAction()))
  9742. return transform(expr->queryChild(0));
  9743. HqlExprArray children;
  9744. if (translator.queryOptions().convertWhenExecutedToCompound && !expr->queryChild(2))
  9745. {
  9746. //For the moment, for maximal compatibility, convert no_executewhen to a no_compound
  9747. children.append(*transformedAction.getClear());
  9748. children.append(*transform(expr->queryChild(0)));
  9749. OwnedHqlExpr ret = createCompound(children);
  9750. return expr->cloneAllAnnotations(ret);
  9751. }
  9752. //Need to create a unique id to differentiate the different side effects.
  9753. transformChildren(expr, children);
  9754. assertex(!expr->hasProperty(_uid_Atom));
  9755. children.append(*createUniqueId());
  9756. return expr->clone(children);
  9757. }
  9758. IHqlExpression * HqlTreeNormalizer::transformWithinFilter(IHqlExpression * expr)
  9759. {
  9760. OwnedHqlExpr ds = transform(expr->queryChild(0));
  9761. HqlExprArray children;
  9762. children.append(*LINK(ds));
  9763. ForEachChildFrom(i, expr, 1)
  9764. {
  9765. IHqlExpression * filter = expr->queryChild(i);
  9766. if (filter->getOperator() == no_within)
  9767. {
  9768. IHqlExpression * scope = filter->queryChild(0);
  9769. while (scope->getOperator() == no_filter)
  9770. {
  9771. ForEachChildFrom(i2, scope, 1)
  9772. children.append(*transform(scope->queryChild(i2)));
  9773. scope = scope->queryChild(0);
  9774. }
  9775. ds.setown(createDataset(no_related, LINK(ds), transform(scope)));
  9776. }
  9777. else
  9778. children.append(*transform(filter));
  9779. }
  9780. if (children.ordinality() == 1)
  9781. return ds.getClear();
  9782. children.replace(*ds.getClear(), 0);
  9783. return expr->clone(children);
  9784. }
  9785. IHqlExpression * HqlTreeNormalizer::validateKeyedJoin(IHqlExpression * expr)
  9786. {
  9787. //Transform join(x, local(key), ....) to join(x, key, ...., local);
  9788. HqlExprArray children;
  9789. transformChildren(expr, children);
  9790. unsigned prevChildren = children.ordinality();
  9791. IHqlExpression * rhs = &children.item(1);
  9792. loop
  9793. {
  9794. node_operator op = rhs->getOperator();
  9795. if (op == no_forcelocal)
  9796. children.append(*createLocalAttribute());
  9797. else if (op == no_forcenolocal)
  9798. children.append(*createAttribute(noLocalAtom));
  9799. else if ((op == no_section) || (op == no_sectioninput))
  9800. {
  9801. //remove the section
  9802. }
  9803. else
  9804. break;
  9805. rhs = rhs->queryChild(0);
  9806. }
  9807. if (prevChildren != children.ordinality())
  9808. {
  9809. if (isKey(rhs))
  9810. children.replace(*LINK(rhs), 1);
  9811. else
  9812. children.trunc(prevChildren);
  9813. }
  9814. //Now check that a join marked as keyed has a key as the rhs.
  9815. IHqlExpression * keyed = expr->queryProperty(keyedAtom);
  9816. if (!keyed || keyed->queryChild(0) || isKey(rhs))
  9817. return expr->clone(children);
  9818. if (options.allowActivityForKeyedJoin)
  9819. {
  9820. children.append(*createAttribute(_complexKeyed_Atom));
  9821. return expr->clone(children);
  9822. }
  9823. StringBuffer s;
  9824. if (expr->queryName())
  9825. s.append(" (").append(expr->queryName()).append(")");
  9826. throwError1(HQLERR_RhsKeyedNotKey, s.str());
  9827. return NULL;
  9828. }
  9829. //A bit of a nasty dependency - this should match the capabilities of the code in hqlsource for finding selectors
  9830. static void gatherPotentialSelectors(HqlExprArray & args, IHqlExpression * expr)
  9831. {
  9832. node_operator op = expr->getOperator();
  9833. switch (op)
  9834. {
  9835. case no_and:
  9836. case no_or:
  9837. case no_eq:
  9838. case no_ne:
  9839. case no_gt:
  9840. case no_lt:
  9841. case no_ge:
  9842. case no_le:
  9843. gatherPotentialSelectors(args, expr->queryChild(0));
  9844. gatherPotentialSelectors(args, expr->queryChild(1));
  9845. break;
  9846. case no_if:
  9847. case no_case:
  9848. case no_map:
  9849. case no_mapto:
  9850. {
  9851. ForEachChild(i, expr)
  9852. gatherPotentialSelectors(args, expr->queryChild(i));
  9853. break;
  9854. }
  9855. case no_assertkeyed:
  9856. case no_assertstepped:
  9857. case no_not:
  9858. case no_between:
  9859. case no_notbetween:
  9860. case no_cast:
  9861. case no_implicitcast:
  9862. case no_notin:
  9863. case no_in:
  9864. case no_add:
  9865. case no_sub:
  9866. case no_substring:
  9867. gatherPotentialSelectors(args, expr->queryChild(0));
  9868. break;
  9869. case no_select:
  9870. {
  9871. IHqlExpression * selector = expr->queryNormalizedSelector();
  9872. if (!args.contains(*selector))
  9873. args.append(*LINK(selector));
  9874. break;
  9875. }
  9876. }
  9877. }
  9878. //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
  9879. //Remove as many named symbols as we can - try and keep for datasets and statements so can go in the tree.
  9880. IHqlExpression * HqlTreeNormalizer::createTransformed(IHqlExpression * expr)
  9881. {
  9882. IHqlExpression * body = expr->queryBody(true);
  9883. node_operator op = expr->getOperator();
  9884. if (expr != body)
  9885. {
  9886. #if 0
  9887. OwnedHqlExpr transformedBody = transform(body);
  9888. #else
  9889. OwnedHqlExpr transformedBody;
  9890. try
  9891. {
  9892. transformedBody.setown(transform(body));
  9893. }
  9894. catch (IException * e)
  9895. {
  9896. if (dynamic_cast<IECLError *>(e))
  9897. throw;
  9898. IHqlExpression * location = queryLocation(expr);
  9899. if (location)
  9900. {
  9901. IECLError * error = annotateExceptionWithLocation(e, location);
  9902. e->Release();
  9903. throw error;
  9904. }
  9905. throw;
  9906. }
  9907. #endif
  9908. switch (expr->getAnnotationKind())
  9909. {
  9910. case annotate_warning:
  9911. case annotate_parsemeta:
  9912. return transformedBody.getClear();
  9913. case annotate_javadoc:
  9914. return expr->cloneAnnotation(transformedBody);
  9915. case annotate_meta:
  9916. {
  9917. HqlExprArray preservedMeta;
  9918. IHqlExpression * cur;
  9919. bool changed = false;
  9920. for (unsigned i=0; (cur = expr->queryAnnotationParameter(i)) != 0; i++)
  9921. {
  9922. _ATOM name = cur->queryName();
  9923. bool keep = true;
  9924. if (name == deprecatedAtom)
  9925. keep = false;
  9926. else if (!options.allowSections && (name == sectionAtom))
  9927. keep = false;
  9928. if (keep)
  9929. preservedMeta.append(*LINK(cur));
  9930. else
  9931. changed = true;
  9932. }
  9933. if (changed)
  9934. {
  9935. if (preservedMeta.ordinality() == 0)
  9936. return transformedBody.getClear();
  9937. return createMetaAnnotation(transformedBody.getClear(), preservedMeta);
  9938. }
  9939. break; // default action
  9940. }
  9941. case annotate_symbol:
  9942. {
  9943. if (hasNamedSymbol(transformedBody))
  9944. return transformedBody.getClear();
  9945. _ATOM name = expr->queryName();
  9946. if (options.commonUniqueNameAttributes)
  9947. {
  9948. _ATOM simpleName = simplifyUniqueAttributeName(name);
  9949. if (simpleName)
  9950. return cloneSymbol(expr, simpleName, transformedBody, NULL, NULL);
  9951. }
  9952. break;
  9953. }
  9954. } // switch(kind)
  9955. if (body == transformedBody)
  9956. return LINK(expr);
  9957. return expr->cloneAnnotation(transformedBody);
  9958. }
  9959. //MORE: Types of all pattern attributes should also be normalized. Currently they aren't which causes discrepancies between types
  9960. //for ghoogle.hql. It could conceivably cause problems later on.
  9961. if (forwardReferences.ordinality())
  9962. {
  9963. if (op == no_pat_use && expr->hasProperty(nameAtom))
  9964. return transformPatNamedUse(expr);
  9965. if (op == no_pat_instance)
  9966. {
  9967. OwnedHqlExpr ret = queryTransformPatternDefine (expr);
  9968. if (ret)
  9969. return ret.getClear();
  9970. }
  9971. }
  9972. IHqlExpression * sideEffects = expr->queryProperty(_sideEffect_Atom);
  9973. if (sideEffects)
  9974. {
  9975. HqlExprArray args;
  9976. unwindChildren(args, expr);
  9977. args.zap(*sideEffects);
  9978. OwnedHqlExpr next = createCompound(LINK(sideEffects->queryChild(0)), expr->clone(args));
  9979. return transform(next);
  9980. }
  9981. if (!options.constantFoldNormalize)
  9982. return createTransformedBody(expr);
  9983. switch (op)
  9984. {
  9985. case no_if:
  9986. {
  9987. OwnedHqlExpr cond = transform(expr->queryChild(0));
  9988. IValue * condValue = cond->queryValue();
  9989. if (condValue)
  9990. {
  9991. unsigned idx = condValue->getBoolValue() ? 1 : 2;
  9992. IHqlExpression * branch = expr->queryChild(idx);
  9993. if (branch)
  9994. return transform(branch);
  9995. assertex(expr->isAction());
  9996. return createValue(no_null, makeVoidType());
  9997. }
  9998. break;
  9999. }
  10000. case no_and:
  10001. {
  10002. IHqlExpression * left = expr->queryChild(0);
  10003. IHqlExpression * right = expr->queryChild(1);
  10004. OwnedHqlExpr simpleRight = transformSimpleConst(right);
  10005. if (simpleRight->queryValue())
  10006. {
  10007. if (simpleRight->queryValue()->getBoolValue())
  10008. return transform(left);
  10009. return simpleRight.getClear();
  10010. }
  10011. OwnedHqlExpr newLeft = transform(left);
  10012. IValue * leftValue = newLeft->queryValue();
  10013. if (leftValue)
  10014. {
  10015. if (!leftValue->getBoolValue())
  10016. return newLeft.getClear();
  10017. return transform(right);
  10018. }
  10019. break;
  10020. }
  10021. case no_or:
  10022. {
  10023. IHqlExpression * left = expr->queryChild(0);
  10024. IHqlExpression * right = expr->queryChild(1);
  10025. OwnedHqlExpr simpleRight = transformSimpleConst(right);
  10026. if (simpleRight->queryValue())
  10027. {
  10028. if (!simpleRight->queryValue()->getBoolValue())
  10029. return transform(left);
  10030. return simpleRight.getClear();
  10031. }
  10032. OwnedHqlExpr newLeft = transform(left);
  10033. IValue * leftValue = newLeft->queryValue();
  10034. if (leftValue)
  10035. {
  10036. if (leftValue->getBoolValue())
  10037. return newLeft.getClear();
  10038. return transform(right);
  10039. }
  10040. break;
  10041. }
  10042. case no_attr:
  10043. if (expr->queryName() == _original_Atom)
  10044. return LINK(expr);
  10045. break;
  10046. }
  10047. OwnedHqlExpr transformed = createTransformedBody(expr);
  10048. return foldConstantOperator(transformed, 0, NULL);
  10049. }
  10050. IHqlExpression * HqlTreeNormalizer::createTransformedBody(IHqlExpression * expr)
  10051. {
  10052. node_operator op = expr->getOperator();
  10053. switch (op)
  10054. {
  10055. case no_constant:
  10056. return LINK(expr); // avoid creating an array in default code...
  10057. case no_case:
  10058. if (isVoidOrDatasetOrList(expr))
  10059. return transformCase(expr);
  10060. break;
  10061. case no_map:
  10062. if (isVoidOrDatasetOrList(expr))
  10063. return transformMap(expr);
  10064. break;
  10065. case no_transform:
  10066. //optimize location of skips
  10067. return transformTransform(expr);
  10068. case no_getresult:
  10069. case no_newtransform:
  10070. {
  10071. IHqlExpression * record = queryOriginalRecord(expr);
  10072. if (record)
  10073. ::Release(transform(record));
  10074. LinkedHqlExpr cleaned = expr;
  10075. //remove any no_assignall children... could really do for no_transform as well... would reduce clarity of graph ecl
  10076. if ((op == no_newtransform) && queryChildOperator(no_assignall, expr))
  10077. {
  10078. HqlExprArray args;
  10079. ForEachChild(i, expr)
  10080. expr->queryChild(i)->unwindList(args, no_assignall);
  10081. cleaned.setown(expr->clone(args));
  10082. }
  10083. return Parent::createTransformed(cleaned);
  10084. }
  10085. case no_usertable:
  10086. case no_selectfields:
  10087. {
  10088. OwnedHqlExpr newRecord = transform(expr->queryChild(1));
  10089. return convertSelectToProject(newRecord, expr);
  10090. }
  10091. case no_parse:
  10092. return removeDefaultsFromExpr(expr, 3, no_newparse);
  10093. case no_xmlparse:
  10094. return removeDefaultsFromExpr(expr, 2, no_newxmlparse);
  10095. case no_soapcall:
  10096. return removeDefaultsFromExpr(expr, 2, no_newsoapcall);
  10097. case no_soapcall_ds:
  10098. return removeDefaultsFromExpr(expr, 3, no_newsoapcall_ds);
  10099. case no_soapaction_ds:
  10100. return removeDefaultsFromExpr(expr, 3, no_newsoapaction_ds);
  10101. #ifdef OPTIMIZE_IMPLICIT_CAST
  10102. //Following is a good idea, but makes some things worse because of the way we currently spot table invariants.
  10103. case no_implicitcast:
  10104. {
  10105. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  10106. return ensureExprType(transformed->queryChild(0), transformed->queryType());
  10107. }
  10108. #endif
  10109. case no_record:
  10110. {
  10111. OwnedHqlExpr transformed = completeTransform(expr);
  10112. if (transformed->hasProperty(packedAtom))
  10113. transformed.setown(getPackedRecord(transformed));
  10114. if (options.ensureRecordsHaveSymbols)
  10115. {
  10116. //Ensure all records only have a single unique name, and transform it here so that record types also map to that unique name
  10117. IHqlExpression * recordSymbol = queryCommonExtra(expr)->symbol;
  10118. if (recordSymbol)
  10119. {
  10120. _ATOM name = recordSymbol->queryName();
  10121. _ATOM simpleName = simplifyUniqueAttributeName(name);
  10122. if (simpleName)
  10123. name = simpleName;
  10124. return createSymbol(name, transformed.getClear(), ob_private);
  10125. }
  10126. }
  10127. return transformed.getClear();
  10128. }
  10129. case no_left:
  10130. case no_right:
  10131. case no_top:
  10132. case no_self:
  10133. {
  10134. HqlExprArray children;
  10135. IHqlExpression * record = expr->queryChild(0);
  10136. //Ensure that the first parameter to one of these nodes is the body of the record, not a named symbol
  10137. if (record)
  10138. {
  10139. OwnedHqlExpr transformedRecord = transform(record);
  10140. children.append(*LINK(transformedRecord->queryBody()));
  10141. }
  10142. return completeTransform(expr, children);
  10143. }
  10144. case no_field:
  10145. {
  10146. //Remove the default values...
  10147. HqlExprArray children;
  10148. bool same = true;
  10149. ForEachChild(idx, expr)
  10150. {
  10151. IHqlExpression * cur = expr->queryChild(idx);
  10152. if (cur->isAttribute())
  10153. {
  10154. IHqlExpression * transformed = transform(cur);
  10155. children.append(*transformed);
  10156. if (cur != transformed)
  10157. same = false;
  10158. }
  10159. else
  10160. same = false;
  10161. }
  10162. ITypeInfo * type = expr->queryType();
  10163. OwnedITypeInfo newType = transformType(type);
  10164. if (type != newType)
  10165. return createField(expr->queryName(), newType.getClear(), children);
  10166. if (same)
  10167. return LINK(expr);
  10168. return expr->clone(children);
  10169. }
  10170. case no_trim:
  10171. //TRIM(x,RIGHT) should be represented the same way as TRIM(x) - and it's more efficient
  10172. if ((expr->numChildren() == 2) && (expr->queryChild(1)->queryName() == rightAtom))
  10173. {
  10174. HqlExprArray children;
  10175. children.append(*transform(expr->queryChild(0)));
  10176. return expr->clone(children);
  10177. }
  10178. break;
  10179. case no_pat_pattern:
  10180. return LINK(expr->queryChild(1));
  10181. case no_temptable:
  10182. return transformTempTable(expr);
  10183. case no_temprow:
  10184. return transformTempRow(expr);
  10185. case no_keyindex:
  10186. return transformKeyIndex(expr);
  10187. case no_newkeyindex:
  10188. // seenIndex = true;
  10189. return transformNewKeyIndex(expr);
  10190. case no_table:
  10191. if (expr->hasProperty(localUploadAtom))
  10192. seenLocalUpload = true;
  10193. return transformTable(expr);
  10194. case no_pat_checkin:
  10195. if (expr->queryChild(0)->getOperator() == no_pat_anychar)
  10196. {
  10197. IHqlExpression * transformed = transformPatCheckIn(expr);
  10198. if (transformed)
  10199. return transformed;
  10200. }
  10201. break;
  10202. case no_denormalize:
  10203. case no_denormalizegroup:
  10204. {
  10205. OwnedHqlExpr transformed = validateKeyedJoin(expr);
  10206. //Explicitly add a left outer flag to a denormalize if no other join type is specified.
  10207. //Do here rather than in parser so crc for persists isn't changed.
  10208. if (!transformed->hasProperty(innerAtom) &&
  10209. !transformed->hasProperty(leftonlyAtom) && !transformed->hasProperty(leftouterAtom) &&
  10210. !transformed->hasProperty(rightonlyAtom) && !transformed->hasProperty(rightouterAtom) &&
  10211. !transformed->hasProperty(fullonlyAtom) && !transformed->hasProperty(fullouterAtom))
  10212. {
  10213. return appendOwnedOperand(transformed, createAttribute(leftouterAtom));
  10214. }
  10215. return transformed.getClear();
  10216. }
  10217. case no_colon:
  10218. {
  10219. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  10220. LinkedHqlExpr value = transformed->queryChild(0);
  10221. bool same = true;
  10222. bool needToPreserveOriginal = false;
  10223. HqlExprArray actions, scheduleActions;
  10224. unwindChildren(actions, transformed, 1);
  10225. ForEachItemInRev(i, actions)
  10226. {
  10227. IHqlExpression & cur = actions.item(i);
  10228. IHqlExpression * replacement = NULL;
  10229. switch (cur.getOperator())
  10230. {
  10231. case no_global:
  10232. {
  10233. HqlExprArray scopeArgs;
  10234. scopeArgs.append(*LINK(value));
  10235. unwindChildren(scopeArgs, &cur);
  10236. replacement = createWrapper(no_globalscope, scopeArgs);
  10237. break;
  10238. }
  10239. case no_persist:
  10240. {
  10241. needToPreserveOriginal = true;
  10242. same = false;
  10243. break;
  10244. }
  10245. case no_attr:
  10246. case no_attr_expr:
  10247. case no_attr_link:
  10248. if (cur.queryName() == defineAtom)
  10249. replacement = createValue(no_define, transformed->getType(), LINK(value), LINK(cur.queryChild(0)));
  10250. break;
  10251. //Separate scheduled items into a separate no_colon.
  10252. case no_when:
  10253. case no_priority:
  10254. scheduleActions.append(OLINK(cur));
  10255. actions.remove(i);
  10256. same = false;
  10257. break;
  10258. }
  10259. if (replacement)
  10260. {
  10261. value.setown(replacement);
  10262. actions.remove(i);
  10263. same = false;
  10264. }
  10265. }
  10266. if (same)
  10267. return transformed.getClear();
  10268. if (needToPreserveOriginal)
  10269. actions.append(*createAttribute(_original_Atom, LINK(expr->queryChild(0))));
  10270. OwnedHqlExpr result;
  10271. if (actions.ordinality() == 0)
  10272. result.set(value);
  10273. else
  10274. result.setown(createColon(LINK(value), actions));
  10275. if (scheduleActions.ordinality())
  10276. result.setown(createColon(result.getClear(), scheduleActions));
  10277. return result.getClear();
  10278. }
  10279. case no_evaluate:
  10280. return transformEvaluate(expr);
  10281. case no_selectnth:
  10282. {
  10283. IHqlExpression * ds = expr->queryChild(0);
  10284. if (isGrouped(ds))
  10285. {
  10286. OwnedHqlExpr newChild = createDataset(no_group, LINK(ds));
  10287. OwnedHqlExpr mapped = replaceChild(expr, 0, newChild);
  10288. return transform(mapped);
  10289. }
  10290. break;
  10291. }
  10292. case no_assert_ds:
  10293. if (options.removeAsserts)
  10294. return transform(expr->queryChild(0));
  10295. break;
  10296. case no_section:
  10297. case no_sectioninput:
  10298. if (!options.allowSections)
  10299. return transform(expr->queryChild(0));
  10300. break;
  10301. case no_type:
  10302. return transformAlienType(expr);
  10303. case no_param:
  10304. {
  10305. //no_param may be retained by library call definitions + they need the type transforming for consistency
  10306. ITypeInfo * type = expr->queryType();
  10307. OwnedITypeInfo newType = transformType(type);
  10308. if (type != newType)
  10309. {
  10310. //Attributes shouldn't need transforming, but simplest
  10311. HqlExprArray attrs;
  10312. transformChildren(expr, attrs);
  10313. return createParameter(expr->queryName(), (unsigned)expr->querySequenceExtra(), newType.getClear(), attrs);
  10314. }
  10315. break;
  10316. }
  10317. case no_libraryscope:
  10318. {
  10319. OwnedHqlExpr ret = transformScope(expr);
  10320. if (translator.targetHThor())
  10321. return appendOwnedOperand(ret, createAttribute(_noStreaming_Atom));
  10322. return ret.getClear();
  10323. }
  10324. case no_virtualscope:
  10325. return transformScope(expr);
  10326. case no_libraryscopeinstance:
  10327. {
  10328. IHqlExpression * oldFunction = expr->queryDefinition();
  10329. OwnedHqlExpr newFunction = transform(oldFunction);
  10330. HqlExprArray children;
  10331. bool same = true;
  10332. ForEachChild(i, expr)
  10333. {
  10334. LinkedHqlExpr cur = expr->queryChild(i);
  10335. if (cur->getOperator() == no_virtualscope)
  10336. {
  10337. cur.setown(checkCreateConcreteModule(NULL, cur, cur->queryProperty(_location_Atom)));
  10338. assertex(cur->getOperator() != no_virtualscope);
  10339. same = false;
  10340. }
  10341. else if (cur->getOperator() == no_purevirtual)
  10342. {
  10343. _ATOM name = cur->queryName();
  10344. throwError1(HQLERR_LibraryMemberArgNotDefined, name ? name->str() : "");
  10345. }
  10346. IHqlExpression * transformed = transform(cur);
  10347. children.append(*transformed);
  10348. if (cur != transformed)
  10349. same = false;
  10350. }
  10351. if (same && (oldFunction == newFunction))
  10352. return LINK(expr);
  10353. return createLibraryInstance(newFunction.getClear(), children);
  10354. }
  10355. case no_transformascii:
  10356. case no_transformebcdic:
  10357. {
  10358. HqlExprArray children;
  10359. transformChildren(expr, children);
  10360. OwnedHqlExpr transformed = createDataset(no_hqlproject, children);
  10361. return transform(transformed);
  10362. }
  10363. case no_join:
  10364. {
  10365. OwnedHqlExpr transformed = validateKeyedJoin(expr);
  10366. if (isSelfJoin(expr))
  10367. {
  10368. HqlExprArray children;
  10369. unwindChildren(children, transformed);
  10370. children.replace(*createAttribute(_selfJoinPlaceholder_Atom), 1); // replace the 1st dataset with an attribute so parameters are still in the same place.
  10371. return createDataset(no_selfjoin, children);
  10372. }
  10373. if (isKeyedJoin(transformed) && translator.targetRoxie() && !expr->hasProperty(_ordered_Atom))
  10374. return appendOwnedOperand(transformed, createAttribute(_ordered_Atom));
  10375. return transformed.getClear();
  10376. }
  10377. case no_projectrow:
  10378. {
  10379. //Work around a problem where left is ambiguous - either outer LEFT, or left within this ROW
  10380. //Not a full solution since PROJECT(PROJECT(LEFT),t(LEFT)) where project(LEFT) doesn't change types
  10381. //would suffer from the same problem.
  10382. //Remove as many instances of PROJECT(row, transform) as we can since ROW(transform) is handled more efficient.
  10383. HqlExprArray children;
  10384. OwnedHqlExpr ds = transform(expr->queryChild(0));
  10385. node_operator dsOp = ds->getOperator();
  10386. if (dsOp == no_left)
  10387. // if (isAlwaysActiveRow(ds))
  10388. {
  10389. //MORE: The call to replaceExpression below isn't actually correct unless selectors are unique
  10390. //this optimization may have to move elsewhere.
  10391. OwnedHqlExpr newTransform = transform(expr->queryChild(1));
  10392. OwnedHqlExpr newSel = transform(querySelSeq(expr));
  10393. OwnedHqlExpr myLeft = createSelector(no_left, ds, newSel);
  10394. OwnedHqlExpr replaced = quickFullReplaceExpression(newTransform, myLeft, ds);
  10395. return createRow(no_createrow, LINK(replaced));
  10396. }
  10397. children.append(*ds.getClear());
  10398. return completeTransform(expr, children);
  10399. }
  10400. case no_sorted:
  10401. return transformIfAssert(no_assertsorted, expr);
  10402. case no_grouped:
  10403. return transformIfAssert(no_assertgrouped, expr);
  10404. case no_distributed:
  10405. //remove distributed(x)
  10406. if (expr->hasProperty(unknownAtom))
  10407. return transform(expr->queryChild(0));
  10408. return transformIfAssert(no_assertdistributed, expr);
  10409. #if defined(MAP_PROJECT_TO_USERTABLE)
  10410. case no_hqlproject:
  10411. if (!isCountProject(expr))
  10412. {
  10413. HqlExprArray children;
  10414. transformChildren(expr, children);
  10415. IHqlExpression * ds = &children.item(0);
  10416. OwnedHqlExpr left = createSelector(no_left, ds, querySelSeq(expr));
  10417. OwnedHqlExpr mapped = replaceExpression(&children.item(1), left, ds->queryNormalizedSelector());
  10418. children.add(*LINK(mapped->queryRecord()), 1);
  10419. HqlExprArray assigns;
  10420. unwindChildren(assigns, mapped);
  10421. children.replace(*createValue(no_newtransform, mapped->getType(), assigns), 2);
  10422. OwnedHqlExpr transformed = createDataset(no_newusertable, children);
  10423. return transform(transformed);
  10424. }
  10425. break;
  10426. #endif
  10427. case no_comma:
  10428. case no_compound:
  10429. if (expr->queryChild(0)->getOperator() == no_setmeta)
  10430. return transform(expr->queryChild(1));
  10431. if ((op == no_compound) && expr->isAction())
  10432. {
  10433. HqlExprArray args;
  10434. expr->unwindList(args, no_compound);
  10435. OwnedHqlExpr compound = createAction(no_actionlist, args);
  10436. return transform(compound);
  10437. }
  10438. break;
  10439. case no_actionlist:
  10440. return transformActionList(expr);
  10441. case no_forcelocal:
  10442. case no_forcenolocal:
  10443. case no_allnodes:
  10444. case no_thisnode:
  10445. seenForceLocal = true;
  10446. break;
  10447. case no_enth:
  10448. {
  10449. HqlExprArray children;
  10450. bool same = transformChildren(expr, children);
  10451. IHqlExpression * denom = queryRealChild(expr, 2);
  10452. if (!denom && !expr->queryProperty(localAtom))
  10453. {
  10454. children.add(*createValue(no_count, LINK(defaultIntegralType), LINK(&children.item(0))), 2);
  10455. same = false;
  10456. }
  10457. if (!same)
  10458. return expr->clone(children);
  10459. return LINK(expr);
  10460. }
  10461. case no_assertconstant:
  10462. {
  10463. IHqlExpression * child = expr->queryChild(0);
  10464. OwnedHqlExpr ret = transform(child);
  10465. OwnedHqlExpr folded = foldHqlExpression(ret, NULL, HFOforcefold);
  10466. if (!folded->isConstant())
  10467. {
  10468. StringBuffer s;
  10469. getExprECL(child, s);
  10470. translator.ERRORAT1(expr->queryChild(1), HQLERR_ExpectedConstant, s.str());
  10471. }
  10472. return folded.getClear();
  10473. }
  10474. case no_pat_instance:
  10475. {
  10476. OwnedHqlExpr child = transform(expr->queryChild(0));
  10477. if (child->getOperator() == no_pat_instance && child->hasProperty(tempAtom))
  10478. return createValue(no_pat_instance, child->getType(), LINK(child->queryChild(0)));
  10479. //default action
  10480. break;
  10481. }
  10482. case no_if:
  10483. {
  10484. //Parameters are being used a lot to select between two items in inside a function/module
  10485. //so much better if we trim the tree earlier....
  10486. IValue * value = expr->queryChild(0)->queryValue();
  10487. if (value && !expr->isAction())
  10488. {
  10489. unsigned branch = value->getBoolValue() ? 1 : 2;
  10490. IHqlExpression * arg = expr->queryChild(branch);
  10491. if (arg)
  10492. return transform(arg);
  10493. }
  10494. break;
  10495. }
  10496. case no_stored:
  10497. {
  10498. HqlExprArray children;
  10499. OwnedHqlExpr name = transform(expr->queryChild(0));
  10500. children.append(*lowerCaseHqlExpr(name));
  10501. return completeTransform(expr, children);
  10502. }
  10503. case no_merge:
  10504. return transformMerge(expr);
  10505. //yuk: Sets of datasets need special casing because their type isn't implicitly calculated from their inputs.
  10506. case no_datasetlist:
  10507. case no_rowset:
  10508. {
  10509. HqlExprArray children;
  10510. transformChildren(expr, children);
  10511. OwnedITypeInfo setType = makeSetType(children.item(0).getType());
  10512. return createValue(expr->getOperator(), setType.getClear(), children);
  10513. }
  10514. case no_rowsetrange:
  10515. {
  10516. HqlExprArray children;
  10517. transformChildren(expr, children);
  10518. OwnedITypeInfo setType = children.item(0).getType();
  10519. return createValue(expr->getOperator(), setType.getClear(), children);
  10520. }
  10521. case no_buildindex:
  10522. {
  10523. //Normalize the index build by splitting out the sort here, so that constant percolating
  10524. //is also done on these parameters
  10525. OwnedHqlExpr transformed = Parent::createTransformed(expr);
  10526. loop
  10527. {
  10528. IHqlExpression * ret = normalizeIndexBuild(transformed, options.sortIndexPayload, !translator.targetThor(), options.implicitShuffle);
  10529. if (!ret)
  10530. return LINK(transformed);
  10531. transformed.setown(ret);
  10532. }
  10533. }
  10534. case no_keyed:
  10535. {
  10536. HqlExprArray args;
  10537. bool same = transformChildren(expr, args);
  10538. IHqlExpression * ds = &args.item(0);
  10539. if ((ds->getOperator() == no_section) || (ds->getOperator() == no_sectioninput))
  10540. {
  10541. args.replace(*LINK(ds->queryChild(0)), 0);
  10542. same = false;
  10543. }
  10544. if (!same)
  10545. return expr->clone(args);
  10546. return LINK(expr);
  10547. }
  10548. case no_eclcrc:
  10549. {
  10550. OwnedHqlExpr arg = transform(expr->queryChild(0)->queryChild(0));
  10551. return createConstant(expr->queryType()->castFrom(true, (__int64)getExpressionCRC(arg)));
  10552. }
  10553. case no_cast:
  10554. if (options.normalizeExplicitCasts)
  10555. {
  10556. Owned<ITypeInfo> type = transformType(expr->queryType());
  10557. OwnedHqlExpr arg = transform(expr->queryChild(0));
  10558. return createValue(no_implicitcast, type.getClear(), arg.getClear());
  10559. }
  10560. break;
  10561. #if 0
  10562. //This code adds a assertsorted activity after an nary-join, but I don't think it is actually correct, so removed. I may revisit.
  10563. case no_nwayjoin:
  10564. if (expr->hasProperty(assertAtom) && !removeAsserts)
  10565. {
  10566. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);;
  10567. IHqlExpression * ds = transformed->queryChild(0);
  10568. IHqlExpression * selSeq = querySelSeq(transformed);
  10569. OwnedHqlExpr left = createSelector(no_left, ds, selSeq);
  10570. IHqlExpression * sortOrder = transformed->queryChild(3);
  10571. HqlExprArray args;
  10572. args.append(*LINK(transformed));
  10573. //MORE: Need fixing once join can have a different output format
  10574. args.append(*replaceSelector(sortOrder, left, transformed->queryNormalizedSelector()));
  10575. return createDataset(no_assertsorted, args);
  10576. }
  10577. break;
  10578. #endif
  10579. case no_attr:
  10580. case no_attr_link:
  10581. case no_attr_expr:
  10582. {
  10583. _ATOM name = expr->queryName();
  10584. if ((name == _uid_Atom) && (expr->numChildren() > 0))
  10585. {
  10586. //Make sure we ignore any line number information on the parameters mangled with the uid - otherwise
  10587. //they may create too many unique ids.
  10588. IHqlExpression * normalForm = queryLocationIndependent(expr);
  10589. if (normalForm != expr)
  10590. return transform(normalForm);
  10591. return ::createUniqueId();
  10592. }
  10593. #ifdef USE_SELSEQ_UID
  10594. if (name == _selectorSequence_Atom)
  10595. {
  10596. //Purely for testing what effect adding the unique sequences has on the parse time
  10597. if (options.simplifySelectorSequence)
  10598. return createDummySelectorSequence();
  10599. //Ensure parameterised sequences generate a unique sequence number...
  10600. //Not sure the following is really necessary, but will reduce in memory tree size....
  10601. //also saves complications from having weird attributes in the tree
  10602. if (expr->numChildren() > 0)
  10603. {
  10604. //Make sure we ignore any line number information on the parameters mangled with the uid - otherwise
  10605. //they may create too many unique ids.
  10606. IHqlExpression * normalForm = queryLocationIndependent(expr);
  10607. if (normalForm != expr)
  10608. return transform(normalForm);
  10609. return createSelectorSequence();
  10610. }
  10611. }
  10612. #endif
  10613. break;
  10614. }
  10615. case no_call:
  10616. return transformCall(expr);
  10617. case no_externalcall:
  10618. //Yuk.... Because we ensure that all records have a name, we need to make sure that external functions that return records
  10619. //also have there return value normalized - otherwise (jtolbert2.xhql) you can create an ambiguity
  10620. //We could also want to do this for user functions - but better would be to have a different node type.
  10621. if (options.ensureRecordsHaveSymbols)
  10622. {
  10623. if (expr->queryRecord())
  10624. return transformExternalCall(expr);
  10625. }
  10626. break;
  10627. case no_external:
  10628. {
  10629. ITypeInfo * type = expr->queryType();
  10630. OwnedITypeInfo newType = transformType(type);
  10631. HqlExprArray args;
  10632. bool same = transformChildren(expr, args);
  10633. if (same && (type == newType))
  10634. return LINK(expr);
  10635. return createExternalReference(expr->queryName(), newType.getClear(), args);
  10636. }
  10637. case no_outputscalar:
  10638. if (options.outputRowsAsDatasets && expr->queryChild(0)->isDatarow())
  10639. {
  10640. HqlExprArray args;
  10641. bool same = transformChildren(expr, args);
  10642. args.replace(*createDatasetFromRow(LINK(&args.item(0))), 0);
  10643. return createValue(no_output, makeVoidType(), args);
  10644. }
  10645. break;
  10646. case no_nameof:
  10647. {
  10648. OwnedHqlExpr newChild = transform(expr->queryChild(0));
  10649. switch (newChild->getOperator())
  10650. {
  10651. case no_newkeyindex:
  10652. return LINK(newChild->queryChild(3));
  10653. case no_table:
  10654. return LINK(newChild->queryChild(0));
  10655. default:
  10656. throwError(HQLERR_CannotDeduceNameDataset);
  10657. }
  10658. break;
  10659. }
  10660. case no_assertkeyed:
  10661. {
  10662. //Ensure assertkeyed is tagged with the selectors of each of the fields that are keyed, otherwise
  10663. //when expressions are constant folded, the information about keyed fields is lost.
  10664. HqlExprArray children;
  10665. transformChildren(expr, children);
  10666. HqlExprArray args;
  10667. gatherPotentialSelectors(args, expr);
  10668. OwnedHqlExpr selectors = createExprAttribute(_selectors_Atom, args);
  10669. children.append(*transform(selectors));
  10670. return expr->clone(children);
  10671. }
  10672. case no_sequence:
  10673. return getSizetConstant(nextSequenceValue++);
  10674. case no_filter:
  10675. return transformWithinFilter(expr);
  10676. case no_executewhen:
  10677. return transformExecuteWhen(expr);
  10678. case no_funcdef:
  10679. {
  10680. HqlExprArray children;
  10681. if (transformChildren(expr, children))
  10682. return LINK(expr);
  10683. return createFunctionDefinition(expr->queryName(), children);
  10684. }
  10685. case no_debug_option_value:
  10686. {
  10687. if (!matchesConstantString(expr->queryChild(0), "targetClusterType", true))
  10688. return getDebugValueExpr(translator.wu(), expr);
  10689. break;
  10690. }
  10691. case no_loop:
  10692. {
  10693. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  10694. IHqlExpression * loopCond = queryRealChild(transformed, 3);
  10695. if (loopCond)
  10696. {
  10697. //Create a firstCond attribute so that the condition for whether to execute the loop
  10698. //the first time will be efficiently optimized.
  10699. IHqlExpression * dataset = transformed->queryChild(0);
  10700. IHqlExpression * filter = queryRealChild(transformed, 2);
  10701. IHqlExpression * rowsid = transformed->queryProperty(_rowsid_Atom);
  10702. IHqlExpression * selSeq = querySelSeq(transformed);
  10703. IHqlExpression * counter = queryPropertyChild(expr, _countProject_Atom, 0);
  10704. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  10705. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(left), LINK(rowsid));
  10706. OwnedHqlExpr initialLoopDataset = LINK(dataset);
  10707. if (filter)
  10708. {
  10709. //If there is a loop filter then the global condition is applied to dataset filtered by that.
  10710. OwnedHqlExpr mappedFilter = replaceSelector(filter, left, dataset);
  10711. initialLoopDataset.setown(createDataset(no_filter, initialLoopDataset.getClear(), LINK(mappedFilter)));
  10712. }
  10713. OwnedHqlExpr firstCond = replaceExpression(loopCond, rowsExpr, initialLoopDataset);
  10714. if (counter)
  10715. {
  10716. //Whether to evaluate the 1st time round the loop requires COUNTER=1
  10717. OwnedHqlExpr one = createConstant(createIntValue(1, counter->getType()));
  10718. firstCond.setown(replaceExpression(firstCond, counter, one));
  10719. }
  10720. return appendOwnedOperand(transformed, createExprAttribute(_loopFirst_Atom, firstCond.getClear()));
  10721. }
  10722. return transformed.getClear();
  10723. }
  10724. break;
  10725. }
  10726. unsigned max = expr->numChildren();
  10727. if (max == 0)
  10728. return LINK(expr);
  10729. bool same = true;
  10730. HqlExprArray children;
  10731. children.ensure(max);
  10732. for (unsigned idx=0;idx<max;idx++)
  10733. {
  10734. IHqlExpression * child = expr->queryChild(idx);
  10735. IHqlExpression * tchild = transform(child);
  10736. children.append(*tchild);
  10737. if (child != tchild)
  10738. same = false;
  10739. }
  10740. //MORE: Test for pattern type here!
  10741. if (!same)
  10742. return expr->clone(children);
  10743. return LINK(expr);
  10744. }
  10745. IHqlExpression * HqlTreeNormalizer::createTransformedSelector(IHqlExpression * expr)
  10746. {
  10747. throwUnexpected();
  10748. }
  10749. IHqlExpression * normalizeRecord(HqlCppTranslator & translator, IHqlExpression * record)
  10750. {
  10751. HqlTreeNormalizer normalizer(translator);
  10752. HqlExprArray transformed;
  10753. return normalizer.transformRoot(record);
  10754. }
  10755. void normalizeHqlTree(HqlCppTranslator & translator, HqlExprArray & exprs)
  10756. {
  10757. bool seenForceLocal;
  10758. bool seenLocalUpload;
  10759. {
  10760. //First iterate through the expressions and call queryLocationIndependent() to avoid nested transforms (which are less efficient)
  10761. // ForEachItemIn(iInit, exprs)
  10762. // queryLocationIndependent(&exprs.item(iInit));
  10763. unsigned time = msTick();
  10764. HqlTreeNormalizer normalizer(translator);
  10765. HqlExprArray transformed;
  10766. normalizer.analyseArray(exprs, 0);
  10767. normalizer.transformRoot(exprs, transformed);
  10768. // logTreeStats(exprs);
  10769. // logTreeStats(transformed);
  10770. // DBGLOG("Before normalize %u unique expressions, after normalize %u unique expressions", getNumUniqueExpressions(exprs), getNumUniqueExpressions(transformed));
  10771. replaceArray(exprs, transformed);
  10772. seenForceLocal = normalizer.querySeenForceLocal();
  10773. seenLocalUpload = normalizer.querySeenLocalUpload();
  10774. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.initial", msTick()-time);
  10775. }
  10776. if (translator.queryOptions().constantFoldPostNormalize)
  10777. {
  10778. unsigned time = msTick();
  10779. HqlExprArray transformed;
  10780. quickFoldExpressions(transformed, exprs, NULL, 0);
  10781. replaceArray(exprs, transformed);
  10782. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.fold", msTick()-time);
  10783. }
  10784. translator.traceExpressions("before scope tag", exprs);
  10785. {
  10786. unsigned time = msTick();
  10787. HqlScopeTagger normalizer(translator.queryErrors());
  10788. HqlExprArray transformed;
  10789. normalizer.transformRoot(exprs, transformed);
  10790. replaceArray(exprs, transformed);
  10791. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.scope", msTick()-time);
  10792. normalizer.reportWarnings();
  10793. }
  10794. if (translator.queryOptions().normalizeLocations)
  10795. normalizeAnnotations(translator, exprs);
  10796. translator.traceExpressions("after scope tag", exprs);
  10797. {
  10798. unsigned time = msTick();
  10799. HqlLinkedChildRowTransformer transformer(translator.queryOptions().implicitLinkedChildRows);
  10800. HqlExprArray transformed;
  10801. transformer.transformArray(exprs, transformed);
  10802. replaceArray(exprs, transformed);
  10803. DEBUG_TIMERX(translator.queryTimeReporter(), "EclServer: tree transform: normalize.linkedChildRows", msTick()-time);;
  10804. }
  10805. if (seenLocalUpload)
  10806. {
  10807. LocalUploadTransformer transformer(translator.wu());
  10808. HqlExprArray transformed;
  10809. transformer.transformRoot(exprs, transformed);
  10810. replaceArray(exprs, transformed);
  10811. }
  10812. if (seenForceLocal)
  10813. {
  10814. //Add ,local to all sources, so that count(x) inside local() is differentiated from a global count(x)
  10815. ForceLocalTransformer localizer(translator.getTargetClusterType());
  10816. HqlExprArray transformed;
  10817. localizer.transformRoot(exprs, transformed);
  10818. replaceArray(exprs, transformed);
  10819. }
  10820. #ifdef USE_SELSEQ_UID
  10821. if (translator.queryOptions().detectAmbiguousSelector || translator.queryOptions().allowAmbiguousSelector)
  10822. {
  10823. LeftRightSelectorNormalizer transformer(translator.queryOptions().allowAmbiguousSelector);
  10824. transformer.analyseArray(exprs, 0);
  10825. if (!transformer.containsAmbiguity())
  10826. {
  10827. HqlExprArray transformed;
  10828. transformer.transformRoot(exprs, transformed);
  10829. replaceArray(exprs, transformed);
  10830. }
  10831. }
  10832. #endif
  10833. if (false)
  10834. {
  10835. NestedSelectorNormalizer transformer;
  10836. transformer.analyseArray(exprs, 0);
  10837. if (transformer.requiresTransforming())
  10838. {
  10839. HqlExprArray transformed;
  10840. transformer.transformRoot(exprs, transformed);
  10841. replaceArray(exprs, transformed);
  10842. }
  10843. }
  10844. #if 0
  10845. if (seenIndex)
  10846. {
  10847. FilteredIndexOptimizer transformer(true, false);
  10848. HqlExprArray transformed;
  10849. transformer.transformRoot(exprs, transformed);
  10850. replaceArray(exprs, transformed);
  10851. }
  10852. #endif
  10853. #ifdef _DEBUG
  10854. //spotPotentialDuplicateCode(exprs);
  10855. #endif
  10856. }
  10857. IHqlExpression * normalizeHqlTree(HqlCppTranslator & translator, IHqlExpression * expr)
  10858. {
  10859. HqlExprArray exprs;
  10860. expr->unwindList(exprs, no_comma);
  10861. normalizeHqlTree(translator, exprs);
  10862. return createComma(exprs);
  10863. }
  10864. void hoistNestedCompound(HqlCppTranslator & translator, HqlExprArray & exprs)
  10865. {
  10866. if (containsCompound(exprs))
  10867. {
  10868. NestedCompoundTransformer normalizer(translator);
  10869. normalizer.analyseArray(exprs, 0);
  10870. HqlExprArray transformed;
  10871. normalizer.transformRoot(exprs, transformed);
  10872. replaceArray(exprs, transformed);
  10873. }
  10874. }
  10875. void hoistNestedCompound(HqlCppTranslator & translator, WorkflowArray & workflow)
  10876. {
  10877. ForEachItemIn(i, workflow)
  10878. hoistNestedCompound(translator, workflow.item(i).queryExprs());
  10879. }
  10880. //---------------------------------------------------------------------------
  10881. static IHqlExpression * substituteClusterSize(unsigned numNodes, IHqlExpression * expr, ICodegenContextCallback * ctxCallback, IWorkUnit * wu);
  10882. static HqlTransformerInfo clusterSubstitueTransformerInfo("ClusterSubstitueTransformer");
  10883. class ClusterSubstitueTransformer : public NewHqlTransformer
  10884. {
  10885. public:
  10886. ClusterSubstitueTransformer(unsigned size, ICodegenContextCallback * _ctxCallback, IWorkUnit * _wu)
  10887. : NewHqlTransformer(clusterSubstitueTransformerInfo)
  10888. {
  10889. ctxCallback = _ctxCallback;
  10890. wu = _wu;
  10891. OwnedHqlExpr clusterSizeExpr = createValue(no_clustersize, makeIntType(4, false));
  10892. if (size)
  10893. clusterSizeValue.setown(getSizetConstant(size));
  10894. setTransformed(clusterSizeExpr, clusterSizeValue);
  10895. }
  10896. protected:
  10897. IHqlExpression * createTransformed(IHqlExpression * expr)
  10898. {
  10899. if (expr->isConstant())
  10900. return LINK(expr);
  10901. switch (expr->getOperator())
  10902. {
  10903. case no_clustersize:
  10904. //Cope if CLUSTERSIZE is assigned to a named symbol
  10905. if (clusterSizeValue)
  10906. return LINK(clusterSizeValue);
  10907. break;
  10908. case no_cluster:
  10909. return createSubstitutedChild(expr, expr->queryChild(1));
  10910. case no_colon:
  10911. {
  10912. ForEachChild(i, expr)
  10913. {
  10914. IHqlExpression * child = expr->queryChild(i);
  10915. if (child->getOperator() == no_persist)
  10916. {
  10917. IHqlExpression * cluster = queryRealChild(child, 1);
  10918. if (cluster && !isBlankString(cluster))
  10919. return createSubstitutedChild(expr, cluster);
  10920. }
  10921. else if (child->getOperator() == no_global)
  10922. {
  10923. IHqlExpression * cluster = queryRealChild(child, 0);
  10924. if (cluster && !isBlankString(cluster))
  10925. return createSubstitutedChild(expr, cluster);
  10926. }
  10927. }
  10928. break;
  10929. }
  10930. }
  10931. return NewHqlTransformer::createTransformed(expr);
  10932. }
  10933. IHqlExpression * createSubstitutedChild(IHqlExpression * expr, IHqlExpression * cluster)
  10934. {
  10935. StringBuffer clusterText;
  10936. getStringValue(clusterText, cluster);
  10937. if (clusterText.length())
  10938. ctxCallback->noteCluster(clusterText.str());
  10939. #if 0
  10940. Owned<IConstWUClusterInfo> clusterInfo = wu->getClusterInfo(clusterText.str());
  10941. if (clusterInfo)
  10942. {
  10943. unsigned numNodes = clusterInfo->getSize();
  10944. if (numNodes == 0) numNodes = 1;
  10945. HqlExprArray args;
  10946. unwindChildren(args, expr);
  10947. args.replace(*substituteClusterSize(numNodes, &args.item(0), ctxCallback, wu), 0);
  10948. return expr->clone(args);
  10949. }
  10950. #endif
  10951. return LINK(expr);
  10952. }
  10953. protected:
  10954. ICodegenContextCallback * ctxCallback;
  10955. IWorkUnit * wu;
  10956. OwnedHqlExpr clusterSizeValue;
  10957. };
  10958. IHqlExpression * substituteClusterSize(unsigned numNodes, IHqlExpression * expr, ICodegenContextCallback * ctxCallback, IWorkUnit * wu)
  10959. {
  10960. ClusterSubstitueTransformer transformer(numNodes, ctxCallback, wu);
  10961. return transformer.transformRoot(expr);
  10962. }
  10963. void HqlCppTranslator::substituteClusterSize(HqlExprArray & exprs)
  10964. {
  10965. unsigned numNodes = options.specifiedClusterSize;
  10966. ClusterSubstitueTransformer transformer(numNodes, ctxCallback, wu());
  10967. HqlExprArray transformed;
  10968. ForEachItemIn(i, exprs)
  10969. transformed.append(*transformer.transformRoot(&exprs.item(i)));
  10970. replaceArray(exprs, transformed);
  10971. }
  10972. IHqlExpression * HqlCppTranslator::separateLibraries(IHqlExpression * query, HqlExprArray & internalLibraries)
  10973. {
  10974. HqlExprArray exprs;
  10975. query->unwindList(exprs, no_comma);
  10976. traceExpressions("before transform graph for generation", exprs);
  10977. //Remove any meta entries from the tree.
  10978. ForEachItemInRev(i, exprs)
  10979. if (exprs.item(i).getOperator() == no_setmeta)
  10980. exprs.remove(i);
  10981. processEmbeddedLibraries(exprs, internalLibraries, isLibraryScope(query));
  10982. return createComma(exprs);
  10983. }
  10984. bool HqlCppTranslator::transformGraphForGeneration(IHqlExpression * query, WorkflowArray & workflow)
  10985. {
  10986. HqlExprArray exprs;
  10987. if (isLibraryScope(query))
  10988. outputLibrary->mapLogicalToImplementation(exprs, query);
  10989. else
  10990. query->unwindList(exprs, no_comma);
  10991. traceExpressions("before transform graph for generation", exprs);
  10992. //Don't change the engine if libraries are involved, otherwise things will get very confused.
  10993. unsigned timeCall = msTick();
  10994. expandDelayedFunctionCalls(queryErrors(), exprs);
  10995. DEBUG_TIMER("EclServer: tree transform: expand delayed calls", msTick()-timeCall);
  10996. unsigned time1 = msTick();
  10997. traceExpressions("before normalize", exprs);
  10998. normalizeHqlTree(*this, exprs);
  10999. DEBUG_TIMER("EclServer: tree transform: normalize", msTick()-time1);
  11000. checkNormalized(exprs);
  11001. #ifdef PICK_ENGINE_EARLY
  11002. if (options.pickBestEngine)
  11003. pickBestEngine(exprs);
  11004. #endif
  11005. allocateSequenceNumbers(exprs); // Added to all expressions/output statements etc.
  11006. traceExpressions("allocate Sequence", exprs);
  11007. checkNormalized(exprs);
  11008. if (options.generateLogicalGraph || options.generateLogicalGraphOnly)
  11009. {
  11010. LogicalGraphCreator creator(wu());
  11011. creator.createLogicalGraph(exprs);
  11012. if (options.generateLogicalGraphOnly)
  11013. return false;
  11014. curActivityId = creator.queryMaxActivityId();
  11015. }
  11016. traceExpressions("begin transformGraphForGeneration", exprs);
  11017. checkNormalized(exprs);
  11018. {
  11019. unsigned startTime = msTick();
  11020. substituteClusterSize(exprs);
  11021. DEBUG_TIMER("EclServer: tree transform: substituteClusterSize", msTick()-startTime);
  11022. }
  11023. if (options.globalFold)
  11024. {
  11025. unsigned startTime = msTick();
  11026. HqlExprArray folded;
  11027. unsigned foldOptions = DEFAULT_FOLD_OPTIONS;
  11028. if (options.foldConstantDatasets) foldOptions |= HFOconstantdatasets;
  11029. if (options.percolateConstants) foldOptions |= HFOpercolateconstants;
  11030. if (options.percolateFilters) foldOptions |= HFOpercolatefilters;
  11031. if (options.globalFoldOptions != (unsigned)-1)
  11032. foldOptions = options.globalFoldOptions;
  11033. foldHqlExpression(folded, exprs, foldOptions);
  11034. replaceArray(exprs, folded);
  11035. DEBUG_TIMER("EclServer: tree transform: global fold", msTick()-startTime);
  11036. }
  11037. traceExpressions("after global fold", exprs);
  11038. checkNormalized(exprs);
  11039. if (options.globalOptimize)
  11040. {
  11041. unsigned startTime = msTick();
  11042. HqlExprArray folded;
  11043. optimizeHqlExpression(folded, exprs, options.globalFold ? HOOfold : 0);
  11044. replaceArray(exprs, folded);
  11045. DEBUG_TIMER("EclServer: tree transform: global optimize", msTick()-startTime);
  11046. }
  11047. traceExpressions("alloc", exprs);
  11048. checkNormalized(exprs);
  11049. modifyOutputLocations(exprs);
  11050. if (exprs.ordinality() == 0)
  11051. return false; // No action needed
  11052. unsigned time4 = msTick();
  11053. ::extractWorkflow(*this, exprs, workflow);
  11054. traceExpressions("workflow", workflow);
  11055. checkNormalized(workflow);
  11056. DEBUG_TIMER("EclServer: tree transform: stored results", msTick()-time4);
  11057. #ifdef USE_SELSEQ_UID
  11058. if (options.normalizeSelectorSequence)
  11059. {
  11060. unsigned time = msTick();
  11061. ForEachItemIn(i, workflow)
  11062. {
  11063. LeftRightTransformer normalizer;
  11064. normalizer.process(workflow.item(i).queryExprs());
  11065. }
  11066. DEBUG_TIMERX(queryTimeReporter(), "EclServer: tree transform: left right", msTick()-time);
  11067. //traceExpressions("after implicit alias", workflow);
  11068. }
  11069. #endif
  11070. if (queryOptions().createImplicitAliases)
  11071. {
  11072. unsigned time = msTick();
  11073. ForEachItemIn(i, workflow)
  11074. {
  11075. ImplicitAliasTransformer normalizer;
  11076. normalizer.process(workflow.item(i).queryExprs());
  11077. }
  11078. DEBUG_TIMERX(queryTimeReporter(), "EclServer: tree transform: implicit alias", msTick()-time);
  11079. //traceExpressions("after implicit alias", workflow);
  11080. }
  11081. if (outputLibrary && workflow.ordinality() > 1)
  11082. {
  11083. unsigned cnt = 0;
  11084. ForEachItemIn(i, workflow)
  11085. {
  11086. if (!workflow.item(i).isFunction())
  11087. cnt++;
  11088. }
  11089. if (cnt > 1)
  11090. {
  11091. SCMStringBuffer libraryName;
  11092. getOutputLibraryName(libraryName, wu());
  11093. throwError2(HQLERR_LibraryCannotContainWorkflow, libraryName.str(), "");
  11094. }
  11095. }
  11096. {
  11097. unsigned startTime = msTick();
  11098. hoistNestedCompound(*this, workflow);
  11099. DEBUG_TIMER("EclServer: tree transform: hoist nested compound", msTick()-startTime);
  11100. }
  11101. if (options.optimizeNestedConditional)
  11102. {
  11103. cycle_t time = msTick();
  11104. ForEachItemIn(idx, workflow)
  11105. optimizeNestedConditional(workflow.item(idx).queryExprs());
  11106. DEBUG_TIMER("EclServer: optimize nested conditional", msTick()-time);
  11107. traceExpressions("nested", workflow);
  11108. checkNormalized(workflow);
  11109. }
  11110. checkNormalized(workflow);
  11111. //sort(x)[n] -> topn(x, n)[]n, count(x)>n -> count(choosen(x,n+1)) > n and possibly others
  11112. {
  11113. unsigned startTime = msTick();
  11114. optimizeActivities(workflow, !targetThor(), options.optimizeNonEmpty);
  11115. DEBUG_TIMER("EclServer: tree transform: optimize activities", msTick()-startTime);
  11116. }
  11117. checkNormalized(workflow);
  11118. unsigned time5 = msTick();
  11119. migrateExprToNaturalLevel(workflow, wu(), *this); // Ensure expressions are evaluated at the best level - e.g., counts moved to most appropriate level.
  11120. DEBUG_TIMER("EclServer: tree transform: migrate", msTick()-time5);
  11121. //transformToAliases(exprs);
  11122. traceExpressions("migrate", workflow);
  11123. checkNormalized(workflow);
  11124. unsigned time2 = msTick();
  11125. markThorBoundaries(workflow); // work out which engine is going to perform which operation.
  11126. DEBUG_TIMER("EclServer: tree transform: thor hole", msTick()-time2);
  11127. traceExpressions("boundary", workflow);
  11128. checkNormalized(workflow);
  11129. if (options.optimizeGlobalProjects)
  11130. {
  11131. cycle_t time = msTick();
  11132. ForEachItemIn(idx, workflow)
  11133. insertImplicitProjects(*this, workflow.item(idx).queryExprs());
  11134. DEBUG_TIMER("EclServer: global implicit projects", msTick()-time);
  11135. traceExpressions("implicit", workflow);
  11136. checkNormalized(workflow);
  11137. }
  11138. unsigned time3 = msTick();
  11139. normalizeResultFormat(workflow, options);
  11140. DEBUG_TIMER("EclServer: tree transform: normalize result", msTick()-time3);
  11141. traceExpressions("results", workflow);
  11142. checkNormalized(workflow);
  11143. optimizePersists(workflow);
  11144. traceExpressions("per", workflow);
  11145. checkNormalized(workflow);
  11146. // flattenDatasets(workflow);
  11147. // traceExpressions("flatten", workflow);
  11148. {
  11149. unsigned startTime = msTick();
  11150. mergeThorGraphs(workflow, options.resourceConditionalActions, options.resourceSequential); // reduces number of graphs sent to thor
  11151. DEBUG_TIMER("EclServer: tree transform: merge thor", msTick()-startTime);
  11152. }
  11153. traceExpressions("merged", workflow);
  11154. checkNormalized(workflow);
  11155. if (queryOptions().normalizeLocations)
  11156. normalizeAnnotations(*this, workflow);
  11157. spotGlobalCSE(workflow); // spot CSE within those graphs, and create some more
  11158. checkNormalized(workflow);
  11159. //expandGlobalDatasets(workflow, wu(), *this);
  11160. {
  11161. unsigned startTime = msTick();
  11162. mergeThorGraphs(workflow, options.resourceConditionalActions, options.resourceSequential);
  11163. DEBUG_TIMER("EclServer: tree transform: merge thor", msTick()-startTime);
  11164. }
  11165. checkNormalized(workflow);
  11166. removeTrivialGraphs(workflow);
  11167. checkNormalized(workflow);
  11168. #ifndef PICK_ENGINE_EARLY
  11169. if (options.pickBestEngine)
  11170. pickBestEngine(workflow);
  11171. #endif
  11172. updateClusterType();
  11173. traceExpressions("before convert to logical", workflow);
  11174. convertLogicalToActivities(workflow); // e.g., merge disk reads, transform group, all to sort etc.
  11175. #ifndef _DEBUG
  11176. if (options.regressionTest)
  11177. #endif
  11178. {
  11179. unsigned startTime = msTick();
  11180. ForEachItemIn(icheck, workflow)
  11181. checkDependencyConsistency(workflow.item(icheck).queryExprs());
  11182. DEBUG_TIMER("EclServer: tree transform: check dependency", msTick()-startTime);
  11183. }
  11184. traceExpressions("end transformGraphForGeneration", workflow);
  11185. checkNormalized(workflow);
  11186. return true;
  11187. }
  11188. //---------------------------------------------------------------------------
  11189. /*
  11190. Different transformers:
  11191. merge: required if a child get removed or merged with a parent of a non-table dataset.
  11192. adding is not a problem (unless tables are inserted) because all refs to ds.x will remain valid.
  11193. 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
  11194. It is also ok if only scalars are transformed.
  11195. Transformer base merge dependants [should be]
  11196. filterExtractor simple N
  11197. resource Scoped (Y) complex - could possibly derive from merging...? why scoped?
  11198. HqlThorBoundary New N
  11199. HqlResult New N isConditional,insideThor,insideCondition
  11200. creation of getresult only done on scalars, so I think it is ok.
  11201. could possibly remove the scoping if count() etc. were tagged as outer level or not
  11202. ThorHql Merging Y Again scoped because of no_count etc.
  11203. CompoundSource New add* Either added, or non-tables(limits) are cloned, so no merging issues.
  11204. CompoundActivity Merging Y When limit merged into a dataset. [ need a new way? ]
  11205. Workflow New [inTransform] I think no for the same reason as above, or it adds. layers.
  11206. NewScopeMigrate New ? I think it might be ok, because doesn't modify any tables, only scalars
  11207. ThorCount New N no issues.
  11208. Cse New ? Probably, but ok, if only done on scalars.
  11209. HqlTreeNormalizer Scoped * I don't think it does any, but need to be careful none are introduced.
  11210. */
  11211. /*
  11212. NOTES:
  11213. Consider adding a hqlmeta.hpp that defines all the characteristics of an IHqlExpression node - e.g.,
  11214. is it constant, number of child files, text, what filenames does it generate? what does it read,
  11215. what results does it read/write.
  11216. Dependancy code:
  11217. 1. In the resourcer
  11218. 2. TableDependencies In hqlttcpp to stop reordering when not valid.
  11219. ?Is GetResultHash called on globals that haven't been calculated???
  11220. */