hqlutil.cpp 251 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jliball.hpp"
  14. #include "hql.hpp"
  15. #include "eclrtl.hpp"
  16. #include "platform.h"
  17. #include "jlib.hpp"
  18. #include "jmisc.hpp"
  19. #include "jstream.ipp"
  20. #include "hql.hpp"
  21. #include "hqlexpr.hpp"
  22. #include "hqlutil.hpp"
  23. #include "hqlpmap.hpp"
  24. #include "hqlfold.hpp"
  25. #include "hqlerrors.hpp"
  26. #include "hqltrans.ipp"
  27. #include "hqlusage.hpp"
  28. #include "hqlthql.hpp"
  29. #include "deffield.hpp"
  30. #include "workunit.hpp"
  31. #include "jencrypt.hpp"
  32. #include "hqlattr.hpp"
  33. #include "hqlerror.hpp"
  34. #include "hqlexpr.ipp"
  35. #include "hqlrepository.hpp"
  36. #define SIZET_CACHE_SIZE 5001
  37. #define FIXEDATTR_CACHE_SIZE 1001
  38. static ITypeInfo * sizetType;
  39. static ITypeInfo * signedType;
  40. static ITypeInfo * constUnknownVarStringType;
  41. static CriticalSection * sizetCacheCs;
  42. static IHqlExpression * sizetCache[SIZET_CACHE_SIZE];
  43. static IHqlExpression * fixedAttrSizeCache[FIXEDATTR_CACHE_SIZE];
  44. static IHqlExpression * defaultMaxRecordLengthExpr;
  45. static IHqlExpression * cacheAlignedAttr;
  46. static IHqlExpression * cacheEmbeddedAttr;
  47. static IHqlExpression * cacheInlineAttr;
  48. static IHqlExpression * cacheLinkCountedAttr;
  49. static IHqlExpression * cacheReferenceAttr;
  50. static IHqlExpression * cacheStreamedAttr;
  51. static IHqlExpression * cacheUnadornedAttr;
  52. static IHqlExpression * matchxxxPseudoFile;
  53. static IHqlExpression * cachedQuotedNullExpr;
  54. static IHqlExpression * cachedGlobalSequenceNumber;
  55. static IHqlExpression * cachedLocalSequenceNumber;
  56. static IHqlExpression * cachedStoredSequenceNumber;
  57. static IHqlExpression * cachedOmittedValueExpr;
  58. static void initBoolAttr(IAtom * name, IHqlExpression * x[2])
  59. {
  60. x[0] = createExprAttribute(name, createConstant(false));
  61. x[1] = createExprAttribute(name, createConstant(true));
  62. }
  63. MODULE_INIT(INIT_PRIORITY_STANDARD)
  64. {
  65. sizetType = makeIntType(sizeof(size32_t), false);
  66. signedType = makeIntType(sizeof(signed), true);
  67. sizetCacheCs = new CriticalSection;
  68. constUnknownVarStringType = makeConstantModifier(makeVarStringType(UNKNOWN_LENGTH));
  69. defaultMaxRecordLengthExpr = createQuoted("<default-max-length>", makeIntType(sizeof(size32_t), false));
  70. cacheAlignedAttr = createAttribute(_propAligned_Atom);
  71. cacheEmbeddedAttr = createAttribute(embeddedAtom);
  72. cacheInlineAttr = createAttribute(inlineAtom);
  73. cacheLinkCountedAttr = createAttribute(_linkCounted_Atom);
  74. cacheReferenceAttr = createAttribute(referenceAtom);
  75. cacheStreamedAttr = createAttribute(streamedAtom);
  76. cacheUnadornedAttr = createAttribute(_propUnadorned_Atom);
  77. matchxxxPseudoFile = createDataset(no_pseudods, createRecord()->closeExpr(), createAttribute(matchxxxPseudoFileAtom));
  78. cachedQuotedNullExpr = createValue(no_nullptr, makeBoolType());
  79. cachedOmittedValueExpr = createValue(no_omitted, makeAnyType());
  80. cachedGlobalSequenceNumber = createConstant(signedType->castFrom(true, (__int64)ResultSequencePersist));
  81. cachedLocalSequenceNumber = createConstant(signedType->castFrom(true, (__int64)ResultSequenceInternal));
  82. cachedStoredSequenceNumber = createConstant(signedType->castFrom(true, (__int64)ResultSequenceStored));
  83. return true;
  84. }
  85. MODULE_EXIT()
  86. {
  87. delete sizetCacheCs;
  88. sizetType->Release();
  89. signedType->Release();
  90. defaultMaxRecordLengthExpr->Release();
  91. for (unsigned i=0; i < SIZET_CACHE_SIZE; i++)
  92. ::Release(sizetCache[i]);
  93. for (unsigned i2=0; i2 < FIXEDATTR_CACHE_SIZE; i2++)
  94. ::Release(fixedAttrSizeCache[i2]);
  95. cacheAlignedAttr->Release();
  96. cacheEmbeddedAttr->Release();
  97. cacheInlineAttr->Release();
  98. cacheLinkCountedAttr->Release();
  99. cacheReferenceAttr->Release();
  100. cacheStreamedAttr->Release();
  101. cacheUnadornedAttr->Release();
  102. matchxxxPseudoFile->Release();
  103. cachedQuotedNullExpr->Release();
  104. cachedGlobalSequenceNumber->Release();
  105. cachedLocalSequenceNumber->Release();
  106. cachedStoredSequenceNumber->Release();
  107. cachedOmittedValueExpr->Release();
  108. constUnknownVarStringType->Release();
  109. }
  110. inline int TFI(bool value) { return value ? 0 : 1; }
  111. IHqlExpression * getSizetConstant(unsigned size)
  112. {
  113. if (size >= SIZET_CACHE_SIZE)
  114. return createConstant(sizetType->castFrom(false, (__int64)size));
  115. CriticalBlock block(*sizetCacheCs);
  116. IHqlExpression * match = sizetCache[size];
  117. if (!match)
  118. match = sizetCache[size] = createConstant(sizetType->castFrom(false, (__int64)size));
  119. return LINK(match);
  120. }
  121. IHqlExpression * createIntConstant(__int64 val)
  122. {
  123. return createConstant(createMinIntValue(val));
  124. }
  125. IHqlExpression * createUIntConstant(unsigned __int64 val)
  126. {
  127. return createConstant(createMinIntValue(val));
  128. }
  129. inline IIdAtom * createMangledName(IHqlExpression * module, IHqlExpression * child)
  130. {
  131. StringBuffer mangledName;
  132. mangledName.append(module->queryName()).append(".").append(child->queryName());
  133. return createIdAtom(mangledName.str());
  134. }
  135. IHqlExpression * queryDefaultMaxRecordLengthExpr()
  136. {
  137. return defaultMaxRecordLengthExpr;
  138. };
  139. HQL_API IHqlExpression * getFixedSizeAttr(unsigned size)
  140. {
  141. if (size >= FIXEDATTR_CACHE_SIZE)
  142. {
  143. OwnedHqlExpr sizeExpr = getSizetConstant(size);
  144. return createExprAttribute(_propSize_Atom, LINK(sizeExpr), LINK(sizeExpr), LINK(sizeExpr));
  145. }
  146. CriticalBlock block(*sizetCacheCs); // reuse the critical section
  147. IHqlExpression * match = fixedAttrSizeCache[size];
  148. if (!match)
  149. {
  150. OwnedHqlExpr sizeExpr = getSizetConstant(size);
  151. match = fixedAttrSizeCache[size] = createExprAttribute(_propSize_Atom, LINK(sizeExpr), LINK(sizeExpr), LINK(sizeExpr));
  152. }
  153. return LINK(match);
  154. }
  155. extern HQL_API IHqlExpression * queryQuotedNullExpr()
  156. {
  157. return cachedQuotedNullExpr;
  158. }
  159. extern HQL_API IHqlExpression * createOmittedValue()
  160. {
  161. return LINK(cachedOmittedValueExpr);
  162. }
  163. #if 0
  164. IHqlExpression * queryRequiresDestructorAttr(bool value)
  165. {
  166. return cacheRequiresDestructorAttr[TFI(value)];
  167. }
  168. #endif
  169. IHqlExpression * queryUnadornedAttr()
  170. {
  171. return cacheUnadornedAttr;
  172. }
  173. IHqlExpression * queryAlignedAttr()
  174. {
  175. return cacheAlignedAttr;
  176. }
  177. extern HQL_API IHqlExpression * queryLinkCountedAttr()
  178. {
  179. return cacheLinkCountedAttr;
  180. }
  181. extern HQL_API IHqlExpression * getLinkCountedAttr()
  182. {
  183. return LINK(cacheLinkCountedAttr);
  184. }
  185. extern HQL_API IHqlExpression * getStreamedAttr()
  186. {
  187. return LINK(cacheStreamedAttr);
  188. }
  189. extern HQL_API IHqlExpression * getInlineAttr()
  190. {
  191. return LINK(cacheInlineAttr);
  192. }
  193. extern HQL_API IHqlExpression * getEmbeddedAttr()
  194. {
  195. return LINK(cacheEmbeddedAttr);
  196. }
  197. extern HQL_API IHqlExpression * getReferenceAttr()
  198. {
  199. return LINK(cacheReferenceAttr);
  200. }
  201. extern HQL_API IHqlExpression * queryMatchxxxPseudoFile()
  202. {
  203. return matchxxxPseudoFile;
  204. }
  205. IHqlExpression * getGlobalSequenceNumber() { return LINK(cachedGlobalSequenceNumber); }
  206. IHqlExpression * getLocalSequenceNumber() { return LINK(cachedLocalSequenceNumber); }
  207. IHqlExpression * getStoredSequenceNumber() { return LINK(cachedStoredSequenceNumber); }
  208. IHqlExpression * getOnceSequenceNumber() { return createConstant(signedType->castFrom(true, (__int64)ResultSequenceOnce)); }
  209. //---------------------------------------------------------------------------
  210. bool containsAggregate(IHqlExpression * expr)
  211. {
  212. return expr->isGroupAggregateFunction();
  213. }
  214. bool containsComplexAggregate(IHqlExpression * expr)
  215. {
  216. unsigned childIndex = (unsigned)-1;
  217. switch (expr->getOperator())
  218. {
  219. case no_record:
  220. childIndex = 0;
  221. break;
  222. case no_newtransform:
  223. case no_transform:
  224. childIndex = 1;
  225. break;
  226. default:
  227. UNIMPLEMENTED;
  228. }
  229. unsigned num = expr->numChildren();
  230. unsigned idx;
  231. for (idx = 0; idx < num; idx++)
  232. {
  233. IHqlExpression * cur = expr->queryChild(idx);
  234. if (cur->isAttribute())
  235. continue;
  236. IHqlExpression * value = cur->queryChild(childIndex);
  237. if (value && value->isGroupAggregateFunction())
  238. {
  239. //HOLe can cast aggregate values.
  240. node_operator op = value->getOperator();
  241. if ((op == no_cast) || (op == no_implicitcast))
  242. value = value->queryChild(0);
  243. switch (value->getOperator())
  244. {
  245. case NO_AGGREGATEGROUP:
  246. break;
  247. default:
  248. return true;
  249. }
  250. }
  251. }
  252. return false;
  253. }
  254. static node_operator containsSingleAggregate(IHqlExpression * expr)
  255. {
  256. switch (expr->getOperator())
  257. {
  258. case no_assign:
  259. {
  260. node_operator rhsOp = expr->queryChild(1)->getOperator();
  261. switch (rhsOp)
  262. {
  263. case NO_AGGREGATEGROUP:
  264. return rhsOp;
  265. }
  266. return no_none;
  267. }
  268. case no_assignall:
  269. case no_transform:
  270. case no_newtransform:
  271. {
  272. node_operator ret = no_none;
  273. ForEachChild(i, expr)
  274. {
  275. node_operator childOp = containsSingleAggregate(expr->queryChild(i));
  276. if (childOp != no_none)
  277. {
  278. if (ret == no_none)
  279. ret = childOp;
  280. else
  281. return no_all;
  282. }
  283. }
  284. return ret;
  285. }
  286. }
  287. return no_none;
  288. }
  289. node_operator queryTransformSingleAggregate(IHqlExpression * expr)
  290. {
  291. return containsSingleAggregate(expr);
  292. }
  293. static bool containsOnlyLeftTable(IHqlExpression * expr, bool ignoreSelfOrFilepos)
  294. {
  295. switch (expr->getOperator())
  296. {
  297. case no_self:
  298. return ignoreSelfOrFilepos;
  299. case no_left:
  300. return true;
  301. case no_selectnth:
  302. return containsOnlyLeftTable(expr->queryChild(0), ignoreSelfOrFilepos) && containsOnlyLeft(expr->queryChild(1), ignoreSelfOrFilepos);
  303. case no_select:
  304. return containsOnlyLeftTable(expr->queryChild(0), ignoreSelfOrFilepos);
  305. }
  306. return false;
  307. }
  308. bool containsOnlyLeft(IHqlExpression * expr, bool ignoreSelfOrFilepos)
  309. {
  310. switch (expr->getOperator())
  311. {
  312. case no_right:
  313. return false;
  314. case no_select:
  315. return containsOnlyLeftTable(expr, ignoreSelfOrFilepos);
  316. case no_field:
  317. case no_table:
  318. return false;
  319. case no_filepos:
  320. case no_file_logicalname:
  321. return ignoreSelfOrFilepos;
  322. default:
  323. {
  324. unsigned max = expr->numChildren();
  325. unsigned idx;
  326. for (idx = 0; idx < max; idx++)
  327. {
  328. if (!containsOnlyLeft(expr->queryChild(idx), ignoreSelfOrFilepos))
  329. return false;
  330. }
  331. return true;
  332. }
  333. }
  334. }
  335. IHqlExpression * queryPhysicalRootTable(IHqlExpression * expr)
  336. {
  337. loop
  338. {
  339. switch (expr->getOperator())
  340. {
  341. case no_keyindex:
  342. case no_newkeyindex:
  343. case no_table:
  344. return expr;
  345. }
  346. switch (getNumChildTables(expr))
  347. {
  348. case 1:
  349. expr = expr->queryChild(0);
  350. break;
  351. default:
  352. return NULL;
  353. }
  354. }
  355. }
  356. IHqlExpression * queryTableFilename(IHqlExpression * expr)
  357. {
  358. IHqlExpression * table = queryPhysicalRootTable(expr);
  359. if (table)
  360. {
  361. switch (table->getOperator())
  362. {
  363. case no_keyindex:
  364. return table->queryChild(2);
  365. case no_newkeyindex:
  366. return table->queryChild(3);
  367. case no_table:
  368. return table->queryChild(0);
  369. }
  370. }
  371. return NULL;
  372. }
  373. IHqlExpression * createRawIndex(IHqlExpression * index)
  374. {
  375. IHqlExpression * indexRecord = index->queryRecord();
  376. HqlExprArray fields;
  377. unwindChildren(fields, indexRecord);
  378. fields.pop();
  379. return createDataset(no_null, createRecord(fields), NULL);
  380. }
  381. //---------------------------------------------------------------------------------------------
  382. IHqlExpression * createRecord(IHqlExpression * field)
  383. {
  384. HqlExprArray fields;
  385. fields.append(*LINK(field));
  386. return createRecord(fields);
  387. }
  388. IHqlExpression * queryLastField(IHqlExpression * record)
  389. {
  390. unsigned max = record->numChildren();
  391. while (max--)
  392. {
  393. IHqlExpression * cur = record->queryChild(max);
  394. switch (cur->getOperator())
  395. {
  396. case no_field:
  397. return cur;
  398. case no_ifblock:
  399. return queryLastField(cur->queryChild(1));
  400. case no_record:
  401. return queryLastField(cur);
  402. }
  403. }
  404. return NULL;
  405. }
  406. IHqlExpression * queryFirstField(IHqlExpression * record)
  407. {
  408. unsigned idx = 0;
  409. return queryNextRecordField(record, idx);
  410. }
  411. bool recordContainsBlobs(IHqlExpression * record)
  412. {
  413. ForEachChild(i, record)
  414. {
  415. IHqlExpression * cur = record->queryChild(i);
  416. switch (cur->getOperator())
  417. {
  418. case no_field:
  419. {
  420. if (cur->hasProperty(blobAtom))
  421. return true;
  422. IHqlExpression * childRecord = cur->queryRecord();
  423. if (childRecord && recordContainsBlobs(childRecord))
  424. return true;
  425. break;
  426. }
  427. case no_ifblock:
  428. if (recordContainsBlobs(cur->queryChild(1)))
  429. return true;
  430. break;
  431. case no_record:
  432. if (recordContainsBlobs(cur))
  433. return true;
  434. break;
  435. case no_attr:
  436. case no_attr_expr:
  437. case no_attr_link:
  438. break;
  439. default:
  440. UNIMPLEMENTED;
  441. }
  442. }
  443. return false;
  444. }
  445. IHqlExpression * queryVirtualFileposField(IHqlExpression * record)
  446. {
  447. ForEachChild(idx, record)
  448. {
  449. IHqlExpression * cur = record->queryChild(idx);
  450. IHqlExpression * attr = cur->queryProperty(virtualAtom);
  451. if (attr)
  452. return cur;
  453. }
  454. return NULL;
  455. }
  456. IHqlExpression * queryLastNonAttribute(IHqlExpression * expr)
  457. {
  458. unsigned max = expr->numChildren();
  459. while (max--)
  460. {
  461. IHqlExpression * cur = expr->queryChild(max);
  462. if (!cur->isAttribute())
  463. return cur;
  464. }
  465. return NULL;
  466. }
  467. void expandRecord(HqlExprArray & selects, IHqlExpression * selector, IHqlExpression * expr)
  468. {
  469. switch (expr->getOperator())
  470. {
  471. case no_record:
  472. {
  473. ForEachChild(i, expr)
  474. expandRecord(selects, selector, expr->queryChild(i));
  475. break;
  476. }
  477. case no_field:
  478. {
  479. OwnedHqlExpr subSelector = createSelectExpr(LINK(selector), LINK(expr));
  480. if (expr->queryRecord() && !expr->isDataset() && !expr->isDictionary())
  481. expandRecord(selects, subSelector, expr->queryRecord());
  482. else
  483. {
  484. if (selects.find(*subSelector) == NotFound)
  485. selects.append(*subSelector.getClear());
  486. }
  487. break;
  488. }
  489. case no_ifblock:
  490. expandRecord(selects, selector, expr->queryChild(1));
  491. break;
  492. }
  493. }
  494. //---------------------------------------------------------------------------
  495. static IHqlExpression * queryOnlyTableChild(IHqlExpression * expr)
  496. {
  497. switch (expr->getOperator())
  498. {
  499. case no_select: case no_evaluate:
  500. return NULL;
  501. }
  502. IHqlExpression * ret = NULL;
  503. ForEachChild(i, expr)
  504. {
  505. IHqlExpression * cur = expr->queryChild(i);
  506. if (containsActiveDataset(cur))
  507. {
  508. if (ret)
  509. return NULL;
  510. ret = cur;
  511. }
  512. }
  513. return ret;
  514. }
  515. //The common bit between upper and lower has to be a function of right, and therefore not table invariant.
  516. //Find it by unwinding all candidates from the lower, and then match from the upper.
  517. static IHqlExpression * findCommonExpression(IHqlExpression * lower, IHqlExpression * upper)
  518. {
  519. HqlExprCopyArray candidates;
  520. do
  521. {
  522. candidates.append(*lower);
  523. lower = queryOnlyTableChild(lower);
  524. } while (lower);
  525. do
  526. {
  527. if (candidates.find(*upper) != NotFound)
  528. return upper;
  529. upper = queryOnlyTableChild(upper);
  530. } while (upper);
  531. return NULL;
  532. }
  533. class JoinOrderSpotter
  534. {
  535. public:
  536. JoinOrderSpotter(IHqlExpression * _leftDs, IHqlExpression * _rightDs, IHqlExpression * seq, HqlExprArray & _leftSorts, HqlExprArray & _rightSorts) : leftSorts(_leftSorts), rightSorts(_rightSorts)
  537. {
  538. if (_leftDs)
  539. left.setown(createSelector(no_left, _leftDs, seq));
  540. if (_rightDs)
  541. right.setown(createSelector(no_right, _rightDs, seq));
  542. }
  543. IHqlExpression * doFindJoinSortOrders(IHqlExpression * condition, HqlExprArray * slidingMatches, HqlExprCopyArray & matched);
  544. void findImplicitBetween(IHqlExpression * condition, HqlExprArray & slidingMatches, HqlExprCopyArray & matched, HqlExprCopyArray & pending);
  545. protected:
  546. IHqlExpression * traverseStripSelect(IHqlExpression * expr, node_operator & kind);
  547. IHqlExpression * cachedTraverseStripSelect(IHqlExpression * expr, node_operator & kind);
  548. IHqlExpression * doTraverseStripSelect(IHqlExpression * expr, node_operator & kind);
  549. void unwindSelectorRecord(HqlExprArray & target, IHqlExpression * selector, IHqlExpression * record);
  550. protected:
  551. OwnedHqlExpr left;
  552. OwnedHqlExpr right;
  553. HqlExprArray & leftSorts;
  554. HqlExprArray & rightSorts;
  555. };
  556. IHqlExpression * JoinOrderSpotter::traverseStripSelect(IHqlExpression * expr, node_operator & kind)
  557. {
  558. TransformMutexBlock block;
  559. return cachedTraverseStripSelect(expr, kind);
  560. }
  561. IHqlExpression * JoinOrderSpotter::cachedTraverseStripSelect(IHqlExpression * expr, node_operator & kind)
  562. {
  563. IHqlExpression * matched = static_cast<IHqlExpression *>(expr->queryTransformExtra());
  564. if (matched)
  565. return LINK(matched);
  566. IHqlExpression * ret = doTraverseStripSelect(expr, kind);
  567. expr->setTransformExtra(ret);
  568. return ret;
  569. }
  570. IHqlExpression * JoinOrderSpotter::doTraverseStripSelect(IHqlExpression * expr, node_operator & kind)
  571. {
  572. if (expr->getOperator()==no_select)
  573. {
  574. IHqlExpression * table = expr->queryChild(0);
  575. node_operator curKind = table->getOperator();
  576. if (curKind == no_select || expr->hasProperty(newAtom))
  577. {
  578. //I'm not sure this is a good idea for elements with newAtom - can end up with weird join conditions
  579. HqlExprArray args;
  580. args.append(*cachedTraverseStripSelect(table, kind));
  581. unwindChildren(args, expr, 1);
  582. return cloneOrLink(expr, args);
  583. }
  584. else if ((table == left) || (table == right))
  585. {
  586. if ((kind == no_none) || (kind == curKind))
  587. {
  588. kind = curKind;
  589. //return the unselected id.
  590. return createSelectExpr(getActiveTableSelector(), LINK(expr->queryChild(1)));
  591. }
  592. kind = no_fail;
  593. }
  594. //Cope with case when called from the parser and the expression tree isn't normalized.
  595. else if (!left && !right && ((curKind == no_left) || (curKind == no_right)))
  596. {
  597. kind = curKind;
  598. //return the unselected id.
  599. return createSelectExpr(getActiveTableSelector(), LINK(expr->queryChild(1)));
  600. }
  601. }
  602. else
  603. {
  604. unsigned max = expr->numChildren();
  605. if (max != 0)
  606. {
  607. HqlExprArray args;
  608. args.ensure(max);
  609. unsigned idx;
  610. bool same = true;
  611. for (idx = 0; idx<max;idx++)
  612. {
  613. IHqlExpression * cur = expr->queryChild(idx);
  614. IHqlExpression * stripped = cachedTraverseStripSelect(cur, kind);
  615. args.append(*stripped);
  616. if (cur != stripped)
  617. same = false;
  618. }
  619. if (!same)
  620. return expr->clone(args);
  621. }
  622. }
  623. return LINK(expr);
  624. }
  625. void JoinOrderSpotter::unwindSelectorRecord(HqlExprArray & target, IHqlExpression * selector, IHqlExpression * record)
  626. {
  627. ForEachChild(i, record)
  628. {
  629. IHqlExpression * cur = record->queryChild(i);
  630. switch (cur->getOperator())
  631. {
  632. case no_record:
  633. unwindSelectorRecord(target, selector, cur);
  634. break;
  635. case no_ifblock:
  636. unwindSelectorRecord(target, selector, cur->queryChild(1));
  637. break;
  638. case no_field:
  639. {
  640. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  641. target.append(*selected.getClear());
  642. //MORE: Could expand nested rows
  643. break;
  644. }
  645. }
  646. }
  647. }
  648. IHqlExpression * JoinOrderSpotter::doFindJoinSortOrders(IHqlExpression * condition, HqlExprArray * slidingMatches, HqlExprCopyArray & matched)
  649. {
  650. IHqlExpression *l = condition->queryChild(0);
  651. IHqlExpression *r = condition->queryChild(1);
  652. switch(condition->getOperator())
  653. {
  654. case no_and:
  655. {
  656. IHqlExpression *lmatch = doFindJoinSortOrders(l, slidingMatches, matched);
  657. IHqlExpression *rmatch = doFindJoinSortOrders(r, slidingMatches, matched);
  658. if (lmatch)
  659. {
  660. if (rmatch)
  661. return createValue(no_and, lmatch, rmatch);
  662. else
  663. return lmatch;
  664. }
  665. else
  666. return rmatch;
  667. }
  668. case no_constant:
  669. //remove silly "and true" conditions
  670. if (condition->queryValue()->getBoolValue())
  671. return NULL;
  672. return LINK(condition);
  673. case no_eq:
  674. {
  675. node_operator leftSelectKind = no_none;
  676. node_operator rightSelectKind = no_none;
  677. OwnedHqlExpr leftStrip = traverseStripSelect(l, leftSelectKind);
  678. OwnedHqlExpr rightStrip = traverseStripSelect(r, rightSelectKind);
  679. if ((leftSelectKind == no_left) && (rightSelectKind == no_right))
  680. {
  681. leftSorts.append(*leftStrip.getClear());
  682. rightSorts.append(*rightStrip.getClear());
  683. return NULL;
  684. }
  685. if ((leftSelectKind == no_right) && (rightSelectKind == no_left))
  686. {
  687. leftSorts.append(*rightStrip.getClear());
  688. rightSorts.append(*leftStrip.getClear());
  689. return NULL;
  690. }
  691. if (((l == left) && (r == right)) || ((l == right) && (r == left)))
  692. {
  693. unwindSelectorRecord(leftSorts, queryActiveTableSelector(), left->queryRecord());
  694. unwindSelectorRecord(rightSorts, queryActiveTableSelector(), right->queryRecord());
  695. return NULL;
  696. }
  697. }
  698. return LINK(condition);
  699. case no_between:
  700. if (slidingMatches)
  701. {
  702. node_operator leftSelectKind = no_none;
  703. node_operator rightSelectKind = no_none;
  704. OwnedHqlExpr leftStrip = traverseStripSelect(l, leftSelectKind);
  705. OwnedHqlExpr lowerStrip = traverseStripSelect(r, rightSelectKind);
  706. OwnedHqlExpr upperStrip = traverseStripSelect(condition->queryChild(2), rightSelectKind);
  707. if ((leftSelectKind == no_left) && (rightSelectKind == no_right))
  708. {
  709. //Find the expression of the rhs that is common to lower and upper
  710. IHqlExpression * common = findCommonExpression(lowerStrip,upperStrip);
  711. if (common)
  712. {
  713. slidingMatches->append(*createValue(no_between, makeBoolType(), LINK(leftStrip), LINK(lowerStrip), LINK(upperStrip), createExprAttribute(commonAtom, LINK(common))));
  714. return NULL;
  715. }
  716. }
  717. }
  718. return LINK(condition);
  719. case no_le:
  720. case no_ge:
  721. if (matched.find(*condition) != NotFound)
  722. return NULL;
  723. return LINK(condition);
  724. default:
  725. return LINK(condition);
  726. }
  727. }
  728. void JoinOrderSpotter::findImplicitBetween(IHqlExpression * condition, HqlExprArray & slidingMatches, HqlExprCopyArray & matched, HqlExprCopyArray & pending)
  729. {
  730. IHqlExpression *l = condition->queryChild(0);
  731. IHqlExpression *r = condition->queryChild(1);
  732. node_operator op = condition->getOperator();
  733. switch (op)
  734. {
  735. case no_and:
  736. {
  737. findImplicitBetween(l, slidingMatches, matched, pending);
  738. findImplicitBetween(r, slidingMatches, matched, pending);
  739. break;
  740. }
  741. case no_ge:
  742. case no_le:
  743. {
  744. node_operator search = (op == no_ge) ? no_le : no_ge;
  745. ForEachItemIn(idx, pending)
  746. {
  747. IHqlExpression & cur = pending.item(idx);
  748. if ((cur.getOperator() == search) && (cur.queryChild(0) == condition->queryChild(0)))
  749. {
  750. node_operator leftSelectKind = no_none;
  751. node_operator rightSelectKind = no_none;
  752. IHqlExpression * lower = (op == no_ge) ? condition->queryChild(1) : cur.queryChild(1);
  753. IHqlExpression * upper = (op == no_ge) ? cur.queryChild(1) : condition->queryChild(1);
  754. OwnedHqlExpr leftStrip = traverseStripSelect(condition->queryChild(0), leftSelectKind);
  755. OwnedHqlExpr lowerStrip = traverseStripSelect(lower, rightSelectKind);
  756. OwnedHqlExpr upperStrip = traverseStripSelect(upper, rightSelectKind);
  757. if ((leftSelectKind == no_left) && (rightSelectKind == no_right))
  758. {
  759. //Find the expression of the rhs that is common to lower and upper
  760. IHqlExpression * common = findCommonExpression(lowerStrip,upperStrip);
  761. if (common)
  762. {
  763. slidingMatches.append(*createValue(no_between, makeBoolType(), LINK(leftStrip), LINK(lowerStrip), LINK(upperStrip), createExprAttribute(commonAtom, LINK(common))));
  764. matched.append(*condition);
  765. matched.append(cur);
  766. pending.zap(cur);
  767. return;
  768. }
  769. }
  770. }
  771. }
  772. pending.append(*condition);
  773. break;
  774. }
  775. }
  776. }
  777. static bool isCommonSubstringRange(IHqlExpression * expr)
  778. {
  779. if (expr->getOperator() != no_substring)
  780. return false;
  781. IHqlExpression * range = expr->queryChild(1);
  782. return (range->getOperator() == no_rangecommon);
  783. }
  784. static IHqlExpression * getSimplifiedCommonSubstringRange(IHqlExpression * expr)
  785. {
  786. IHqlExpression * rawSelect = expr->queryChild(0);
  787. IHqlExpression * range = expr->queryChild(1);
  788. IHqlExpression * rangeLow = range->queryChild(0);
  789. if (matchesConstantValue(rangeLow, 1))
  790. return LINK(rawSelect);
  791. HqlExprArray args;
  792. args.append(*LINK(rawSelect));
  793. args.append(*createValue(no_rangefrom, makeNullType(), LINK(rangeLow)));
  794. return expr->clone(args);
  795. }
  796. IHqlExpression * findJoinSortOrders(IHqlExpression * condition, IHqlExpression * leftDs, IHqlExpression * rightDs, IHqlExpression * seq, HqlExprArray &leftSorts, HqlExprArray &rightSorts, bool & isLimitedSubstringJoin, HqlExprArray * slidingMatches)
  797. {
  798. JoinOrderSpotter spotter(leftDs, rightDs, seq, leftSorts, rightSorts);
  799. HqlExprCopyArray matched;
  800. if (slidingMatches)
  801. {
  802. //First spot any implicit betweens using x >= a and x <= b. Do it first so that the second pass doesn't
  803. //reorder the join condition (this still reorders it slightly by moving the implicit betweens before explicit)
  804. HqlExprCopyArray pending;
  805. spotter.findImplicitBetween(condition, *slidingMatches, matched, pending);
  806. }
  807. OwnedHqlExpr ret = spotter.doFindJoinSortOrders(condition, slidingMatches, matched);
  808. //Check for x[n..*] - a no_rangecommon, and ensure they are tagged as the last sorts.
  809. unsigned numCommonRange = 0;
  810. ForEachItemInRev(i, leftSorts)
  811. {
  812. IHqlExpression & left = leftSorts.item(i);
  813. IHqlExpression & right = rightSorts.item(i);
  814. if (isCommonSubstringRange(&left))
  815. {
  816. if (isCommonSubstringRange(&right))
  817. {
  818. //MORE: May be best to remove the substring syntax as this point - or modify it if start != 1.
  819. leftSorts.append(*getSimplifiedCommonSubstringRange(&left));
  820. leftSorts.remove(i);
  821. rightSorts.append(*getSimplifiedCommonSubstringRange(&right));
  822. rightSorts.remove(i);
  823. numCommonRange++;
  824. }
  825. else
  826. throwError(HQLERR_AtmostSubstringNotMatch);
  827. }
  828. else
  829. {
  830. if (isCommonSubstringRange(&right))
  831. throwError(HQLERR_AtmostSubstringNotMatch);
  832. }
  833. }
  834. isLimitedSubstringJoin = numCommonRange != 0;
  835. if (numCommonRange > 1)
  836. throwError(HQLERR_AtmostSubstringSingleInstance);
  837. if ((numCommonRange == 0) && slidingMatches)
  838. {
  839. ForEachItemIn(i, *slidingMatches)
  840. {
  841. IHqlExpression & cur = slidingMatches->item(i);
  842. leftSorts.append(*LINK(cur.queryChild(0)));
  843. rightSorts.append(*LINK(cur.queryChild(3)->queryChild(0)));
  844. }
  845. }
  846. return ret.getClear();
  847. }
  848. extern HQL_API IHqlExpression * findJoinSortOrders(IHqlExpression * expr, HqlExprArray &leftSorts, HqlExprArray &rightSorts, bool & isLimitedSubstringJoin, HqlExprArray * slidingMatches)
  849. {
  850. IHqlExpression * lhs = expr->queryChild(0);
  851. return findJoinSortOrders(expr->queryChild(2), lhs, queryJoinRhs(expr), querySelSeq(expr), leftSorts, rightSorts, isLimitedSubstringJoin, slidingMatches);
  852. }
  853. IHqlExpression * createImpureOwn(IHqlExpression * expr)
  854. {
  855. return createValue(no_impure, expr->getType(), expr);
  856. }
  857. IHqlExpression * getNormalizedFilename(IHqlExpression * filename)
  858. {
  859. OwnedHqlExpr folded = foldHqlExpression(filename, NULL, HFOloseannotations);
  860. return lowerCaseHqlExpr(folded);
  861. }
  862. bool canBeSlidingJoin(IHqlExpression * expr)
  863. {
  864. if (expr->hasProperty(hashAtom) || expr->hasProperty(lookupAtom) || expr->hasProperty(allAtom))
  865. return false;
  866. if (expr->hasProperty(rightouterAtom) || expr->hasProperty(fullouterAtom) ||
  867. expr->hasProperty(leftonlyAtom) || expr->hasProperty(rightonlyAtom) || expr->hasProperty(fullonlyAtom))
  868. return false;
  869. if (expr->hasProperty(atmostAtom))
  870. return false;
  871. return true;
  872. }
  873. //==============================================================================================================
  874. extern HQL_API bool dedupMatchesWholeRecord(IHqlExpression * expr)
  875. {
  876. assertex(expr->getOperator() == no_dedup);
  877. unsigned max = expr->numChildren();
  878. unsigned idx;
  879. for (idx = 1; idx < max; idx++)
  880. {
  881. IHqlExpression * cur = expr->queryChild(idx);
  882. switch (cur->getOperator())
  883. {
  884. case no_attr:
  885. case no_attr_expr:
  886. case no_attr_link:
  887. break;
  888. default:
  889. return false;
  890. }
  891. }
  892. return true;
  893. }
  894. IHqlExpression * getEquality(IHqlExpression * equality, IHqlExpression * left, IHqlExpression * right, IHqlExpression * activeSelector)
  895. {
  896. IHqlExpression * lhs = equality->queryChild(0);
  897. IHqlExpression * rhs = equality->queryChild(1);
  898. if (containsSelector(lhs, left))
  899. {
  900. OwnedHqlExpr mappedLeft = replaceSelector(lhs, left, activeSelector);
  901. OwnedHqlExpr mappedRight = replaceSelector(rhs, right, activeSelector);
  902. if (mappedLeft == mappedRight)
  903. return mappedLeft.getClear();
  904. }
  905. else if (containsSelector(lhs, right))
  906. {
  907. OwnedHqlExpr mappedLeft = replaceSelector(lhs, right, activeSelector);
  908. OwnedHqlExpr mappedRight = replaceSelector(rhs, left, activeSelector);
  909. if (mappedLeft == mappedRight)
  910. return mappedLeft.getClear();
  911. }
  912. return NULL;
  913. }
  914. DedupInfoExtractor::DedupInfoExtractor(IHqlExpression * expr)
  915. {
  916. IHqlExpression * dataset = expr->queryChild(0);
  917. IHqlExpression * record = dataset->queryRecord();
  918. IHqlExpression * selSeq = querySelSeq(expr);
  919. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  920. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  921. compareAllRows = false;
  922. compareAllFields = false;
  923. isLocal = false;
  924. keepLeft = true;
  925. numToKeep.setown(createConstantOne());
  926. unsigned max = expr->numChildren();
  927. unsigned idx;
  928. for (idx = 1; idx < max; idx++)
  929. {
  930. IHqlExpression * cur = expr->queryChild(idx);
  931. switch (cur->getOperator())
  932. {
  933. case no_attr:
  934. case no_attr_expr:
  935. case no_attr_link:
  936. {
  937. IAtom * name = cur->queryName();
  938. if (name == hashAtom)
  939. compareAllRows = true;
  940. else if (name == localAtom)
  941. isLocal = true;
  942. else if (name == allAtom)
  943. compareAllRows = true;
  944. else if (name == keepAtom)
  945. numToKeep.set(cur->queryChild(0));
  946. else if (name == leftAtom)
  947. keepLeft = true;
  948. else if (name == rightAtom)
  949. keepLeft = false;
  950. }
  951. break;
  952. case no_negate:
  953. {
  954. IHqlExpression * field = cur->queryChild(0);
  955. if (field->getOperator() == no_select)
  956. field = field->queryChild(1);
  957. if (!equalities.zap(*field))
  958. throwError(HQLERR_DedupFieldNotFound);
  959. }
  960. break;
  961. case no_eq:
  962. {
  963. OwnedHqlExpr mapped = getEquality(cur, left, right, dataset->queryNormalizedSelector());
  964. if (mapped)
  965. {
  966. equalities.append(*mapped.getClear());
  967. break;
  968. }
  969. //fall through
  970. }
  971. default:
  972. if (containsSelector(cur, left) || containsSelector(cur, right))
  973. conds.append(*LINK(cur));
  974. else
  975. equalities.append(*LINK(cur));
  976. break;
  977. }
  978. }
  979. if ((equalities.ordinality() == 0) && (conds.ordinality() == 0))
  980. {
  981. unwindRecordAsSelects(equalities, record, dataset->queryNormalizedSelector());
  982. compareAllFields = true;
  983. }
  984. #ifdef _DEBUG
  985. //Check to ensure the function stays in sync with the code above
  986. assertex(compareAllFields == dedupMatchesWholeRecord(expr));
  987. #endif
  988. }
  989. DedupInfoExtractor::DedupKeyCompareKind DedupInfoExtractor::compareKeys(const DedupInfoExtractor & other)
  990. {
  991. //MORE: These could be coped with a bit better...
  992. if ((conds.ordinality() != 0) || (other.conds.ordinality() != 0))
  993. return DedupKeyIsDifferent;
  994. const HqlExprArray & otherEqualities = other.equalities;
  995. unsigned num1 = equalities.ordinality();
  996. unsigned num2 = otherEqualities.ordinality();
  997. unsigned numMissing = 0;
  998. ForEachItemIn(i, equalities)
  999. {
  1000. if (otherEqualities.find(equalities.item(i)) == NotFound)
  1001. numMissing++;
  1002. }
  1003. if (numMissing)
  1004. {
  1005. if (num1 == num2 + numMissing)
  1006. return DedupKeyIsSuperset;
  1007. return DedupKeyIsDifferent;
  1008. }
  1009. if (num1 == num2)
  1010. return DedupKeyIsSame;
  1011. return DedupKeyIsSubset;
  1012. }
  1013. DedupInfoExtractor::DedupCompareKind DedupInfoExtractor::compareWith(const DedupInfoExtractor & other)
  1014. {
  1015. if ((keepLeft != other.keepLeft) || !getConstantKeep() || !other.getConstantKeep())
  1016. return DedupIsDifferent;
  1017. if (isLocal != other.isLocal)
  1018. return DedupIsDifferent;
  1019. switch (compareKeys(other))
  1020. {
  1021. case DedupKeyIsSame:
  1022. if (compareAllRows == other.compareAllRows)
  1023. {
  1024. if (getConstantKeep() < other.getConstantKeep())
  1025. return DedupDoesAll;
  1026. else
  1027. return DedupDoesNothing;
  1028. }
  1029. else
  1030. {
  1031. //dedup(dedup(x,y),y,all) cannot be reduced to dedup(x,y,all) because it may include
  1032. //records that wouldn't have otherwise got through. dedup(dedup(x,y,all),y) can be though
  1033. if (other.compareAllRows)
  1034. {
  1035. if (getConstantKeep() >= other.getConstantKeep())
  1036. return DedupDoesNothing;
  1037. }
  1038. }
  1039. break;
  1040. case DedupKeyIsSubset:
  1041. //optimize dedup(dedup(x,y1,y2,keep(2)),y1,keep(2)) to dedup(x,y1,keep(2)) if keep is same
  1042. if (compareAllRows == other.compareAllRows && (getConstantKeep() == other.getConstantKeep()))
  1043. return DedupDoesAll;
  1044. //optimize dedup(dedup(x,y1,y2,keep(2),all),y1,keep(1)) to dedup(x,y1,keep(1))
  1045. if (compareAllRows && other.compareAllRows && (getConstantKeep() <= other.getConstantKeep()))
  1046. return DedupDoesAll;
  1047. break;
  1048. case DedupKeyIsSuperset:
  1049. if (compareAllRows == other.compareAllRows && (getConstantKeep() == other.getConstantKeep()))
  1050. return DedupDoesNothing;
  1051. if (compareAllRows && other.compareAllRows && (getConstantKeep() >= other.getConstantKeep()))
  1052. return DedupDoesNothing;
  1053. break;
  1054. }
  1055. return DedupIsDifferent;
  1056. }
  1057. IHqlExpression * replaceChild(IHqlExpression * expr, unsigned childIndex, IHqlExpression * newChild)
  1058. {
  1059. IHqlExpression * oldChild = expr->queryChild(childIndex);
  1060. if (oldChild == newChild)
  1061. return LINK(expr);
  1062. HqlExprArray args;
  1063. if (childIndex == 0)
  1064. {
  1065. args.append(*LINK(newChild));
  1066. unwindChildren(args, expr, 1);
  1067. }
  1068. else
  1069. {
  1070. unwindChildren(args, expr);
  1071. args.replace(*LINK(newChild), childIndex);
  1072. }
  1073. return expr->clone(args);
  1074. }
  1075. IHqlExpression * createIf(IHqlExpression * cond, IHqlExpression * left, IHqlExpression * right)
  1076. {
  1077. assertex(right);
  1078. if (left->isDataset() || right->isDataset())
  1079. return createDataset(no_if, cond, createComma(left, right));
  1080. if (left->isDictionary() || right->isDictionary())
  1081. return createDictionary(no_if, cond, createComma(left, right));
  1082. if (left->isDatarow() || right->isDatarow())
  1083. return createRow(no_if, cond, createComma(left, right));
  1084. ITypeInfo * type = ::getPromotedECLType(left->queryType(), right->queryType());
  1085. return createValue(no_if, type, cond, left, right);
  1086. }
  1087. extern HQL_API unsigned numRealChildren(IHqlExpression * expr)
  1088. {
  1089. unsigned max = expr->numChildren();
  1090. //Assumes all attributes occur at the end of the operand lists
  1091. while (max && expr->queryChild(max-1)->isAttribute())
  1092. max--;
  1093. return max;
  1094. }
  1095. //---------------------------------------------------------------------------
  1096. static IHqlExpression * getExpandSelectExprTest(IHqlExpression * expr)
  1097. {
  1098. assertex(expr->getOperator() == no_select);
  1099. IHqlExpression * ds = expr->queryChild(0);
  1100. IHqlExpression * field = expr->queryChild(1);
  1101. if (field->queryRecord() || !queryNewColumnProvider(ds))
  1102. return NULL;
  1103. TableProjectMapper mapper(ds);
  1104. return mapper.expandFields(expr, ds, ds->queryChild(0)->queryNormalizedSelector());
  1105. }
  1106. IHqlExpression * getExpandSelectExpr(IHqlExpression * expr)
  1107. {
  1108. assertex(expr->getOperator() == no_select);
  1109. IHqlExpression * ds = expr->queryChild(0);
  1110. IHqlExpression * field = expr->queryChild(1);
  1111. if (field->queryRecord())
  1112. return NULL;
  1113. IHqlExpression * mappingExpr = queryNewColumnProvider(ds);
  1114. if (mappingExpr)
  1115. {
  1116. IHqlExpression * ret = NULL;
  1117. switch (mappingExpr->getOperator())
  1118. {
  1119. case no_record:
  1120. {
  1121. IHqlSimpleScope * scope = mappingExpr->querySimpleScope();
  1122. OwnedHqlExpr matched = scope->lookupSymbol(field->queryId());
  1123. assertex(matched == field);
  1124. ret = LINK(queryRealChild(field, 0));
  1125. break;
  1126. }
  1127. case no_newtransform:
  1128. {
  1129. ForEachChild(idx, mappingExpr)
  1130. {
  1131. IHqlExpression * cur = mappingExpr->queryChild(idx);
  1132. IHqlExpression * tgt = cur->queryChild(0);
  1133. if (tgt->getOperator() == no_select && tgt->queryChild(1) == field)
  1134. {
  1135. IHqlExpression * src = cur->queryChild(1);
  1136. ret = ensureExprType(src, tgt->queryType());
  1137. break;
  1138. }
  1139. }
  1140. assertex(ret);
  1141. break;
  1142. }
  1143. case no_transform:
  1144. {
  1145. //probably just as efficient..., and not used.
  1146. ret = getExpandSelectExprTest(expr);
  1147. break;
  1148. }
  1149. }
  1150. //OwnedHqlExpr test = getExpandSelectExprTest(expr);
  1151. //assertex(ret==test);
  1152. return ret;
  1153. }
  1154. return NULL;
  1155. }
  1156. //---------------------------------------------------------------------------
  1157. IHqlExpression * replaceChildDataset(IHqlExpression * expr, IHqlExpression * newChild, unsigned whichChild)
  1158. {
  1159. HqlMapTransformer mapper;
  1160. IHqlExpression * oldChild = expr->queryChild(whichChild);
  1161. mapper.setMapping(oldChild, newChild);
  1162. mapper.setSelectorMapping(oldChild, newChild);
  1163. return mapper.transformRoot(expr);
  1164. }
  1165. IHqlExpression * insertChildDataset(IHqlExpression * expr, IHqlExpression * newChild, unsigned whichChild)
  1166. {
  1167. assertex(expr->queryChild(whichChild) == newChild->queryChild(0));
  1168. //No need to map because children are still valid...
  1169. HqlExprArray args;
  1170. unwindChildren(args, expr);
  1171. args.replace(*LINK(newChild), whichChild);
  1172. return expr->clone(args);
  1173. }
  1174. IHqlExpression * swapDatasets(IHqlExpression * parent)
  1175. {
  1176. IHqlExpression * child = parent->queryChild(0);
  1177. OwnedHqlExpr newChild = replaceChildDataset(parent, child->queryChild(0), 0); // any refs to child must be mapped.
  1178. return insertChildDataset(child, newChild, 0);
  1179. }
  1180. //---------------------------------------------------------------------------
  1181. interface IHintVisitor
  1182. {
  1183. virtual IHqlExpression * visit(IHqlExpression * hint) = 0;
  1184. };
  1185. class SearchHintVisitor : implements IHintVisitor
  1186. {
  1187. public:
  1188. SearchHintVisitor(IAtom * _name) : name(_name) {}
  1189. virtual IHqlExpression * visit(IHqlExpression * hint)
  1190. {
  1191. return hint->queryProperty(name);
  1192. }
  1193. IAtom * name;
  1194. };
  1195. class GatherHintVisitor : implements IHintVisitor
  1196. {
  1197. public:
  1198. GatherHintVisitor(HqlExprCopyArray & _target) : target(_target) {}
  1199. virtual IHqlExpression * visit(IHqlExpression * hint)
  1200. {
  1201. unwindChildren(target, hint);
  1202. return NULL;
  1203. }
  1204. HqlExprCopyArray & target;
  1205. };
  1206. static IHqlExpression * walkHints(IHqlExpression * expr, IHintVisitor & visitor)
  1207. {
  1208. //First look for any hint annotations.
  1209. loop
  1210. {
  1211. annotate_kind kind = expr->getAnnotationKind();
  1212. if (kind == annotate_meta)
  1213. {
  1214. unsigned i=0;
  1215. IHqlExpression * cur;
  1216. while ((cur = expr->queryAnnotationParameter(i++)) != NULL)
  1217. {
  1218. if (cur->queryName() == hintAtom && cur->isAttribute())
  1219. {
  1220. IHqlExpression * ret = visitor.visit(cur);
  1221. if (ret)
  1222. return ret;
  1223. }
  1224. }
  1225. }
  1226. if (kind == annotate_none)
  1227. break;
  1228. expr = expr->queryBody(true);
  1229. }
  1230. //Then look for any hint attributes.
  1231. ForEachChild(i, expr)
  1232. {
  1233. IHqlExpression * cur = expr->queryChild(i);
  1234. if ((cur->queryName() == hintAtom) && cur->isAttribute())
  1235. {
  1236. IHqlExpression * match = visitor.visit(cur);
  1237. if (match)
  1238. return match;
  1239. }
  1240. }
  1241. return NULL;
  1242. }
  1243. IHqlExpression * queryHint(IHqlExpression * expr, IAtom * name)
  1244. {
  1245. SearchHintVisitor visitor(name);
  1246. return walkHints(expr, visitor);
  1247. }
  1248. void gatherHints(HqlExprCopyArray & target, IHqlExpression * expr)
  1249. {
  1250. GatherHintVisitor visitor(target);
  1251. walkHints(expr, visitor);
  1252. }
  1253. IHqlExpression * queryHintChild(IHqlExpression * expr, IAtom * name, unsigned idx)
  1254. {
  1255. IHqlExpression * match = queryHint(expr, name);
  1256. if (match)
  1257. return match->queryChild(idx);
  1258. return NULL;
  1259. }
  1260. void unwindHintAttrs(HqlExprArray & args, IHqlExpression * expr)
  1261. {
  1262. ForEachChild(i, expr)
  1263. {
  1264. IHqlExpression * cur = expr->queryChild(i);
  1265. if ((cur->queryName() == hintAtom) && cur->isAttribute())
  1266. args.append(*LINK(cur));
  1267. }
  1268. }
  1269. //---------------------------------------------------------------------------
  1270. IHqlExpression * createCompare(node_operator op, IHqlExpression * l, IHqlExpression * r)
  1271. {
  1272. if ((l->getOperator() == no_constant) && (r->getOperator() != no_constant))
  1273. return createCompare(getReverseOp(op), r, l);
  1274. ITypeInfo * t1 = l->queryType();
  1275. ITypeInfo * t2 = r->queryType();
  1276. //Check for comparisons that are always true/false....
  1277. IValue * value = r->queryValue();
  1278. if (value)
  1279. {
  1280. //Sometimes comparing an unsigned field with a constant can cause both parameters to be promoted
  1281. //to a larger type, because constants default to signed if small enough.
  1282. if (t1->getTypeCode() == type_int)
  1283. {
  1284. if (!t1->isSigned() && t2->isSigned() && t1->getSize() >= t2->getSize())
  1285. {
  1286. if (value->getIntValue() >= 0)
  1287. return createValue(op, makeBoolType(), LINK(l), ensureExprType(r, t1));
  1288. }
  1289. if ((queryUnqualifiedType(t1) != queryUnqualifiedType(t2)) && preservesValue(t1, r))
  1290. {
  1291. OwnedHqlExpr cast = ensureExprType(r, t1);
  1292. if (r != cast)
  1293. return createCompare(op, l, cast);
  1294. }
  1295. }
  1296. }
  1297. Owned<ITypeInfo> compareType = getPromotedECLCompareType(t1, t2);
  1298. return createValue(op, makeBoolType(), ensureExprType(l, compareType), ensureExprType(r, compareType));
  1299. }
  1300. IHqlExpression * flattenListOwn(IHqlExpression * list)
  1301. {
  1302. HqlExprArray args;
  1303. ITypeInfo * type = list->getType();
  1304. flattenListOwn(args, list);
  1305. return createValue(no_comma, type, args);
  1306. }
  1307. void flattenListOwn(HqlExprArray & out, IHqlExpression * list)
  1308. {
  1309. list->unwindList(out, no_comma);
  1310. releaseList(list);
  1311. }
  1312. void releaseList(IHqlExpression * list)
  1313. {
  1314. //normally lists are (((((a,b),c),d),e),f)
  1315. //so release rhs, and loop through lhs to reduce stack usage
  1316. while (list->getOperator() == no_comma)
  1317. {
  1318. IHqlExpression * next = LINK(list->queryChild(0));
  1319. list->Release();
  1320. list = next;
  1321. }
  1322. list->Release();
  1323. }
  1324. void expandRowSelectors(HqlExprArray & target, HqlExprArray const & source)
  1325. {
  1326. ForEachItemIn(i, source)
  1327. {
  1328. IHqlExpression & cur = source.item(i);
  1329. if (cur.isDatarow())
  1330. {
  1331. RecordSelectIterator iter(cur.queryRecord(), &cur);
  1332. ForEach(iter)
  1333. target.append(*iter.get());
  1334. }
  1335. else
  1336. target.append(OLINK(cur));
  1337. }
  1338. }
  1339. //---------------------------------------------------------------------------
  1340. unsigned getFirstActivityArgument(IHqlExpression * expr)
  1341. {
  1342. switch (expr->getOperator())
  1343. {
  1344. case no_mapto:
  1345. case no_if:
  1346. case no_case:
  1347. case no_fetch:
  1348. case no_libraryselect:
  1349. case no_chooseds:
  1350. case no_choose:
  1351. return 1;
  1352. }
  1353. return 0;
  1354. }
  1355. unsigned getNumActivityArguments(IHqlExpression * expr)
  1356. {
  1357. switch (expr->getOperator())
  1358. {
  1359. case no_compound_diskread:
  1360. case no_compound_indexread:
  1361. case no_compound_disknormalize:
  1362. case no_compound_diskaggregate:
  1363. case no_compound_diskcount:
  1364. case no_compound_diskgroupaggregate:
  1365. case no_compound_indexnormalize:
  1366. case no_compound_indexaggregate:
  1367. case no_compound_indexcount:
  1368. case no_compound_indexgroupaggregate:
  1369. case no_compound_childread:
  1370. case no_compound_childnormalize:
  1371. case no_compound_childaggregate:
  1372. case no_compound_childcount:
  1373. case no_compound_childgroupaggregate:
  1374. case no_compound_inline:
  1375. case no_keyindex:
  1376. case no_newkeyindex:
  1377. case no_table:
  1378. case no_preload:
  1379. case no_allnodes:
  1380. case no_thisnode:
  1381. case no_keydiff:
  1382. case no_keypatch:
  1383. case no_datasetfromdictionary:
  1384. return 0;
  1385. case no_setresult:
  1386. if (expr->queryChild(0)->isAction())
  1387. return 1;
  1388. return 0;
  1389. case no_compound_selectnew:
  1390. case no_libraryselect:
  1391. return 1;
  1392. case no_libraryscopeinstance:
  1393. {
  1394. //It would be very nice to be able to cache this, but because the arguments are associated with the
  1395. //no_funcdef instead of the no_libraryscope it is a bit tricky. It could be optimized onto the
  1396. //no_libraryscopeinstance I guess.
  1397. IHqlExpression * libraryFuncDef = expr->queryDefinition();
  1398. IHqlExpression * library = libraryFuncDef->queryChild(0);
  1399. if (library->hasProperty(_noStreaming_Atom))
  1400. return 0;
  1401. IHqlExpression * libraryFormals = libraryFuncDef->queryChild(1);
  1402. unsigned numStreaming = 0;
  1403. ForEachChild(i, libraryFormals)
  1404. {
  1405. if (libraryFormals->queryChild(i)->isDataset())
  1406. numStreaming++;
  1407. }
  1408. return numStreaming;
  1409. }
  1410. case no_select:
  1411. if (isNewSelector(expr))
  1412. return 1;
  1413. return 0;
  1414. case no_datasetfromrow:
  1415. {
  1416. IHqlExpression * row = expr->queryChild(0);
  1417. //Is this special casing really the best way to handle this? I'm not completely convinced.
  1418. loop
  1419. {
  1420. switch (row->getOperator())
  1421. {
  1422. case no_selectnth:
  1423. case no_split:
  1424. case no_spill:
  1425. return 1;
  1426. case no_alias:
  1427. case no_alias_scope:
  1428. case no_nofold:
  1429. case no_nohoist:
  1430. case no_section:
  1431. case no_sectioninput:
  1432. case no_globalscope:
  1433. case no_thisnode:
  1434. break;
  1435. default:
  1436. return 0;
  1437. }
  1438. row = row->queryChild(0);
  1439. }
  1440. }
  1441. case no_fetch:
  1442. case no_mapto:
  1443. case no_evaluate:
  1444. case no_extractresult:
  1445. case no_outputscalar:
  1446. case no_keyeddistribute:
  1447. case no_normalize:
  1448. case no_process:
  1449. case no_mergejoin:
  1450. case no_nwayjoin:
  1451. case no_nwaymerge:
  1452. case no_related: // not an activity
  1453. return 1;
  1454. case no_denormalize:
  1455. case no_denormalizegroup:
  1456. case no_join:
  1457. case no_joincount:
  1458. if (isKeyedJoin(expr) && !expr->hasProperty(_complexKeyed_Atom))
  1459. return 1;
  1460. return 2;
  1461. case no_combine:
  1462. case no_combinegroup:
  1463. case no_executewhen:
  1464. return 2;
  1465. case no_if:
  1466. if (queryRealChild(expr, 2))
  1467. return 2;
  1468. return 1;
  1469. case no_sequential:
  1470. case no_parallel:
  1471. case no_actionlist:
  1472. case no_comma:
  1473. case no_compound:
  1474. case no_addfiles:
  1475. case no_map:
  1476. return expr->numChildren();
  1477. case no_case:
  1478. return expr->numChildren()-1;
  1479. case no_forcelocal:
  1480. return 0;
  1481. default:
  1482. return getNumChildTables(expr);
  1483. }
  1484. }
  1485. bool isDistributedSourceActivity(IHqlExpression * expr)
  1486. {
  1487. switch (expr->getOperator())
  1488. {
  1489. case no_table:
  1490. case no_keyindex:
  1491. case no_newkeyindex:
  1492. case no_compound_indexread:
  1493. case no_compound_diskread:
  1494. case no_compound_disknormalize:
  1495. case no_compound_diskaggregate:
  1496. case no_compound_diskcount:
  1497. case no_compound_diskgroupaggregate:
  1498. case no_compound_indexnormalize:
  1499. case no_compound_indexaggregate:
  1500. case no_compound_indexcount:
  1501. case no_compound_indexgroupaggregate:
  1502. return true;
  1503. case no_getgraphresult:
  1504. return expr->hasProperty(_distributed_Atom);
  1505. case no_workunit_dataset:
  1506. case no_getgraphloopresult:
  1507. case no_temptable:
  1508. case no_inlinetable:
  1509. case no_xmlproject:
  1510. case no_datasetfromrow:
  1511. case no_null:
  1512. case no_all:
  1513. case no_select:
  1514. case no_soapcall:
  1515. case no_newsoapcall:
  1516. case no_compound_childread:
  1517. case no_compound_childnormalize:
  1518. case no_compound_childaggregate:
  1519. case no_compound_childcount:
  1520. case no_compound_childgroupaggregate:
  1521. case no_compound_selectnew:
  1522. case no_compound_inline:
  1523. case no_rows:
  1524. case no_datasetfromdictionary:
  1525. return false;
  1526. default:
  1527. UNIMPLEMENTED;
  1528. }
  1529. }
  1530. bool isSourceActivity(IHqlExpression * expr, bool ignoreCompound)
  1531. {
  1532. switch (expr->getOperator())
  1533. {
  1534. case no_table:
  1535. case no_keyindex:
  1536. case no_newkeyindex:
  1537. case no_workunit_dataset:
  1538. case no_getgraphresult:
  1539. case no_getgraphloopresult:
  1540. case no_temptable:
  1541. case no_inlinetable:
  1542. case no_xmlproject:
  1543. // case no_all:
  1544. case no_httpcall:
  1545. case no_soapcall:
  1546. case no_newsoapcall:
  1547. case no_rows:
  1548. case no_allnodes:
  1549. case no_thisnode:
  1550. case no_datasetfromdictionary:
  1551. return true;
  1552. case no_null:
  1553. return expr->isDataset();
  1554. case no_select:
  1555. if (isNewSelector(expr))
  1556. return false;
  1557. return expr->isDataset();
  1558. case no_compound_indexread:
  1559. case no_compound_diskread:
  1560. case no_compound_disknormalize:
  1561. case no_compound_diskaggregate:
  1562. case no_compound_diskcount:
  1563. case no_compound_diskgroupaggregate:
  1564. case no_compound_indexnormalize:
  1565. case no_compound_indexaggregate:
  1566. case no_compound_indexcount:
  1567. case no_compound_indexgroupaggregate:
  1568. case no_compound_childread:
  1569. case no_compound_childnormalize:
  1570. case no_compound_childaggregate:
  1571. case no_compound_childcount:
  1572. case no_compound_childgroupaggregate:
  1573. case no_compound_inline:
  1574. return !ignoreCompound;
  1575. case no_datasetfromrow:
  1576. return (getNumActivityArguments(expr) == 0);
  1577. }
  1578. return false;
  1579. }
  1580. bool isSinkActivity(IHqlExpression * expr)
  1581. {
  1582. switch (expr->getOperator())
  1583. {
  1584. case no_parallel:
  1585. case no_actionlist:
  1586. case no_sequential:
  1587. case no_apply:
  1588. case no_output:
  1589. case no_buildindex:
  1590. case no_distribution:
  1591. case no_keydiff:
  1592. case no_keypatch:
  1593. case no_returnresult:
  1594. case no_extractresult:
  1595. case no_setresult:
  1596. case no_setgraphresult:
  1597. case no_setgraphloopresult:
  1598. case no_definesideeffect:
  1599. //case no_callsideeffect: //??
  1600. return true;
  1601. case no_soapcall:
  1602. case no_newsoapcall:
  1603. case no_if:
  1604. case no_null:
  1605. case no_choose:
  1606. return expr->isAction();
  1607. }
  1608. return false;
  1609. }
  1610. bool isDistributedActivity(IHqlExpression * expr)
  1611. {
  1612. switch (expr->getOperator())
  1613. {
  1614. case no_table:
  1615. case no_keyindex:
  1616. case no_newkeyindex:
  1617. case no_compound_indexread:
  1618. case no_compound_diskread:
  1619. case no_compound_disknormalize:
  1620. case no_compound_diskaggregate:
  1621. case no_compound_diskcount:
  1622. case no_compound_diskgroupaggregate:
  1623. case no_compound_indexnormalize:
  1624. case no_compound_indexaggregate:
  1625. case no_compound_indexcount:
  1626. case no_compound_indexgroupaggregate:
  1627. return true;
  1628. case no_join:
  1629. case no_joincount:
  1630. case no_denormalize:
  1631. case no_denormalizegroup:
  1632. return isKeyedJoin(expr);
  1633. case no_fetch:
  1634. case no_compound_fetch:
  1635. return true;
  1636. }
  1637. return false;
  1638. }
  1639. unsigned getFieldCount(IHqlExpression * expr)
  1640. {
  1641. switch (expr->getOperator())
  1642. {
  1643. case no_record:
  1644. {
  1645. unsigned count = 0;
  1646. ForEachChild(i, expr)
  1647. count += getFieldCount(expr->queryChild(i));
  1648. return count;
  1649. }
  1650. case no_ifblock:
  1651. return getFieldCount(expr->queryChild(1));
  1652. case no_field:
  1653. {
  1654. ITypeInfo * type = expr->queryType();
  1655. if (type->getTypeCode() == type_row)
  1656. return getFieldCount(expr->queryRecord());
  1657. return 1;
  1658. }
  1659. case no_attr:
  1660. case no_attr_link:
  1661. case no_attr_expr:
  1662. return 0;
  1663. default:
  1664. //UNIMPLEMENTED;
  1665. return 0;
  1666. }
  1667. }
  1668. IHqlExpression * queryChildActivity(IHqlExpression * expr, unsigned index)
  1669. {
  1670. unsigned firstActivityIndex = 0;
  1671. switch (expr->getOperator())
  1672. {
  1673. case no_compound_selectnew:
  1674. if (index == 0)
  1675. return queryRoot(expr)->queryChild(0);
  1676. return NULL;
  1677. case no_mapto:
  1678. case no_if:
  1679. case no_case:
  1680. case no_fetch:
  1681. case no_choose:
  1682. case no_chooseds:
  1683. firstActivityIndex = 1;
  1684. break;
  1685. }
  1686. return queryRealChild(expr, firstActivityIndex + index);
  1687. }
  1688. unsigned getFlatFieldCount(IHqlExpression * expr)
  1689. {
  1690. switch (expr->getOperator())
  1691. {
  1692. case no_record:
  1693. {
  1694. unsigned count = 0;
  1695. ForEachChild(i, expr)
  1696. count += getFlatFieldCount(expr->queryChild(i));
  1697. return count;
  1698. }
  1699. case no_ifblock:
  1700. return getFlatFieldCount(expr->queryChild(1));
  1701. case no_field:
  1702. return 1;
  1703. case no_attr:
  1704. case no_attr_link:
  1705. case no_attr_expr:
  1706. return 0;
  1707. default:
  1708. UNIMPLEMENTED;
  1709. }
  1710. }
  1711. unsigned isEmptyRecord(IHqlExpression * record)
  1712. {
  1713. ForEachChild(i, record)
  1714. {
  1715. IHqlExpression * cur = record->queryChild(i);
  1716. switch (cur->getOperator())
  1717. {
  1718. case no_record:
  1719. if (!isEmptyRecord(cur))
  1720. return false;
  1721. break;
  1722. case no_ifblock:
  1723. if (!isEmptyRecord(cur->queryChild(1)))
  1724. return false;
  1725. break;
  1726. case no_field:
  1727. return false;
  1728. }
  1729. }
  1730. return true;
  1731. }
  1732. bool isTrivialSelectN(IHqlExpression * expr)
  1733. {
  1734. if (expr->getOperator() == no_index || expr->getOperator() == no_selectnth)
  1735. {
  1736. IHqlExpression * index = expr->queryChild(1);
  1737. if (matchesConstantValue(index, 1))
  1738. return hasSingleRow(expr->queryChild(0));
  1739. }
  1740. return false;
  1741. }
  1742. IHqlExpression * queryPropertyChild(IHqlExpression * expr, IAtom * name, unsigned idx)
  1743. {
  1744. IHqlExpression * match = expr->queryProperty(name);
  1745. if (match)
  1746. return match->queryChild(idx);
  1747. return NULL;
  1748. }
  1749. int getResultSequenceValue(IHqlExpression * set)
  1750. {
  1751. switch (set->getOperator())
  1752. {
  1753. case no_setresult:
  1754. case no_ensureresult:
  1755. case no_extractresult:
  1756. case no_output:
  1757. return (int)getIntValue(queryPropertyChild(set, sequenceAtom, 0), 0);
  1758. }
  1759. return 0;
  1760. }
  1761. IHqlExpression * querySequence(IHqlExpression * expr)
  1762. {
  1763. IHqlExpression * seq = expr->queryProperty(sequenceAtom);
  1764. if (seq)
  1765. return seq->queryChild(0);
  1766. if (expr->queryValue())
  1767. return expr;
  1768. return NULL;
  1769. }
  1770. IHqlExpression * queryResultName(IHqlExpression * expr)
  1771. {
  1772. IHqlExpression * name = expr->queryProperty(namedAtom);
  1773. if (name)
  1774. return name->queryChild(0);
  1775. return NULL;
  1776. }
  1777. //---------------------------------------------------------------------------
  1778. IHqlExpression * queryConvertChoosenNSort(IHqlExpression * expr, unsigned __int64 topNlimit)
  1779. {
  1780. OwnedHqlExpr first = foldHqlExpression(queryRealChild(expr, 2));
  1781. IHqlExpression * child = expr->queryChild(0);
  1782. if ((child->getOperator() != no_sort) || isGroupedActivity(child))
  1783. return NULL;
  1784. IHqlExpression * cosort = queryRealChild(child, 2);
  1785. if (cosort)
  1786. return NULL;
  1787. //grouped sort->choosen. Don't convert unless choosen preserves grouping
  1788. if (isGrouped(child) && !expr->hasProperty(groupedAtom))
  1789. return NULL;
  1790. OwnedHqlExpr count = foldHqlExpression(expr->queryChild(1));
  1791. bool clone = false;
  1792. if (count->queryValue())
  1793. {
  1794. unsigned __int64 limit = count->queryValue()->getIntValue();
  1795. if (first)
  1796. {
  1797. if (!first->queryValue())
  1798. return NULL;
  1799. limit += (first->queryValue()->getIntValue() - 1);
  1800. count.setown(createConstant((__int64)limit));
  1801. clone = true;
  1802. }
  1803. if (limit > topNlimit)
  1804. return NULL;
  1805. }
  1806. else
  1807. {
  1808. if (!expr->hasProperty(fewAtom) || first)
  1809. return NULL;
  1810. }
  1811. //choosen(sort(x,a,local),n) -> do the topn local, but need to reapply the global choosen
  1812. if (expr->hasProperty(localAtom))
  1813. {
  1814. if (!child->hasProperty(localAtom))
  1815. return NULL;
  1816. }
  1817. else
  1818. {
  1819. if (child->hasProperty(localAtom))
  1820. clone = true;
  1821. }
  1822. HqlExprArray args;
  1823. unwindChildren(args, child);
  1824. args.add(*LINK(count), 2);
  1825. IHqlExpression * top = createDataset(no_topn, args);
  1826. if (!clone)
  1827. return top;
  1828. args.kill();
  1829. unwindChildren(args, expr);
  1830. args.replace(*top, 0);
  1831. return expr->clone(args);
  1832. }
  1833. //---------------------------------------------------------------------------
  1834. void DependenciesUsed::clear()
  1835. {
  1836. tablesRead.kill();
  1837. tablesWritten.kill();
  1838. resultsRead.kill();
  1839. resultsWritten.kill();
  1840. allRead = false;
  1841. allWritten = false;
  1842. }
  1843. bool DependenciesUsed::canSwapOrder(const DependenciesUsed & other) const
  1844. {
  1845. //Dependant on output from the previous
  1846. if (isDependantOn(other) || other.isDependantOn(*this))
  1847. return false;
  1848. return true;
  1849. }
  1850. bool DependenciesUsed::isDependantOn(const DependenciesUsed & other) const
  1851. {
  1852. //Dependant on output from the previous
  1853. if (allRead && (other.allWritten || other.tablesWritten.ordinality()))
  1854. return true;
  1855. if (other.allWritten && tablesRead.ordinality())
  1856. return true;
  1857. return isExplicitlyDependantOn(other);
  1858. }
  1859. bool DependenciesUsed::isExplicitlyDependantOn(const DependenciesUsed & other) const
  1860. {
  1861. ForEachItemIn(idx1, tablesRead)
  1862. {
  1863. if (other.tablesWritten.find(tablesRead.item(idx1)) != NotFound)
  1864. return true;
  1865. }
  1866. ForEachItemIn(idx2, resultsRead)
  1867. {
  1868. if (other.resultsWritten.find(resultsRead.item(idx2)) != NotFound)
  1869. return true;
  1870. }
  1871. return false;
  1872. }
  1873. void DependenciesUsed::addFilenameRead(IHqlExpression * expr)
  1874. {
  1875. OwnedHqlExpr normalized = getNormalizedFilename(expr);
  1876. if (tablesRead.find(*normalized) == NotFound)
  1877. {
  1878. appendUniqueExpr(tablesRead, LINK(normalized));
  1879. if (!normalized->queryValue())
  1880. allRead = true;
  1881. }
  1882. }
  1883. void DependenciesUsed::addFilenameWrite(IHqlExpression * expr)
  1884. {
  1885. OwnedHqlExpr normalized = getNormalizedFilename(expr);
  1886. if (appendUniqueExpr(tablesWritten, LINK(normalized)))
  1887. if (tablesRead.contains(*normalized))
  1888. noteInconsistency(normalized);
  1889. if (!normalized->queryValue())
  1890. allWritten = true;
  1891. }
  1892. void DependenciesUsed::addResultRead(IHqlExpression * seq, IHqlExpression * name, bool isGraphResult)
  1893. {
  1894. if (!isGraphResult)
  1895. if (!seq || !seq->queryValue())
  1896. return; //Can be called in parser when no sequence has been allocated
  1897. OwnedHqlExpr result = createAttribute(resultAtom, LINK(seq), LINK(name));
  1898. if (resultsWritten.find(*result) == NotFound)
  1899. appendUniqueExpr(resultsRead, LINK(result));
  1900. }
  1901. void DependenciesUsed::addResultWrite(IHqlExpression * seq, IHqlExpression * name, bool isGraphResult)
  1902. {
  1903. if (!isGraphResult)
  1904. if (!seq || !seq->queryValue())
  1905. return; //Can be called in parser when no sequence has been allocated
  1906. OwnedHqlExpr result = createAttribute(resultAtom, LINK(seq), LINK(name));
  1907. if (appendUniqueExpr(resultsWritten, LINK(result)))
  1908. if (resultsRead.contains(*result))
  1909. noteInconsistency(result);
  1910. }
  1911. void DependenciesUsed::addRefDependency(IHqlExpression * expr)
  1912. {
  1913. IHqlExpression * filename = queryTableFilename(expr);
  1914. if (filename)
  1915. addFilenameRead(filename);
  1916. }
  1917. IHqlExpression * DependenciesUsed::getNormalizedFilename(IHqlExpression * filename)
  1918. {
  1919. if (normalize)
  1920. return ::getNormalizedFilename(filename);
  1921. return LINK(filename);
  1922. }
  1923. bool DependenciesUsed::isSubsetOf(const DependenciesUsed & other) const
  1924. {
  1925. ForEachItemIn(idx1, tablesRead)
  1926. if (!other.tablesRead.contains(tablesRead.item(idx1)))
  1927. return false;
  1928. ForEachItemIn(idx2, resultsRead)
  1929. if (!other.resultsRead.contains(resultsRead.item(idx2)))
  1930. return false;
  1931. return true;
  1932. }
  1933. void DependenciesUsed::mergeIn(const DependenciesUsed & other)
  1934. {
  1935. appendArray(tablesRead, other.tablesRead);
  1936. appendArray(tablesWritten, other.tablesWritten);
  1937. appendArray(resultsRead, other.resultsRead);
  1938. appendArray(resultsWritten, other.resultsWritten);
  1939. if (other.allRead)
  1940. allRead = true;
  1941. if (other.allWritten)
  1942. allWritten = true;
  1943. }
  1944. void DependenciesUsed::extractDependencies(IHqlExpression * expr, unsigned flags)
  1945. {
  1946. switch (expr->getOperator())
  1947. {
  1948. case no_buildindex:
  1949. case no_output:
  1950. {
  1951. IHqlExpression * out = queryRealChild(expr, 1);
  1952. if (out)
  1953. {
  1954. if (flags & GatherFileWrite)
  1955. {
  1956. switch (out->getOperator())
  1957. {
  1958. case no_pipe:
  1959. allWritten = true;
  1960. break;
  1961. default:
  1962. addFilenameWrite(out);
  1963. break;
  1964. }
  1965. }
  1966. }
  1967. else
  1968. {
  1969. if (flags & GatherResultWrite)
  1970. addResultWrite(querySequence(expr), queryResultName(expr), false);
  1971. }
  1972. }
  1973. break;
  1974. case no_newkeyindex:
  1975. case no_keyindex:
  1976. if (flags & GatherFileRead)
  1977. addRefDependency(expr);
  1978. break;
  1979. case no_keydiff:
  1980. if (flags & GatherFileRead)
  1981. {
  1982. addRefDependency(expr->queryChild(0));
  1983. addRefDependency(expr->queryChild(1));
  1984. }
  1985. if (flags & GatherFileWrite)
  1986. addFilenameWrite(expr->queryChild(2));
  1987. break;
  1988. case no_keypatch:
  1989. if (flags & GatherFileRead)
  1990. {
  1991. addRefDependency(expr->queryChild(0));
  1992. addFilenameRead(expr->queryChild(1));
  1993. }
  1994. if (flags & GatherFileWrite)
  1995. addFilenameWrite(expr->queryChild(2));
  1996. break;
  1997. case no_table:
  1998. if (flags & GatherFileRead)
  1999. {
  2000. IHqlExpression * in = expr->queryChild(0);
  2001. IHqlExpression * mode = expr->queryChild(2);
  2002. if (mode->getOperator() == no_pipe)
  2003. allRead = true;
  2004. addFilenameRead(in);
  2005. }
  2006. break;
  2007. case no_workunit_dataset:
  2008. if (flags & GatherResultRead)
  2009. {
  2010. IHqlExpression * sequence = queryPropertyChild(expr, sequenceAtom, 0);
  2011. IHqlExpression * name = queryPropertyChild(expr, nameAtom, 0);
  2012. addResultRead(sequence, name, false);
  2013. }
  2014. break;
  2015. case no_getgraphresult:
  2016. if (flags & GatherGraphResultRead)
  2017. addResultRead(expr->queryChild(1), expr->queryChild(2), true);
  2018. break;
  2019. case no_setgraphresult:
  2020. if (flags & GatherGraphResultWrite)
  2021. addResultWrite(expr->queryChild(1), expr->queryChild(2), true);
  2022. break;
  2023. case no_getresult:
  2024. if (flags & GatherResultRead)
  2025. {
  2026. IHqlExpression * sequence = queryPropertyChild(expr, sequenceAtom, 0);
  2027. IHqlExpression * name = queryPropertyChild(expr, namedAtom, 0);
  2028. addResultRead(sequence, name, false);
  2029. }
  2030. break;
  2031. case no_ensureresult:
  2032. case no_setresult:
  2033. case no_extractresult:
  2034. if (flags & GatherResultWrite)
  2035. {
  2036. IHqlExpression * sequence = queryPropertyChild(expr, sequenceAtom, 0);
  2037. IHqlExpression * name = queryPropertyChild(expr, namedAtom, 0);
  2038. addResultWrite(sequence, name, false);
  2039. }
  2040. break;
  2041. case no_definesideeffect:
  2042. if (flags & GatherResultWrite)
  2043. {
  2044. addResultWrite(expr->queryProperty(_uid_Atom), NULL, false);
  2045. }
  2046. break;
  2047. case no_callsideeffect:
  2048. if (flags & GatherResultRead)
  2049. {
  2050. addResultRead(expr->queryProperty(_uid_Atom), NULL, false);
  2051. }
  2052. break;
  2053. }
  2054. }
  2055. void DependenciesUsed::noteInconsistency(IHqlExpression * expr)
  2056. {
  2057. if (!inconsistent)
  2058. inconsistent.set(expr);
  2059. }
  2060. void DependenciesUsed::removeInternalReads()
  2061. {
  2062. ForEachItemInRev(idx1, tablesRead)
  2063. {
  2064. IHqlExpression & cur = tablesRead.item(idx1);
  2065. if (tablesWritten.contains(cur))
  2066. tablesRead.remove(idx1);
  2067. }
  2068. }
  2069. void checkDependencyConsistency(IHqlExpression * expr)
  2070. {
  2071. DependenciesUsed depends(true);
  2072. gatherDependencies(expr, depends, GatherAll);
  2073. if (depends.inconsistent)
  2074. {
  2075. StringBuffer s;
  2076. if (depends.inconsistent->queryName() == resultAtom)
  2077. {
  2078. getStoredDescription(s, depends.inconsistent->queryChild(0), depends.inconsistent->queryChild(1), true);
  2079. throw MakeStringException(ERR_RECURSIVE_DEPENDENCY, "Result '%s' used before it is written", s.str());
  2080. }
  2081. else
  2082. {
  2083. depends.inconsistent->toString(s);
  2084. // DBGLOG("Filename %s used before it is written", s.str());
  2085. throw MakeStringException(ERR_RECURSIVE_DEPENDENCY, "Filename %s used before it is written", s.str());
  2086. }
  2087. }
  2088. }
  2089. void checkDependencyConsistency(const HqlExprArray & exprs)
  2090. {
  2091. DependenciesUsed depends(true);
  2092. DependencyGatherer gatherer(depends, GatherAll);
  2093. ForEachItemIn(i, exprs)
  2094. gatherer.gatherDependencies(&exprs.item(i));
  2095. if (depends.inconsistent)
  2096. {
  2097. StringBuffer s;
  2098. if (depends.inconsistent->queryName() == resultAtom)
  2099. {
  2100. getStoredDescription(s, depends.inconsistent->queryChild(0), depends.inconsistent->queryChild(1), true);
  2101. throw MakeStringException(ERR_RECURSIVE_DEPENDENCY, "Result '%s' used before it is written", s.str());
  2102. }
  2103. else
  2104. {
  2105. depends.inconsistent->toString(s);
  2106. // DBGLOG("Filename %s used before it is written", s.str());
  2107. throw MakeStringException(ERR_RECURSIVE_DEPENDENCY, "Filename %s used before it is written", s.str());
  2108. }
  2109. }
  2110. }
  2111. //---------------------------------------------------------------------------
  2112. static HqlTransformerInfo selectConsistencyCheckerInfo("SelectConsistencyChecker");
  2113. class SelectConsistencyChecker : public NewHqlTransformer
  2114. {
  2115. public:
  2116. SelectConsistencyChecker() : NewHqlTransformer(selectConsistencyCheckerInfo)
  2117. {
  2118. }
  2119. virtual void analyseExpr(IHqlExpression * expr)
  2120. {
  2121. if (alreadyVisited(expr))
  2122. return;
  2123. if (expr->getOperator() == no_select)
  2124. checkSelect(expr);
  2125. NewHqlTransformer::analyseExpr(expr);
  2126. }
  2127. virtual void analyseSelector(IHqlExpression * expr)
  2128. {
  2129. if (expr->getOperator() == no_select)
  2130. checkSelect(expr);
  2131. NewHqlTransformer::analyseSelector(expr);
  2132. }
  2133. protected:
  2134. void checkSelect(IHqlExpression * expr)
  2135. {
  2136. IHqlExpression * ds = expr->queryChild(0);
  2137. if (ds->getOperator() == no_activetable)
  2138. return;
  2139. IHqlExpression * field = expr->queryChild(1);
  2140. IHqlExpression * record = ds->queryRecord();
  2141. assertex(record);
  2142. IHqlSimpleScope * scope = record->querySimpleScope();
  2143. OwnedHqlExpr match = scope->lookupSymbol(field->queryId());
  2144. if (match != field)
  2145. {
  2146. EclIR::dbglogIR(2, field, match.get());
  2147. throw MakeStringException(ERR_RECURSIVE_DEPENDENCY, "Inconsistent select - field doesn't match parent record's field");
  2148. }
  2149. }
  2150. };
  2151. void checkSelectConsistency(IHqlExpression * expr)
  2152. {
  2153. SelectConsistencyChecker checker;
  2154. checker.analyse(expr, 0);
  2155. }
  2156. //---------------------------------------------------------------------------
  2157. void DependencyGatherer::doGatherDependencies(IHqlExpression * expr)
  2158. {
  2159. if (expr->queryTransformExtra())
  2160. return;
  2161. expr->setTransformExtraUnlinked(expr);
  2162. used.extractDependencies(expr, flags);
  2163. unsigned first = 0;
  2164. unsigned max = expr->numChildren();
  2165. switch (expr->getOperator())
  2166. {
  2167. case no_field: // by now there should be no default values as children of fields.
  2168. case no_attr:
  2169. case no_attr_link:
  2170. return;
  2171. case no_select:
  2172. if (!isNewSelector(expr))
  2173. return;
  2174. max = 1; // by now there should be no default values as children of fields.
  2175. break;
  2176. case no_keyindex:
  2177. first = 2;
  2178. break;
  2179. case no_newkeyindex:
  2180. first = 3;
  2181. break;
  2182. case no_executewhen:
  2183. if (expr->hasProperty(beforeAtom))
  2184. {
  2185. for (unsigned i=max; i-- != 0; )
  2186. doGatherDependencies(expr->queryChild(i));
  2187. return;
  2188. }
  2189. break;
  2190. }
  2191. for (unsigned i = first; i < max; i++)
  2192. doGatherDependencies(expr->queryChild(i));
  2193. }
  2194. void DependencyGatherer::gatherDependencies(IHqlExpression * expr)
  2195. {
  2196. TransformMutexBlock lock;
  2197. doGatherDependencies(expr);
  2198. }
  2199. extern HQL_API void gatherDependencies(IHqlExpression * expr, DependenciesUsed & used, unsigned flags)
  2200. {
  2201. DependencyGatherer gatherer(used, flags);
  2202. gatherer.gatherDependencies(expr);
  2203. }
  2204. extern HQL_API bool introducesNewDependencies(IHqlExpression * oldExpr, IHqlExpression * newExpr)
  2205. {
  2206. DependenciesUsed oldDepends(true);
  2207. DependenciesUsed newDepends(true);
  2208. gatherDependencies(newExpr, newDepends, GatherAllRead);
  2209. gatherDependencies(oldExpr, oldDepends, GatherAllRead);
  2210. return !newDepends.isSubsetOf(oldDepends);
  2211. }
  2212. //---------------------------------------------------------------------------
  2213. RecordSelectIterator::RecordSelectIterator(IHqlExpression * record, IHqlExpression * selector)
  2214. {
  2215. rootRecord.set(record);
  2216. rootSelector.set(selector);
  2217. nestingDepth = 0;
  2218. ifblockDepth = 0;
  2219. }
  2220. bool RecordSelectIterator::doNext()
  2221. {
  2222. while (indices.ordinality())
  2223. {
  2224. loop
  2225. {
  2226. unsigned next = indices.tos();
  2227. IHqlExpression & curRecord = records.tos();
  2228. unsigned max = curRecord.numChildren();
  2229. if (next >= max)
  2230. break;
  2231. indices.pop();
  2232. indices.append(next+1);
  2233. IHqlExpression * cur = curRecord.queryChild(next);
  2234. switch (cur->getOperator())
  2235. {
  2236. case no_record:
  2237. beginRecord(cur);
  2238. break;
  2239. case no_field:
  2240. switch (cur->queryType()->getTypeCode())
  2241. {
  2242. case type_row:
  2243. beginRecord(cur->queryRecord());
  2244. selector.setown(createSelectExpr(LINK(selector), LINK(cur)));
  2245. nestingDepth++;
  2246. break;
  2247. default:
  2248. curSelector.setown(createSelectExpr(LINK(selector), LINK(cur)));
  2249. return true;
  2250. }
  2251. break;
  2252. case no_ifblock:
  2253. beginRecord(cur->queryChild(1));
  2254. ifblockDepth++;
  2255. break;
  2256. case no_attr:
  2257. case no_attr_link:
  2258. case no_attr_expr:
  2259. break;
  2260. default:
  2261. UNIMPLEMENTED;
  2262. }
  2263. }
  2264. indices.pop();
  2265. records.pop();
  2266. selector.setown(&savedSelector.popGet());
  2267. if (records.ordinality())
  2268. {
  2269. switch (records.tos().queryChild(indices.tos()-1)->getOperator())
  2270. {
  2271. case no_ifblock:
  2272. ifblockDepth--;
  2273. break;
  2274. case no_field:
  2275. nestingDepth--;
  2276. break;
  2277. }
  2278. }
  2279. }
  2280. curSelector.clear();
  2281. return false;
  2282. }
  2283. void RecordSelectIterator::beginRecord(IHqlExpression * record)
  2284. {
  2285. savedSelector.append(*LINK(selector));
  2286. records.append(*record);
  2287. indices.append(0);
  2288. }
  2289. bool RecordSelectIterator::first()
  2290. {
  2291. savedSelector.kill();
  2292. records.kill();
  2293. indices.kill();
  2294. selector.set(rootSelector);
  2295. beginRecord(rootRecord);
  2296. ifblockDepth = 0;
  2297. nestingDepth = 0;
  2298. return doNext();
  2299. }
  2300. bool RecordSelectIterator::next()
  2301. {
  2302. return doNext();
  2303. }
  2304. bool RecordSelectIterator::isValid()
  2305. {
  2306. return (curSelector != NULL);
  2307. }
  2308. bool RecordSelectIterator::isInsideIfBlock()
  2309. {
  2310. return ifblockDepth > 0;
  2311. }
  2312. IHqlExpression * RecordSelectIterator::get()
  2313. {
  2314. return LINK(curSelector);
  2315. }
  2316. IHqlExpression * RecordSelectIterator::query()
  2317. {
  2318. return curSelector;
  2319. }
  2320. //---------------------------------------------------------------------------
  2321. unsigned countTotalFields(IHqlExpression * record, bool includeVirtual)
  2322. {
  2323. unsigned count = 0;
  2324. ForEachChild(i, record)
  2325. {
  2326. IHqlExpression * expr = record->queryChild(i);
  2327. switch (expr->getOperator())
  2328. {
  2329. case no_record:
  2330. count += countTotalFields(expr, includeVirtual);
  2331. break;
  2332. case no_ifblock:
  2333. count += countTotalFields(expr->queryChild(1), includeVirtual);
  2334. break;
  2335. case no_field:
  2336. switch (expr->queryType()->getTypeCode())
  2337. {
  2338. case type_record:
  2339. throwUnexpected();
  2340. case type_row:
  2341. count += countTotalFields(expr->queryRecord(), includeVirtual);
  2342. break;
  2343. default:
  2344. if (includeVirtual || !expr->hasProperty(virtualAtom))
  2345. count++;
  2346. break;
  2347. }
  2348. break;
  2349. }
  2350. }
  2351. return count;
  2352. }
  2353. bool transformContainsSkip(IHqlExpression * transform)
  2354. {
  2355. return containsSkip(transform);
  2356. }
  2357. bool transformListContainsSkip(IHqlExpression * transforms)
  2358. {
  2359. ForEachChild(i, transforms)
  2360. {
  2361. if (transformContainsSkip(transforms->queryChild(i)))
  2362. return true;
  2363. }
  2364. return false;
  2365. }
  2366. IHqlExpression * queryNextRecordField(IHqlExpression * record, unsigned & idx)
  2367. {
  2368. loop
  2369. {
  2370. IHqlExpression * cur = record->queryChild(idx++);
  2371. if (!cur || cur->getOperator() == no_field)
  2372. return cur;
  2373. }
  2374. }
  2375. IHqlExpression * ensureTransformType(IHqlExpression * transform, node_operator op)
  2376. {
  2377. if (transform->getOperator() == op)
  2378. return LINK(transform);
  2379. if (transform->getOperator() == no_call)
  2380. return LINK(transform); // This needs handling some other way!
  2381. HqlExprArray args;
  2382. unwindChildren(args, transform);
  2383. return createValue(op, transform->getType(), args);
  2384. }
  2385. //---------------------------------------------------------------------------
  2386. //NB: This needs to be kept in sync with the capabilities of the code generator.
  2387. extern HQL_API IHqlExpression * queryInvalidCsvRecordField(IHqlExpression * expr)
  2388. {
  2389. switch (expr->getOperator())
  2390. {
  2391. case no_ifblock:
  2392. return queryInvalidCsvRecordField(expr->queryChild(1));
  2393. case no_record:
  2394. {
  2395. ForEachChild(i, expr)
  2396. {
  2397. IHqlExpression * invalid = queryInvalidCsvRecordField(expr->queryChild(i));
  2398. if (invalid)
  2399. return invalid;
  2400. }
  2401. return NULL;
  2402. }
  2403. case no_field:
  2404. {
  2405. ITypeInfo * type = expr->queryType();
  2406. switch (type->getTypeCode())
  2407. {
  2408. case type_row:
  2409. return queryInvalidCsvRecordField(expr->queryRecord());
  2410. case type_table:
  2411. case type_groupedtable:
  2412. case type_set:
  2413. return expr;
  2414. default:
  2415. return NULL;
  2416. }
  2417. }
  2418. }
  2419. return NULL;
  2420. }
  2421. bool isValidCsvRecord(IHqlExpression * expr)
  2422. {
  2423. return queryInvalidCsvRecordField(expr) == NULL;
  2424. }
  2425. bool isValidXmlRecord(IHqlExpression * expr)
  2426. {
  2427. return true;
  2428. }
  2429. bool getBoolValue(IHqlExpression * expr, bool dft)
  2430. {
  2431. if (expr)
  2432. {
  2433. if (expr->getOperator() == no_translated)
  2434. expr = expr->queryChild(0);
  2435. IValue * value = expr->queryValue();
  2436. if (value)
  2437. return value->getBoolValue();
  2438. }
  2439. return dft;
  2440. }
  2441. __int64 getIntValue(IHqlExpression * expr, __int64 dft)
  2442. {
  2443. if (expr)
  2444. {
  2445. if (expr->getOperator() == no_translated)
  2446. expr = expr->queryChild(0);
  2447. IValue * value = expr->queryValue();
  2448. if (value)
  2449. return value->getIntValue();
  2450. }
  2451. return dft;
  2452. }
  2453. StringBuffer & getStringValue(StringBuffer & out, IHqlExpression * expr, const char * dft)
  2454. {
  2455. if (expr)
  2456. {
  2457. if (expr->getOperator() == no_translated)
  2458. expr = expr->queryChild(0);
  2459. IValue * value = expr->queryValue();
  2460. if (value)
  2461. {
  2462. value->getStringValue(out);
  2463. return out;
  2464. }
  2465. }
  2466. if (dft)
  2467. out.append(dft);
  2468. return out;
  2469. }
  2470. bool matchesConstantValue(IHqlExpression * expr, __int64 test)
  2471. {
  2472. if (!expr) return false;
  2473. if (expr->getOperator() == no_translated)
  2474. expr = expr->queryChild(0);
  2475. IValue * value = expr->queryValue();
  2476. return value && value->queryType()->isInteger() && (value->getIntValue() == test);
  2477. }
  2478. bool matchesBoolean(IHqlExpression * expr, bool test)
  2479. {
  2480. if (!expr) return false;
  2481. if (expr->getOperator() == no_translated)
  2482. expr = expr->queryChild(0);
  2483. IValue * value = expr->queryValue();
  2484. return value && value->queryType()->getTypeCode() == type_boolean && (value->getBoolValue() == test);
  2485. }
  2486. bool matchesConstantString(IHqlExpression * expr, const char * text, bool ignoreCase)
  2487. {
  2488. if (!expr) return false;
  2489. if (expr->getOperator() == no_translated)
  2490. expr = expr->queryChild(0);
  2491. IValue * value = expr->queryValue();
  2492. if (!value || !isStringType(value->queryType()))
  2493. return false;
  2494. //Would be more efficient to compare directly, but would need to handle all the variants
  2495. StringBuffer temp;
  2496. value->getStringValue(temp);
  2497. if (ignoreCase)
  2498. return stricmp(temp.str(), text) == 0;
  2499. return strcmp(temp.str(), text) == 0;
  2500. }
  2501. bool isEmptyList(IHqlExpression * expr)
  2502. {
  2503. switch (expr->getOperator())
  2504. {
  2505. case no_null:
  2506. return true;
  2507. case no_list:
  2508. case no_datasetlist:
  2509. return (expr->numChildren() == 0);
  2510. default:
  2511. return false;
  2512. }
  2513. }
  2514. bool recordContainsNestedRecord(IHqlExpression * record)
  2515. {
  2516. ForEachChild(i, record)
  2517. {
  2518. IHqlExpression * cur = record->queryChild(i);
  2519. switch (cur->getOperator())
  2520. {
  2521. case no_record:
  2522. if (recordContainsNestedRecord(cur))
  2523. return true;
  2524. break;
  2525. case no_ifblock:
  2526. if (recordContainsNestedRecord(cur->queryChild(1)))
  2527. return true;
  2528. break;
  2529. case no_field:
  2530. if (cur->queryType()->getTypeCode() == type_row)
  2531. return true;
  2532. break;
  2533. }
  2534. }
  2535. return false;
  2536. }
  2537. //Is this a select of the form a.b.c where only a is active, and b,c are datasets.
  2538. //If a is a row e.g., ds[1] and b is a record field then not true.
  2539. IHqlExpression * queryNextMultiLevelDataset(IHqlExpression * expr, bool followActiveSelectors)
  2540. {
  2541. while (expr->isDatarow())
  2542. {
  2543. switch (expr->getOperator())
  2544. {
  2545. case no_select:
  2546. case no_selectnth:
  2547. expr = expr->queryChild(0);
  2548. break;
  2549. default:
  2550. return NULL;
  2551. }
  2552. }
  2553. IHqlExpression * root = queryRoot(expr);
  2554. if (!root || (root->getOperator() != no_select))
  2555. return NULL;
  2556. if (!followActiveSelectors && !isNewSelector(root))
  2557. return NULL;
  2558. IHqlExpression * ds = root->queryChild(0);
  2559. loop
  2560. {
  2561. if (ds->isDataset())
  2562. return ds;
  2563. if (ds->getOperator() != no_select)
  2564. return NULL;
  2565. ds = ds->queryChild(0);
  2566. }
  2567. }
  2568. bool isMultiLevelDatasetSelector(IHqlExpression * expr, bool followActiveSelectors)
  2569. {
  2570. return queryNextMultiLevelDataset(expr, followActiveSelectors) != NULL;
  2571. }
  2572. IHqlExpression * getInverse(IHqlExpression * op)
  2573. {
  2574. node_operator opKind = op->getOperator();
  2575. if (opKind == no_not)
  2576. {
  2577. IHqlExpression * arg0 = op->queryChild(0);
  2578. if (arg0->isBoolean())
  2579. return LINK(arg0);
  2580. }
  2581. if (opKind == no_constant)
  2582. return createConstant(!op->queryValue()->getBoolValue());
  2583. if (opKind == no_alias_scope)
  2584. {
  2585. HqlExprArray args;
  2586. args.append(*getInverse(op->queryChild(0)));
  2587. unwindChildren(args, op, 1);
  2588. return op->clone(args);
  2589. }
  2590. node_operator inv = getInverseOp(opKind);
  2591. if (inv)
  2592. {
  2593. IHqlExpression * value = createOpenValue(inv, op->getType());
  2594. ForEachChild(i, op)
  2595. value->addOperand(LINK(op->queryChild(i)));
  2596. return value->closeExpr();
  2597. }
  2598. switch (opKind)
  2599. {
  2600. case no_if:
  2601. return createBoolExpr(no_if, LINK(op->queryChild(0)), getInverse(op->queryChild(1)), getInverse(op->queryChild(2)));
  2602. }
  2603. Owned<ITypeInfo> boolType = makeBoolType();
  2604. return createValue(no_not, LINK(boolType), ensureExprType(op, boolType));
  2605. }
  2606. IHqlExpression * getNormalizedCondition(IHqlExpression * expr)
  2607. {
  2608. if (expr->getOperator() == no_not)
  2609. return getInverse(expr->queryChild(0)->queryBody());
  2610. return LINK(expr->queryBody());
  2611. }
  2612. bool areInverseExprs(IHqlExpression * left, IHqlExpression* right)
  2613. {
  2614. if (left->getOperator() == no_not)
  2615. return left->queryChild(0)->queryBody() == right->queryBody();
  2616. if (right->getOperator() == no_not)
  2617. return right->queryChild(0)->queryBody() == left->queryBody();
  2618. node_operator leftOp = left->getOperator();
  2619. node_operator rightOp = right->getOperator();
  2620. if (leftOp != rightOp)
  2621. {
  2622. if (getInverseOp(leftOp) != rightOp)
  2623. return false;
  2624. }
  2625. OwnedHqlExpr inverseLeft = getInverse(left->queryBody());
  2626. return inverseLeft->queryBody() == right->queryBody();
  2627. }
  2628. IHqlExpression * getNegative(IHqlExpression * expr)
  2629. {
  2630. IValue * value = expr->queryValue();
  2631. if (value && isNumericType(value->queryType()))
  2632. return createConstant(negateValue(value));
  2633. if (expr->getOperator() == no_negate)
  2634. return LINK(expr->queryChild(0));
  2635. return createValue(no_negate, expr->getType(), LINK(expr));
  2636. }
  2637. bool isCompoundSource(IHqlExpression * expr)
  2638. {
  2639. switch (expr->getOperator())
  2640. {
  2641. case no_compound_diskread:
  2642. case no_compound_disknormalize:
  2643. case no_compound_diskaggregate:
  2644. case no_compound_diskcount:
  2645. case no_compound_diskgroupaggregate:
  2646. case no_compound_indexread:
  2647. case no_compound_indexnormalize:
  2648. case no_compound_indexaggregate:
  2649. case no_compound_indexcount:
  2650. case no_compound_indexgroupaggregate:
  2651. case no_compound_childread:
  2652. case no_compound_childnormalize:
  2653. case no_compound_childaggregate:
  2654. case no_compound_childcount:
  2655. case no_compound_childgroupaggregate:
  2656. case no_compound_inline:
  2657. return true;
  2658. }
  2659. return false;
  2660. }
  2661. static void convertRecordToAssigns(HqlExprArray & assigns, IHqlExpression * record, IHqlExpression * targetSelector, bool canOmit)
  2662. {
  2663. ForEachChild(idx, record)
  2664. {
  2665. IHqlExpression * cur = record->queryChild(idx);
  2666. switch (cur->getOperator())
  2667. {
  2668. case no_record:
  2669. convertRecordToAssigns(assigns, cur, targetSelector, canOmit);
  2670. break;
  2671. case no_ifblock:
  2672. convertRecordToAssigns(assigns, cur->queryChild(1), targetSelector, canOmit);
  2673. break;
  2674. case no_field:
  2675. {
  2676. IHqlExpression * fieldRecord = cur->queryRecord();
  2677. IHqlExpression * value = queryRealChild(cur, 0);
  2678. OwnedHqlExpr newTargetSelector = createSelectExpr(LINK(targetSelector), LINK(cur));
  2679. if (fieldRecord && !cur->isDataset() && !value)
  2680. {
  2681. //convertRecordToAssigns(assigns, cur->queryRecord(), newTargetSelector, canOmit);
  2682. IHqlExpression * transform = convertRecordToTransform(fieldRecord, canOmit);
  2683. IHqlExpression * newValue = createRow(no_createrow, transform);
  2684. assigns.append(*createAssign(LINK(newTargetSelector), newValue));
  2685. }
  2686. else
  2687. {
  2688. assertex(value || canOmit);
  2689. if (value)
  2690. assigns.append(*createAssign(LINK(newTargetSelector), LINK(value)));
  2691. }
  2692. break;
  2693. }
  2694. }
  2695. }
  2696. }
  2697. IHqlExpression * convertRecordToTransform(IHqlExpression * record, bool canOmit)
  2698. {
  2699. HqlExprArray assigns;
  2700. OwnedHqlExpr self = getSelf(record);
  2701. convertRecordToAssigns(assigns, record, self, canOmit);
  2702. return createValue(no_transform, makeTransformType(record->getType()), assigns);
  2703. }
  2704. IHqlExpression * createTransformForField(IHqlExpression * field, IHqlExpression * value)
  2705. {
  2706. OwnedHqlExpr record = createRecord(field);
  2707. OwnedHqlExpr self = getSelf(record);
  2708. OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(field));
  2709. OwnedHqlExpr assign = createAssign(LINK(target), LINK(value));
  2710. return createValue(no_transform, makeTransformType(record->getType()), assign.getClear());
  2711. }
  2712. IHqlExpression * convertScalarToRow(IHqlExpression * value, ITypeInfo * fieldType)
  2713. {
  2714. if (!fieldType)
  2715. fieldType = value->queryType();
  2716. OwnedHqlExpr field = createField(unnamedId, LINK(fieldType), NULL, NULL);
  2717. OwnedHqlExpr record = createRecord(field);
  2718. OwnedHqlExpr dataset;
  2719. OwnedHqlExpr attribute;
  2720. if (splitResultValue(dataset, attribute, value))
  2721. {
  2722. OwnedHqlExpr transform = createTransformForField(field, attribute);
  2723. OwnedHqlExpr ds = createDataset(no_newusertable, LINK(dataset), createComma(LINK(record), LINK(transform)));
  2724. return createRow(no_selectnth, LINK(ds), getSizetConstant(1));
  2725. }
  2726. OwnedHqlExpr transform = createTransformForField(field, value);
  2727. return createRow(no_createrow, transform.getClear());
  2728. }
  2729. inline bool isScheduleAction(IHqlExpression * expr)
  2730. {
  2731. switch (expr->getOperator())
  2732. {
  2733. case no_when:
  2734. case no_priority:
  2735. return true;
  2736. }
  2737. return false;
  2738. }
  2739. bool workflowContainsSchedule(IHqlExpression * colonExpr)
  2740. {
  2741. HqlExprArray actions;
  2742. colonExpr->queryChild(1)->unwindList(actions, no_comma);
  2743. ForEachItemIn(i, actions)
  2744. if (isScheduleAction(&actions.item(i)))
  2745. return true;
  2746. return false;
  2747. }
  2748. bool workflowContainsNonSchedule(IHqlExpression * colonExpr)
  2749. {
  2750. HqlExprArray actions;
  2751. colonExpr->queryChild(1)->unwindList(actions, no_comma);
  2752. ForEachItemIn(i, actions)
  2753. if (!isScheduleAction(&actions.item(i)))
  2754. return true;
  2755. return false;
  2756. }
  2757. bool isUngroup(IHqlExpression * expr)
  2758. {
  2759. return (expr->getOperator() == no_group) && !queryRealChild(expr, 1);
  2760. }
  2761. void unwindFilterConditions(HqlExprArray & conds, IHqlExpression * expr)
  2762. {
  2763. unsigned max = expr->numChildren();
  2764. for (unsigned idx=1; idx < max; idx++)
  2765. {
  2766. IHqlExpression * cur = queryRealChild(expr, idx);
  2767. if (cur)
  2768. cur->unwindList(conds, no_and);
  2769. }
  2770. }
  2771. unsigned getBestLengthEstimate(IHqlExpression * expr)
  2772. {
  2773. ITypeInfo * exprType = expr->queryType();
  2774. unsigned len = exprType->getStringLen();
  2775. if (len != UNKNOWN_LENGTH)
  2776. return len;
  2777. switch (expr->getOperator())
  2778. {
  2779. case no_cast:
  2780. case no_implicitcast:
  2781. if ((isStringType(exprType) || isUnicodeType(exprType)))
  2782. {
  2783. IHqlExpression * uncast = expr->queryChild(0);
  2784. ITypeInfo * uncastType = uncast->queryType();
  2785. if ((uncastType->getSize() != UNKNOWN_LENGTH) && (isStringType(uncastType) || isUnicodeType(uncastType)))
  2786. return uncastType->getStringLen();
  2787. }
  2788. break;
  2789. }
  2790. return len;
  2791. }
  2792. //---------------------------------------------------------------------------
  2793. SubStringHelper::SubStringHelper(IHqlExpression * expr)
  2794. {
  2795. init(expr->queryChild(0), expr->queryChild(1));
  2796. }
  2797. SubStringHelper::SubStringHelper(IHqlExpression * _src, IHqlExpression * range)
  2798. {
  2799. init(_src, range);
  2800. }
  2801. void SubStringHelper::init(IHqlExpression * _src, IHqlExpression * range)
  2802. {
  2803. special = false;
  2804. infiniteString = false;
  2805. from = NULL;
  2806. to = NULL;
  2807. src = _src;
  2808. srcType = src->queryType();
  2809. unsigned strSize = getBestLengthEstimate(src);
  2810. switch (range->getOperator())
  2811. {
  2812. case no_range:
  2813. from = range->queryChild(0);
  2814. to = range->queryChild(1);
  2815. break;
  2816. case no_rangeto:
  2817. to = range->queryChild(0);
  2818. break;
  2819. case no_rangefrom:
  2820. case no_rangecommon:
  2821. from = range->queryChild(0);
  2822. break;
  2823. default:
  2824. from = range;
  2825. to = range;
  2826. break;
  2827. }
  2828. if (from)
  2829. {
  2830. IValue * startValue = from->queryValue();
  2831. if (startValue)
  2832. {
  2833. fixedStart = (unsigned)startValue->getIntValue();
  2834. if ((int)fixedStart <= 0)
  2835. fixedStart = 1;
  2836. }
  2837. else
  2838. fixedStart = UNKNOWN_LENGTH;
  2839. }
  2840. else
  2841. fixedStart = 1;
  2842. if (to)
  2843. {
  2844. IValue * endValue = to->queryValue();
  2845. if (endValue)
  2846. {
  2847. fixedEnd = (unsigned)endValue->getIntValue();
  2848. if ((int)fixedEnd <= 0)
  2849. fixedEnd = 1;
  2850. if (knownStart() && fixedEnd < fixedStart)
  2851. fixedEnd = fixedStart-1;
  2852. }
  2853. else
  2854. fixedEnd = UNKNOWN_LENGTH;
  2855. }
  2856. else
  2857. fixedEnd = strSize;
  2858. bool isStringOrData = false;
  2859. switch (srcType->getTypeCode())
  2860. {
  2861. case type_string:
  2862. case type_data:
  2863. case type_unicode:
  2864. isStringOrData = true;
  2865. break;
  2866. }
  2867. bool isUnicode = srcType->getTypeCode() == type_unicode;
  2868. if (isStringOrData)
  2869. {
  2870. if (srcType->getSize() == UNKNOWN_LENGTH)
  2871. {
  2872. if ((src->getOperator() == no_cast) || (src->getOperator() == no_implicitcast))
  2873. {
  2874. ITypeInfo * childType = src->queryChild(0)->queryType();
  2875. type_t childTC = childType->getTypeCode();
  2876. type_t srcTC = srcType->getTypeCode();
  2877. switch (childType->getTypeCode())
  2878. {
  2879. case type_string:
  2880. case type_data:
  2881. if ((srcTC == type_data) || (childTC == type_data) || (srcType->queryCharset() == childType->queryCharset()))
  2882. {
  2883. src = src->queryChild(0);
  2884. srcType = childType;
  2885. }
  2886. break;
  2887. case type_unicode:
  2888. if(isUnicode && (srcType->queryLocale() == childType->queryLocale()))
  2889. {
  2890. src = src->queryChild(0);
  2891. srcType = childType;
  2892. }
  2893. break;
  2894. }
  2895. }
  2896. }
  2897. if (srcType->getSize() != UNKNOWN_LENGTH)
  2898. if (knownStart() && knownEnd())
  2899. special = true;
  2900. }
  2901. if (isStringOrData && srcType->getSize() == INFINITE_LENGTH)
  2902. infiniteString = true;
  2903. }
  2904. void unwindFields(HqlExprArray & fields, IHqlExpression * record)
  2905. {
  2906. ForEachChild(i, record)
  2907. {
  2908. IHqlExpression * cur = record->queryChild(i);
  2909. switch (cur->getOperator())
  2910. {
  2911. case no_record:
  2912. unwindFields(fields, cur);
  2913. break;
  2914. case no_ifblock:
  2915. unwindFields(fields, cur->queryChild(1));
  2916. break;
  2917. case no_field:
  2918. fields.append(*LINK(cur));
  2919. break;
  2920. }
  2921. }
  2922. }
  2923. void unwindFields(HqlExprCopyArray & fields, IHqlExpression * record)
  2924. {
  2925. ForEachChild(i, record)
  2926. {
  2927. IHqlExpression * cur = record->queryChild(i);
  2928. switch (cur->getOperator())
  2929. {
  2930. case no_record:
  2931. unwindFields(fields, cur);
  2932. break;
  2933. case no_ifblock:
  2934. unwindFields(fields, cur->queryChild(1));
  2935. break;
  2936. case no_field:
  2937. fields.append(*LINK(cur));
  2938. break;
  2939. }
  2940. }
  2941. }
  2942. unsigned numAttributes(const HqlExprArray & args)
  2943. {
  2944. unsigned cnt = 0;
  2945. ForEachItemIn(i, args)
  2946. if (args.item(i).isAttribute())
  2947. cnt++;
  2948. return cnt;
  2949. }
  2950. unsigned numAttributes(const IHqlExpression * expr)
  2951. {
  2952. unsigned cnt = 0;
  2953. ForEachChild(i, expr)
  2954. if (expr->queryChild(i)->isAttribute())
  2955. cnt++;
  2956. return cnt;
  2957. }
  2958. IHqlExpression * createGetResultFromSetResult(IHqlExpression * setResult, ITypeInfo * type)
  2959. {
  2960. IHqlExpression * seqAttr = setResult->queryProperty(sequenceAtom);
  2961. IHqlExpression * aliasAttr = setResult->queryProperty(namedAtom);
  2962. Linked<ITypeInfo> valueType = type;
  2963. if (!valueType)
  2964. {
  2965. IHqlExpression * value;
  2966. if (setResult->getOperator() == no_extractresult)
  2967. value = setResult->queryChild(1);
  2968. else
  2969. value = setResult->queryChild(0);
  2970. valueType.setown(value->getType());
  2971. }
  2972. switch (valueType->getTypeCode())
  2973. {
  2974. case type_table:
  2975. return createDataset(no_getresult, LINK(queryOriginalRecord(valueType)), createComma(LINK(seqAttr), LINK(aliasAttr)));
  2976. case type_groupedtable:
  2977. return createDataset(no_getresult, LINK(queryOriginalRecord(valueType)), createComma(LINK(seqAttr), createAttribute(groupedAtom), LINK(aliasAttr)));
  2978. case type_dictionary:
  2979. return createDictionary(no_workunit_dataset, LINK(queryOriginalRecord(valueType)), createComma(LINK(seqAttr), LINK(aliasAttr)));
  2980. case type_row:
  2981. case type_record:
  2982. return createRow(no_getresult, LINK(queryOriginalRecord(valueType)), createComma(LINK(seqAttr), LINK(aliasAttr)));
  2983. }
  2984. return createValue(no_getresult, valueType.getLink(), LINK(seqAttr), LINK(aliasAttr));
  2985. }
  2986. //---------------------------------------------------------------------------------------------------------------------
  2987. IHqlExpression * convertScalarToGraphResult(IHqlExpression * value, ITypeInfo * fieldType, IHqlExpression * represents, unsigned seq)
  2988. {
  2989. OwnedHqlExpr row = convertScalarToRow(value, fieldType);
  2990. OwnedHqlExpr ds = createDatasetFromRow(LINK(row));
  2991. HqlExprArray args;
  2992. args.append(*LINK(ds));
  2993. args.append(*LINK(represents));
  2994. args.append(*getSizetConstant(seq));
  2995. args.append(*createAttribute(rowAtom));
  2996. return createValue(no_setgraphresult, makeVoidType(), args);
  2997. }
  2998. IHqlExpression * createScalarFromGraphResult(ITypeInfo * scalarType, ITypeInfo * fieldType, IHqlExpression * represents, unsigned seq)
  2999. {
  3000. OwnedHqlExpr counterField = createField(unnamedId, LINK(fieldType), NULL, NULL);
  3001. OwnedHqlExpr counterRecord = createRecord(counterField);
  3002. HqlExprArray args;
  3003. args.append(*LINK(counterRecord));
  3004. args.append(*LINK(represents));
  3005. args.append(*getSizetConstant(seq));
  3006. args.append(*createAttribute(rowAtom));
  3007. OwnedHqlExpr counterResult = createDataset(no_getgraphresult, args);
  3008. OwnedHqlExpr select = createNewSelectExpr(createRow(no_selectnth, LINK(counterResult), getSizetConstant(1)), LINK(counterField));
  3009. return ensureExprType(select, scalarType);
  3010. }
  3011. IAtom * queryCsvEncoding(IHqlExpression * mode)
  3012. {
  3013. if (mode)
  3014. {
  3015. if (mode->queryProperty(asciiAtom))
  3016. return asciiAtom;
  3017. if (mode->queryProperty(ebcdicAtom))
  3018. return ebcdicAtom;
  3019. if (mode->queryProperty(unicodeAtom))
  3020. return unicodeAtom;
  3021. }
  3022. return NULL;
  3023. }
  3024. IAtom * queryCsvTableEncoding(IHqlExpression * tableExpr)
  3025. {
  3026. if (!tableExpr)
  3027. return NULL;
  3028. IHqlExpression * mode = tableExpr->queryChild(2);
  3029. assertex(mode->getOperator() == no_csv);
  3030. return queryCsvEncoding(mode);
  3031. }
  3032. IHqlExpression * createTrimExpr(IHqlExpression * value, IHqlExpression * flags)
  3033. {
  3034. LinkedHqlExpr expr = value;
  3035. ITypeInfo * exprType = expr->queryType()->queryPromotedType();
  3036. if (!isSimpleStringType(exprType) && !isUnicodeType(exprType))
  3037. {
  3038. unsigned strLen = isStringType(exprType) ? exprType->getStringLen() : UNKNOWN_LENGTH;
  3039. Owned<ITypeInfo> type = makeStringType(strLen, NULL, NULL);
  3040. expr.setown(ensureExprType(expr, type));
  3041. }
  3042. ITypeInfo * srcType = expr->queryType();
  3043. ITypeInfo * tgtType;
  3044. if (srcType->getTypeCode() == type_utf8)
  3045. tgtType = makeUtf8Type(UNKNOWN_LENGTH, srcType->queryLocale());
  3046. else if (isUnicodeType(srcType))
  3047. tgtType = makeUnicodeType(UNKNOWN_LENGTH, srcType->queryLocale());
  3048. else
  3049. tgtType = makeStringType(UNKNOWN_LENGTH, getCharset(asciiAtom), getCollation(asciiAtom));
  3050. HqlExprArray args;
  3051. args.append(*LINK(expr));
  3052. if (flags)
  3053. flags->unwindList(args, no_comma);
  3054. return createValue(no_trim, tgtType, args);
  3055. }
  3056. bool isLengthPreservingCast(IHqlExpression * expr)
  3057. {
  3058. if (!isCast(expr))
  3059. return false;
  3060. ITypeInfo * type = expr->queryType();
  3061. ITypeInfo * baseType = expr->queryChild(0)->queryType();
  3062. if ((isStringType(type) || isUnicodeType(type)) &&
  3063. (isStringType(baseType) || isUnicodeType(baseType)))
  3064. {
  3065. if (type->getStringLen() == baseType->getStringLen())
  3066. return true;
  3067. }
  3068. return false;
  3069. }
  3070. static void createDefaultTransformAssigns(HqlExprArray & args, IHqlExpression * self, IHqlExpression * right, IHqlExpression * record)
  3071. {
  3072. ForEachChild(i, record)
  3073. {
  3074. IHqlExpression * cur = record->queryChild(i);
  3075. switch (cur->getOperator())
  3076. {
  3077. case no_record:
  3078. createDefaultTransformAssigns(args, self, right, cur);
  3079. break;
  3080. case no_ifblock:
  3081. createDefaultTransformAssigns(args, self, right, cur->queryChild(1));
  3082. break;
  3083. case no_field:
  3084. {
  3085. IHqlExpression * target = createSelectExpr(LINK(self), LINK(cur));
  3086. IHqlExpression * value;
  3087. if (right)
  3088. value = createSelectExpr(LINK(right), LINK(cur));
  3089. else
  3090. value = createNullExpr(cur);
  3091. args.append(*createAssign(target, value));
  3092. break;
  3093. }
  3094. }
  3095. }
  3096. }
  3097. IHqlExpression * createTransformFromRow(IHqlExpression * expr)
  3098. {
  3099. IHqlExpression * record = expr->queryRecord();
  3100. OwnedHqlExpr self = createSelector(no_self, record, NULL);
  3101. HqlExprArray args;
  3102. createDefaultTransformAssigns(args, self, expr, record);
  3103. return createValue(no_transform, makeTransformType(record->getType()), args);
  3104. }
  3105. IHqlExpression * createNullTransform(IHqlExpression * record)
  3106. {
  3107. OwnedHqlExpr self = createSelector(no_self, record, NULL);
  3108. HqlExprArray args;
  3109. createDefaultTransformAssigns(args, self, NULL, record);
  3110. return createValue(no_transform, makeTransformType(record->getType()), args);
  3111. }
  3112. static bool foundDifference()
  3113. {
  3114. return false;
  3115. }
  3116. bool debugFindFirstDifference(IHqlExpression * left, IHqlExpression * right)
  3117. {
  3118. if (left == right)
  3119. return true;
  3120. if (!left || !right)
  3121. return foundDifference();
  3122. if (left->queryBody() == right->queryBody())
  3123. {
  3124. if ((left->getOperator() == no_call) && (right->getOperator() == no_call))
  3125. {
  3126. IHqlExpression * leftDefinition = left->queryDefinition();
  3127. IHqlExpression * rightDefinition = right->queryDefinition();
  3128. if ((left != leftDefinition) || (right != rightDefinition))
  3129. {
  3130. if (debugFindFirstDifference(left->queryDefinition(), right->queryDefinition()))
  3131. return false;
  3132. }
  3133. return foundDifference(); // break point here.
  3134. }
  3135. IHqlExpression * leftBody = left->queryBody(true);
  3136. IHqlExpression * rightBody = right->queryBody(true);
  3137. annotate_kind leftAK = left->getAnnotationKind();
  3138. annotate_kind rightAK = right->getAnnotationKind();
  3139. if (leftBody != rightBody)
  3140. {
  3141. if ((left == leftBody) || (right == rightBody))
  3142. return foundDifference(); // one side has an annotation, the other doesn't
  3143. return debugFindFirstDifference(leftBody, rightBody);
  3144. }
  3145. if (leftAK != rightAK)
  3146. return foundDifference(); // different annotation
  3147. return foundDifference(); // some difference in the annotation details
  3148. }
  3149. if (left->getOperator() != right->getOperator())
  3150. return foundDifference();
  3151. if (left->queryName() != right->queryName())
  3152. return foundDifference();
  3153. ForEachChild(i, left)
  3154. {
  3155. if (!debugFindFirstDifference(left->queryChild(i), right->queryChild(i)))
  3156. return false;
  3157. }
  3158. if (left->getOperator() != no_record)
  3159. {
  3160. IHqlExpression * leftRecord = queryOriginalRecord(left);
  3161. IHqlExpression * rightRecord = queryOriginalRecord(right);
  3162. if (leftRecord || rightRecord)
  3163. {
  3164. if (!debugFindFirstDifference(leftRecord, rightRecord))
  3165. return false;
  3166. }
  3167. }
  3168. if (left->queryType() != right->queryType())
  3169. {
  3170. IHqlExpression * lTypeExpr = queryExpression(left->queryType());
  3171. IHqlExpression * rTypeExpr = queryExpression(right->queryType());
  3172. if (((left != lTypeExpr) || (right != rTypeExpr)) &&
  3173. (lTypeExpr && rTypeExpr && lTypeExpr != rTypeExpr))
  3174. return debugFindFirstDifference(lTypeExpr, rTypeExpr);
  3175. return foundDifference();
  3176. }
  3177. return foundDifference();//something else
  3178. }
  3179. void debugTrackDifference(IHqlExpression * expr)
  3180. {
  3181. static IHqlExpression * prev;
  3182. if (prev && prev != expr)
  3183. debugFindFirstDifference(prev, expr);
  3184. prev = expr;
  3185. }
  3186. //------------------------------------------------------------------------------------------------
  3187. static IHqlExpression * expandConditions(IHqlExpression * expr, DependenciesUsed & dependencies, HqlExprArray & conds, HqlExprArray & values)
  3188. {
  3189. if (expr->getOperator() != no_if)
  3190. return expr;
  3191. IHqlExpression * cond = expr->queryChild(0);
  3192. //don't combine if conditions it it means that extra dependencies will be needed to test the if condition
  3193. //since it may cause unnecessary code to be executed.
  3194. if (conds.ordinality() == 0)
  3195. gatherDependencies(cond, dependencies, GatherAllResultRead);
  3196. else
  3197. {
  3198. DependenciesUsed condDependencies(true);
  3199. gatherDependencies(cond, condDependencies, GatherAllResultRead);
  3200. if (!condDependencies.isSubsetOf(dependencies))
  3201. return expr;
  3202. }
  3203. conds.append(*LINK(cond));
  3204. values.append(*LINK(expr->queryChild(1)));
  3205. return expandConditions(expr->queryChild(2), dependencies, conds, values);
  3206. }
  3207. IHqlExpression * combineIfsToMap(IHqlExpression * expr)
  3208. {
  3209. if (expr->isAction())
  3210. return NULL;
  3211. HqlExprArray conds, values;
  3212. DependenciesUsed dependencies(true);
  3213. IHqlExpression * falseExpr = expandConditions(expr, dependencies, conds, values);
  3214. if (conds.ordinality() <= 1)
  3215. return NULL;
  3216. HqlExprArray args;
  3217. ForEachItemIn(i, conds)
  3218. {
  3219. IHqlExpression & curValue = values.item(i);
  3220. args.append(*createValue(no_mapto, curValue.getType(), LINK(&conds.item(i)), LINK(&curValue)));
  3221. }
  3222. args.append(*LINK(falseExpr));
  3223. return createWrapper(no_map, expr->queryType(), args);
  3224. }
  3225. bool castPreservesValueAndOrder(IHqlExpression * expr)
  3226. {
  3227. assertex(isCast(expr));
  3228. IHqlExpression * uncast = expr->queryChild(0);
  3229. ITypeInfo * castType = expr->queryType();
  3230. ITypeInfo * uncastType = uncast->queryType();
  3231. if (castLosesInformation(castType, uncastType))
  3232. return false;
  3233. if (!preservesOrder(castType, uncastType))
  3234. return false;
  3235. return true;
  3236. }
  3237. //------------------------------------------------------------------------------------------------
  3238. class RecordMetaCreator
  3239. {
  3240. public:
  3241. RecordMetaCreator(IMaxSizeCallback * _callback) { callback = _callback; }
  3242. IDefRecordElement * createRecord(IHqlExpression * record, IHqlExpression * self);
  3243. protected:
  3244. IDefRecordElement * createField(IHqlExpression * cur, IHqlExpression * self);
  3245. IDefRecordElement * createIfBlock(IHqlExpression * cur, IHqlExpression * self);
  3246. bool createRecord(IDefRecordBuilder * builder, IHqlExpression * record, IHqlExpression * self);
  3247. protected:
  3248. HqlExprArray selects;
  3249. IDefRecordElementArray created;
  3250. IMaxSizeCallback * callback;
  3251. };
  3252. IDefRecordElement * RecordMetaCreator::createField(IHqlExpression * cur, IHqlExpression * self)
  3253. {
  3254. IHqlExpression * fieldRecord = cur->queryRecord();
  3255. Owned<IDefRecordElement> childDefRecord;
  3256. ITypeInfo * type = cur->queryType();
  3257. Linked<ITypeInfo> defType = type;
  3258. switch (type->getTypeCode())
  3259. {
  3260. case type_row:
  3261. //Backward compatibility!
  3262. defType.setown(makeRecordType());
  3263. childDefRecord.setown(createRecord(fieldRecord, self));
  3264. break;
  3265. case type_table:
  3266. defType.setown(makeTableType(makeRowType(makeRecordType()), NULL, NULL, NULL));
  3267. childDefRecord.setown(::createMetaRecord(fieldRecord, callback));
  3268. break;
  3269. case type_groupedtable:
  3270. {
  3271. ITypeInfo * tableType = makeTableType(makeRowType(makeRecordType()), NULL, NULL, NULL);
  3272. defType.setown(makeGroupedTableType(tableType, createAttribute(groupedAtom), NULL));
  3273. childDefRecord.setown(::createMetaRecord(fieldRecord, callback));
  3274. break;
  3275. }
  3276. case type_alien:
  3277. case type_any:
  3278. case type_bitfield:
  3279. //MORE: Not Allowed....
  3280. return NULL;
  3281. }
  3282. size32_t maxSize = 0;
  3283. Owned<IDefRecordElement> elem = createDEfield(cur->queryName(), defType, childDefRecord, maxSize);
  3284. if (cur->hasProperty(blobAtom))
  3285. {
  3286. Owned<ITypeInfo> blobType = makeBlobType();
  3287. return createDEfield(cur->queryName(), blobType, elem, 0);
  3288. }
  3289. return elem.getClear();
  3290. }
  3291. IDefRecordElement * RecordMetaCreator::createIfBlock(IHqlExpression * cur, IHqlExpression * self)
  3292. {
  3293. IHqlExpression * cond = cur->queryChild(0);
  3294. IHqlExpression * select;
  3295. LinkedHqlExpr value;
  3296. switch (cond->getOperator())
  3297. {
  3298. case no_select:
  3299. //ifblock(self.booleanField)
  3300. select = cond;
  3301. value.setown(createConstant(true));
  3302. break;
  3303. case no_eq:
  3304. select = cond->queryChild(0);
  3305. value.set(cond->queryChild(1));
  3306. if (select->getOperator() != no_select)
  3307. return NULL;
  3308. if (value->getOperator() != no_constant)
  3309. return NULL;
  3310. break;
  3311. default:
  3312. return NULL;
  3313. }
  3314. unsigned match = selects.find(*select);
  3315. if (match == NotFound)
  3316. return NULL;
  3317. IDefRecordElement & condField = created.item(match);
  3318. Owned<IDefRecordElement> record = createRecord(cur->queryChild(1), self);
  3319. if (!record)
  3320. return NULL;
  3321. return createDEifblock(&condField, value->queryValue(), record);
  3322. }
  3323. bool RecordMetaCreator::createRecord(IDefRecordBuilder * builder, IHqlExpression * record, IHqlExpression * self)
  3324. {
  3325. ForEachChild(i, record)
  3326. {
  3327. IHqlExpression * cur = record->queryChild(i);
  3328. switch (cur->getOperator())
  3329. {
  3330. case no_record:
  3331. if (!createRecord(builder, cur, self))
  3332. return false;
  3333. break;
  3334. case no_field:
  3335. {
  3336. OwnedHqlExpr selector = createSelectExpr(LINK(self), LINK(cur));
  3337. IDefRecordElement * next = createField(cur, selector);
  3338. if (!next)
  3339. return false;
  3340. builder->addChildOwn(next);
  3341. selects.append(*LINK(selector));
  3342. created.append(*LINK(next));
  3343. break;
  3344. }
  3345. case no_ifblock:
  3346. {
  3347. IDefRecordElement * next = createIfBlock(cur, self);
  3348. if (!next)
  3349. return false;
  3350. builder->addChildOwn(next);
  3351. break;
  3352. }
  3353. default:
  3354. break;
  3355. }
  3356. }
  3357. return true;
  3358. }
  3359. IDefRecordElement * RecordMetaCreator::createRecord(IHqlExpression * record, IHqlExpression * self)
  3360. {
  3361. size32_t maxSize = callback ? callback->getMaxSize(record) : 4096;
  3362. Owned<IDefRecordBuilder> builder = createDErecord(maxSize);
  3363. if (!createRecord(builder, record, self))
  3364. return NULL;
  3365. return builder->close();
  3366. }
  3367. IDefRecordElement * createMetaRecord(IHqlExpression * record, IMaxSizeCallback * callback)
  3368. {
  3369. RecordMetaCreator creator(callback);
  3370. return creator.createRecord(record, querySelfReference());
  3371. }
  3372. static bool doContainsExpression(IHqlExpression * expr, IHqlExpression * search)
  3373. {
  3374. loop
  3375. {
  3376. if (expr->queryTransformExtra())
  3377. return false;
  3378. if (expr == search)
  3379. return true;
  3380. expr->setTransformExtraUnlinked(expr);
  3381. IHqlExpression * body = expr->queryBody(true);
  3382. if (body == expr)
  3383. break;
  3384. expr = body;
  3385. }
  3386. ForEachChild(i, expr)
  3387. {
  3388. if (doContainsExpression(expr->queryChild(i), search))
  3389. return true;
  3390. }
  3391. return false;
  3392. }
  3393. bool containsExpression(IHqlExpression * expr, IHqlExpression * search)
  3394. {
  3395. TransformMutexBlock lock;
  3396. return doContainsExpression(expr, search);
  3397. }
  3398. static bool doContainsOperator(IHqlExpression * expr, node_operator search)
  3399. {
  3400. if (expr->queryTransformExtra())
  3401. return false;
  3402. if (expr->getOperator() == search)
  3403. return true;
  3404. expr->setTransformExtraUnlinked(expr);
  3405. ForEachChild(i, expr)
  3406. {
  3407. if (doContainsOperator(expr->queryChild(i), search))
  3408. return true;
  3409. }
  3410. return false;
  3411. }
  3412. bool containsOperator(IHqlExpression * expr, node_operator search)
  3413. {
  3414. TransformMutexBlock lock;
  3415. return doContainsOperator(expr, search);
  3416. }
  3417. static HqlTransformerInfo annotationRemoverInfo("AnnotationRemover");
  3418. class AnnotationRemover : public NewHqlTransformer
  3419. {
  3420. public:
  3421. AnnotationRemover(IHqlExpression * _searchExpr)
  3422. : NewHqlTransformer(annotationRemoverInfo), searchExpr(_searchExpr)
  3423. {
  3424. }
  3425. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  3426. {
  3427. if (expr->queryBody() == searchExpr)
  3428. return LINK(searchExpr);
  3429. return NewHqlTransformer::createTransformed(expr);
  3430. }
  3431. protected:
  3432. IHqlExpression * searchExpr;
  3433. };
  3434. IHqlExpression * removeAnnotations(IHqlExpression * expr, IHqlExpression * search)
  3435. {
  3436. AnnotationRemover remover(search);
  3437. return remover.transformRoot(expr);
  3438. }
  3439. bool containsIfBlock(IHqlExpression * record)
  3440. {
  3441. ForEachChild(i, record)
  3442. {
  3443. IHqlExpression * cur = record->queryChild(i);
  3444. switch (cur->getOperator())
  3445. {
  3446. case no_record:
  3447. if (containsIfBlock(cur))
  3448. return true;
  3449. break;
  3450. case no_field:
  3451. if (cur->isDatarow() && containsIfBlock(cur->queryRecord()))
  3452. return true;
  3453. break;
  3454. case no_ifblock:
  3455. return true;
  3456. }
  3457. }
  3458. return false;
  3459. }
  3460. IHqlExpression * getFailCode(IHqlExpression * failExpr)
  3461. {
  3462. IHqlExpression * arg0 = failExpr->queryChild(0);
  3463. if (arg0 && arg0->queryType()->isInteger())
  3464. return LINK(arg0);
  3465. return createConstant(0);
  3466. }
  3467. IHqlExpression * getFailMessage(IHqlExpression * failExpr, bool nullIfOmitted)
  3468. {
  3469. IHqlExpression * arg0 = failExpr->queryChild(0);
  3470. if (arg0)
  3471. {
  3472. if (!arg0->queryType()->isInteger())
  3473. return LINK(arg0);
  3474. IHqlExpression * arg1 = failExpr->queryChild(1);
  3475. if (arg1)
  3476. return LINK(arg1);
  3477. }
  3478. if (nullIfOmitted)
  3479. return NULL;
  3480. return createConstant("");
  3481. }
  3482. int compareAtoms(IInterface * * pleft, IInterface * * pright)
  3483. {
  3484. IAtom * left = static_cast<IAtom *>(*pleft);
  3485. IAtom * right = static_cast<IAtom *>(*pright);
  3486. return stricmp(left->str(), right->str());
  3487. }
  3488. int compareSymbolsByName(IInterface * * pleft, IInterface * * pright)
  3489. {
  3490. IHqlExpression * left = static_cast<IHqlExpression *>(*pleft);
  3491. IHqlExpression * right = static_cast<IHqlExpression *>(*pright);
  3492. return stricmp(left->queryName()->str(), right->queryName()->str());
  3493. }
  3494. int compareScopesByName(IInterface * * pleft, IInterface * * pright)
  3495. {
  3496. IHqlScope * left = static_cast<IHqlScope *>(*pleft);
  3497. IHqlScope * right = static_cast<IHqlScope *>(*pright);
  3498. const char * leftName = left->queryName()->str();
  3499. const char * rightName = right->queryName()->str();
  3500. if (leftName && rightName)
  3501. return stricmp(leftName, rightName);
  3502. if (leftName)
  3503. return +1;
  3504. if (rightName)
  3505. return -1;
  3506. return 0;
  3507. }
  3508. class ModuleExpander
  3509. {
  3510. public:
  3511. ModuleExpander(HqlLookupContext & _ctx, bool _expandCallsWhenBound, node_operator _outputOp)
  3512. : ctx(_ctx), expandCallsWhenBound(_expandCallsWhenBound), outputOp(_outputOp) {}
  3513. IHqlExpression * createExpanded(IHqlExpression * scopeExpr, IHqlExpression * ifaceExpr, const char * prefix);
  3514. protected:
  3515. HqlLookupContext ctx;
  3516. bool expandCallsWhenBound;
  3517. node_operator outputOp;
  3518. };
  3519. IHqlExpression * ModuleExpander::createExpanded(IHqlExpression * scopeExpr, IHqlExpression * ifaceExpr, const char * prefix)
  3520. {
  3521. IHqlScope * scope = scopeExpr->queryScope();
  3522. HqlExprArray symbols;
  3523. ensureSymbolsDefined(ifaceExpr, ctx);
  3524. ifaceExpr->queryScope()->getSymbols(symbols);
  3525. symbols.sort(compareSymbolsByName); // should really be in definition order, but that isn't currently preserved
  3526. HqlExprArray outputs;
  3527. StringBuffer lowername;
  3528. ForEachItemIn(i, symbols)
  3529. {
  3530. IHqlExpression & cur = symbols.item(i);
  3531. IIdAtom * name = cur.queryId();
  3532. OwnedHqlExpr resolved = scope->lookupSymbol(name, LSFpublic, ctx);
  3533. LinkedHqlExpr value = resolved;
  3534. if (value && value->isFunction())
  3535. {
  3536. bool allArgumentsHaveDefaults = false;
  3537. if (value->isFunctionDefinition())
  3538. {
  3539. //Allow functions that supply default values for each of the parameters to be expanded
  3540. IHqlExpression * formals = value->queryChild(1);
  3541. IHqlExpression * defaults = value->queryChild(2);
  3542. unsigned numFormals = formals->numChildren();
  3543. if (numFormals == 0)
  3544. allArgumentsHaveDefaults = true;
  3545. else if (defaults && (defaults->numChildren() == numFormals))
  3546. {
  3547. allArgumentsHaveDefaults = true;
  3548. ForEachChild(i, defaults)
  3549. {
  3550. IHqlExpression * param = defaults->queryChild(i);
  3551. if (param->getOperator() == no_omitted)
  3552. allArgumentsHaveDefaults = false;
  3553. }
  3554. }
  3555. }
  3556. if (allArgumentsHaveDefaults)
  3557. {
  3558. HqlExprArray args;
  3559. value.setown(createBoundFunction(NULL, value, args, NULL, expandCallsWhenBound));
  3560. }
  3561. else
  3562. value.clear();
  3563. }
  3564. if (value && isExported(resolved))
  3565. {
  3566. lowername.clear().append(prefix).append(name->lower()).toLowerCase();
  3567. node_operator op = no_none;
  3568. if (outputOp == no_output)
  3569. {
  3570. if (value->isDataset())
  3571. {
  3572. value.setown(createDataset(no_selectfields, LINK(value), createValue(no_null)));
  3573. op = no_output;
  3574. }
  3575. else if (value->isDatarow())
  3576. op = no_output;
  3577. else if (value->isList() || value->queryType()->isScalar())
  3578. op = no_outputscalar;
  3579. }
  3580. else
  3581. {
  3582. assertex(outputOp == no_evaluate_stmt);
  3583. if (value->isList() || value->queryType()->isScalar())
  3584. op = no_evaluate_stmt;
  3585. }
  3586. switch (value->getOperator())
  3587. {
  3588. case no_typedef:
  3589. op = no_none;
  3590. break;
  3591. }
  3592. if (op != no_none)
  3593. outputs.append(*createValue(op, makeVoidType(), LINK(value), createAttribute(namedAtom, createConstant(lowername))));
  3594. else if (value->isAction())
  3595. outputs.append(*LINK(value));
  3596. else if (value->isScope())
  3597. {
  3598. lowername.append(".");
  3599. OwnedHqlExpr child = createExpanded(value, value, lowername.str());
  3600. if (child->getOperator() != no_null)
  3601. outputs.append(*child.getClear());
  3602. }
  3603. }
  3604. }
  3605. return createActionList(outputs);
  3606. }
  3607. IHqlExpression * createEvaluateOutputModule(HqlLookupContext & ctx, IHqlExpression * scopeExpr, IHqlExpression * ifaceExpr, bool expandCallsWhenBound, node_operator outputOp)
  3608. {
  3609. ModuleExpander expander(ctx, expandCallsWhenBound, outputOp);
  3610. return expander.createExpanded(scopeExpr, ifaceExpr, NULL);
  3611. }
  3612. extern HQL_API IHqlExpression * createStoredModule(IHqlExpression * scopeExpr)
  3613. {
  3614. IHqlScope * scope = scopeExpr->queryScope();
  3615. HqlExprArray symbols;
  3616. scope->getSymbols(symbols);
  3617. symbols.sort(compareSymbolsByName); // should really be in definition order, but that isn't currently preserved
  3618. Owned<IHqlScope> newScope = createVirtualScope();
  3619. IHqlExpression * newScopeExpr = queryExpression(newScope);
  3620. newScopeExpr->addOperand(LINK(scopeExpr));
  3621. HqlExprArray noParameters;
  3622. IIdAtom * moduleName = NULL;
  3623. ForEachItemIn(i, symbols)
  3624. {
  3625. IHqlExpression & cur = symbols.item(i);
  3626. if (isExported(&cur) && !cur.isFunction())
  3627. {
  3628. LinkedHqlExpr value = &cur;
  3629. if (value->isDataset() || value->isDatarow() || value->isList() || value->queryType()->isScalar())
  3630. {
  3631. if (value->getOperator() == no_purevirtual)
  3632. value.setown(createNullExpr(value));
  3633. IIdAtom * name = symbols.item(i).queryId();
  3634. OwnedHqlExpr failure = createValue(no_stored, makeVoidType(), createConstant(name->lower()->str()));
  3635. HqlExprArray meta;
  3636. value.setown(attachWorkflowOwn(meta, value.getClear(), failure, NULL));
  3637. newScope->defineSymbol(name, moduleName, value.getClear(),
  3638. true, false, cur.getSymbolFlags());
  3639. }
  3640. }
  3641. }
  3642. return queryExpression(newScope.getClear())->closeExpr();
  3643. }
  3644. extern HQL_API IHqlExpression * convertScalarAggregateToDataset(IHqlExpression * expr)
  3645. {
  3646. IHqlExpression * dataset = expr->queryChild(0);
  3647. IHqlExpression * arg = queryRealChild(expr, 1);
  3648. node_operator newop;
  3649. switch (expr->getOperator())
  3650. {
  3651. case no_ave: newop = no_avegroup; break;
  3652. case no_count: newop = no_countgroup; break;
  3653. case no_min: newop = no_mingroup; break;
  3654. case no_max: newop = no_maxgroup; break;
  3655. case no_sum: newop = no_sumgroup; break;
  3656. case no_exists:newop = no_existsgroup; break;
  3657. case no_variance: newop = no_vargroup; break;
  3658. case no_covariance: newop = no_covargroup; break;
  3659. case no_correlation:newop = no_corrgroup; break;
  3660. default:
  3661. return NULL;
  3662. }
  3663. OwnedHqlExpr field;
  3664. if ((newop == no_mingroup || newop == no_maxgroup) && (arg->getOperator() == no_select))
  3665. field.set(arg->queryChild(1)); // inherit maxlength etc...
  3666. else
  3667. field.setown(createField(valueId, expr->getType(), NULL));
  3668. IHqlExpression * aggregateRecord = createRecord(field);
  3669. IHqlExpression * keyedAttr = expr->queryProperty(keyedAtom);
  3670. IHqlExpression * prefetchAttr = expr->queryProperty(prefetchAtom);
  3671. HqlExprArray valueArgs;
  3672. unwindChildren(valueArgs, expr, 1);
  3673. IHqlExpression * newValue = createValue(newop, expr->getType(), valueArgs);
  3674. IHqlExpression * assign = createAssign(createSelectExpr(getSelf(aggregateRecord), LINK(field)), newValue);
  3675. IHqlExpression * transform = createValue(no_newtransform, makeTransformType(aggregateRecord->getType()), assign);
  3676. //remove grouping if dataset happens to be grouped...
  3677. dataset->Link();
  3678. if (dataset->queryType()->getTypeCode() == type_groupedtable)
  3679. dataset = createDataset(no_group, dataset, NULL);
  3680. IHqlExpression * project = createDataset(no_newusertable, dataset, createComma(aggregateRecord, transform, LINK(keyedAttr), LINK(prefetchAttr)));
  3681. return createRow(no_selectnth, project, createConstantOne());
  3682. }
  3683. //---------------------------------------------------------------------------
  3684. void HqlExprHashTable::onAdd(void *et)
  3685. {
  3686. ((IHqlExpression*)et)->Link();
  3687. }
  3688. void HqlExprHashTable::onRemove(void *et)
  3689. {
  3690. ((IHqlExpression*)et)->Release();
  3691. }
  3692. unsigned HqlExprHashTable::getHashFromElement(const void *et) const
  3693. {
  3694. return ((IHqlExpression*)et)->getHash();
  3695. }
  3696. unsigned HqlExprHashTable::getHashFromFindParam(const void *fp) const
  3697. {
  3698. return ((IHqlExpression*)fp)->getHash();
  3699. }
  3700. const void * HqlExprHashTable::getFindParam(const void *et) const
  3701. {
  3702. return et;
  3703. }
  3704. bool HqlExprHashTable::matchesFindParam(const void *et, const void *key, unsigned fphash) const
  3705. {
  3706. return et == key;
  3707. }
  3708. //---------------------------------------------------------------------------
  3709. bool BitfieldPacker::checkSpaceAvailable(unsigned & thisBitOffset, unsigned & thisBits, ITypeInfo * type)
  3710. {
  3711. bool fitted = true;
  3712. thisBits = type->getBitSize();
  3713. if (thisBits > bitsRemaining)
  3714. {
  3715. ITypeInfo * storeType = type->queryChildType();
  3716. unsigned unitSize = storeType->getSize();
  3717. bitsRemaining = unitSize * 8;
  3718. nextBitOffset = 0;
  3719. fitted = false;
  3720. }
  3721. thisBitOffset = nextBitOffset;
  3722. nextBitOffset += thisBits;
  3723. bitsRemaining -= thisBits;
  3724. return fitted;
  3725. }
  3726. void reorderAttributesToEnd(HqlExprArray & target, const HqlExprArray & source)
  3727. {
  3728. ForEachItemIn(i1, source)
  3729. {
  3730. IHqlExpression & cur = source.item(i1);
  3731. if (!cur.isAttribute())
  3732. target.append(OLINK(cur));
  3733. }
  3734. ForEachItemIn(i2, source)
  3735. {
  3736. IHqlExpression & cur = source.item(i2);
  3737. if (cur.isAttribute())
  3738. target.append(OLINK(cur));
  3739. }
  3740. }
  3741. bool hasActiveTopDataset(IHqlExpression * expr)
  3742. {
  3743. switch (getChildDatasetType(expr))
  3744. {
  3745. case childdataset_dataset:
  3746. case childdataset_datasetleft:
  3747. case childdataset_top_left_right:
  3748. return true;
  3749. }
  3750. return false;
  3751. }
  3752. //-------------------------------------------------------------------------------------------------------
  3753. void getStoredDescription(StringBuffer & text, IHqlExpression * sequence, IHqlExpression * name, bool includeInternalName)
  3754. {
  3755. if (sequence)
  3756. {
  3757. switch (sequence->queryValue()->getIntValue())
  3758. {
  3759. case ResultSequencePersist:
  3760. text.append("PERSIST(");
  3761. name->toString(text);
  3762. text.append(")");
  3763. break;
  3764. case ResultSequenceStored:
  3765. text.append("STORED(");
  3766. name->toString(text);
  3767. text.append(")");
  3768. break;
  3769. case ResultSequenceInternal:
  3770. text.append("Internal");
  3771. if (includeInternalName)
  3772. name->toString(text.append("(")).append(")");
  3773. break;
  3774. default:
  3775. if (name)
  3776. name->toString(text);
  3777. else
  3778. text.append("Result #").append(sequence->queryValue()->getIntValue()+1);
  3779. break;
  3780. }
  3781. }
  3782. }
  3783. IHqlExpression * appendOwnedOperandsF(IHqlExpression * expr, ...)
  3784. {
  3785. HqlExprArray children;
  3786. unwindChildren(children, expr);
  3787. va_list args;
  3788. va_start(args, expr);
  3789. for (;;)
  3790. {
  3791. IHqlExpression *parm = va_arg(args, IHqlExpression *);
  3792. if (!parm)
  3793. break;
  3794. children.append(*parm);
  3795. }
  3796. va_end(args);
  3797. return expr->clone(children);
  3798. }
  3799. extern HQL_API void inheritAttribute(HqlExprArray & attrs, IHqlExpression * donor, IAtom * name)
  3800. {
  3801. IHqlExpression * match = donor->queryProperty(name);
  3802. if (match)
  3803. attrs.append(*LINK(match));
  3804. }
  3805. IHqlExpression * inheritAttribute(IHqlExpression * expr, IHqlExpression * donor, IAtom * name)
  3806. {
  3807. return appendOwnedOperand(expr, LINK(donor->queryProperty(name)));
  3808. }
  3809. IHqlExpression * appendAttribute(IHqlExpression * expr, IAtom * attr)
  3810. {
  3811. return appendOwnedOperand(expr, createAttribute(attr));
  3812. }
  3813. IHqlExpression * appendOwnedOperand(IHqlExpression * expr, IHqlExpression * ownedOperand)
  3814. {
  3815. if (!ownedOperand)
  3816. return LINK(expr);
  3817. HqlExprArray args;
  3818. unwindChildren(args, expr);
  3819. args.append(*ownedOperand);
  3820. return expr->clone(args);
  3821. }
  3822. IHqlExpression * removeOperand(IHqlExpression * expr, IHqlExpression * operand)
  3823. {
  3824. HqlExprArray args;
  3825. unwindChildren(args, expr);
  3826. args.zap(*operand);
  3827. return expr->clone(args);
  3828. }
  3829. IHqlExpression * removeChildOp(IHqlExpression * expr, node_operator op)
  3830. {
  3831. HqlExprArray args;
  3832. unwindChildren(args, expr);
  3833. ForEachItemInRev(i, args)
  3834. if (args.item(i).getOperator() == op)
  3835. args.remove(i);
  3836. return expr->clone(args);
  3837. }
  3838. IHqlExpression * removeProperty(IHqlExpression * expr, IAtom * attr)
  3839. {
  3840. HqlExprArray args;
  3841. unwindChildren(args, expr);
  3842. if (removeProperty(args, attr))
  3843. return expr->clone(args);
  3844. return LINK(expr);
  3845. }
  3846. IHqlExpression * replaceOwnedProperty(IHqlExpression * expr, IHqlExpression * ownedOperand)
  3847. {
  3848. HqlExprArray args;
  3849. unwindChildren(args, expr);
  3850. removeProperty(args, ownedOperand->queryName());
  3851. args.append(*ownedOperand);
  3852. return expr->clone(args);
  3853. }
  3854. IHqlExpression * appendLocalAttribute(IHqlExpression * expr)
  3855. {
  3856. return appendOwnedOperand(expr, createLocalAttribute());
  3857. }
  3858. IHqlExpression * removeLocalAttribute(IHqlExpression * expr)
  3859. {
  3860. return removeProperty(expr, localAtom);
  3861. }
  3862. bool hasOperand(IHqlExpression * expr, IHqlExpression * child)
  3863. {
  3864. expr = expr->queryBody();
  3865. ForEachChild(i, expr)
  3866. {
  3867. if (expr->queryChild(i) == child)
  3868. return true;
  3869. }
  3870. return false;
  3871. }
  3872. //-------------------------------------------------------------------------------------------------------
  3873. class HQL_API SplitDatasetAttributeTransformer : public NewHqlTransformer
  3874. {
  3875. public:
  3876. SplitDatasetAttributeTransformer();
  3877. virtual void analyseExpr(IHqlExpression * expr);
  3878. virtual IHqlExpression * createTransformed(IHqlExpression * expr);
  3879. bool split(SharedHqlExpr & dataset, SharedHqlExpr & attribute, IHqlExpression * expr);
  3880. protected:
  3881. void doAnalyseSelect(IHqlExpression * expr);
  3882. IHqlExpression * doTransformSelect(IHqlExpression * expr);
  3883. protected:
  3884. OwnedHqlExpr selSeq;
  3885. OwnedHqlExpr rowsId;
  3886. HqlExprCopyArray datasets;
  3887. HqlExprArray newDatasets;
  3888. HqlExprArray selectors;
  3889. };
  3890. static HqlTransformerInfo hqlSplitDatasetAttributeInfo("SplitDatasetAttributeTransformer");
  3891. SplitDatasetAttributeTransformer::SplitDatasetAttributeTransformer(): NewHqlTransformer(hqlSplitDatasetAttributeInfo)
  3892. {
  3893. }
  3894. void SplitDatasetAttributeTransformer::analyseExpr(IHqlExpression * expr)
  3895. {
  3896. if (alreadyVisited(expr))
  3897. return;
  3898. switch (expr->getOperator())
  3899. {
  3900. case no_select:
  3901. doAnalyseSelect(expr);
  3902. return;
  3903. case NO_AGGREGATE:
  3904. case no_createset:
  3905. case no_colon:
  3906. case no_globalscope:
  3907. case no_nothor:
  3908. //Ugly, should really be normalized to no_select(no_aggregate[1], x)
  3909. return;
  3910. case no_if:
  3911. case no_mapto:
  3912. analyseExpr(expr->queryChild(0));
  3913. return;
  3914. case no_add:
  3915. case no_sub:
  3916. case no_mul:
  3917. case no_div:
  3918. case no_cast:
  3919. case no_implicitcast:
  3920. case no_concat:
  3921. case no_eq: case no_ne: case no_gt: case no_ge: case no_lt: case no_le:
  3922. case no_case:
  3923. case no_map:
  3924. case no_externalcall:
  3925. case no_call:
  3926. break;
  3927. // default:
  3928. // return;
  3929. }
  3930. ITypeInfo * type = expr->queryType();
  3931. if (type && type->getTypeCode() == type_void)
  3932. return;
  3933. NewHqlTransformer::analyseExpr(expr);
  3934. }
  3935. void SplitDatasetAttributeTransformer::doAnalyseSelect(IHqlExpression * expr)
  3936. {
  3937. IHqlExpression * ds = expr->queryChild(0);
  3938. if (expr->hasProperty(newAtom))
  3939. {
  3940. if (!datasets.contains(*ds))
  3941. {
  3942. IHqlExpression * lhs = LINK(ds);
  3943. if (lhs->isDataset()) lhs = createRow(no_activerow, lhs);
  3944. datasets.append(*ds);
  3945. newDatasets.append(*createDatasetFromRow(lhs));
  3946. }
  3947. return;
  3948. }
  3949. //ds is a no_select, so will be handled correctly.
  3950. NewHqlTransformer::analyseExpr(expr);
  3951. }
  3952. IHqlExpression * SplitDatasetAttributeTransformer::createTransformed(IHqlExpression * expr)
  3953. {
  3954. switch (expr->getOperator())
  3955. {
  3956. case no_select:
  3957. if (expr->hasProperty(newAtom))
  3958. return doTransformSelect(expr);
  3959. break;
  3960. case no_colon:
  3961. case no_globalscope:
  3962. case no_nothor:
  3963. return LINK(expr);
  3964. }
  3965. return NewHqlTransformer::createTransformed(expr);
  3966. }
  3967. IHqlExpression * SplitDatasetAttributeTransformer::doTransformSelect(IHqlExpression * expr)
  3968. {
  3969. IHqlExpression * ds = expr->queryChild(0);
  3970. IHqlExpression * field = expr->queryChild(1);
  3971. unsigned match = datasets.find(*ds);
  3972. if (match == NotFound)
  3973. return NewHqlTransformer::createTransformed(expr);
  3974. return createSelectExpr(transform(&selectors.item(match)), LINK(field)); // note, remove new attributes
  3975. }
  3976. bool SplitDatasetAttributeTransformer::split(SharedHqlExpr & dataset, SharedHqlExpr & attribute, IHqlExpression * expr)
  3977. {
  3978. analyseExpr(expr);
  3979. //First remove trivial datasets...
  3980. {
  3981. unsigned num = datasets.ordinality();
  3982. for (unsigned i=0; i< num;)
  3983. {
  3984. IHqlExpression * cur = &datasets.item(i);
  3985. while ((cur->getOperator() == no_selectnth) || (cur->getOperator() == no_preservemeta))
  3986. cur = cur->queryChild(0);
  3987. bool remove = false;
  3988. switch (cur->getOperator())
  3989. {
  3990. case no_getgraphresult:
  3991. remove = !expr->hasProperty(_distributed_Atom);
  3992. break;
  3993. case no_workunit_dataset:
  3994. case no_getgraphloopresult:
  3995. case no_left:
  3996. case no_right:
  3997. case no_colon:
  3998. case no_globalscope:
  3999. case no_nothor:
  4000. remove = true;
  4001. break;
  4002. }
  4003. if (remove)
  4004. {
  4005. datasets.remove(i);
  4006. newDatasets.remove(i);
  4007. num--;
  4008. }
  4009. else
  4010. i++;
  4011. }
  4012. }
  4013. const unsigned maxDatasets = 1;
  4014. datasets.trunc(maxDatasets);
  4015. newDatasets.trunc(maxDatasets);
  4016. switch (datasets.ordinality())
  4017. {
  4018. case 0:
  4019. return false;
  4020. case 1:
  4021. selectors.append(*LINK(&newDatasets.item(0)));
  4022. break;
  4023. case 2:
  4024. selSeq.setown(createSelectorSequence());
  4025. selectors.append(*createSelector(no_left, &datasets.item(0), selSeq));
  4026. selectors.append(*createSelector(no_right, &datasets.item(1), selSeq));
  4027. break;
  4028. default:
  4029. {
  4030. selSeq.setown(createSelectorSequence());
  4031. rowsId.setown(createUniqueRowsId());
  4032. ForEachItemIn(i, newDatasets)
  4033. {
  4034. IHqlExpression & cur = newDatasets.item(i);
  4035. OwnedHqlExpr rows = createDataset(no_rows, LINK(&cur), LINK(rowsId));
  4036. selectors.append(*createRow(no_selectnth, LINK(rows), createComma(getSizetConstant(i+1), createAttribute(noBoundCheckAtom))));
  4037. }
  4038. break;
  4039. }
  4040. }
  4041. OwnedHqlExpr value = transform(expr);
  4042. switch (datasets.ordinality())
  4043. {
  4044. case 1:
  4045. dataset.set(&newDatasets.item(0));
  4046. attribute.set(value);
  4047. break;
  4048. case 2:
  4049. {
  4050. OwnedHqlExpr field = createField(unnamedId, value->getType(), NULL);
  4051. OwnedHqlExpr transform = createTransformForField(field, value);
  4052. OwnedHqlExpr combine = createDatasetF(no_combine, LINK(&newDatasets.item(0)), LINK(&newDatasets.item(1)), LINK(transform), LINK(selSeq), NULL);
  4053. OwnedHqlExpr first = createRowF(no_selectnth, LINK(combine), getSizetConstant(1), createAttribute(noBoundCheckAtom), NULL);
  4054. dataset.setown(createDatasetFromRow(first.getClear()));
  4055. attribute.setown(createSelectExpr(LINK(dataset->queryNormalizedSelector()), LINK(field)));
  4056. break;
  4057. }
  4058. default:
  4059. return false;
  4060. }
  4061. return true;
  4062. }
  4063. static bool splitDatasetAttribute(SharedHqlExpr & dataset, SharedHqlExpr & attribute, IHqlExpression * expr)
  4064. {
  4065. #if 0
  4066. //The following code works. However I think it has the side-effect of modifying expressions so that they are no longer
  4067. //csed with other expressions (similar to including too many items in the case statement below). So currently disabled.
  4068. SplitDatasetAttributeTransformer transformer;
  4069. return transformer.split(dataset, attribute, queryNonAliased(expr));
  4070. #else
  4071. IHqlExpression * left = expr->queryChild(0);
  4072. node_operator op = expr->getOperator();
  4073. switch (op)
  4074. {
  4075. case no_evaluate:
  4076. case no_field:
  4077. throwUnexpectedOp(op);
  4078. case no_constant:
  4079. return false;
  4080. case no_select:
  4081. break;
  4082. //Play it safe, by only containing a subset of the expressions here
  4083. //The list of expressions to include here seems to be a bit of a black art. For instance including and/or/not makes many queries worse.
  4084. case no_add:
  4085. case no_sub:
  4086. case no_mul:
  4087. case no_div:
  4088. case no_cast:
  4089. case no_implicitcast:
  4090. case no_concat:
  4091. case no_eq: case no_ne: case no_gt: case no_ge: case no_lt: case no_le:
  4092. case no_if:
  4093. case no_mapto:
  4094. case no_case:
  4095. case no_map:
  4096. case no_externalcall:
  4097. case no_call:
  4098. // case no_not:
  4099. // case no_and:
  4100. // case no_or:
  4101. // case no_substring:
  4102. // case no_charlen:
  4103. {
  4104. HqlExprArray args;
  4105. bool mapped = false;
  4106. ForEachChild(i, expr)
  4107. {
  4108. IHqlExpression * cur = expr->queryChild(i);
  4109. OwnedHqlExpr ds, attr;
  4110. if (splitDatasetAttribute(ds, attr, cur) && (!dataset || ds.get() == dataset.get()))
  4111. {
  4112. args.append(*attr.getClear());
  4113. dataset.set(ds);
  4114. mapped = true;
  4115. }
  4116. else
  4117. args.append(*LINK(cur));
  4118. }
  4119. if (!mapped)
  4120. return false;
  4121. attribute.setown(expr->clone(args));
  4122. return true;
  4123. }
  4124. default:
  4125. return false;
  4126. }
  4127. #ifdef _SR6_
  4128. if (isInlineTrivialDataset(left))
  4129. {
  4130. attribute.set(expr);
  4131. return true;
  4132. }
  4133. #endif
  4134. node_operator leftOp = left->getOperator();
  4135. if ((leftOp !=no_select) || expr->hasProperty(newAtom))
  4136. {
  4137. //Ensure selections from dictionaries do not have a separate activity for the row lookup.
  4138. if (leftOp == no_selectmap)
  4139. return false;
  4140. //If this is a selection from an inscope dataset then this must not be assumed to be an input dataset.
  4141. if (expr->isDataset() && !expr->hasProperty(newAtom))
  4142. return false;
  4143. IHqlExpression * lhs = LINK(left);
  4144. IHqlExpression * field = expr->queryChild(1);
  4145. if (lhs->isDataset()) lhs = createRow(no_activerow, lhs);
  4146. dataset.setown(createDatasetFromRow(lhs));
  4147. attribute.setown(createSelectExpr(LINK(dataset), LINK(field))); // remove new attributes
  4148. return true;
  4149. }
  4150. if (!splitDatasetAttribute(dataset, attribute, left))
  4151. return false;
  4152. HqlExprArray args;
  4153. args.append(*attribute.getClear());
  4154. unwindChildren(args, expr, 1);
  4155. attribute.setown(expr->clone(args));
  4156. return true;
  4157. #endif
  4158. }
  4159. bool splitResultValue(SharedHqlExpr & dataset, SharedHqlExpr & attribute, IHqlExpression * value)
  4160. {
  4161. if (value->isDataset())
  4162. return false;
  4163. if (splitDatasetAttribute(dataset, attribute, value))
  4164. return true;
  4165. if (value->isDatarow())
  4166. {
  4167. dataset.setown(createDatasetFromRow(LINK(value)));
  4168. attribute.setown(ensureActiveRow(dataset));
  4169. return true;
  4170. }
  4171. return false;
  4172. }
  4173. IHqlExpression * createSetResult(HqlExprArray & args)
  4174. {
  4175. HqlExprAttr dataset, attribute;
  4176. IHqlExpression * value = &args.item(0);
  4177. assertex(value->getOperator() != no_param);
  4178. if (splitResultValue(dataset, attribute, value))
  4179. {
  4180. args.replace(*dataset.getClear(), 0);
  4181. args.add(*attribute.getClear(), 1);
  4182. return createValue(no_extractresult, makeVoidType(), args);
  4183. }
  4184. if (value->isDataset() || value->isDictionary())
  4185. return createValue(no_output, makeVoidType(), args);
  4186. return createValue(no_setresult, makeVoidType(), args);
  4187. }
  4188. IHqlExpression * convertSetResultToExtract(IHqlExpression * setResult)
  4189. {
  4190. HqlExprAttr dataset, attribute;
  4191. if (splitResultValue(dataset, attribute, setResult->queryChild(0)))
  4192. {
  4193. HqlExprArray args;
  4194. args.append(*dataset.getClear());
  4195. args.append(*attribute.getClear());
  4196. unwindChildren(args, setResult, 1);
  4197. return createValue(no_extractresult, makeVoidType(), args);
  4198. }
  4199. return NULL;
  4200. }
  4201. IHqlExpression * removeDatasetWrapper(IHqlExpression * ds)
  4202. {
  4203. node_operator dsOp = ds->getOperator();
  4204. switch (dsOp)
  4205. {
  4206. case no_datasetfromrow:
  4207. return LINK(ds->queryChild(0));
  4208. case no_inlinetable:
  4209. {
  4210. IHqlExpression * values = ds->queryChild(0);
  4211. assertex(values->numChildren() == 1);
  4212. return createRow(no_createrow, LINK(values->queryChild(0)));
  4213. }
  4214. }
  4215. if (hasSingleRow(ds))
  4216. return createRow(no_selectnth, LINK(ds), createConstantOne());
  4217. throwUnexpectedOp(dsOp);
  4218. }
  4219. //-------------------------------------------------------------------------------------------------------
  4220. bool containsVirtualFields(IHqlExpression * record)
  4221. {
  4222. ForEachChild(i, record)
  4223. {
  4224. IHqlExpression * cur = record->queryChild(i);
  4225. switch (cur->getOperator())
  4226. {
  4227. case no_field:
  4228. if (cur->hasProperty(virtualAtom))
  4229. return true;
  4230. //does not walk into nested records
  4231. break;
  4232. case no_ifblock:
  4233. if (containsVirtualFields(cur->queryChild(1)))
  4234. return true;
  4235. break;
  4236. case no_record:
  4237. if (containsVirtualFields(cur))
  4238. return true;
  4239. break;
  4240. }
  4241. }
  4242. return false;
  4243. }
  4244. IHqlExpression * removeVirtualFields(IHqlExpression * record)
  4245. {
  4246. HqlExprArray args;
  4247. args.ensure(record->numChildren());
  4248. ForEachChild(i, record)
  4249. {
  4250. IHqlExpression * cur = record->queryChild(i);
  4251. switch (cur->getOperator())
  4252. {
  4253. case no_field:
  4254. if (!cur->hasProperty(virtualAtom))
  4255. args.append(*LINK(cur));
  4256. //does not walk into nested records
  4257. break;
  4258. case no_ifblock:
  4259. {
  4260. HqlExprArray ifargs;
  4261. ifargs.append(*LINK(cur->queryChild(0)));
  4262. ifargs.append(*removeVirtualFields(cur->queryChild(1)));
  4263. args.append(*cur->clone(ifargs));
  4264. break;
  4265. }
  4266. case no_record:
  4267. args.append(*removeVirtualFields(cur));
  4268. break;
  4269. default:
  4270. args.append(*LINK(cur));
  4271. break;
  4272. }
  4273. }
  4274. return record->clone(args);
  4275. }
  4276. static HqlTransformerInfo fieldPropertyRemoverInfo("FieldPropertyRemover");
  4277. class FieldPropertyRemover : public NewHqlTransformer
  4278. {
  4279. public:
  4280. FieldPropertyRemover(IAtom * _name) : NewHqlTransformer(fieldPropertyRemoverInfo), name(_name) {}
  4281. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  4282. {
  4283. switch (expr->getOperator())
  4284. {
  4285. //By default fields within the following are not transformed...
  4286. case no_record:
  4287. case no_ifblock:
  4288. case no_select: // Ensure fields used by ifblocks get transformed
  4289. return completeTransform(expr);
  4290. case no_field:
  4291. {
  4292. OwnedHqlExpr transformed = transformField(expr);
  4293. while (transformed->hasProperty(name))
  4294. transformed.setown(removeProperty(transformed, name));
  4295. return transformed.getClear();
  4296. }
  4297. default:
  4298. return NewHqlTransformer::createTransformed(expr);
  4299. }
  4300. }
  4301. private:
  4302. IAtom * name;
  4303. };
  4304. IHqlExpression * removePropertyFromFields(IHqlExpression * expr, IAtom * name)
  4305. {
  4306. FieldPropertyRemover remover(name);
  4307. return remover.transformRoot(expr);
  4308. }
  4309. #if 0
  4310. void VirtualReplacer::createProjectAssignments(HqlExprArray & assigns, IHqlExpression * expr, IHqlExpression * tgtSelector, IHqlExpression * srcSelector, IHqlExpression * dataset)
  4311. {
  4312. switch (expr->getOperator())
  4313. {
  4314. case no_record:
  4315. {
  4316. ForEachChild(i, expr)
  4317. createProjectAssignments(assigns, expr->queryChild(i), tgtSelector, srcSelector, dataset);
  4318. break;
  4319. }
  4320. case no_ifblock:
  4321. createProjectAssignments(assigns, expr->queryChild(1), tgtSelector, srcSelector, dataset);
  4322. break;
  4323. case no_field:
  4324. {
  4325. OwnedHqlExpr target = createSelectExpr(LINK(tgtSelector), LINK(expr));
  4326. IHqlExpression * newValue;
  4327. if (expr->hasProperty(virtualAtom))
  4328. newValue = getVirtualReplacement(expr, expr->queryProperty(virtualAtom)->queryChild(0), dataset);
  4329. else
  4330. newValue = createSelectExpr(LINK(srcSelector), LINK(expr));
  4331. assigns.append(*createAssign(target.getClear(), newValue));
  4332. break;
  4333. }
  4334. }
  4335. }
  4336. #endif
  4337. void unwindTransform(HqlExprCopyArray & exprs, IHqlExpression * transform)
  4338. {
  4339. ForEachChild(i, transform)
  4340. {
  4341. IHqlExpression * cur = transform->queryChild(i);
  4342. switch (cur->getOperator())
  4343. {
  4344. case no_assignall:
  4345. unwindTransform(exprs, cur);
  4346. break;
  4347. default:
  4348. exprs.append(*cur);
  4349. break;
  4350. }
  4351. }
  4352. }
  4353. bool isConstantTransform(IHqlExpression * transform)
  4354. {
  4355. ForEachChild(i, transform)
  4356. {
  4357. IHqlExpression * cur = transform->queryChild(i);
  4358. switch (cur->getOperator())
  4359. {
  4360. case no_assignall:
  4361. if (!isConstantTransform(cur))
  4362. return false;
  4363. break;
  4364. case no_assign:
  4365. {
  4366. IHqlExpression * rhs = cur->queryChild(1);
  4367. if (!rhs->isConstant())
  4368. {
  4369. switch (rhs->getOperator())
  4370. {
  4371. case no_null:
  4372. case no_all:
  4373. break;
  4374. default:
  4375. return false;
  4376. }
  4377. }
  4378. break;
  4379. }
  4380. case no_attr:
  4381. case no_attr_expr:
  4382. break;
  4383. default:
  4384. return false;
  4385. }
  4386. }
  4387. return true;
  4388. }
  4389. //would be sensible to extend this to some simple expressions
  4390. static bool isSimpleValue(IHqlExpression * expr)
  4391. {
  4392. loop
  4393. {
  4394. if (expr->isConstant())
  4395. return true;
  4396. node_operator op = expr->getOperator();
  4397. switch (op)
  4398. {
  4399. case no_null:
  4400. case no_all:
  4401. return true;
  4402. case no_select:
  4403. return !isNewSelector(expr);
  4404. case no_cast:
  4405. case no_implicitcast:
  4406. break;
  4407. default:
  4408. //Do not include access to stored variables
  4409. return false;
  4410. }
  4411. expr = expr->queryChild(0);
  4412. }
  4413. }
  4414. IHqlExpression * queryUncastExpr(IHqlExpression * expr)
  4415. {
  4416. loop
  4417. {
  4418. if (!isCast(expr))
  4419. return expr;
  4420. expr = expr->queryChild(0);
  4421. }
  4422. }
  4423. bool isSimpleTransformToMergeWith(IHqlExpression * expr, int & varSizeCount)
  4424. {
  4425. ForEachChild(i, expr)
  4426. {
  4427. IHqlExpression * cur = expr->queryChild(i);
  4428. switch (cur->getOperator())
  4429. {
  4430. case no_assignall:
  4431. {
  4432. if (!isSimpleTransformToMergeWith(cur, varSizeCount))
  4433. return false;
  4434. break;
  4435. }
  4436. case no_assign:
  4437. {
  4438. IHqlExpression * rhs = cur->queryChild(1);
  4439. if (!isSimpleValue(rhs))
  4440. return false;
  4441. //Want to take note of whether it reduces the number of variable size fields, if it makes many variable sized into fixed size then it won't be good to remove
  4442. ITypeInfo * srcType = queryUncastExpr(rhs)->queryType();
  4443. ITypeInfo * tgtType = cur->queryChild(0)->queryType();
  4444. if (tgtType->getSize() == UNKNOWN_LENGTH)
  4445. varSizeCount--;
  4446. if (srcType->getSize() == UNKNOWN_LENGTH)
  4447. varSizeCount++;
  4448. break;
  4449. }
  4450. case no_attr:
  4451. case no_attr_link:
  4452. case no_attr_expr:
  4453. break;
  4454. default:
  4455. return false;
  4456. }
  4457. }
  4458. return true;
  4459. }
  4460. bool isSimpleTransformToMergeWith(IHqlExpression * expr)
  4461. {
  4462. int varSizeCount = 0;
  4463. return isSimpleTransformToMergeWith(expr, varSizeCount) && varSizeCount < 3;
  4464. }
  4465. bool isConstantDataset(IHqlExpression * expr)
  4466. {
  4467. assertex(expr->getOperator() == no_inlinetable);
  4468. IHqlExpression * values = expr->queryChild(0);
  4469. ForEachChild(i, values)
  4470. {
  4471. if (!isConstantTransform(values->queryChild(i)))
  4472. return false;
  4473. }
  4474. return true;
  4475. }
  4476. bool isConstantDictionary(IHqlExpression * expr)
  4477. {
  4478. if (expr->getOperator() == no_null)
  4479. return true;
  4480. if (expr->getOperator() != no_createdictionary)
  4481. return false;
  4482. IHqlExpression * dataset = expr->queryChild(0);
  4483. if (dataset->getOperator() == no_inlinetable)
  4484. return isConstantDataset(dataset);
  4485. return false;
  4486. }
  4487. inline bool iseol(char c) { return c == '\r' || c == '\n'; }
  4488. static unsigned skipSpace(unsigned start, unsigned len, const char * buffer)
  4489. {
  4490. while (start < len && isspace((byte)buffer[start]))
  4491. start++;
  4492. return start;
  4493. }
  4494. static unsigned trimSpace(unsigned len, const char * buffer)
  4495. {
  4496. while (len && isspace((byte)buffer[len-1]))
  4497. len--;
  4498. return len;
  4499. }
  4500. static void stripQuotes(unsigned & start, unsigned & end, const char * buffer)
  4501. {
  4502. if (end - start >= 2)
  4503. {
  4504. if (buffer[start] == '\'' && buffer[end-1] == '\'')
  4505. {
  4506. start++;
  4507. end--;
  4508. }
  4509. }
  4510. }
  4511. static bool matchOption(unsigned & cur, unsigned max, const char * buffer, unsigned lenMatch, const char * match)
  4512. {
  4513. if (cur + lenMatch > max)
  4514. return false;
  4515. if (memicmp(buffer+cur, match, lenMatch) != 0)
  4516. return false;
  4517. if (cur + lenMatch < max)
  4518. {
  4519. if (isalnum(buffer[cur+lenMatch]))
  4520. return false;
  4521. }
  4522. cur = skipSpace(cur+lenMatch, max, buffer);
  4523. return true;
  4524. }
  4525. IHqlExpression * extractCppBodyAttrs(unsigned lenBuffer, const char * buffer)
  4526. {
  4527. OwnedHqlExpr attrs;
  4528. unsigned prev = '\n';
  4529. for (unsigned i=0; i < lenBuffer; i++)
  4530. {
  4531. char next = buffer[i];
  4532. switch (next)
  4533. {
  4534. case ' ': case '\t':
  4535. // allow whitespace in front of #option
  4536. break;
  4537. case '#':
  4538. if (prev == '\n')
  4539. {
  4540. if ((i + 1 + 6 < lenBuffer) && memicmp(buffer+i+1, "option", 6) == 0)
  4541. {
  4542. unsigned start = skipSpace(i+1+6, lenBuffer, buffer);
  4543. unsigned end = start;
  4544. while (end < lenBuffer && !iseol((byte)buffer[end]))
  4545. end++;
  4546. end = trimSpace(end, buffer);
  4547. if (matchOption(start, lenBuffer, buffer, 4, "pure"))
  4548. attrs.setown(createComma(attrs.getClear(), createAttribute(pureAtom)));
  4549. else if (matchOption(start, lenBuffer, buffer, 4, "once"))
  4550. attrs.setown(createComma(attrs.getClear(), createAttribute(onceAtom)));
  4551. else if (matchOption(start, lenBuffer, buffer, 6, "action"))
  4552. attrs.setown(createComma(attrs.getClear(), createAttribute(actionAtom)));
  4553. else if (matchOption(start, lenBuffer, buffer, 7, "library"))
  4554. {
  4555. stripQuotes(start, end, buffer);
  4556. Owned<IValue> restOfLine = createUtf8Value(end-start, buffer+start, makeUtf8Type(UNKNOWN_LENGTH, NULL));
  4557. OwnedHqlExpr arg = createConstant(restOfLine.getClear());
  4558. attrs.setown(createComma(attrs.getClear(), createAttribute(libraryAtom, arg.getClear())));
  4559. }
  4560. else if (matchOption(start, lenBuffer, buffer, 4, "link"))
  4561. {
  4562. Owned<IValue> restOfLine = createUtf8Value(end-start, buffer+start, makeUtf8Type(UNKNOWN_LENGTH, NULL));
  4563. OwnedHqlExpr arg = createConstant(restOfLine.getClear());
  4564. attrs.setown(createComma(attrs.getClear(), createAttribute(linkAtom, arg.getClear())));
  4565. }
  4566. }
  4567. }
  4568. //fallthrough
  4569. default:
  4570. prev = next;
  4571. break;
  4572. }
  4573. }
  4574. return attrs.getClear();
  4575. }
  4576. unsigned cleanupEmbeddedCpp(unsigned len, char * buffer)
  4577. {
  4578. unsigned delta = 0;
  4579. unsigned prev = '\n';
  4580. for (unsigned i=0; i < len; i++)
  4581. {
  4582. char next = buffer[i];
  4583. unsigned skip = 0;
  4584. switch (next)
  4585. {
  4586. case '\r':
  4587. skip = 1;
  4588. prev = next;
  4589. break;
  4590. case ' ': case '\t':
  4591. break;
  4592. case '#':
  4593. if (prev == '\n')
  4594. {
  4595. if ((i + 1 + 6 < len) && memicmp(buffer+i+1, "option", 6) == 0)
  4596. {
  4597. //skip to newline after #option
  4598. unsigned end = i + 1 + 6;
  4599. while (end < len && !iseol(buffer[end]))
  4600. end++;
  4601. skip = end - i;
  4602. }
  4603. }
  4604. //fallthrough
  4605. default:
  4606. prev = next;
  4607. break;
  4608. }
  4609. if (skip != 0)
  4610. {
  4611. delta += skip;
  4612. i += (skip - 1);
  4613. }
  4614. else if (delta)
  4615. buffer[i-delta] = next;
  4616. }
  4617. return len-delta;
  4618. }
  4619. bool isNullList(IHqlExpression * expr)
  4620. {
  4621. switch (expr->getOperator())
  4622. {
  4623. case no_null:
  4624. return true;
  4625. case no_list:
  4626. case no_datasetlist:
  4627. case no_sortlist:
  4628. return expr->numChildren() == 0;
  4629. }
  4630. return false;
  4631. }
  4632. //--------------------------------------------------------------------------------------
  4633. class TempTableTransformer
  4634. {
  4635. public:
  4636. TempTableTransformer(IErrorReceiver * _errors, ECLlocation & _location, bool _strictTypeChecking = false)
  4637. : errors(_errors), defaultLocation(_location), strictTypeChecking(_strictTypeChecking)
  4638. {}
  4639. IHqlExpression * createTempTableTransform(IHqlExpression * curRow, IHqlExpression * record);
  4640. protected:
  4641. void createTempTableAssign(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * curRow, IHqlExpression * expr, unsigned & col, IHqlExpression * selector, HqlMapTransformer & mapper, bool included);
  4642. IHqlExpression * createTempTableTransform(IHqlExpression * self, IHqlExpression * curRow, IHqlExpression * expr, unsigned & col, IHqlExpression * selector, HqlMapTransformer & mapper, bool included);
  4643. void reportWarning(IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 4, 5)));
  4644. void reportError(IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 4, 5)));
  4645. protected:
  4646. IErrorReceiver * errors;
  4647. ECLlocation & defaultLocation;
  4648. bool strictTypeChecking;
  4649. };
  4650. IHqlExpression * TempTableTransformer::createTempTableTransform(IHqlExpression * self, IHqlExpression * curRow, IHqlExpression * expr, unsigned & col, IHqlExpression * selector, HqlMapTransformer & mapper, bool included)
  4651. {
  4652. HqlExprArray assigns;
  4653. createTempTableAssign(assigns, self, curRow, expr, col, selector, mapper, included);
  4654. return createValue(no_transform, makeTransformType(createRecordType(expr)), assigns);
  4655. }
  4656. IHqlExpression * TempTableTransformer::createTempTableTransform(IHqlExpression * curRow, IHqlExpression * record)
  4657. {
  4658. OwnedHqlExpr self = getSelf(record);
  4659. HqlMapTransformer mapping;
  4660. unsigned col = 0;
  4661. IHqlExpression * rowPayloadAttr = curRow->queryProperty(_payload_Atom);
  4662. IHqlExpression * recordPayloadAttr = record->queryProperty(_payload_Atom);
  4663. if (rowPayloadAttr)
  4664. {
  4665. unsigned rowPayload = (unsigned) getIntValue(rowPayloadAttr->queryChild(0));
  4666. col++;
  4667. if (recordPayloadAttr)
  4668. {
  4669. unsigned recordPayload = (unsigned) getIntValue(recordPayloadAttr->queryChild(0));
  4670. if (rowPayload != recordPayload)
  4671. ERRORAT(curRow->queryProperty(_location_Atom), HQLERR_PayloadMismatch);
  4672. }
  4673. else
  4674. ERRORAT(curRow->queryProperty(_location_Atom), HQLERR_PayloadMismatch);
  4675. }
  4676. else if (recordPayloadAttr)
  4677. ERRORAT(curRow->queryProperty(_location_Atom), HQLERR_PayloadMismatch);
  4678. OwnedHqlExpr ret = createTempTableTransform(self, curRow, record, col, self, mapping, true);
  4679. if (queryRealChild(curRow, col))
  4680. {
  4681. StringBuffer s;
  4682. getExprECL(curRow->queryChild(col), s);
  4683. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_TooManyInitializers, s.str());
  4684. }
  4685. return ret.getClear();
  4686. }
  4687. //NB: Skating on thin ice - can't call transform() inside here because the mapper has the transform mutex.
  4688. //So don't make it a member function...
  4689. void TempTableTransformer::createTempTableAssign(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * curRow, IHqlExpression * expr, unsigned & col, IHqlExpression * selector, HqlMapTransformer & mapper, bool included)
  4690. {
  4691. switch (expr->getOperator())
  4692. {
  4693. case no_field:
  4694. {
  4695. OwnedHqlExpr target = createSelectExpr(LINK(selector), LINK(expr));
  4696. OwnedHqlExpr castValue;
  4697. IHqlExpression * record = expr->queryRecord();
  4698. if (record)
  4699. {
  4700. if (included)
  4701. {
  4702. LinkedHqlExpr src = queryRealChild(curRow, col);
  4703. if (expr->isDataset() || expr->isDictionary())
  4704. {
  4705. if (src)
  4706. col++;
  4707. else
  4708. {
  4709. src.set(expr->queryChild(0));
  4710. if (!src || src->isAttribute())
  4711. {
  4712. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_NoDefaultProvided, expr->queryName()->str());
  4713. return;
  4714. }
  4715. }
  4716. src.setown(replaceSelfRefSelector(src, self));
  4717. if (src->getOperator() == no_list)
  4718. {
  4719. HqlExprArray children;
  4720. children.append(*LINK(src));
  4721. children.append(*LINK(record));
  4722. OwnedHqlExpr tempTable = createValue(no_temptable, children);
  4723. // castValue.setown(transform(tempTable));
  4724. castValue.set(tempTable);
  4725. }
  4726. else if (src->getOperator() == no_recordlist)
  4727. {
  4728. HqlExprArray transforms;
  4729. ForEachChild(idx, src)
  4730. transforms.append(*createTempTableTransform(src->queryChild(idx), record));
  4731. HqlExprArray children;
  4732. children.append(*createValue(no_transformlist, transforms));
  4733. children.append(*LINK(record));
  4734. castValue.setown(createDataset(no_inlinetable, children));
  4735. }
  4736. else if (src->isDataset())
  4737. {
  4738. if (!recordTypesMatch(src, target))
  4739. {
  4740. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_IncompatibleTypesForField, expr->queryName()->str());
  4741. return;
  4742. }
  4743. if (isGrouped(src))
  4744. castValue.setown(createDataset(no_group, LINK(src)));
  4745. else
  4746. castValue.set(src);
  4747. }
  4748. else
  4749. {
  4750. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_IncompatibleTypesForField, expr->queryName()->str());
  4751. return;
  4752. }
  4753. }
  4754. else
  4755. {
  4756. if (src && src->isDatarow())
  4757. {
  4758. if (!recordTypesMatch(src, target))
  4759. {
  4760. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_IncompatibleTypesForField, expr->queryName()->str());
  4761. return;
  4762. }
  4763. castValue.set(src);
  4764. col++;
  4765. }
  4766. else
  4767. {
  4768. //structured initialisers for nested records...
  4769. OwnedHqlExpr transform;
  4770. if (src && src->getOperator() == no_rowvalue)
  4771. {
  4772. col++;
  4773. transform.setown(createTempTableTransform(src, record));
  4774. }
  4775. else
  4776. {
  4777. OwnedHqlExpr localSelf = getSelf(record);
  4778. HqlMapTransformer localMapping;
  4779. transform.setown(createTempTableTransform(self, curRow, record, col, localSelf, localMapping, true));
  4780. }
  4781. castValue.setown(createRow(no_createrow, LINK(transform)));
  4782. }
  4783. }
  4784. if (target->isDictionary() && !castValue->isDictionary())
  4785. castValue.setown(createDictionary(no_createdictionary, castValue.getClear()));
  4786. }
  4787. else
  4788. {
  4789. if (expr->isDictionary())
  4790. castValue.setown(createDictionary(no_null, LINK(record)));
  4791. else if (expr->isDataset())
  4792. castValue.setown(createDataset(no_null, LINK(record)));
  4793. else
  4794. castValue.setown(createRow(no_null, LINK(record)));
  4795. }
  4796. }
  4797. else
  4798. {
  4799. ITypeInfo * type = expr->queryType()->queryPromotedType();
  4800. if (included)
  4801. {
  4802. LinkedHqlExpr src = queryRealChild(curRow, col++);
  4803. if (!src)
  4804. {
  4805. IHqlExpression * defaultValue = expr->queryChild(0);
  4806. src.setown(replaceSelfRefSelector(defaultValue, self));
  4807. if (src)
  4808. src.setown(mapper.transformRoot(src));
  4809. }
  4810. if (!src || src->isAttribute())
  4811. {
  4812. if (expr->hasProperty(virtualAtom))
  4813. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_VirtualFieldInTempTable, expr->queryName()->str());
  4814. else
  4815. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_NoDefaultProvided, expr->queryName()->str());
  4816. return;
  4817. }
  4818. if (src->getOperator() == no_recordlist)
  4819. {
  4820. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_IncompatiableInitailiser, expr->queryName()->str());
  4821. return;
  4822. }
  4823. else if (type->isScalar() != src->queryType()->isScalar())
  4824. {
  4825. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_IncompatibleTypesForField, expr->queryName()->str());
  4826. return;
  4827. }
  4828. else if (strictTypeChecking && !type->assignableFrom(src->queryType()))
  4829. {
  4830. ERRORAT1(curRow->queryProperty(_location_Atom), HQLERR_IncompatibleTypesForField, expr->queryName()->str());
  4831. }
  4832. castValue.setown(ensureExprType(src, type));
  4833. }
  4834. else
  4835. castValue.setown(createNullExpr(expr));
  4836. }
  4837. assigns.append(*createAssign(LINK(target), LINK(castValue)));
  4838. mapper.setMapping(target, castValue);
  4839. break;
  4840. }
  4841. case no_ifblock:
  4842. {
  4843. OwnedHqlExpr cond = replaceSelfRefSelector(expr->queryChild(0), selector);
  4844. OwnedHqlExpr mapped = mapper.transformRoot(cond);
  4845. mapped.setown(foldHqlExpression(mapped, NULL, HFOfoldimpure|HFOforcefold));
  4846. IValue * mappedValue = mapped->queryValue();
  4847. if (included)
  4848. {
  4849. if (!mappedValue)
  4850. reportWarning(NULL, HQLWRN_CouldNotConstantFoldIf, HQLWRN_CouldNotConstantFoldIf_Text);
  4851. else if (!mappedValue->getBoolValue())
  4852. included = false;
  4853. }
  4854. createTempTableAssign(assigns, self, curRow, expr->queryChild(1), col, selector, mapper, included);
  4855. break;
  4856. }
  4857. case no_record:
  4858. {
  4859. ForEachChild(idx, expr)
  4860. createTempTableAssign(assigns, self, curRow, expr->queryChild(idx), col, selector, mapper, included);
  4861. break;
  4862. }
  4863. case no_attr:
  4864. case no_attr_expr:
  4865. case no_attr_link:
  4866. break;
  4867. }
  4868. }
  4869. void TempTableTransformer::reportError(IHqlExpression * location, int code,const char *format, ...)
  4870. {
  4871. if (!errors) return;
  4872. ECLlocation * where = &defaultLocation;
  4873. ECLlocation thisLocation;
  4874. if (location)
  4875. {
  4876. thisLocation.extractLocationAttr(location);
  4877. where = &thisLocation;
  4878. }
  4879. StringBuffer errorMsg;
  4880. va_list args;
  4881. va_start(args, format);
  4882. errorMsg.valist_appendf(format, args);
  4883. va_end(args);
  4884. errors->reportError(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
  4885. }
  4886. void TempTableTransformer::reportWarning(IHqlExpression * location, int code,const char *format, ...)
  4887. {
  4888. if (!errors) return;
  4889. ECLlocation * where = &defaultLocation;
  4890. ECLlocation thisLocation;
  4891. if (location)
  4892. {
  4893. thisLocation.extractLocationAttr(location);
  4894. where = &thisLocation;
  4895. }
  4896. StringBuffer errorMsg;
  4897. va_list args;
  4898. va_start(args, format);
  4899. errorMsg.valist_appendf(format, args);
  4900. va_end(args);
  4901. errors->reportWarning(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
  4902. }
  4903. IHqlExpression *getDictionaryKeyRecord(IHqlExpression *record)
  4904. {
  4905. IHqlExpression * payload = record->queryProperty(_payload_Atom);
  4906. unsigned payloadSize = payload ? getIntValue(payload->queryChild(0)) : 0;
  4907. unsigned max = record->numChildren() - payloadSize;
  4908. IHqlExpression *newrec = createRecord();
  4909. for (unsigned idx = 0; idx < max; idx++)
  4910. {
  4911. IHqlExpression *child = record->queryChild(idx);
  4912. if (!child->isAttribute() || child->queryName()!=_payload_Atom) // Strip off the payload attribute
  4913. newrec->addOperand(LINK(child));
  4914. }
  4915. return newrec->closeExpr();
  4916. }
  4917. IHqlExpression *recursiveStretchFields(IHqlExpression *record)
  4918. {
  4919. IHqlExpression *newrec = createRecord();
  4920. ForEachChild (idx, record)
  4921. {
  4922. IHqlExpression *child = record->queryChild(idx);
  4923. if (child->getOperator()==no_field)
  4924. {
  4925. ITypeInfo *fieldType = child->queryType();
  4926. switch (fieldType->getTypeCode())
  4927. {
  4928. case type_row:
  4929. {
  4930. OwnedHqlExpr childType = recursiveStretchFields(child->queryRecord());
  4931. newrec->addOperand(createField(child->queryId(), makeRowType(childType->getType()), NULL, NULL));
  4932. break;
  4933. }
  4934. default:
  4935. {
  4936. Owned<ITypeInfo> stretched = getMaxLengthType(fieldType);
  4937. newrec->addOperand(createField(child->queryId(), stretched.getClear(), NULL, NULL));
  4938. break;
  4939. }
  4940. }
  4941. }
  4942. else
  4943. newrec->addOperand(LINK(child));
  4944. }
  4945. return newrec->closeExpr();
  4946. }
  4947. IHqlExpression *getDictionarySearchRecord(IHqlExpression *record)
  4948. {
  4949. OwnedHqlExpr keyrec = getDictionaryKeyRecord(record);
  4950. return recursiveStretchFields(keyrec);
  4951. }
  4952. IHqlExpression * createSelectMapRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * dict, IHqlExpression *values)
  4953. {
  4954. OwnedHqlExpr record = getDictionarySearchRecord(dict->queryRecord());
  4955. TempTableTransformer transformer(errors, location, true);
  4956. OwnedHqlExpr newTransform = transformer.createTempTableTransform(values, record);
  4957. return createRow(no_selectmap, LINK(dict), createRow(no_createrow, newTransform.getClear()));
  4958. }
  4959. IHqlExpression *createINDictExpr(IErrorReceiver * errors, ECLlocation & location, IHqlExpression *expr, IHqlExpression *dict)
  4960. {
  4961. OwnedHqlExpr record = getDictionarySearchRecord(dict->queryRecord());
  4962. TempTableTransformer transformer(errors, location, true);
  4963. OwnedHqlExpr newTransform = transformer.createTempTableTransform(expr, record);
  4964. return createBoolExpr(no_indict, createRow(no_createrow, newTransform.getClear()), LINK(dict));
  4965. }
  4966. IHqlExpression *createINDictRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression *row, IHqlExpression *dict)
  4967. {
  4968. OwnedHqlExpr record = getDictionarySearchRecord(dict->queryRecord());
  4969. Owned<ITypeInfo> rowType = makeRowType(record->getType());
  4970. OwnedHqlExpr castRow = ensureExprType(row, rowType);
  4971. return createBoolExpr(no_indict, castRow.getClear(), LINK(dict));
  4972. }
  4973. IHqlExpression * convertTempRowToCreateRow(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * expr)
  4974. {
  4975. IHqlExpression * oldValues = expr->queryChild(0);
  4976. IHqlExpression * record = expr->queryChild(1);
  4977. OwnedHqlExpr values = normalizeListCasts(oldValues); // ??? not used
  4978. TempTableTransformer transformer(errors, location);
  4979. OwnedHqlExpr newTransform = transformer.createTempTableTransform(oldValues, record);
  4980. HqlExprArray children;
  4981. children.append(*LINK(newTransform));
  4982. OwnedHqlExpr ret = createRow(no_createrow, children);
  4983. return expr->cloneAllAnnotations(ret);
  4984. }
  4985. static IHqlExpression * convertTempTableToInline(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * expr)
  4986. {
  4987. IHqlExpression * oldValues = expr->queryChild(0);
  4988. IHqlExpression * record = expr->queryChild(1);
  4989. OwnedHqlExpr values = normalizeListCasts(oldValues);
  4990. node_operator valueOp = values->getOperator();
  4991. if ((valueOp == no_list) && (values->numChildren() == 0))
  4992. return createDataset(no_null, LINK(record));
  4993. if ((valueOp != no_recordlist) && (valueOp != no_list))
  4994. return LINK(expr);
  4995. TempTableTransformer transformer(errors, location);
  4996. HqlExprArray transforms;
  4997. ForEachChild(idx, values)
  4998. {
  4999. LinkedHqlExpr cur = values->queryChild(idx);
  5000. if (valueOp == no_list)
  5001. cur.setown(createValue(no_rowvalue, makeNullType(), LINK(cur)));
  5002. if (cur->getOperator() == no_record)
  5003. {
  5004. HqlExprArray row;
  5005. ForEachChild(idx, cur)
  5006. {
  5007. IHqlExpression * field = cur->queryChild(idx);
  5008. if (field->getOperator() == no_field)
  5009. row.append(*LINK(field->queryChild(0)));
  5010. }
  5011. cur.setown(createValue(no_rowvalue, makeNullType(), row));
  5012. }
  5013. transforms.append(*transformer.createTempTableTransform(cur, record));
  5014. }
  5015. HqlExprArray children;
  5016. children.append(*createValue(no_transformlist, makeNullType(), transforms));
  5017. children.append(*LINK(record));
  5018. OwnedHqlExpr ret = createDataset(no_inlinetable, children);
  5019. return expr->cloneAllAnnotations(ret);
  5020. }
  5021. IHqlExpression * convertTempTableToInlineTable(IErrorReceiver * errors, ECLlocation & location, IHqlExpression * expr)
  5022. {
  5023. return convertTempTableToInline(errors, location, expr);
  5024. }
  5025. void setPayloadAttribute(HqlExprArray &args)
  5026. {
  5027. // Locate a payload attribute in an initializer value list. If found, move it to front and give it a position
  5028. int payloadPos = -1;
  5029. ForEachItemIn(idx, args)
  5030. {
  5031. IHqlExpression *cur = &args.item(idx);
  5032. if (cur->isAttribute())
  5033. {
  5034. assertex(payloadPos==-1);
  5035. assertex(cur->queryName()==_payload_Atom);
  5036. payloadPos = idx;
  5037. }
  5038. }
  5039. if (payloadPos != -1)
  5040. {
  5041. args.remove(payloadPos);
  5042. args.add(*createAttribute(_payload_Atom, createConstant((__int64) args.length()-payloadPos)), 0);
  5043. }
  5044. }
  5045. bool areTypesComparable(ITypeInfo * leftType, ITypeInfo * rightType)
  5046. {
  5047. if (leftType == rightType)
  5048. return true;
  5049. if (!leftType || !rightType)
  5050. return false;
  5051. type_t ltc = leftType->getTypeCode();
  5052. type_t rtc = rightType->getTypeCode();
  5053. if (ltc != rtc)
  5054. return false;
  5055. switch (ltc)
  5056. {
  5057. case type_unicode:
  5058. case type_varunicode:
  5059. case type_utf8:
  5060. return haveCommonLocale(leftType, rightType);
  5061. case type_data:
  5062. case type_decimal:
  5063. return true;
  5064. case type_qstring:
  5065. case type_varstring:
  5066. case type_string:
  5067. return (leftType->queryCharset() == rightType->queryCharset()) &&
  5068. (leftType->queryCollation() == rightType->queryCollation());
  5069. case type_set:
  5070. case type_array:
  5071. return areTypesComparable(leftType->queryChildType(), rightType->queryChildType());
  5072. case type_row:
  5073. case type_dictionary:
  5074. case type_table:
  5075. case type_groupedtable:
  5076. return recordTypesMatch(leftType, rightType);
  5077. }
  5078. return false;
  5079. }
  5080. bool arraysMatch(const HqlExprArray & left, const HqlExprArray & right)
  5081. {
  5082. unsigned numLeft = left.ordinality();
  5083. unsigned numRight = right.ordinality();
  5084. if (numLeft != numRight)
  5085. return false;
  5086. for (unsigned i=0; i < numLeft; i++)
  5087. {
  5088. if (&left.item(i) != &right.item(i))
  5089. return false;
  5090. }
  5091. return true;
  5092. }
  5093. bool isBlankString(IHqlExpression * expr)
  5094. {
  5095. if (expr->getOperator() != no_constant)
  5096. return false;
  5097. IValue * value = expr->queryValue();
  5098. if (value->getTypeCode() != type_string)
  5099. return false;
  5100. unsigned size = value->getSize();
  5101. return rtlCompareStrBlank(size, (const char *)value->queryValue()) == 0;
  5102. }
  5103. bool isNullString(IHqlExpression * expr)
  5104. {
  5105. ITypeInfo * exprType = expr->queryType();
  5106. switch (exprType->getTypeCode())
  5107. {
  5108. case type_data:
  5109. case type_string:
  5110. case type_qstring:
  5111. return exprType->getSize() == 0;
  5112. }
  5113. return false;
  5114. }
  5115. const char * queryChildNodeTraceText(StringBuffer & s, IHqlExpression * expr)
  5116. {
  5117. s.clear().append(getOpString(expr->getOperator()));
  5118. if (expr->queryName())
  5119. s.append("[").append(expr->queryName()).append("]");
  5120. // s.appendf(" {%lx}", (unsigned)expr);
  5121. return s.str();
  5122. }
  5123. extern HQL_API bool areConstant(const HqlExprArray & args)
  5124. {
  5125. ForEachItemIn(i, args)
  5126. {
  5127. if (!args.item(i).isConstant())
  5128. return false;
  5129. }
  5130. return true;
  5131. }
  5132. bool getFoldedConstantText(StringBuffer& ret, IHqlExpression * expr)
  5133. {
  5134. OwnedHqlExpr folded = foldExprIfConstant(expr);
  5135. IValue * value = folded->queryValue();
  5136. if (!value)
  5137. return false;
  5138. value->getStringValue(ret);
  5139. return true;
  5140. }
  5141. //===========================================================================
  5142. void appendArray(HqlExprCopyArray & tgt, const HqlExprCopyArray & src)
  5143. {
  5144. ForEachItemIn(idx, src)
  5145. tgt.append(src.item(idx));
  5146. }
  5147. void appendArray(HqlExprCopyArray & tgt, const HqlExprArray & src)
  5148. {
  5149. ForEachItemIn(idx, src)
  5150. tgt.append(src.item(idx));
  5151. }
  5152. void replaceArray(HqlExprArray & tgt, const HqlExprArray & src)
  5153. {
  5154. tgt.kill();
  5155. appendArray(tgt, src);
  5156. }
  5157. //--------------------------------------------------------------
  5158. static void gatherSortOrder(HqlExprArray & sorts, IHqlExpression * ds, IHqlExpression * record, unsigned maxfield = NotFound)
  5159. {
  5160. unsigned max = record->numChildren();
  5161. if (max > maxfield) max = maxfield;
  5162. for (unsigned idx=0; idx < max; idx++)
  5163. {
  5164. IHqlExpression * cur = record->queryChild(idx);
  5165. switch (cur->getOperator())
  5166. {
  5167. case no_record:
  5168. gatherSortOrder(sorts, ds, cur);
  5169. break;
  5170. case no_ifblock:
  5171. gatherSortOrder(sorts, ds, cur->queryChild(1));
  5172. break;
  5173. case no_field:
  5174. sorts.append(*createSelectExpr(LINK(ds), LINK(cur)));
  5175. break;
  5176. }
  5177. }
  5178. }
  5179. void gatherIndexBuildSortOrder(HqlExprArray & sorts, IHqlExpression * expr, bool sortIndexPayload)
  5180. {
  5181. // If any field types collate differently before and after translation to their hozed
  5182. // format, then we need to do the translation here, otherwise this
  5183. // sort may not be in the correct order. (ebcdic->ascii? integers are ok; unicode isn't!)
  5184. // First build the sort order we need....
  5185. LinkedHqlExpr dataset = expr->queryChild(0);
  5186. IHqlExpression * normalizedDs = dataset->queryNormalizedSelector();
  5187. IHqlExpression * buildRecord = dataset->queryRecord();
  5188. unsigned payloadCount = numPayloadFields(expr);
  5189. //Option to not sort by fields that aren't part of the sorted key.
  5190. unsigned indexFirstPayload = firstPayloadField(buildRecord, payloadCount);
  5191. unsigned max;
  5192. bool sortPayload = sortIndexPayload ? !expr->hasProperty(sort_KeyedAtom) : expr->hasProperty(sort_AllAtom);
  5193. if (sortPayload)
  5194. {
  5195. max = buildRecord->numChildren();
  5196. //If the last field is an implicit fpos, then they will all have the same value, so no point sorting.
  5197. if (queryLastField(buildRecord)->hasProperty(_implicitFpos_Atom))
  5198. max--;
  5199. }
  5200. else
  5201. max = indexFirstPayload;
  5202. gatherSortOrder(sorts, normalizedDs, buildRecord, max);
  5203. ForEachItemIn(i0, sorts)
  5204. {
  5205. IHqlExpression & cur = sorts.item(i0);
  5206. if (cur.isDataset())
  5207. {
  5208. sorts.replace(*createValue(no_typetransfer, makeDataType(UNKNOWN_LENGTH), LINK(&cur)), i0);
  5209. }
  5210. else if ((i0 < indexFirstPayload) && isUnicodeType(cur.queryType()))
  5211. {
  5212. sorts.replace(*createValue(no_typetransfer, makeDataType(cur.queryType()->getSize()), LINK(&cur)), i0);
  5213. }
  5214. }
  5215. }
  5216. //------------------------- Library processing -------------------------------------
  5217. int compareLibraryParameterOrder(IInterface * * pleft, IInterface * * pright)
  5218. {
  5219. IHqlExpression * left = static_cast<IHqlExpression *>(*pleft);
  5220. IHqlExpression * right = static_cast<IHqlExpression *>(*pright);
  5221. //datasets come first - even if not streamed
  5222. if (left->isDataset())
  5223. {
  5224. if (!right->isDataset())
  5225. return -1;
  5226. }
  5227. else
  5228. {
  5229. if (right->isDataset())
  5230. return +1;
  5231. }
  5232. //Then fixed size fields - to minimize the code generated to access them
  5233. if (left->queryType()->getSize() == UNKNOWN_LENGTH)
  5234. {
  5235. if (right->queryType()->getSize() != UNKNOWN_LENGTH)
  5236. return +1;
  5237. }
  5238. else
  5239. {
  5240. if (right->queryType()->getSize() == UNKNOWN_LENGTH)
  5241. return -1;
  5242. }
  5243. //then by name
  5244. return stricmp(left->queryName()->str(), right->queryName()->str());
  5245. }
  5246. LibraryInputMapper::LibraryInputMapper(IHqlExpression * _libraryInterface)
  5247. : libraryInterface(_libraryInterface)
  5248. {
  5249. assertex(libraryInterface->getOperator() == no_funcdef);
  5250. scopeExpr.set(libraryInterface->queryChild(0));
  5251. streamingAllowed = !scopeExpr->hasProperty(_noStreaming_Atom); // ?? is this in the correct place, probably, just nasty
  5252. expandParameters();
  5253. }
  5254. void LibraryInputMapper::expandParameters()
  5255. {
  5256. IHqlExpression * formals = libraryInterface->queryChild(1);
  5257. unsigned nextParameter = formals->numChildren()+1;
  5258. ForEachChild(i, formals)
  5259. expandParameter(formals->queryChild(i), nextParameter);
  5260. realParameters.sort(compareLibraryParameterOrder);
  5261. //Count number of datasets (always at the front), so can use to adjust library counts when streaming
  5262. numDatasets = 0;
  5263. while ((numDatasets < realParameters.ordinality()) && realParameters.item(numDatasets).isDataset())
  5264. numDatasets++;
  5265. }
  5266. void LibraryInputMapper::expandParameter(IHqlExpression * expr, unsigned & nextParameter)
  5267. {
  5268. if (expr->isScope())
  5269. {
  5270. IHqlScope * scope = expr->queryScope();
  5271. HqlExprArray symbols;
  5272. scope->getSymbols(symbols);
  5273. ForEachItemIn(i, symbols)
  5274. {
  5275. IHqlExpression & cur = symbols.item(i);
  5276. IIdAtom * nestedName = createMangledName(expr, &cur);
  5277. //default values are handled elsewhere - lost from the mapped values here.
  5278. HqlExprArray attrs;
  5279. OwnedHqlExpr renamed = createParameter(nestedName, nextParameter++, cur.getType(), attrs);
  5280. expandParameter(renamed, nextParameter);
  5281. }
  5282. }
  5283. else
  5284. realParameters.append(*LINK(expr));
  5285. }
  5286. unsigned LibraryInputMapper::findParameter(IIdAtom * searchId)
  5287. {
  5288. IAtom * searchName = searchId->lower();
  5289. ForEachItemIn(i, realParameters)
  5290. {
  5291. if (realParameters.item(i).queryName() == searchName)
  5292. return i;
  5293. }
  5294. return NotFound;
  5295. }
  5296. IHqlExpression * LibraryInputMapper::resolveParameter(IIdAtom * search)
  5297. {
  5298. unsigned match = findParameter(search);
  5299. assertex(match != NotFound);
  5300. return &realParameters.item(match);
  5301. }
  5302. void LibraryInputMapper::mapRealToLogical(HqlExprArray & inputExprs, HqlExprArray & logicalParams, IHqlExpression * libraryId, bool canStream, bool distributed)
  5303. {
  5304. //Create a list of expressions representing each of the inputs...
  5305. ForEachItemIn(i1, realParameters)
  5306. {
  5307. IHqlExpression * cur = &realParameters.item(i1);
  5308. IHqlExpression * result = NULL;
  5309. unsigned inputIndex = i1;
  5310. if (canStream && streamingAllowed)
  5311. {
  5312. if (cur->isDataset())
  5313. {
  5314. HqlExprArray args;
  5315. args.append(*LINK(cur->queryRecord()));
  5316. args.append(*LINK(libraryId));
  5317. args.append(*getSizetConstant(inputIndex));
  5318. args.append(*createAttribute(_streaming_Atom));
  5319. if (isGrouped(cur))
  5320. args.append(*createAttribute(groupedAtom));
  5321. if (distributed)
  5322. args.append(*createAttribute(_distributed_Atom));
  5323. result = createDataset(no_getgraphresult, args);
  5324. }
  5325. else
  5326. inputIndex -= numDatasets;
  5327. }
  5328. if (!result)
  5329. {
  5330. IHqlExpression * seq = getSizetConstant(inputIndex);
  5331. if (cur->isDataset())
  5332. {
  5333. IHqlExpression * groupAttr = isGrouped(cur) ? createAttribute(groupedAtom) : NULL;
  5334. result = createDataset(no_libraryinput, LINK(cur->queryRecord()), createComma(seq, groupAttr));
  5335. }
  5336. else if (cur->isDatarow())
  5337. result = createDataset(no_libraryinput, LINK(cur->queryRecord()), seq); // should this be a row?
  5338. else
  5339. result = createValue(no_libraryinput, cur->getType(), seq);
  5340. }
  5341. inputExprs.append(*createSymbol(cur->queryId(), result, ob_private));
  5342. }
  5343. IHqlExpression * formals = libraryInterface->queryChild(1);
  5344. ForEachChild(i, formals)
  5345. logicalParams.append(*mapRealToLogical(inputExprs, formals->queryChild(i), libraryId));
  5346. }
  5347. IHqlExpression * LibraryInputMapper::mapRealToLogical(const HqlExprArray & inputExprs, IHqlExpression * expr, IHqlExpression * libraryId)
  5348. {
  5349. if (expr->isScope())
  5350. {
  5351. IHqlScope * scope = expr->queryScope();
  5352. HqlExprArray symbols;
  5353. scope->getSymbols(symbols);
  5354. Owned<IHqlScope> newScope = createVirtualScope();
  5355. ForEachItemIn(i, symbols)
  5356. {
  5357. IHqlExpression & cur = symbols.item(i);
  5358. IHqlExpression * param = resolveParameter(createMangledName(expr, &cur));
  5359. OwnedHqlExpr mapped = mapRealToLogical(inputExprs, param, libraryId);
  5360. OwnedHqlExpr named = createSymbol(cur.queryId(), LINK(mapped), ob_private);
  5361. newScope->defineSymbol(named.getClear());
  5362. }
  5363. return queryExpression(closeScope(newScope.getClear()));
  5364. }
  5365. else
  5366. {
  5367. unsigned inputIndex = realParameters.find(*expr);
  5368. return LINK(&inputExprs.item(inputIndex));
  5369. }
  5370. }
  5371. void LibraryInputMapper::mapLogicalToReal(HqlExprArray & mapped, HqlExprArray & params)
  5372. {
  5373. IHqlExpression * placeholder = queryActiveTableSelector();
  5374. ForEachItemIn(i1, realParameters)
  5375. mapped.append(*LINK(placeholder));
  5376. IHqlExpression * formals = libraryInterface->queryChild(1);
  5377. ForEachChild(i, formals)
  5378. mapLogicalToReal(mapped, formals->queryChild(i), &params.item(i));
  5379. }
  5380. void LibraryInputMapper::mapLogicalToReal(HqlExprArray & mapped, IHqlExpression * expr, IHqlExpression * value)
  5381. {
  5382. if (expr->isScope())
  5383. {
  5384. IHqlScope * scope = expr->queryScope();
  5385. IHqlScope * valueScope = value->queryScope();
  5386. HqlExprArray symbols;
  5387. scope->getSymbols(symbols);
  5388. HqlDummyLookupContext lookupCtx(NULL);
  5389. ForEachItemIn(i, symbols)
  5390. {
  5391. IHqlExpression & cur = symbols.item(i);
  5392. IHqlExpression * param = resolveParameter(createMangledName(expr, &cur));
  5393. OwnedHqlExpr childValue = valueScope->lookupSymbol(cur.queryId(), LSFpublic, lookupCtx);
  5394. mapLogicalToReal(mapped, param, childValue);
  5395. }
  5396. }
  5397. else
  5398. {
  5399. //Replace the real parameter at the appropriate position
  5400. unsigned match = realParameters.find(*expr);
  5401. assertex(match != NotFound);
  5402. mapped.replace(*LINK(value), match);
  5403. }
  5404. }
  5405. static byte key[32] = {
  5406. 0xf7, 0xe8, 0x79, 0x40, 0x44, 0x16, 0x66, 0x18, 0x52, 0xb8, 0x18, 0x6e, 0x77, 0xd1, 0x68, 0xd3,
  5407. 0x87, 0x47, 0x01, 0xe6, 0x66, 0x62, 0x2f, 0xbe, 0xc1, 0xd5, 0x9f, 0x4a, 0x53, 0x27, 0xae, 0xa1,
  5408. };
  5409. extern HQL_API void encryptEclAttribute(IStringVal & out, size32_t len, const void * in)
  5410. {
  5411. MemoryBuffer encrypted;
  5412. aesEncrypt(key, sizeof(key), in, len, encrypted);
  5413. StringBuffer base64;
  5414. JBASE64_Encode(encrypted.toByteArray(), encrypted.length(), base64, false);
  5415. StringBuffer text;
  5416. text.append("ENC").append('R').append('Y').append("PTE").append("D(").newline();
  5417. const char * base64Text = base64.str();
  5418. unsigned max = base64.length();
  5419. const unsigned chunk = 60;
  5420. unsigned i;
  5421. for (i = 0; i + chunk < max; i += chunk)
  5422. {
  5423. text.append('\t').append("'").append(chunk, base64Text+i).append("',").newline();
  5424. }
  5425. text.append('\t').append("'").append(max-i, base64Text+i).append("'").newline().append(");").newline();
  5426. out.set(text.str());
  5427. }
  5428. void decryptEclAttribute(MemoryBuffer & out, const char * in)
  5429. {
  5430. StringBuffer decoded;
  5431. JBASE64_Decode(in, decoded);
  5432. aesDecrypt(key, sizeof(key), decoded.str(), decoded.length(), out);
  5433. }
  5434. //---------------------------------------------------------------------------
  5435. class HQL_API GraphIdCollector : public NewHqlTransformer
  5436. {
  5437. public:
  5438. GraphIdCollector(HqlExprCopyArray & _graphs, bool _externalIds);
  5439. virtual void analyseExpr(IHqlExpression * expr);
  5440. protected:
  5441. HqlExprCopyArray & graphs;
  5442. bool externalIds;
  5443. };
  5444. static HqlTransformerInfo hqlGraphIdCollectorInfo("GraphIdCollector");
  5445. GraphIdCollector::GraphIdCollector(HqlExprCopyArray & _graphs, bool _externalIds)
  5446. : NewHqlTransformer(hqlGraphIdCollectorInfo), graphs(_graphs), externalIds(_externalIds)
  5447. {
  5448. }
  5449. void GraphIdCollector::analyseExpr(IHqlExpression * expr)
  5450. {
  5451. if (alreadyVisited(expr))
  5452. return;
  5453. switch (expr->getOperator())
  5454. {
  5455. case no_loopcounter:
  5456. if (!externalIds)
  5457. graphs.append(*expr->queryChild(0));
  5458. return;
  5459. case no_getgraphresult:
  5460. if (externalIds)
  5461. {
  5462. IHqlExpression * id = queryPropertyChild(expr, externalAtom, 0);
  5463. if (id)
  5464. graphs.append(*id);
  5465. }
  5466. else
  5467. graphs.append(*expr->queryChild(1));
  5468. return;
  5469. }
  5470. NewHqlTransformer::analyseExpr(expr);
  5471. }
  5472. void gatherGraphReferences(HqlExprCopyArray & graphs, IHqlExpression * value, bool externalIds)
  5473. {
  5474. GraphIdCollector collector(graphs, externalIds);
  5475. collector.analyse(value, 0);
  5476. }
  5477. //---------------------------------------------------------------------------
  5478. IAtom * getWarningAction(unsigned errorCode, const HqlExprArray & overrides, unsigned first)
  5479. {
  5480. //warnings are assumed to be infrequent, so don't worry about efficiency here.
  5481. const unsigned max = overrides.ordinality();
  5482. for (unsigned i=first; i < max; i++)
  5483. {
  5484. IHqlExpression & cur = overrides.item(i);
  5485. if (matchesConstantValue(cur.queryChild(0), errorCode))
  5486. return cur.queryChild(1)->queryName();
  5487. }
  5488. return defaultAtom;
  5489. }
  5490. WarningProcessor::WarningProcessor()
  5491. {
  5492. firstLocalOnWarning = 0;
  5493. activeSymbol = NULL;
  5494. }
  5495. void WarningProcessor::addWarning(IECLError * warning)
  5496. {
  5497. //warnings are assumed to be infrequent, so don't worry about efficiency here.
  5498. IAtom * action = getWarningAction(warning->errorCode(), localOnWarnings, firstLocalOnWarning);
  5499. if (action == defaultAtom)
  5500. appendUnique(possibleWarnings, warning);
  5501. else if (action == warningAtom)
  5502. appendUnique(warnings, warning);
  5503. else if (action == errorAtom)
  5504. {
  5505. allErrors.append(*changeErrorType(true, warning));
  5506. }
  5507. else
  5508. {
  5509. assertex(action == ignoreAtom);
  5510. }
  5511. }
  5512. void WarningProcessor::addGlobalOnWarning(unsigned code, IAtom * action)
  5513. {
  5514. globalOnWarnings.append(*createAttribute(onWarningAtom, getSizetConstant(code), createAttribute(action)));
  5515. }
  5516. void WarningProcessor::addGlobalOnWarning(IHqlExpression * setMetaExpr)
  5517. {
  5518. globalOnWarnings.append(*createAttribute(onWarningAtom, LINK(setMetaExpr->queryChild(1)), LINK(setMetaExpr->queryChild(2))));
  5519. }
  5520. void WarningProcessor::processMetaAnnotation(IHqlExpression * expr)
  5521. {
  5522. gatherMetaProperties(localOnWarnings, onWarningAtom, expr);
  5523. }
  5524. void WarningProcessor::processWarningAnnotation(IHqlExpression * expr)
  5525. {
  5526. //would be cleaner if each annotation defined an interface, and this was a dynamic cast
  5527. //but not sufficiently complicated to warrent it.
  5528. IECLError * error = static_cast<CHqlWarningAnnotation *>(expr)->queryWarning();
  5529. addWarning(error);
  5530. }
  5531. void WarningProcessor::pushSymbol(OnWarningState & saved, IHqlExpression * _symbol)
  5532. {
  5533. saveState(saved);
  5534. setSymbol(_symbol);
  5535. }
  5536. void WarningProcessor::saveState(OnWarningState & saved)
  5537. {
  5538. saved.firstOnWarning = firstLocalOnWarning;
  5539. saved.onWarningMax = localOnWarnings.ordinality();
  5540. saved.symbol = activeSymbol;
  5541. }
  5542. void WarningProcessor::setSymbol(IHqlExpression * _symbol)
  5543. {
  5544. firstLocalOnWarning = localOnWarnings.ordinality();
  5545. activeSymbol = _symbol;
  5546. }
  5547. void WarningProcessor::restoreState(const OnWarningState & saved)
  5548. {
  5549. while (localOnWarnings.ordinality() > saved.onWarningMax)
  5550. localOnWarnings.pop();
  5551. firstLocalOnWarning = saved.firstOnWarning;
  5552. activeSymbol = saved.symbol;
  5553. }
  5554. void WarningProcessor::report(IErrorReceiver & errors)
  5555. {
  5556. applyGlobalOnWarning();
  5557. combineSandboxWarnings();
  5558. if (allErrors.ordinality())
  5559. reportErrors(errors, allErrors);
  5560. else
  5561. reportErrors(errors, warnings);
  5562. }
  5563. void WarningProcessor::report(IErrorReceiver * errors, IErrorReceiver * warnings, IECLError * warning)
  5564. {
  5565. IAtom * action = getWarningAction(warning->errorCode(), localOnWarnings, firstLocalOnWarning);
  5566. if (action == defaultAtom)
  5567. action = getWarningAction(warning->errorCode(), globalOnWarnings, 0);
  5568. if (action == defaultAtom)
  5569. action = warning->isError() ? errorAtom : warningAtom;
  5570. if ((action == warningAtom) || (action == defaultAtom))
  5571. {
  5572. if (warnings)
  5573. warnings->report(warning);
  5574. }
  5575. else if (action == errorAtom)
  5576. {
  5577. Owned<IECLError> error = changeErrorType(true, warning);
  5578. if (errors)
  5579. errors->report(error);
  5580. else
  5581. throw error.getClear();
  5582. }
  5583. }
  5584. void WarningProcessor::combineSandboxWarnings()
  5585. {
  5586. StringBuffer s;
  5587. ForEachItemInRev(i, warnings)
  5588. {
  5589. IECLError & cur = warnings.item(i);
  5590. if (cur.errorCode() == WRN_DEFINITION_SANDBOXED)
  5591. {
  5592. if (s.length())
  5593. s.append(", ");
  5594. s.append(cur.getFilename());
  5595. warnings.remove(i);
  5596. }
  5597. }
  5598. if (s.length())
  5599. {
  5600. s.insert(0, "The following definitions are sandboxed: ");
  5601. warnings.append(* createECLWarning(WRN_DEFINITION_SANDBOXED, s.str(), NULL, 0, 0, 0));
  5602. }
  5603. }
  5604. void WarningProcessor::applyGlobalOnWarning()
  5605. {
  5606. ForEachItemIn(i, possibleWarnings)
  5607. {
  5608. IECLError & cur = possibleWarnings.item(i);
  5609. IAtom * action = getWarningAction(cur.errorCode(), globalOnWarnings, 0);
  5610. if (action == defaultAtom || action == warningAtom)
  5611. {
  5612. if (cur.isError())
  5613. appendUnique(allErrors, &cur);
  5614. else
  5615. appendUnique(warnings, &cur);
  5616. }
  5617. else if (action == errorAtom)
  5618. allErrors.append(*changeErrorType(true, &cur));
  5619. }
  5620. }
  5621. bool isActiveRow(IHqlExpression * expr)
  5622. {
  5623. switch (expr->getOperator())
  5624. {
  5625. case no_select:
  5626. return !isNewSelector(expr);
  5627. default:
  5628. return isAlwaysActiveRow(expr);
  5629. }
  5630. }
  5631. StringBuffer & convertToValidLabel(StringBuffer &out, const char * in, unsigned inlen)
  5632. {
  5633. for (unsigned o = 0; o < inlen; o++)
  5634. {
  5635. unsigned char c = in[o];
  5636. if (isalnum(c))
  5637. out.append(c);
  5638. else
  5639. out.append('_');
  5640. }
  5641. return out;
  5642. }
  5643. bool arraysSame(CIArray & left, CIArray & right)
  5644. {
  5645. if (left.ordinality() != right.ordinality())
  5646. return false;
  5647. return memcmp(left.getArray(), right.getArray(), left.ordinality() * sizeof(CInterface*)) == 0;
  5648. }
  5649. bool arraysSame(Array & left, Array & right)
  5650. {
  5651. if (left.ordinality() != right.ordinality())
  5652. return false;
  5653. return memcmp(left.getArray(), right.getArray(), left.ordinality() * sizeof(CInterface*)) == 0;
  5654. }
  5655. bool isFailAction(IHqlExpression * expr)
  5656. {
  5657. return expr && (expr->getOperator() == no_fail);
  5658. }
  5659. bool isFailureGuard(IHqlExpression * expr)
  5660. {
  5661. if (expr->getOperator() == no_if)
  5662. return isFailAction(expr->queryChild(1)) || isFailAction(expr->queryChild(2));
  5663. return false;
  5664. }
  5665. extern HQL_API bool isKeyedDataset(IHqlExpression * expr)
  5666. {
  5667. switch (expr->getOperator())
  5668. {
  5669. case no_keyedlimit:
  5670. return true;
  5671. case no_filter:
  5672. return filterIsKeyed(expr);
  5673. case no_hqlproject:
  5674. case no_newusertable:
  5675. case no_aggregate:
  5676. case no_newaggregate:
  5677. return expr->hasProperty(keyedAtom);
  5678. }
  5679. return false;
  5680. }
  5681. extern HQL_API bool isSteppedDataset(IHqlExpression * expr)
  5682. {
  5683. switch (expr->getOperator())
  5684. {
  5685. case no_stepped:
  5686. case no_mergejoin:
  5687. case no_nwayjoin:
  5688. return true;
  5689. }
  5690. return false;
  5691. }
  5692. extern HQL_API IHqlExpression * queryFieldFromExpr(IHqlExpression * expr)
  5693. {
  5694. loop
  5695. {
  5696. switch (expr->getOperator())
  5697. {
  5698. case no_field:
  5699. return expr;
  5700. case no_indirect:
  5701. expr = expr->queryChild(0);
  5702. break;
  5703. case no_select:
  5704. expr = expr->queryChild(1);
  5705. break;
  5706. default:
  5707. return expr;
  5708. }
  5709. }
  5710. }
  5711. extern HQL_API IHqlExpression * queryFieldFromSelect(IHqlExpression * expr)
  5712. {
  5713. IHqlExpression * ret = queryFieldFromExpr(expr);
  5714. assertex(ret->getOperator() == no_field);
  5715. return ret;
  5716. }
  5717. extern HQL_API bool isValidFieldReference(IHqlExpression * expr)
  5718. {
  5719. switch (expr->getOperator())
  5720. {
  5721. case no_select:
  5722. case no_field:
  5723. case no_indirect:
  5724. return true;
  5725. case no_param:
  5726. return expr->hasProperty(fieldAtom);
  5727. }
  5728. return false;
  5729. }
  5730. extern HQL_API bool isFieldSelectedFromRecord(IHqlExpression * expr)
  5731. {
  5732. switch (expr->getOperator())
  5733. {
  5734. case no_select:
  5735. case no_indirect:
  5736. expr = expr->queryChild(0);
  5737. break;
  5738. default:
  5739. return false;
  5740. }
  5741. loop
  5742. {
  5743. switch (expr->getOperator())
  5744. {
  5745. case no_record:
  5746. return true;
  5747. case no_select:
  5748. case no_indirect:
  5749. expr = expr->queryChild(0);
  5750. break;
  5751. default:
  5752. return false;
  5753. }
  5754. }
  5755. }
  5756. void createClearAssigns(HqlExprArray & assigns, IHqlExpression * record, IHqlExpression * targetSelector)
  5757. {
  5758. ForEachChild(idx, record)
  5759. {
  5760. IHqlExpression * field = record->queryChild(idx);
  5761. switch (field->getOperator())
  5762. {
  5763. case no_ifblock:
  5764. createClearAssigns(assigns, field->queryChild(1), targetSelector);
  5765. break;
  5766. case no_record:
  5767. createClearAssigns(assigns, field, targetSelector);
  5768. break;
  5769. case no_field:
  5770. {
  5771. OwnedHqlExpr newTargetSelector = createSelectExpr(LINK(targetSelector), LINK(field));
  5772. IHqlExpression * value = createNullExpr(newTargetSelector);
  5773. assigns.append(*createAssign(LINK(newTargetSelector), value));
  5774. break;
  5775. }
  5776. case no_attr:
  5777. case no_attr_link:
  5778. case no_attr_expr:
  5779. break;
  5780. }
  5781. }
  5782. }
  5783. IHqlExpression * createClearTransform(IHqlExpression * record)
  5784. {
  5785. HqlExprArray assigns;
  5786. OwnedHqlExpr self = getSelf(record);
  5787. createClearAssigns(assigns, record, self);
  5788. return createValue(no_transform, makeTransformType(record->getType()), assigns);
  5789. }
  5790. IHqlExpression * createDefaultAssertMessage(IHqlExpression * cond)
  5791. {
  5792. if (cond->getOperator() == no_assertconstant)
  5793. {
  5794. OwnedHqlExpr msg = createDefaultAssertMessage(cond->queryChild(0));
  5795. return createWrapper(no_assertconstant, msg.getClear());
  5796. }
  5797. StringBuffer suffix;
  5798. getExprECL(cond, suffix, true);
  5799. node_operator op = cond->getOperator();
  5800. StringBuffer temp;
  5801. switch (op)
  5802. {
  5803. case no_eq:
  5804. case no_ne:
  5805. case no_gt:
  5806. case no_ge:
  5807. case no_lt:
  5808. case no_le:
  5809. break;
  5810. default:
  5811. return createConstant(temp.append("Assert failed: ").append(suffix));
  5812. }
  5813. IHqlExpression * lhs = cond->queryChild(0);
  5814. IHqlExpression * rhs = cond->queryChild(1);
  5815. if (!lhs->queryType()->isScalar() || !rhs->queryType()->isScalar())
  5816. return createConstant(temp.append("Assert failed: ").append(suffix));
  5817. StringBuffer prefix;
  5818. prefix.append("Assert (");
  5819. suffix.insert(0, ") failed [");
  5820. suffix.append("]");
  5821. StringBuffer cmpText;
  5822. cmpText.append(" ").append(getOpString(op)).append(" ");
  5823. OwnedITypeInfo unknownStringType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  5824. OwnedITypeInfo unknownVarStringType = makeVarStringType(UNKNOWN_LENGTH, NULL, NULL);
  5825. HqlExprArray args;
  5826. args.append(*createConstant(prefix));
  5827. args.append(*ensureExprType(lhs, unknownStringType));
  5828. args.append(*createConstant(cmpText));
  5829. args.append(*ensureExprType(rhs, unknownStringType));
  5830. args.append(*createConstant(suffix));
  5831. return createBalanced(no_concat, unknownVarStringType, args);
  5832. }
  5833. //-------------------------------------------------------------------------------------------------------------------
  5834. static char const gccMangledIntegers[2][8] = {
  5835. { 'h', 't', 'j', 'j', 'y', 'y', 'y', 'y' },
  5836. { 'c', 's', 'i', 'i', 'x', 'x', 'x', 'x' }
  5837. };
  5838. // gcc see http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
  5839. class GccCppNameMangler
  5840. {
  5841. public:
  5842. bool mangleFunctionName(StringBuffer & mangled, IHqlExpression * funcdef)
  5843. {
  5844. IHqlExpression *body = funcdef->queryChild(0);
  5845. IHqlExpression *formals = funcdef->queryChild(1);
  5846. ITypeInfo * retType = funcdef->queryType()->queryChildType();
  5847. enum { ServiceApi, RtlApi, BcdApi, CApi, LocalApi } api = ServiceApi;
  5848. if (body->hasProperty(eclrtlAtom))
  5849. api = RtlApi;
  5850. else if (body->hasProperty(bcdAtom))
  5851. api = BcdApi;
  5852. else if (body->hasProperty(cAtom))
  5853. api = CApi;
  5854. else if (body->hasProperty(localAtom))
  5855. api = LocalApi;
  5856. StringBuffer entrypoint;
  5857. getProperty(body, entrypointAtom, entrypoint);
  5858. if (entrypoint.length() == 0)
  5859. return false;
  5860. if ((api == ServiceApi) || api == CApi)
  5861. {
  5862. mangled.append(entrypoint); // extern "C"
  5863. return true;
  5864. }
  5865. if (body->hasProperty(oldSetFormatAtom))
  5866. return false;
  5867. mangled.append("_Z").append(entrypoint.length()).append(entrypoint);
  5868. StringBuffer mangledReturn;
  5869. StringBuffer mangledReturnParameters;
  5870. mangleFunctionReturnType(mangledReturn, mangledReturnParameters, retType);
  5871. if (body->hasProperty(contextAtom))
  5872. mangled.append("P12ICodeContext");
  5873. else if (body->hasProperty(globalContextAtom) )
  5874. mangled.append("P18IGlobalCodeContext");
  5875. else if (body->hasProperty(userMatchFunctionAtom))
  5876. mangled.append("P12IMatchWalker");
  5877. mangled.append(mangledReturnParameters);
  5878. ForEachChild(i, formals)
  5879. {
  5880. IHqlExpression * param = formals->queryChild(i);
  5881. ITypeInfo *paramType = param->queryType();
  5882. bool isOut = param->hasProperty(outAtom);
  5883. bool isConst = param->hasProperty(constAtom);
  5884. if (isOut)
  5885. mangled.append("R");
  5886. if (!mangleSimpleType(mangled, paramType, isConst))
  5887. return false;
  5888. }
  5889. return true;
  5890. }
  5891. protected:
  5892. bool mangleSimpleType(StringBuffer & result, ITypeInfo * type, bool hasConst)
  5893. {
  5894. if (!type)
  5895. return false;
  5896. switch (type->getTypeCode())
  5897. {
  5898. case type_boolean:
  5899. result.append("b");
  5900. return true;
  5901. case type_int:
  5902. case type_swapint:
  5903. result.append(gccMangledIntegers[type->isSigned() ? 1 : 0][type->getSize()-1]);
  5904. return true;
  5905. case type_real:
  5906. result.append(type->getSize() == 4 ? "f" : "d");
  5907. return true;
  5908. case type_decimal:
  5909. //Should really define this properly (size, precision, ptr)
  5910. return false;
  5911. case type_string:
  5912. case type_qstring:
  5913. case type_utf8:
  5914. if (type->getSize() == UNKNOWN_LENGTH)
  5915. result.append("j");
  5916. result.append(hasConst ? "PKc" : "Pc");
  5917. return true;
  5918. case type_varstring:
  5919. result.append(hasConst ? "PKc" : "Pc");
  5920. return true;
  5921. case type_data:
  5922. if (type->getSize() == UNKNOWN_LENGTH)
  5923. result.append("j");
  5924. result.append(hasConst ? "PKv" : "Pv");
  5925. return true;
  5926. case type_unicode:
  5927. if (type->getSize() == UNKNOWN_LENGTH)
  5928. result.append("j");
  5929. result.append(hasConst ? "PKt" : "Pt");
  5930. return true;
  5931. case type_varunicode:
  5932. result.append(hasConst ? "PKt" : "Pt");
  5933. return true;
  5934. case type_char:
  5935. result.append("c");
  5936. return true;
  5937. case type_enumerated:
  5938. return mangleSimpleType(result, type->queryChildType(), hasConst);
  5939. case type_pointer:
  5940. result.append("P");
  5941. return mangleSimpleType(result, type->queryChildType(), hasConst);
  5942. case type_array:
  5943. result.append("A").append(type->getSize()).append("_");;
  5944. return mangleSimpleType(result, type->queryChildType(), hasConst);
  5945. case type_table:
  5946. case type_groupedtable:
  5947. result.append("j"); // size32_t
  5948. result.append(hasConst ? "PKv" : "Pv"); // [const] void *
  5949. return true;
  5950. case type_set:
  5951. result.append("b"); // bool
  5952. result.append("j"); // unsigned
  5953. result.append(hasConst ? "PKv" : "Pv"); // *
  5954. return true;
  5955. case type_row:
  5956. result.append("Ph");
  5957. return true;
  5958. case type_void:
  5959. result.append("v");
  5960. return true;
  5961. case type_scope:
  5962. case type_transform:
  5963. case type_function:
  5964. case type_any:
  5965. case type_packedint:
  5966. case type_alien:
  5967. case type_class:
  5968. case type_date:
  5969. //may possibly have some support in the future, but not yet...
  5970. return false;
  5971. }
  5972. throwUnexpected();
  5973. }
  5974. bool mangleFunctionReturnType(StringBuffer & returnType, StringBuffer & params, ITypeInfo * retType)
  5975. {
  5976. type_t tc = retType->getTypeCode();
  5977. switch (tc)
  5978. {
  5979. case type_varstring:
  5980. if (retType->getSize() == UNKNOWN_LENGTH)
  5981. returnType.append("Pc"); // char *
  5982. else
  5983. params.append("Pc"); // char *
  5984. break;
  5985. case type_varunicode:
  5986. if (retType->getSize() == UNKNOWN_LENGTH)
  5987. returnType.append("Pt"); // ushort *
  5988. else
  5989. params.append("Pt"); // ushort *
  5990. break;
  5991. case type_qstring:
  5992. case type_string:
  5993. case type_utf8:
  5994. if (retType->getSize() == UNKNOWN_LENGTH)
  5995. {
  5996. params.append("Rj"); // size32_t &
  5997. params.append("RPc"); // char * &
  5998. }
  5999. else
  6000. params.append("Pc"); // char *
  6001. break;
  6002. case type_data:
  6003. if (retType->getSize() == UNKNOWN_LENGTH)
  6004. {
  6005. params.append("Rj"); // size32_t &
  6006. params.append("RPv"); // void * &
  6007. }
  6008. else
  6009. params.append("Pv"); // void *
  6010. break;
  6011. case type_unicode:
  6012. if (retType->getSize() == UNKNOWN_LENGTH)
  6013. {
  6014. params.append("Rj"); // size32_t &
  6015. params.append("RPt"); // UChar * &
  6016. }
  6017. else
  6018. params.append("Pt"); // UChar *
  6019. break;
  6020. case type_table:
  6021. case type_groupedtable:
  6022. params.append("Rj"); // size32_t &
  6023. params.append("RPv"); // void * &
  6024. break;
  6025. case type_set:
  6026. params.append("Rb"); // bool &
  6027. params.append("Rj"); // size32_t &
  6028. params.append("RPv"); // void * &
  6029. break;
  6030. case type_row:
  6031. params.append("Ph"); // byte *
  6032. break;
  6033. }
  6034. return true;
  6035. }
  6036. };
  6037. //-------------------------------------------------------------------------------------------------------------------
  6038. //See http://www.kegel.com/mangle.html for details
  6039. //See http://www.agner.org/optimize/calling_conventions.pdf for details
  6040. static const char * const vs6MangledIntegers[2][8] = {
  6041. { "E", "G", "I", "I", "_K", "_K", "_K", "_K" },
  6042. { "D", "F", "H", "H", "_J", "_J", "_J", "_J" }
  6043. };
  6044. class Vs6CppNameMangler
  6045. {
  6046. public:
  6047. Vs6CppNameMangler()
  6048. {
  6049. #ifdef __64BIT__
  6050. pointerBaseCode.set("E");
  6051. #endif
  6052. }
  6053. bool mangle(StringBuffer & mangled, IHqlExpression * funcdef)
  6054. {
  6055. IHqlExpression *body = funcdef->queryChild(0);
  6056. IHqlExpression *formals = funcdef->queryChild(1);
  6057. enum { ServiceApi, RtlApi, BcdApi, CApi, LocalApi } api = ServiceApi;
  6058. if (body->hasProperty(eclrtlAtom))
  6059. api = RtlApi;
  6060. else if (body->hasProperty(bcdAtom))
  6061. api = BcdApi;
  6062. else if (body->hasProperty(cAtom))
  6063. api = CApi;
  6064. else if (body->hasProperty(localAtom))
  6065. api = LocalApi;
  6066. StringBuffer entrypoint;
  6067. getProperty(body, entrypointAtom, entrypoint);
  6068. if (entrypoint.length() == 0)
  6069. return false;
  6070. if ((api == ServiceApi) || api == CApi)
  6071. {
  6072. mangled.append(entrypoint); // extern "C"
  6073. return true;
  6074. }
  6075. if (body->hasProperty(oldSetFormatAtom))
  6076. return false;
  6077. mangled.append("?").append(entrypoint).append("@@").append("Y");
  6078. switch (api)
  6079. {
  6080. case CApi:
  6081. mangled.append("A"); // _cdecl
  6082. break;
  6083. case BcdApi:
  6084. mangled.append("T"); // __fastcall"
  6085. break;
  6086. default:
  6087. mangled.append("A"); // _cdecl
  6088. break;
  6089. // mangled.append("G"); // __stdcall
  6090. }
  6091. StringBuffer mangledReturn;
  6092. StringBuffer mangledReturnParameters;
  6093. ITypeInfo * retType = funcdef->queryType()->queryChildType();
  6094. mangleFunctionReturnType(mangledReturn, mangledReturnParameters, retType);
  6095. mangled.append(mangledReturn);
  6096. if (body->hasProperty(contextAtom))
  6097. mangled.append("PVICodeContext@@");
  6098. else if (body->hasProperty(globalContextAtom) )
  6099. mangled.append("PVIGlobalCodeContext@@");
  6100. else if (body->hasProperty(userMatchFunctionAtom))
  6101. mangled.append("PVIMatchWalker@@");
  6102. if (mangledReturnParameters.length())
  6103. mangled.append(mangledReturnParameters);
  6104. ForEachChild(i, formals)
  6105. {
  6106. IHqlExpression * param = formals->queryChild(i);
  6107. ITypeInfo *paramType = param->queryType();
  6108. bool isOut = param->hasProperty(outAtom);
  6109. bool isConst = param->hasProperty(constAtom);
  6110. if (isOut)
  6111. appendRef(mangled, false);
  6112. if (!mangleSimpleType(mangled, paramType, isConst))
  6113. return false;
  6114. }
  6115. mangled.append("@Z");
  6116. return true;
  6117. }
  6118. protected:
  6119. bool mangleSimpleType(StringBuffer & result, ITypeInfo * type, bool hasConst)
  6120. {
  6121. if (!type)
  6122. return false;
  6123. switch (type->getTypeCode())
  6124. {
  6125. case type_boolean:
  6126. result.append("_N");
  6127. return true;
  6128. case type_int:
  6129. case type_swapint:
  6130. result.append(vs6MangledIntegers[type->isSigned() ? 1 : 0][type->getSize()-1]);
  6131. return true;
  6132. case type_real:
  6133. result.append(type->getSize() == 4 ? "M" : "N");
  6134. return true;
  6135. case type_decimal:
  6136. //Should really define this properly (size, precision, ptr)
  6137. return false;
  6138. case type_string:
  6139. case type_qstring:
  6140. case type_utf8:
  6141. if (type->getSize() == UNKNOWN_LENGTH)
  6142. result.append("I");
  6143. appendPtr(result, hasConst).append("D");
  6144. return true;
  6145. case type_varstring:
  6146. appendPtr(result, hasConst).append("D");
  6147. return true;
  6148. case type_data:
  6149. if (type->getSize() == UNKNOWN_LENGTH)
  6150. result.append("I");
  6151. appendPtr(result, hasConst).append("X");
  6152. return true;
  6153. case type_unicode:
  6154. if (type->getSize() == UNKNOWN_LENGTH)
  6155. result.append("I");
  6156. appendPtr(result, hasConst).append("G");
  6157. return true;
  6158. case type_varunicode:
  6159. appendPtr(result, hasConst).append("G");
  6160. return true;
  6161. case type_char:
  6162. result.append("D");
  6163. return true;
  6164. case type_enumerated:
  6165. return mangleSimpleType(result, type->queryChildType(), hasConst);
  6166. case type_pointer:
  6167. result.append("PEB");
  6168. return mangleSimpleType(result, type->queryChildType(), hasConst);
  6169. case type_array:
  6170. return false; // QEA???
  6171. case type_table:
  6172. case type_groupedtable:
  6173. result.append("I"); // size32_t
  6174. appendPtr(result, hasConst).append("X");
  6175. return true;
  6176. case type_set:
  6177. result.append("_N"); // bool
  6178. result.append("I"); // unsigned
  6179. appendPtr(result, hasConst).append("X");
  6180. return true;
  6181. case type_row:
  6182. appendPtr(result, hasConst).append("E");
  6183. return true;
  6184. case type_void:
  6185. result.append("X");
  6186. return true;
  6187. case type_scope:
  6188. case type_transform:
  6189. case type_function:
  6190. case type_any:
  6191. case type_packedint:
  6192. case type_alien:
  6193. case type_class:
  6194. case type_date:
  6195. //may possibly have some support in the future, but not yet...
  6196. return false;
  6197. }
  6198. throwUnexpected();
  6199. }
  6200. bool mangleFunctionReturnType(StringBuffer & returnType, StringBuffer & params, ITypeInfo * retType)
  6201. {
  6202. type_t tc = retType->getTypeCode();
  6203. bool hasConst = false;
  6204. switch (tc)
  6205. {
  6206. case type_varstring:
  6207. if (retType->getSize() == UNKNOWN_LENGTH)
  6208. {
  6209. appendPtr(returnType, hasConst).append("D"); // char *
  6210. }
  6211. else
  6212. {
  6213. returnType.append("X");
  6214. appendPtr(params, hasConst).append("D"); // char *
  6215. }
  6216. break;
  6217. case type_varunicode:
  6218. if (retType->getSize() == UNKNOWN_LENGTH)
  6219. {
  6220. appendPtr(returnType, hasConst).append("G"); // char *
  6221. }
  6222. else
  6223. {
  6224. returnType.append("X");
  6225. appendPtr(params, hasConst).append("G"); // char *
  6226. }
  6227. break;
  6228. case type_qstring:
  6229. case type_string:
  6230. case type_utf8:
  6231. returnType.append("X");
  6232. appendString(params, retType, "D");
  6233. break;
  6234. case type_data:
  6235. returnType.append("X");
  6236. appendString(params, retType, "X");
  6237. break;
  6238. case type_unicode:
  6239. returnType.append("X");
  6240. appendString(params, retType, "G");
  6241. break;
  6242. case type_table:
  6243. case type_groupedtable:
  6244. returnType.append("X");
  6245. appendRef(params, false).append("I"); // size32_t &
  6246. appendRef(params, false);
  6247. appendPtr(params, false).append("X"); // void * &
  6248. break;
  6249. case type_set:
  6250. returnType.append("X");
  6251. appendRef(params, false).append("_N"); // bool &
  6252. appendRef(params, false).append("I"); // size32_t &
  6253. appendRef(params, false);
  6254. appendPtr(params, false).append("X"); // void * &
  6255. break;
  6256. case type_row:
  6257. returnType.append("X");
  6258. appendPtr(params, false).append("E"); // byte *
  6259. break;
  6260. default:
  6261. return mangleSimpleType(returnType, retType, false);
  6262. }
  6263. return true;
  6264. }
  6265. StringBuffer & appendPtr(StringBuffer & s, bool hasConst) { return s.append("P").append(pointerBaseCode).append(hasConst ? "B" : "A"); }
  6266. StringBuffer & appendRef(StringBuffer & s, bool hasConst) { return s.append("A").append(pointerBaseCode).append(hasConst ? "B" : "A"); }
  6267. StringBuffer & appendString(StringBuffer & params, ITypeInfo * type, const char * suffix)
  6268. {
  6269. if (type->getSize() == UNKNOWN_LENGTH)
  6270. {
  6271. appendRef(params, false).append("I"); // size32_t &
  6272. appendRef(params, false);
  6273. appendPtr(params, false).append(suffix); // X * &
  6274. }
  6275. else
  6276. appendPtr(params, false).append(suffix); // X *
  6277. return params;
  6278. }
  6279. protected:
  6280. StringAttr pointerBaseCode;
  6281. };
  6282. //-------------------------------------------------------------------------------------------------------------------
  6283. //This code is provisional, and needs a lot more testing. However it seems to work on my limited examples.
  6284. bool createMangledFunctionName(StringBuffer & mangled, IHqlExpression * funcdef, CompilerType compiler)
  6285. {
  6286. switch (compiler)
  6287. {
  6288. case GccCppCompiler:
  6289. {
  6290. GccCppNameMangler mangler;
  6291. return mangler.mangleFunctionName(mangled, funcdef);
  6292. }
  6293. case Vs6CppCompiler:
  6294. {
  6295. Vs6CppNameMangler mangler;
  6296. return mangler.mangle(mangled, funcdef);
  6297. }
  6298. }
  6299. return false;
  6300. }
  6301. bool createMangledFunctionName(StringBuffer & mangled, IHqlExpression * funcdef)
  6302. {
  6303. return createMangledFunctionName(mangled, funcdef, DEFAULT_COMPILER);
  6304. }
  6305. //-------------------------------------------------------------------------------------------------------------------
  6306. static void trimSlash(StringBuffer & name)
  6307. {
  6308. unsigned len = name.length();
  6309. if (len && name.charAt(len-1) == '/')
  6310. name.setLength(len-1);
  6311. }
  6312. void extractXmlName(StringBuffer & name, StringBuffer * itemName, StringBuffer * valueName, IHqlExpression * field, const char * defaultItemName, bool reading)
  6313. {
  6314. IHqlExpression * xpathAttr = field->queryProperty(xpathAtom);
  6315. if (xpathAttr)
  6316. {
  6317. StringBuffer tagName;
  6318. IHqlExpression * xpath = xpathAttr->queryChild(0);
  6319. xpath->queryValue()->getStringValue(tagName);
  6320. unsigned lenContents = strlen(XPATH_CONTENTS_TEXT);
  6321. unsigned lenTagName = tagName.length();
  6322. if ((lenTagName >= lenContents) && (memcmp(tagName.str() + (lenTagName - lenContents), XPATH_CONTENTS_TEXT, lenContents) == 0))
  6323. tagName.setLength(lenTagName - lenContents);
  6324. //Only take the xpath if it isn't an attribute, sub element, or a filtered element.
  6325. //we should probably think about handling attributes as a special case.
  6326. //would probably mean two passes.
  6327. if (!tagName.length())
  6328. return;
  6329. const char * text = tagName.str();
  6330. if (reading || !strchr(text, '['))
  6331. {
  6332. const char * sep = strchr(text, '/');
  6333. if (valueName && sep)
  6334. {
  6335. const char * sep2 = strchr(sep+1, '/');
  6336. if (sep2)
  6337. {
  6338. valueName->append(sep2+1);
  6339. itemName->append(sep2-(sep+1), (sep+1));
  6340. name.append(sep-text, text);
  6341. trimSlash(name);
  6342. return;
  6343. }
  6344. }
  6345. trimSlash(tagName);
  6346. const char * text = tagName.str();
  6347. if (reading || !strchr(text+1, '@'))
  6348. {
  6349. if (itemName)
  6350. {
  6351. const char * sep = strrchr(text, '/');
  6352. if (sep)
  6353. {
  6354. name.append(sep-text, text);
  6355. itemName->append(strlen(sep+1), sep+1);
  6356. }
  6357. else
  6358. itemName->append(tagName);
  6359. return;
  6360. }
  6361. else
  6362. {
  6363. name.append(tagName);
  6364. }
  6365. }
  6366. }
  6367. }
  6368. else
  6369. {
  6370. IHqlExpression * namedAttr = field->queryProperty(namedAtom);
  6371. if (namedAttr)
  6372. namedAttr->queryChild(0)->queryValue()->getStringValue(name);
  6373. }
  6374. bool useDefaultName = (name.length() == 0);
  6375. if (useDefaultName)
  6376. {
  6377. StringBuffer tagName;
  6378. tagName.append(field->queryName()).toLowerCase();
  6379. name.append(tagName);
  6380. }
  6381. if (itemName && itemName->length() == 0)
  6382. {
  6383. if (useDefaultName)
  6384. itemName->append(defaultItemName);
  6385. else
  6386. {
  6387. itemName->append(name);
  6388. name.clear();
  6389. }
  6390. }
  6391. }
  6392. void extractXmlName(SharedHqlExpr & name, OwnedHqlExpr * itemName, OwnedHqlExpr * valueName, IHqlExpression * field, const char * defaultItemName, bool reading)
  6393. {
  6394. StringBuffer nameText, itemNameText, valueNameText;
  6395. extractXmlName(nameText, itemName ? &itemNameText : NULL, valueName ? &valueNameText : NULL, field, defaultItemName, reading);
  6396. if (valueNameText.length())
  6397. valueName->setown(createConstant(constUnknownVarStringType->castFrom(valueNameText.length(), valueNameText.str())));
  6398. if (itemNameText.length())
  6399. itemName->setown(createConstant(constUnknownVarStringType->castFrom(itemNameText.length(), itemNameText.str())));
  6400. if (nameText.length())
  6401. name.setown(createConstant(constUnknownVarStringType->castFrom(nameText.length(), nameText.str())));
  6402. }
  6403. //-------------------------------------------------------------------------------------------------------------------
  6404. /*
  6405. * the xml schema is being generated
  6406. * there is a dataset with a single element (with xpaths for the element and the row)
  6407. * that element has an xpath of ''
  6408. then generate a simplified schema
  6409. */
  6410. static ITypeInfo * containsSingleSimpleFieldBlankXPath(IHqlExpression * record)
  6411. {
  6412. if (record->numChildren() != 1)
  6413. return NULL;
  6414. IHqlExpression * field = record->queryChild(0);
  6415. if (field->getOperator() != no_field)
  6416. return NULL;
  6417. IHqlExpression * xpath = field->queryProperty(xpathAtom);
  6418. if (!xpath)
  6419. return NULL;
  6420. StringBuffer xpathText;
  6421. if (getStringValue(xpathText, xpath->queryChild(0)).length() != 0)
  6422. return NULL;
  6423. ITypeInfo * type = field->queryType();
  6424. if (type->getTypeCode() == type_alien)
  6425. type = queryAlienType(type)->queryLogicalType();
  6426. return type;
  6427. }
  6428. class EclXmlSchemaBuilder
  6429. {
  6430. public:
  6431. EclXmlSchemaBuilder(ISchemaBuilder & _builder, bool _useXPath)
  6432. : builder(_builder), useXPath(_useXPath)
  6433. {
  6434. }
  6435. void build(IHqlExpression * record) const;
  6436. protected:
  6437. void extractName(StringBuffer & name, StringBuffer * itemName, StringBuffer * valueName, IHqlExpression * field, const char * defaultItemName) const;
  6438. protected:
  6439. ISchemaBuilder & builder;
  6440. bool useXPath;
  6441. };
  6442. void EclXmlSchemaBuilder::build(IHqlExpression * record) const
  6443. {
  6444. StringBuffer name, childName;
  6445. ForEachChild(i, record)
  6446. {
  6447. IHqlExpression * cur = record->queryChild(i);
  6448. switch (cur->getOperator())
  6449. {
  6450. case no_field:
  6451. {
  6452. ITypeInfo * type = cur->queryType();
  6453. switch (cur->queryType()->getTypeCode())
  6454. {
  6455. case type_row:
  6456. {
  6457. extractName(name.clear(), NULL, NULL, cur, NULL);
  6458. builder.beginRecord(name);
  6459. build(cur->queryRecord());
  6460. builder.endRecord(name);
  6461. break;
  6462. }
  6463. case type_set:
  6464. {
  6465. extractName(name.clear(), &childName.clear(), NULL, cur, "Item");
  6466. builder.addSetField(name, childName, *type);
  6467. break;
  6468. }
  6469. case type_dictionary:
  6470. case type_table:
  6471. case type_groupedtable:
  6472. {
  6473. extractName(name.clear(), &childName.clear(), NULL, cur, "Row");
  6474. ITypeInfo * singleFieldType = (useXPath && name.length() && childName.length()) ? containsSingleSimpleFieldBlankXPath(cur->queryRecord()) : NULL;
  6475. if (!singleFieldType || !builder.addSingleFieldDataset(name, childName, *singleFieldType))
  6476. {
  6477. if (builder.beginDataset(name, childName))
  6478. build(cur->queryRecord());
  6479. builder.endDataset(name, childName);
  6480. }
  6481. break;
  6482. }
  6483. case type_alien:
  6484. type = queryAlienType(type)->queryLogicalType();
  6485. default:
  6486. extractName(name.clear(), NULL, NULL, cur, NULL);
  6487. builder.addField(name, *type);
  6488. break;
  6489. }
  6490. break;
  6491. }
  6492. case no_ifblock:
  6493. builder.beginIfBlock();
  6494. build(cur->queryChild(1));
  6495. builder.endIfBlock();
  6496. break;
  6497. case no_record:
  6498. build(cur);
  6499. break;
  6500. }
  6501. }
  6502. }
  6503. void EclXmlSchemaBuilder::extractName(StringBuffer & name, StringBuffer * itemName, StringBuffer * valueName, IHqlExpression * field, const char * defaultItemName) const
  6504. {
  6505. if (useXPath)
  6506. {
  6507. ::extractXmlName(name, itemName, valueName, field, defaultItemName, false);
  6508. }
  6509. else
  6510. {
  6511. name.append(field->queryName()).toLowerCase();
  6512. if (itemName)
  6513. itemName->append(defaultItemName);
  6514. }
  6515. }
  6516. void getRecordXmlSchema(StringBuffer & result, IHqlExpression * record, bool useXPath)
  6517. {
  6518. XmlSchemaBuilder xmlbuilder(false);
  6519. EclXmlSchemaBuilder builder(xmlbuilder, useXPath);
  6520. builder.build(record);
  6521. xmlbuilder.getXml(result);
  6522. }
  6523. //---------------------------------------------------------------------------
  6524. static IHqlExpression * simplifyInExpr(IHqlExpression * expr)
  6525. {
  6526. IHqlExpression * ret = querySimplifyInExpr(expr);
  6527. if (ret)
  6528. return ret;
  6529. return LINK(expr);
  6530. }
  6531. IHqlExpression * querySimplifyInExpr(IHqlExpression * expr)
  6532. {
  6533. node_operator op = expr->getOperator();
  6534. switch (op)
  6535. {
  6536. case no_in:
  6537. case no_notin:
  6538. break;
  6539. default:
  6540. return NULL;
  6541. }
  6542. IHqlExpression * lhs = expr->queryChild(0);
  6543. IHqlExpression * rhs = expr->queryChild(1);
  6544. HqlExprArray args;
  6545. OwnedHqlExpr ret;
  6546. switch (rhs->getOperator())
  6547. {
  6548. case no_addsets:
  6549. {
  6550. OwnedHqlExpr newLeft = createBoolExpr(op, LINK(lhs), LINK(rhs->queryChild(0)));
  6551. OwnedHqlExpr newRight = createBoolExpr(op, LINK(lhs), LINK(rhs->queryChild(1)));
  6552. args.append(*simplifyInExpr(newLeft));
  6553. args.append(*simplifyInExpr(newRight));
  6554. ret.setown(createValue((op == no_in) ? no_or : no_and, makeBoolType(), args));
  6555. break;
  6556. }
  6557. case no_if:
  6558. {
  6559. OwnedHqlExpr newLeft = createBoolExpr(op, LINK(lhs), LINK(rhs->queryChild(1)));
  6560. OwnedHqlExpr newRight = createBoolExpr(op, LINK(lhs), LINK(rhs->queryChild(2)));
  6561. args.append(*LINK(rhs->queryChild(0)));
  6562. args.append(*simplifyInExpr(newLeft));
  6563. args.append(*simplifyInExpr(newRight));
  6564. ret.setown(createValue(no_if, makeBoolType(), args));
  6565. break;
  6566. }
  6567. }
  6568. if (ret)
  6569. return expr->cloneAllAnnotations(ret);
  6570. return NULL;
  6571. }
  6572. bool canSetBeAll(IHqlExpression * expr)
  6573. {
  6574. if (!expr)
  6575. return false;
  6576. switch (expr->getOperator())
  6577. {
  6578. case no_createset:
  6579. case no_list:
  6580. return false;
  6581. //more: no_addsets, no_if
  6582. case no_if:
  6583. return canSetBeAll(expr->queryChild(1)) || canSetBeAll(expr->queryChild(2));
  6584. case no_cast:
  6585. case no_implicitcast:
  6586. return canSetBeAll(expr->queryChild(0));
  6587. }
  6588. return true;
  6589. }
  6590. extern HQL_API bool hasNonNullRecord(ITypeInfo * type)
  6591. {
  6592. IHqlExpression * record = queryRecord(type);
  6593. if (!record)
  6594. return false;
  6595. return record->numChildren() != 0;
  6596. }
  6597. extern HQL_API IHqlExpression * createSizeof(IHqlExpression * expr)
  6598. {
  6599. return createValue(no_sizeof, LINK(sizetType), LINK(expr));
  6600. }
  6601. extern HQL_API bool allParametersHaveDefaults(IHqlExpression * function)
  6602. {
  6603. assertex(function->isFunction());
  6604. IHqlExpression * formals = queryFunctionParameters(function);
  6605. IHqlExpression * defaults = queryFunctionDefaults(function);
  6606. ForEachChild(idx, formals)
  6607. {
  6608. IHqlExpression * defvalue = queryDefaultValue(defaults, idx);
  6609. if (!defvalue)
  6610. return false;
  6611. }
  6612. return true;
  6613. }
  6614. extern HQL_API bool expandMissingDefaultsAsStoreds(HqlExprArray & args, IHqlExpression * function)
  6615. {
  6616. assertex(function->isFunction());
  6617. IHqlExpression * formals = queryFunctionParameters(function);
  6618. IHqlExpression * defaults = queryFunctionDefaults(function);
  6619. try
  6620. {
  6621. ForEachChild(idx, formals)
  6622. {
  6623. IHqlExpression *formal = formals->queryChild(idx);
  6624. IHqlExpression * defvalue = queryDefaultValue(defaults, idx);
  6625. if (defvalue)
  6626. {
  6627. args.append(*LINK(defvalue));
  6628. }
  6629. else
  6630. {
  6631. OwnedHqlExpr nullValue = createNullExpr(formal->queryType());
  6632. OwnedHqlExpr storedName = createConstant(formal->queryName()->str());
  6633. OwnedHqlExpr stored = createValue(no_stored, makeVoidType(), storedName.getClear());
  6634. HqlExprArray colonArgs;
  6635. colonArgs.append(*LINK(nullValue));
  6636. colonArgs.append(*LINK(stored));
  6637. args.append(*createWrapper(no_colon, formal->queryType(), colonArgs));
  6638. }
  6639. }
  6640. }
  6641. catch (IException * e)
  6642. {
  6643. e->Release();
  6644. return false;
  6645. }
  6646. return true;
  6647. }
  6648. //--------------------------------------------------------------------------------------------------------------------
  6649. const unsigned maxSensibleInlineElementSize = 10000;
  6650. class ConstantRowCreator
  6651. {
  6652. public:
  6653. ConstantRowCreator(MemoryBuffer & _out) : out(_out) { expectedIndex = 0; }
  6654. bool buildTransformRow(IHqlExpression * transform);
  6655. protected:
  6656. bool expandAssignChildren(IHqlExpression * expr);
  6657. bool expandAssignElement(IHqlExpression * expr);
  6658. bool processElement(IHqlExpression * expr, IHqlExpression * parentSelector);
  6659. bool processFieldValue(IHqlExpression * optField, ITypeInfo * lhsType, IHqlExpression * rhs);
  6660. bool processRecord(IHqlExpression * record, IHqlExpression * parentSelector);
  6661. IHqlExpression * queryMatchingAssign(IHqlExpression * self, IHqlExpression * search);
  6662. protected:
  6663. Owned<NestedHqlMapTransformer> mapper;
  6664. MemoryBuffer & out;
  6665. HqlExprCopyArray assigns;
  6666. unsigned expectedIndex;
  6667. };
  6668. bool ConstantRowCreator::expandAssignChildren(IHqlExpression * expr)
  6669. {
  6670. ForEachChild(i, expr)
  6671. {
  6672. IHqlExpression * cur = expr->queryChild(i);
  6673. if (!expandAssignElement(cur))
  6674. return false;
  6675. }
  6676. return true;
  6677. }
  6678. bool ConstantRowCreator::expandAssignElement(IHqlExpression * expr)
  6679. {
  6680. switch (expr->getOperator())
  6681. {
  6682. case no_assignall:
  6683. case no_transform:
  6684. case no_newtransform:
  6685. return expandAssignChildren(expr);
  6686. case no_assign:
  6687. assigns.append(*expr);
  6688. return true;
  6689. case no_skip:
  6690. return false;
  6691. case no_alias_scope:
  6692. expandAssignElement(expr->queryChild(0));
  6693. return true;
  6694. case no_attr:
  6695. case no_attr_link:
  6696. case no_attr_expr:
  6697. return true;
  6698. default:
  6699. return false;
  6700. }
  6701. }
  6702. IHqlExpression * ConstantRowCreator::queryMatchingAssign(IHqlExpression * self, IHqlExpression * search)
  6703. {
  6704. const unsigned endIndex = expectedIndex;
  6705. unsigned searchIndex = expectedIndex;
  6706. do
  6707. {
  6708. IHqlExpression & candidate = assigns.item(searchIndex);
  6709. IHqlExpression * lhs = candidate.queryChild(0);
  6710. IHqlExpression * candidateField = lhs->queryChild(1);
  6711. searchIndex++;
  6712. if (searchIndex == assigns.ordinality())
  6713. searchIndex = 0;
  6714. if (candidateField == search)
  6715. {
  6716. expectedIndex = searchIndex;
  6717. return &candidate;
  6718. }
  6719. } while (searchIndex != endIndex);
  6720. throwUnexpected();
  6721. }
  6722. bool ConstantRowCreator::processFieldValue(IHqlExpression * optLhs, ITypeInfo * lhsType, IHqlExpression * rhs)
  6723. {
  6724. size32_t lenLhs = lhsType->getStringLen();
  6725. size32_t sizeLhs = lhsType->getSize();
  6726. node_operator rhsOp = rhs->getOperator();
  6727. switch (lhsType->getTypeCode())
  6728. {
  6729. case type_packedint:
  6730. if (!rhs->queryValue())
  6731. return false;
  6732. //MORE: Could handle this...
  6733. return false;
  6734. case type_set:
  6735. if (isNullList(rhs))
  6736. {
  6737. out.append(false);
  6738. rtlWriteSize32t(out.reserve(sizeof(size32_t)), 0);
  6739. return true;
  6740. }
  6741. if (rhsOp == no_all)
  6742. {
  6743. out.append(true);
  6744. rtlWriteSize32t(out.reserve(sizeof(size32_t)), 0);
  6745. return true;
  6746. }
  6747. if (rhsOp == no_list)
  6748. {
  6749. ITypeInfo * elemType = lhsType->queryChildType();
  6750. out.append(false);
  6751. unsigned patchOffset = out.length();
  6752. out.reserve(sizeof(size32_t));
  6753. const size_t startOffset = out.length();
  6754. ForEachChild(i, rhs)
  6755. {
  6756. if (!processFieldValue(NULL, elemType, rhs->queryChild(i)))
  6757. return false;
  6758. }
  6759. const size_t setLength = out.length() - startOffset;
  6760. out.writeDirect(patchOffset, sizeof(size32_t), &setLength);
  6761. byte * patchPos = (byte *)out.bufferBase() + patchOffset;
  6762. rtlWriteSize32t(patchPos, setLength);
  6763. return true;
  6764. }
  6765. return false;
  6766. case type_row:
  6767. if (rhsOp == no_null)
  6768. return createConstantNullRow(out, queryOriginalRecord(lhsType));
  6769. if (rhsOp == no_createrow)
  6770. return createConstantRow(out, rhs->queryChild(0));
  6771. return false;
  6772. case type_dictionary:
  6773. case type_table:
  6774. case type_groupedtable:
  6775. {
  6776. assertex(optLhs);
  6777. IHqlExpression * field = optLhs->queryChild(1);
  6778. if (!field->hasProperty(countAtom) && !field->hasProperty(sizeofAtom))
  6779. {
  6780. if (rhsOp == no_null)
  6781. {
  6782. if (field->hasProperty(_linkCounted_Atom))
  6783. {
  6784. rtlWriteSize32t(out.reserve(sizeof(size32_t)), 0);
  6785. memset(out.reserve(sizeof(byte * *)), 0, sizeof(byte * *));
  6786. }
  6787. else
  6788. rtlWriteSize32t(out.reserve(sizeof(size32_t)), 0);
  6789. return true;
  6790. }
  6791. //MORE: Could expand if doesn't have linkcounted, but less likely these days.
  6792. }
  6793. return false;
  6794. }
  6795. }
  6796. if ((lenLhs != UNKNOWN_LENGTH) && (lenLhs > maxSensibleInlineElementSize))
  6797. return false;
  6798. OwnedHqlExpr castRhs = ensureExprType(rhs, lhsType);
  6799. IValue * castValue = castRhs->queryValue();
  6800. if (!castValue)
  6801. return false;
  6802. if (optLhs && mapper)
  6803. mapper->setMapping(optLhs, castRhs);
  6804. ITypeInfo * castValueType = castValue->queryType();
  6805. size32_t lenValue = castValueType->getStringLen();
  6806. assertex(lenLhs == UNKNOWN_LENGTH || lenLhs == lenValue);
  6807. switch (lhsType->getTypeCode())
  6808. {
  6809. case type_boolean:
  6810. case type_int:
  6811. case type_swapint:
  6812. case type_real:
  6813. case type_decimal:
  6814. {
  6815. void * temp = out.reserve(sizeLhs);
  6816. castValue->toMem(temp);
  6817. return true;
  6818. }
  6819. case type_data:
  6820. case type_string:
  6821. {
  6822. if (lenLhs == UNKNOWN_LENGTH)
  6823. rtlWriteInt4(out.reserve(sizeof(size32_t)), lenValue);
  6824. castValue->toMem(out.reserve(lenValue));
  6825. return true;
  6826. }
  6827. case type_varstring:
  6828. {
  6829. //Move to else
  6830. if (sizeLhs == UNKNOWN_LENGTH)
  6831. {
  6832. void * target = out.reserve(lenValue+1);
  6833. castValue->toMem(target);
  6834. }
  6835. else
  6836. {
  6837. //Disabled for the moment to prevent the size of generated expressions getting too big.
  6838. if (sizeLhs > 40)
  6839. return false;
  6840. void * target = out.reserve(sizeLhs);
  6841. memset(target, ' ', sizeLhs); // spaces expand better in the c++
  6842. castValue->toMem(target);
  6843. }
  6844. return true;
  6845. }
  6846. case type_unicode:
  6847. case type_qstring:
  6848. {
  6849. if (lenLhs == UNKNOWN_LENGTH)
  6850. rtlWriteInt4(out.reserve(sizeof(size32_t)), lenValue);
  6851. castValue->toMem(out.reserve(castValueType->getSize()));
  6852. return true;
  6853. }
  6854. //MORE:
  6855. //type_varunicode
  6856. //type_packedint
  6857. }
  6858. return false;
  6859. }
  6860. bool ConstantRowCreator::processElement(IHqlExpression * expr, IHqlExpression * parentSelector)
  6861. {
  6862. switch (expr->getOperator())
  6863. {
  6864. case no_ifblock:
  6865. {
  6866. OwnedHqlExpr test = replaceSelector(expr->queryChild(0), querySelfReference(), parentSelector);
  6867. OwnedHqlExpr foldedTest = mapper->transformRoot(test);
  6868. foldedTest.setown(foldHqlExpression(foldedTest)); // can only contain references to self, so don't need to worry about other datasets in scope being messed up.
  6869. IValue * foldedValue = foldedTest->queryValue();
  6870. if (!foldedValue)
  6871. return false;
  6872. if (!foldedValue->getBoolValue())
  6873. return true;
  6874. return processRecord(expr->queryChild(1), parentSelector);
  6875. }
  6876. break;
  6877. case no_record:
  6878. return processRecord(expr, parentSelector);
  6879. case no_field:
  6880. {
  6881. IHqlExpression * match = queryMatchingAssign(parentSelector, expr);
  6882. if (!match || (match->getOperator() != no_assign))
  6883. return false;
  6884. return processFieldValue(match->queryChild(0), expr->queryType(), match->queryChild(1));
  6885. }
  6886. default:
  6887. return true;
  6888. }
  6889. }
  6890. bool ConstantRowCreator::processRecord(IHqlExpression * record, IHqlExpression * parentSelector)
  6891. {
  6892. ForEachChild(idx, record)
  6893. {
  6894. if (!processElement(record->queryChild(idx), parentSelector))
  6895. return false;
  6896. }
  6897. return true;
  6898. }
  6899. bool ConstantRowCreator::buildTransformRow(IHqlExpression * transform)
  6900. {
  6901. expectedIndex = 0;
  6902. if (!expandAssignChildren(transform))
  6903. return false;
  6904. //if (recordContainsIfBlock(record))
  6905. mapper.setown(new NestedHqlMapTransformer);
  6906. unsigned savedLength = out.length();
  6907. OwnedHqlExpr self = getSelf(transform);
  6908. if (processRecord(transform->queryRecord(), self))
  6909. return true;
  6910. out.setLength(savedLength);
  6911. return false;
  6912. }
  6913. bool createConstantRow(MemoryBuffer & target, IHqlExpression * transform)
  6914. {
  6915. ConstantRowCreator builder(target);
  6916. return builder.buildTransformRow(transform);
  6917. }
  6918. IHqlExpression * createConstantRowExpr(IHqlExpression * transform)
  6919. {
  6920. MemoryBuffer rowData;
  6921. if (!createConstantRow(rowData, transform))
  6922. return NULL;
  6923. Owned<IValue> value = createDataValue(rowData.toByteArray(), rowData.length());
  6924. return createConstant(value.getClear());
  6925. }
  6926. bool createConstantNullRow(MemoryBuffer & target, IHqlExpression * record)
  6927. {
  6928. //MORE: More efficient to not go via a temporary transform
  6929. OwnedHqlExpr nullTransform = createClearTransform(record);
  6930. return createConstantRow(target, nullTransform);
  6931. }
  6932. IHqlExpression * createConstantNullRowExpr(IHqlExpression * record)
  6933. {
  6934. //MORE: optimize
  6935. OwnedHqlExpr nullTransform = createClearTransform(record);
  6936. return createConstantRowExpr(nullTransform);
  6937. }
  6938. IHqlExpression * ensureOwned(IHqlExpression * expr)
  6939. {
  6940. if (expr->isDataset())
  6941. {
  6942. if (hasLinkCountedModifier(expr))
  6943. return createDataset(no_owned_ds, LINK(expr));
  6944. }
  6945. return LINK(expr);
  6946. }
  6947. IECLError * annotateExceptionWithLocation(IException * e, IHqlExpression * location)
  6948. {
  6949. StringBuffer errorMsg;
  6950. e->errorMessage(errorMsg);
  6951. unsigned code = e->errorCode();
  6952. return createECLError(code, errorMsg.str(), location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0);
  6953. }
  6954. StringBuffer & appendLocation(StringBuffer & s, IHqlExpression * location, const char * suffix)
  6955. {
  6956. if (location)
  6957. {
  6958. int line = location->getStartLine();
  6959. int column = location->getStartColumn();
  6960. s.append(location->querySourcePath()->str());
  6961. if (line)
  6962. {
  6963. s.append("(").append(location->getStartLine());
  6964. if (column)
  6965. s.append(",").append(location->getStartColumn());
  6966. s.append(")");
  6967. }
  6968. s.append(suffix);
  6969. }
  6970. return s;
  6971. }
  6972. //---------------------------------------------------------------------------------------------------------------------
  6973. static void createMappingAssigns(HqlExprArray & assigns, IHqlExpression * selfSelector, IHqlExpression * oldSelector, IHqlSimpleScope * oldScope, IHqlExpression * newRecord)
  6974. {
  6975. ForEachChild(i, newRecord)
  6976. {
  6977. IHqlExpression * cur = newRecord->queryChild(i);
  6978. switch (cur->getOperator())
  6979. {
  6980. case no_record:
  6981. createMappingAssigns(assigns, selfSelector, oldSelector, oldScope, cur);
  6982. break;
  6983. case no_ifblock:
  6984. createMappingAssigns(assigns, selfSelector, oldSelector, oldScope, cur->queryChild(1));
  6985. break;
  6986. case no_field:
  6987. {
  6988. OwnedHqlExpr oldField = oldScope->lookupSymbol(cur->queryId());
  6989. assertex(oldField);
  6990. OwnedHqlExpr selfSelected = createSelectExpr(LINK(selfSelector), LINK(cur));
  6991. OwnedHqlExpr oldSelected = createSelectExpr(LINK(oldSelector), LINK(oldField));
  6992. if (selfSelected->queryRecord() != oldSelected->queryRecord())
  6993. {
  6994. assertex(oldSelected->isDatarow());
  6995. OwnedHqlExpr childSelf = getSelf(cur);
  6996. OwnedHqlExpr childTransform = createMappingTransform(childSelf, oldSelected);
  6997. OwnedHqlExpr createRowExpr = createRow(no_createrow, childTransform.getClear());
  6998. assigns.append(*createAssign(selfSelected.getClear(), createRowExpr.getClear()));
  6999. }
  7000. else
  7001. assigns.append(*createAssign(selfSelected.getClear(), oldSelected.getClear()));
  7002. }
  7003. }
  7004. }
  7005. }
  7006. IHqlExpression * createMappingTransform(IHqlExpression * selfSelector, IHqlExpression * inSelector)
  7007. {
  7008. HqlExprArray assigns;
  7009. IHqlExpression * selfRecord = selfSelector->queryRecord();
  7010. IHqlExpression * inRecord = inSelector->queryRecord();
  7011. createMappingAssigns(assigns, selfSelector, inSelector, inRecord->querySimpleScope(), selfRecord);
  7012. return createValue(no_transform, makeTransformType(selfRecord->getType()), assigns);
  7013. }
  7014. //---------------------------------------------------------------------------------------------------------------------
  7015. IHqlExpression * expandMacroDefinition(IHqlExpression * expr, HqlLookupContext & ctx, bool reportError)
  7016. {
  7017. assertex(expr->isMacro());
  7018. Owned<IProperties> macroParms = createProperties();
  7019. IHqlExpression * macroBodyExpr;
  7020. if (expr->getOperator() == no_funcdef)
  7021. {
  7022. IHqlExpression * formals = expr->queryChild(1);
  7023. IHqlExpression * defaults = expr->queryChild(2);
  7024. ForEachChild(i, formals)
  7025. {
  7026. IHqlExpression* formal = formals->queryChild(i);
  7027. IHqlExpression* def = queryDefaultValue(defaults, i);
  7028. StringBuffer curParam;
  7029. if (!def || !getFoldedConstantText(curParam, def))
  7030. {
  7031. if (reportError)
  7032. ctx.errs->reportError(HQLERR_CannotSubmitMacroX, "Cannot submit a MACRO with parameters that do no have default values", NULL, 1, 0, 0);
  7033. return NULL;
  7034. }
  7035. macroParms->setProp(formal->queryName()->str(), curParam.str());
  7036. }
  7037. macroBodyExpr = expr->queryChild(0);
  7038. }
  7039. else
  7040. macroBodyExpr = expr;
  7041. IFileContents * macroContents = static_cast<IFileContents *>(macroBodyExpr->queryUnknownExtra());
  7042. size32_t len = macroContents->length();
  7043. //Strangely some macros still have the ENDMACRO on the end, and others don't. This should be removed really.
  7044. StringBuffer macroText;
  7045. macroText.append(len, macroContents->getText());
  7046. if ((len >= 8) && strieq(macroText.str()+(len-8),"ENDMACRO"))
  7047. macroText.setLength(len-8);
  7048. //Now append a semi colon since that is how macros are normally called.
  7049. macroText.append(";");
  7050. //This might be cleaner if it was implemented by parsing the text myModule.myAttribute().
  7051. //It would make implementing default parameters easy. However it could introduce other problems
  7052. //with implicitly importing myModule.
  7053. Owned<IFileContents> mappedContents = createFileContentsFromText(macroText.length(), macroText.str(), macroContents->querySourcePath());
  7054. Owned<IHqlScope> scope = createPrivateScope();
  7055. if (queryLegacyEclSemantics())
  7056. importRootModulesToScope(scope, ctx);
  7057. return parseQuery(scope, mappedContents, ctx, NULL, macroParms, true);
  7058. }
  7059. static IHqlExpression * transformAttributeToQuery(IHqlExpression * expr, HqlLookupContext & ctx)
  7060. {
  7061. if (expr->isMacro())
  7062. return expandMacroDefinition(expr, ctx, true);
  7063. if (expr->isFunction())
  7064. {
  7065. //If a scope with parameters then assume we are building a library.
  7066. if (expr->isScope())
  7067. return LINK(expr);
  7068. HqlExprArray actuals;
  7069. if (!allParametersHaveDefaults(expr))
  7070. {
  7071. if (!expandMissingDefaultsAsStoreds(actuals, expr))
  7072. {
  7073. //For each parameter that doesn't have a default, create a stored variable of the appropriate type
  7074. //with a null value as the default value, and use that.
  7075. const char * name = expr->queryName()->str();
  7076. StringBuffer msg;
  7077. msg.appendf("Definition %s() does not supply default values for all parameters", name ? name : "");
  7078. ctx.errs->reportError(HQLERR_CannotSubmitFunction, msg.str(), NULL, 1, 0, 0);
  7079. return NULL;
  7080. }
  7081. }
  7082. return createBoundFunction(ctx.errs, expr, actuals, ctx.functionCache, ctx.queryExpandCallsWhenBound());
  7083. }
  7084. if (expr->isScope())
  7085. {
  7086. IHqlScope * scope = expr->queryScope();
  7087. OwnedHqlExpr main = scope->lookupSymbol(createIdAtom("main"), LSFpublic, ctx);
  7088. if (main)
  7089. return main.getClear();
  7090. StringBuffer msg;
  7091. const char * name = scope->queryFullName();
  7092. msg.appendf("Module %s does not EXPORT an attribute main()", name ? name : "");
  7093. ctx.errs->reportError(HQLERR_CannotSubmitModule, msg.str(), NULL, 1, 0, 0);
  7094. return NULL;
  7095. }
  7096. return LINK(expr);
  7097. }
  7098. IHqlExpression * convertAttributeToQuery(IHqlExpression * expr, HqlLookupContext & ctx)
  7099. {
  7100. OwnedHqlExpr query = LINK(expr);
  7101. loop
  7102. {
  7103. OwnedHqlExpr transformed = transformAttributeToQuery(query, ctx);
  7104. if (!transformed || transformed == query)
  7105. return transformed.getClear();
  7106. query.set(transformed);
  7107. }
  7108. }
  7109. bool isSetWithUnknownElementSize(ITypeInfo * type)
  7110. {
  7111. switch (type->getTypeCode())
  7112. {
  7113. case type_set:
  7114. case type_array:
  7115. return isUnknownSize(type->queryChildType());
  7116. }
  7117. return false;
  7118. }
  7119. IHqlExpression * replaceParameters(IHqlExpression * body, IHqlExpression * oldParams, IHqlExpression * newParams)
  7120. {
  7121. HqlMapTransformer simpleTransformer;
  7122. ForEachChild(i, oldParams)
  7123. {
  7124. IHqlExpression * from = oldParams->queryChild(i);
  7125. IHqlExpression * to = newParams->queryChild(i);
  7126. simpleTransformer.setMapping(from, to);
  7127. }
  7128. return simpleTransformer.transformRoot(body);
  7129. }
  7130. //---------------------------------------------------------------------------------------------------------------------
  7131. /*
  7132. Aliases are nasty...they can occur in two different situations
  7133. i) The user specifies TABLE(x) to create an alias
  7134. ii) The scope checking spots that an alias is being implicitly created.
  7135. 1) exists(join(ds, ds, left.id*3=right.id));
  7136. ds_1 := table(ds);
  7137. ds(exists(ds_1(ds_1.id=ds.id*3)));
  7138. a) ds is a table
  7139. b) ds is a filtered table.
  7140. c) ds is an implicitly normalized dataset (ds.child);
  7141. d) ds is a projected table
  7142. e) ds is a filtered projected table.
  7143. 2) ds(exists(join(child, child, left.id*3=right.id)));
  7144. child_1 = table(ds.child);
  7145. ds(exists(child(exists(child1(child_1.id = child.id*3)));
  7146. a) ds is a table
  7147. b) ds is a filtered table.
  7148. c) ds is an implicitly normalized dataset (ds.child);
  7149. d) ds is a projected table
  7150. e) ds is a filtered projected table.
  7151. When either of these occurs a no_dataset_alias node is added to the tree with a unique id. We don't want to modify
  7152. any of the input datasets - because we want them to stay common as long as possible - otherwise code like
  7153. ds(field in ds(filter)) would cause ds to become split in two - and it should mean the same thing.
  7154. For implicit aliases they will be added around the dataset that is ambiguous.
  7155. - It would be simpler to add them around the table that is ambiguous (Table is a dataset that defines a column list)
  7156. but that means that sort, filters etc. aren't commoned up.
  7157. - When the code is actually generated the base table is modified - which ensures no ambiguous expressions are
  7158. actually present when generating.
  7159. E.g,
  7160. x := ds(a <> 0);
  7161. x(b in set(x(c <> 0), b))
  7162. becomes
  7163. x := ds(a <> 0);
  7164. x' = table(x);
  7165. x'(b in set(x(c <> 0), b))
  7166. To avoid that the aliases is not added around a dataset that has already been aliased in the dataset that uses it.
  7167. When the expression comes to be generated/evaluated, the underlying table of the dataset expression is modified to
  7168. include a unique id. The root table doesn't need to be modified because no selectors for that can be in scope.
  7169. */
  7170. IHqlExpression * queryTableOrSplitter(IHqlExpression * expr)
  7171. {
  7172. loop
  7173. {
  7174. node_operator op = expr->getOperator();
  7175. if (op == no_compound)
  7176. expr = expr->queryChild(1);
  7177. else if (definesColumnList(expr))
  7178. return expr;
  7179. else if (op == no_split)
  7180. return expr;
  7181. else
  7182. expr = expr->queryChild(0);
  7183. }
  7184. }
  7185. //Convert no_dataset_alias(expr, uid) to expr'
  7186. IHqlExpression * normalizeDatasetAlias(IHqlExpression * expr)
  7187. {
  7188. IHqlExpression * uid = expr->queryProperty(_uid_Atom);
  7189. assertex(uid);
  7190. IHqlExpression * dataset = expr->queryChild(0);
  7191. IHqlExpression * table = queryTableOrSplitter(dataset);
  7192. //If the alias is based on a splitter then we need to ensure the splitter expression stays the same - otherwise
  7193. //if won't be commoned up. So add a alias with a _normalized_Atom to ensure everything followed that will be
  7194. //unique. Otherwise add a unique id onto the underlying table to ensure unique expressions.
  7195. OwnedHqlExpr newTable;
  7196. node_operator tableOp = table->getOperator();
  7197. if ((tableOp == no_split) || (tableOp == no_rows))
  7198. newTable.setown(createDataset(no_dataset_alias, LINK(table), createComma(createUniqueId(), createAttribute(_normalized_Atom))));
  7199. else
  7200. newTable.setown(appendOwnedOperand(table, LINK(uid)));
  7201. return replaceDataset(dataset, table, newTable);
  7202. }
  7203. //---------------------------------------------------------------------------------------------------------------------
  7204. //This should only be called on source activities, and on inline datasets.
  7205. IHqlExpression * normalizeAnyDatasetAliases(IHqlExpression * expr)
  7206. {
  7207. //It is useful to also be able to call this on no_sum(aliased-dataset)
  7208. if (!containsDatasetAliasLocally(expr) && !expr->isAggregate())
  7209. return LINK(expr);
  7210. node_operator op = expr->getOperator();
  7211. IHqlExpression * selector = NULL;
  7212. switch (getChildDatasetType(expr))
  7213. {
  7214. case childdataset_none:
  7215. if ((op == no_select) && isNewSelector(expr))
  7216. break;
  7217. return LINK(expr);
  7218. case childdataset_dataset:
  7219. case childdataset_dataset_noscope:
  7220. case childdataset_datasetleft:
  7221. case childdataset_top_left_right:
  7222. selector = expr->queryChild(0)->queryNormalizedSelector();
  7223. break;
  7224. case childdataset_left:
  7225. case childdataset_leftright:
  7226. case childdataset_many:
  7227. case childdataset_many_noscope:
  7228. break;
  7229. default:
  7230. return LINK(expr);
  7231. throwUnexpected();
  7232. }
  7233. bool same = true;
  7234. HqlExprArray args;
  7235. unsigned max = getNumChildTables(expr);
  7236. for (unsigned i=0; i < max; i++)
  7237. {
  7238. IHqlExpression * dataset = expr->queryChild(i);
  7239. OwnedHqlExpr newDataset = normalizeAnyDatasetAliases(dataset);
  7240. if (dataset != newDataset)
  7241. same = false;
  7242. args.append(*newDataset.getClear());
  7243. }
  7244. OwnedHqlExpr transformed;
  7245. if (same)
  7246. transformed.set(expr);
  7247. else
  7248. {
  7249. if (selector)
  7250. {
  7251. assertex(max == 1);
  7252. replaceSelectors(args, expr, max, selector, args.item(0).queryNormalizedSelector());
  7253. }
  7254. else
  7255. unwindChildren(args, expr, max);
  7256. transformed.setown(expr->clone(args));
  7257. }
  7258. if ((op == no_dataset_alias) && !transformed->hasProperty(_normalized_Atom))
  7259. return normalizeDatasetAlias(transformed);
  7260. return transformed.getClear();
  7261. }
  7262. bool userPreventsSort(IHqlExpression * noSortAttr, node_operator side)
  7263. {
  7264. if (!noSortAttr)
  7265. return false;
  7266. IHqlExpression * child = noSortAttr->queryChild(0);
  7267. if (!child)
  7268. return true;
  7269. IAtom * name = child->queryName();
  7270. if (side == no_left)
  7271. return name == leftAtom;
  7272. if (side == no_right)
  7273. return name == rightAtom;
  7274. throwUnexpected();
  7275. }
  7276. //-------------------------------------------------------------------------------------------------
  7277. IHqlExpression * queryTransformAssign(IHqlExpression * transform, IHqlExpression * searchField)
  7278. {
  7279. ForEachChild(i, transform)
  7280. {
  7281. IHqlExpression * cur = transform->queryChild(i);
  7282. switch (cur->getOperator())
  7283. {
  7284. case no_assignall:
  7285. {
  7286. IHqlExpression * ret = queryTransformAssign(cur, searchField);
  7287. if (ret)
  7288. return ret;
  7289. break;
  7290. }
  7291. case no_assign:
  7292. {
  7293. IHqlExpression * lhs = cur->queryChild(0)->queryChild(1);
  7294. if (lhs == searchField)
  7295. return cur;
  7296. break;
  7297. }
  7298. }
  7299. }
  7300. return NULL;
  7301. }
  7302. IHqlExpression * queryTransformAssignValue(IHqlExpression * transform, IHqlExpression * searchField)
  7303. {
  7304. IHqlExpression * value = queryTransformAssign(transform, searchField);
  7305. if (value)
  7306. return value->queryChild(1);
  7307. return NULL;
  7308. }