hqlhtcpp.cpp 700 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404
  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 <exception>
  15. #include "platform.h"
  16. #include "jlib.hpp"
  17. #include "jmisc.hpp"
  18. #include "jstream.ipp"
  19. #include "jdebug.hpp"
  20. #include "rtldynfield.hpp"
  21. #include "build-config.h"
  22. #include "hql.hpp"
  23. #include "hqlthql.hpp"
  24. #include "hqlmeta.hpp"
  25. #include "hqlutil.hpp"
  26. #include "hqlpmap.hpp"
  27. #include "hqlattr.hpp"
  28. #include "hqlerrors.hpp"
  29. #include "hqlvalid.hpp"
  30. #include "hqlerror.hpp"
  31. #include "hqlhtcpp.ipp"
  32. #include "hqlttcpp.ipp"
  33. #include "hqlwcpp.hpp"
  34. #include "hqlcpputil.hpp"
  35. #include "hqltcppc.ipp"
  36. #include "hqlopt.hpp"
  37. #include "hqlfold.hpp"
  38. #include "hqlcerrors.hpp"
  39. #include "hqlcatom.hpp"
  40. #include "hqllib.ipp"
  41. #include "hqlresource.hpp"
  42. #include "hqlregex.ipp"
  43. #include "hqlsource.ipp"
  44. #include "hqlcse.ipp"
  45. #include "hqlgraph.ipp"
  46. #include "hqlscope.hpp"
  47. #include "hqlccommon.hpp"
  48. #include "deffield.hpp"
  49. #include "hqlinline.hpp"
  50. #include "hqlusage.hpp"
  51. #include "hqlhoist.hpp"
  52. #include "hqlcppds.hpp"
  53. //The following are include to ensure they call compile...
  54. #include "eclhelper.hpp"
  55. #include "eclrtl_imp.hpp"
  56. #include "rtlfield.hpp"
  57. #include "rtlds_imp.hpp"
  58. #include "eclhelper_base.hpp"
  59. #include "ctfile.hpp" // for KEYBUILD_MAXLENGTH
  60. #define MAX_ROWS_OUTPUT_TO_SDS 1000
  61. #define MAX_SAFE_RECORD_SIZE 10000000
  62. #define MAX_GRAPH_ECL_LENGTH 1000
  63. #define MAX_ROW_VALUE_TEXT_LEN 10
  64. //#define TRACE_META_TO_GRAPH
  65. //#define FLATTEN_DATASETS
  66. //#define TraceTableFields
  67. //#define TRACE_ASSIGN_MATCH
  68. //#define TRACE_DUMPTREE
  69. //#define _GATHER_USAGE_STATS
  70. //#define _SR6_
  71. #define MAX_CSV_RECORD_SIZE 4096
  72. #define ECLRTL_LIB "eclrtl"
  73. //===========================================================================
  74. #ifdef _GATHER_USAGE_STATS
  75. unsigned activityCounts[TAKlast][TAKlast];
  76. #endif
  77. MODULE_INIT(INIT_PRIORITY_STANDARD)
  78. {
  79. return true;
  80. }
  81. MODULE_EXIT()
  82. {
  83. dumpActivityCounts();
  84. }
  85. //===========================================================================
  86. static const char * TF[2] = {"false","true"};
  87. const char * boolToText(bool value) { return TF[value]; } // is this strictly legal?
  88. //---------------------------------------------------------------------------
  89. /*
  90. When should an activity be executed?
  91. 1. If it is used unconditionally.
  92. and
  93. 2. if
  94. a) It isn't a result of some kind.
  95. or
  96. b) It is an external result
  97. or
  98. b) It is an internal result that is used by something outside this graph.
  99. Any subgraph that contains unconditional activities should be marked with the <attr name="RootGraph" value="1"/>
  100. And activity that should not be executed unconditionally should have _internal set.
  101. */
  102. inline bool isInternalSeq(IHqlExpression * seq)
  103. {
  104. return !seq || matchesConstantValue(seq, ResultSequenceInternal);
  105. }
  106. static void markSubGraphAsRoot(IPropertyTree * tree)
  107. {
  108. if (!tree->hasProp("att[@name=\"rootGraph\"]"))
  109. addGraphAttributeBool(tree, "rootGraph", true);
  110. }
  111. SubGraphInfo * matchActiveGraph(BuildCtx & ctx, IHqlExpression * graphTag)
  112. {
  113. FilteredAssociationIterator iter(ctx, AssocSubGraph);
  114. ForEach(iter)
  115. {
  116. SubGraphInfo & cur = static_cast<SubGraphInfo &>(iter.get());
  117. if (graphTag == cur.graphTag)
  118. return &cur;
  119. }
  120. return NULL;
  121. }
  122. bool isActiveGraph(BuildCtx & ctx, IHqlExpression * graphTag)
  123. {
  124. return matchActiveGraph(ctx, graphTag) != NULL;
  125. }
  126. //---------------------------------------------------------------------------
  127. class InternalResultTracker : public CInterface
  128. {
  129. public:
  130. InternalResultTracker(IHqlExpression * _name, IPropertyTree * _subGraphTree, unsigned _graphSeq, ActivityInstance * _definingActivity)
  131. : name(_name), subGraphTree(_subGraphTree), graphSeq(_graphSeq), definingActivity(_definingActivity)
  132. {
  133. }
  134. bool noteUse(IHqlExpression * searchName, unsigned curGraphSeq);
  135. public:
  136. LinkedHqlExpr name;
  137. Linked<IPropertyTree> subGraphTree;
  138. unsigned graphSeq;
  139. Linked<ActivityInstance> definingActivity;
  140. };
  141. bool InternalResultTracker::noteUse(IHqlExpression * searchName, unsigned curGraphSeq)
  142. {
  143. if (searchName == name)
  144. {
  145. if ((graphSeq != curGraphSeq) && subGraphTree)
  146. {
  147. markSubGraphAsRoot(subGraphTree);
  148. definingActivity->setInternalSink(false);
  149. subGraphTree.clear();
  150. }
  151. return true;
  152. }
  153. return false;
  154. }
  155. //---------------------------------------------------------------------------
  156. IHqlExpression * getMetaUniqueKey(IHqlExpression * record, bool grouped)
  157. {
  158. if (record) record = record->queryBody();
  159. LinkedHqlExpr search = record;
  160. if (grouped)
  161. search.setown(createAttribute(groupedAtom, search.getClear()));
  162. if (!search)
  163. search.setown(createValue(no_null));
  164. return search.getClear();
  165. }
  166. IHqlExpression * getNullStringPointer(bool translated)
  167. {
  168. IHqlExpression * null = createValue(no_nullptr, LINK(constUnknownVarStringType));
  169. if (translated)
  170. return createTranslatedOwned(null);
  171. return null;
  172. }
  173. //---------------------------------------------------------------------------
  174. bool canIterateTableInline(IHqlExpression * expr)
  175. {
  176. switch (expr->getOperator())
  177. {
  178. case no_filter:
  179. return canIterateTableInline(expr->queryChild(0));
  180. case no_field:
  181. case no_select:
  182. return true;
  183. case no_newaggregate:
  184. {
  185. IHqlExpression * child = expr->queryChild(0);
  186. if (!isGrouped(child))
  187. return canIterateTableInline(child);
  188. return false;
  189. }
  190. default:
  191. return false;
  192. }
  193. }
  194. static IHqlExpression * createResultName(IHqlExpression * name)
  195. {
  196. if (!name)
  197. return createQuoted("0", makeReferenceModifier(makeVarStringType(UNKNOWN_LENGTH)));
  198. return LINK(name);
  199. }
  200. //---------------------------------------------------------------------------
  201. ColumnToOffsetMap * RecordOffsetMap::queryMapping(IHqlExpression * record, unsigned maxRecordSize, bool useAccessorClass)
  202. {
  203. OwnedHqlExpr key = useAccessorClass ? createAttribute(classAtom, LINK(record)) : LINK(record);
  204. ColumnToOffsetMap * match = find(key);
  205. if (!match)
  206. {
  207. match = new ColumnToOffsetMap(key, record, ordinality(), 1, maxRecordSize, false, useAccessorClass);
  208. match->init(*this);
  209. addOwn(*match);
  210. }
  211. return match;
  212. }
  213. //---------------------------------------------------------------------------
  214. MemberFunction::MemberFunction(HqlCppTranslator & _translator, BuildCtx & classctx) : translator(_translator), ctx(classctx)
  215. {
  216. }
  217. MemberFunction::MemberFunction(HqlCppTranslator & _translator, BuildCtx & classctx, const char * text, unsigned _flags) : translator(_translator), ctx(classctx), flags(_flags)
  218. {
  219. stmt = ctx.addQuotedFunction(text, (flags & MFdynamicproto) != 0);
  220. }
  221. MemberFunction::~MemberFunction() noexcept(false)
  222. {
  223. //Do not process the aliases if we are aborting from an error
  224. if (!std::uncaught_exception())
  225. finish();
  226. }
  227. void MemberFunction::finish()
  228. {
  229. if (!stmt)
  230. return;
  231. if ((flags & MFopt) && (stmt->numChildren() == 0))
  232. stmt->setIncluded(false);
  233. stmt = nullptr;
  234. }
  235. unsigned MemberFunction::numStmts() const
  236. {
  237. if (!stmt)
  238. return 0;
  239. return calcTotalChildren(stmt);
  240. }
  241. void MemberFunction::setIncluded(bool value)
  242. {
  243. stmt->setIncluded(value);
  244. }
  245. void MemberFunction::setIncomplete(bool value)
  246. {
  247. stmt->setIncomplete(value);
  248. }
  249. void MemberFunction::start(const char * text, unsigned _flags)
  250. {
  251. flags = _flags;
  252. stmt = ctx.addQuotedFunction(text, (flags & MFdynamicproto) != 0);
  253. }
  254. //---------------------------------------------------------------------------
  255. static HqlTransformerInfo childDatasetSpotterInfo("ChildDatasetSpotter");
  256. class NewChildDatasetSpotter : public ConditionalContextTransformer
  257. {
  258. public:
  259. NewChildDatasetSpotter(HqlCppTranslator & _translator, BuildCtx & _ctx, bool _forceRoot)
  260. : ConditionalContextTransformer(childDatasetSpotterInfo, true), translator(_translator), ctx(_ctx), forceRoot(_forceRoot)
  261. {
  262. //The following line forces the conditionalContextTransformer code to generate a single root subgraph.
  263. //An alternative would be to generate one (or more) graphs at the first unconditional place they are
  264. //used. e.g., adding a no_compound(no_childquery, f(no_getgraphresult)) into the tree.
  265. //This was the initial approach, but it causes problems for subsequent optimizations -
  266. //if an optimzation causes an expression containing the no_getgraphresult to be hoisted so it is
  267. //evaluated before the no_childquery it creates an out-of-order dependency.
  268. createRootGraph = true;
  269. }
  270. virtual void analyseExpr(IHqlExpression * expr)
  271. {
  272. switch (pass)
  273. {
  274. case PassFindCandidates:
  275. if (!alreadyVisited(expr->queryBody()))
  276. markHoistPoints(expr);
  277. break;
  278. default:
  279. ConditionalContextTransformer::analyseExpr(expr);
  280. break;
  281. }
  282. }
  283. //MORE: This is a bit of a hack, and should be improved (share code with resource child hoist?)
  284. inline bool walkFurtherDownTree(IHqlExpression * expr)
  285. {
  286. //There are operators which can occur down the tree which may contain datasets
  287. //This should match the analyse code above
  288. switch (expr->getOperator())
  289. {
  290. case no_createrow:
  291. case no_inlinetable:
  292. //The expressions in the transform may contain datasets
  293. case no_addfiles:
  294. case no_datasetfromrow:
  295. case no_datasetfromdictionary:
  296. case no_alias_scope:
  297. //child datasets may have something worth creating a graph for
  298. case no_if:
  299. //The condition may be worth hoisting (and some of the inputs)
  300. return true;
  301. }
  302. return false;
  303. }
  304. void markHoistPoints(IHqlExpression * expr)
  305. {
  306. node_operator op = expr->getOperator();
  307. if (op == no_sizeof)
  308. return;
  309. if (expr->isDataset() || (expr->isDatarow() && (op != no_select)))
  310. {
  311. if (!translator.canAssignInline(&ctx, expr))
  312. {
  313. noteCandidate(expr);
  314. return;
  315. }
  316. if (!walkFurtherDownTree(expr))
  317. return;
  318. }
  319. doAnalyseExpr(expr);
  320. }
  321. IHqlExpression * createTransformed(IHqlExpression * expr)
  322. {
  323. IHqlExpression * body = expr->queryBody(true);
  324. if (expr != body)
  325. return createTransformedAnnotation(expr);
  326. ConditionalContextInfo * extra = queryBodyExtra(expr);
  327. //The following must preceed transforming the children
  328. OwnedHqlExpr subgraph = createDefinitions(extra);
  329. OwnedHqlExpr transformed = ConditionalContextTransformer::createTransformed(expr);
  330. updateOrphanedSelectors(transformed, expr);
  331. assertex(!extra->moveTo);
  332. if (subgraph)
  333. return createCompound(subgraph.getClear(), transformed.getClear());
  334. return transformed.getClear();
  335. }
  336. virtual void transformCandidate(ConditionalContextInfo * candidate)
  337. {
  338. while (builders.ordinality() < insertLocations.ordinality())
  339. builders.append(* new ChildGraphExprBuilder(0));
  340. IHqlExpression * expr = candidate->original;
  341. ConditionalContextInfo * moveTo = candidate->moveTo;
  342. OwnedHqlExpr guard;
  343. if (moveTo)
  344. {
  345. guard.setown(getGuardCondition(moveTo, expr));
  346. //Expressions which are very simple functions of unconditional expressions are treated as if they
  347. //are unconditional
  348. if (moveTo->isUnconditional() && isUsedUnconditionallyEnough(expr))
  349. guard.set(queryBoolExpr(true));
  350. bool invalid = !canDuplicateExpr(guard);
  351. //version 1: don't guard any child queries.
  352. if (!matchesBoolean(guard, true))
  353. {
  354. assertex(moveTo->guards);
  355. //MORE: For the moment disable any expressions that are only used conditionally.
  356. //Often including conditions improves the code, but sometimes the duplicate evaluation of the
  357. //guard conditions in the parent and the child causes excessive code generation.
  358. //And forcing it into an alias doesn't help because that isn't currently executed in the parent.
  359. //Uncomment: if (moveTo->guards->guardContainsCandidate(expr))
  360. {
  361. invalid = true;
  362. }
  363. }
  364. if (invalid)
  365. {
  366. removeDefinition(moveTo, candidate);
  367. moveTo = NULL;
  368. }
  369. }
  370. //A candidate inside a condition that prevents it being moved just creates a definition where it is.
  371. if (!moveTo)
  372. return;
  373. ChildGraphExprBuilder & builder = queryBuilder(moveTo);
  374. IHqlExpression * annotated = candidate->firstAnnotatedExpr ? candidate->firstAnnotatedExpr : expr;
  375. OwnedHqlExpr guarded = createGuardedDefinition(moveTo, annotated, guard);
  376. OwnedHqlExpr transformed = builder.addDataset(guarded);
  377. if (moveTo == candidate)
  378. {
  379. OwnedHqlExpr subgraph = createDefinitions(moveTo);
  380. transformed.setown(createCompound(subgraph.getClear(), transformed.getClear()));
  381. }
  382. setTransformed(expr, transformed);
  383. }
  384. virtual IHqlExpression * createDefinitions(ConditionalContextInfo * extra)
  385. {
  386. if (!extra->hasDefinitions())
  387. return NULL;
  388. ChildGraphExprBuilder & builder = queryBuilder(extra);
  389. OwnedHqlExpr graph = builder.getGraph();
  390. OwnedHqlExpr cleanedGraph = mapExternalToInternalResults(graph, builder.queryRepresents());
  391. return cleanedGraph.getClear();
  392. }
  393. ChildGraphExprBuilder & queryBuilder(ConditionalContextInfo * extra)
  394. {
  395. unsigned match = insertLocations.find(*extra);
  396. assertex(match != NotFound);
  397. return builders.item(match);
  398. }
  399. inline bool isUsedUnconditionallyEnough(IHqlExpression * expr)
  400. {
  401. IHqlExpression * search = expr;
  402. for (;;)
  403. {
  404. if (isUsedUnconditionally(search))
  405. return true;
  406. switch (search->getOperator())
  407. {
  408. case no_newaggregate:
  409. //Hash aggregate is NOT a trivial operation.
  410. if (queryRealChild(search, 3))
  411. return false;
  412. break;
  413. case no_selectnth:
  414. case no_filter:
  415. break;
  416. case no_select:
  417. if (isNewSelector(search))
  418. break;
  419. return false;
  420. default:
  421. return false;
  422. }
  423. search = search->queryChild(0);
  424. }
  425. }
  426. protected:
  427. CIArrayOf<ChildGraphExprBuilder> builders;
  428. HqlCppTranslator & translator;
  429. BuildCtx & ctx;
  430. bool forceRoot;
  431. };
  432. class StatementCollection : public HqlExprArray
  433. {
  434. public:
  435. //Combine multiple conditional assigns, where the guard condition is the same.
  436. //Combine either IF() or CHOOSE()
  437. void combineConditions()
  438. {
  439. unsigned max = ordinality();
  440. for (unsigned first=0; first+1 < max; first++)
  441. {
  442. IHqlExpression & cur = item(first);
  443. if (cur.getOperator() == no_assign)
  444. {
  445. IHqlExpression * rhs = cur.queryChild(1);
  446. if (isCast(rhs))
  447. rhs = rhs->queryChild(0);
  448. node_operator firstOp = rhs->getOperator();
  449. unsigned numFirstChildren = rhs->numChildren();
  450. //Don't combine choose() operators with large numbers of constant values since an array lookup is probably more efficient.
  451. if ((firstOp == no_if) ||
  452. ((firstOp == no_choose) && (numFirstChildren <= 3 || !allBranchesAreConstant(rhs))))
  453. {
  454. IHqlExpression * cond = rhs->queryChild(0);
  455. unsigned next = first+1;
  456. while (next != max)
  457. {
  458. IHqlExpression & nextAssign = item(next);
  459. if (nextAssign.getOperator() != no_assign)
  460. break;
  461. IHqlExpression * nextRhs = nextAssign.queryChild(1);
  462. if (isCast(nextRhs))
  463. nextRhs = nextRhs->queryChild(0);
  464. if (nextRhs->getOperator() != firstOp)
  465. break;
  466. if (nextRhs->queryChild(0) != cond)
  467. break;
  468. if (nextRhs->numChildren() != numFirstChildren)
  469. break;
  470. next++;
  471. }
  472. if (next != first+1)
  473. {
  474. OwnedHqlExpr combined = combineConditionRange(first, next);
  475. replace(*combined.getClear(), first);
  476. unsigned num = (next - first - 1);
  477. removen(first+1, num);
  478. max -= num;
  479. }
  480. }
  481. //MORE: Combine no_case and no_map - but need to be careful,
  482. //because they don't currently have an implementation for actions, so either need to implement, or convert
  483. //to ifs, but also need to be careful we don't make the implementation worse!
  484. }
  485. }
  486. }
  487. void replaceAssignment(IHqlExpression & search, IHqlExpression & newAssign)
  488. {
  489. unsigned match = find(search);
  490. replace(OLINK(newAssign), match);
  491. }
  492. bool onlyOccursOnce(IHqlExpression * expr)
  493. {
  494. return (getNumOccurences(*this, expr, 2) == 1);
  495. }
  496. protected:
  497. bool allBranchesAreConstant(IHqlExpression * expr)
  498. {
  499. ForEachChildFrom(i, expr, 1)
  500. {
  501. IHqlExpression * cur = expr->queryChild(i);
  502. if (!cur->queryValue())
  503. return false;
  504. }
  505. return true;
  506. }
  507. IHqlExpression * extractBranches(unsigned from, unsigned to, unsigned child)
  508. {
  509. StatementCollection assigns;
  510. for (unsigned i=from; i < to; i++)
  511. {
  512. IHqlExpression & cur = item(i);
  513. IHqlExpression * lhs = cur.queryChild(0);
  514. IHqlExpression * rhs = cur.queryChild(1);
  515. OwnedHqlExpr newRhs;
  516. if (isCast(rhs))
  517. {
  518. IHqlExpression * branch = rhs->queryChild(0)->queryChild(child);
  519. newRhs.setown(ensureExprType(branch, rhs->queryType()));
  520. }
  521. else
  522. newRhs.set(rhs->queryChild(child));
  523. assigns.append(*createAssign(LINK(lhs), LINK(newRhs)));
  524. }
  525. assigns.combineConditions();
  526. return createActionList(assigns);
  527. }
  528. IHqlExpression * combineConditionRange(unsigned from, unsigned to)
  529. {
  530. IHqlExpression * firstRhs = item(from).queryChild(1);
  531. IHqlExpression * conditionExpr = isCast(firstRhs) ? firstRhs->queryChild(0) : firstRhs;
  532. HqlExprArray args;
  533. args.append(*LINK(conditionExpr->queryChild(0)));
  534. ForEachChildFrom(i, conditionExpr, 1)
  535. args.append(*extractBranches(from, to, i));
  536. return createValue(conditionExpr->getOperator(), makeVoidType(), args);
  537. }
  538. };
  539. class DelayedStatementExecutor
  540. {
  541. public:
  542. DelayedStatementExecutor(HqlCppTranslator & _translator, BuildCtx & _ctx)
  543. : translator(_translator), buildctx(_ctx)
  544. {
  545. processed = false;
  546. }
  547. void processAssign(BuildCtx & ctx, IHqlExpression * stmt)
  548. {
  549. pending.append(*LINK(stmt));
  550. }
  551. void processAlias(BuildCtx & ctx, IHqlExpression * stmt)
  552. {
  553. pending.append(*LINK(stmt));
  554. }
  555. void processStmts(IHqlExpression * expr)
  556. {
  557. expr->unwindList(pending, no_actionlist);
  558. }
  559. void clear()
  560. {
  561. pending.kill();
  562. processed = false;
  563. }
  564. IHqlExpression * getPrefetchGraph()
  565. {
  566. spotChildDatasets(true);
  567. if (pending.ordinality() == 0)
  568. return NULL;
  569. IHqlExpression & subquery = pending.item(0);
  570. if (subquery.getOperator() == no_childquery)
  571. {
  572. pending.remove(0, true);
  573. return &subquery;
  574. }
  575. return NULL;
  576. }
  577. void flush(BuildCtx & ctx)
  578. {
  579. spotChildDatasets(false);
  580. combineConditions();
  581. optimizeAssigns();
  582. ForEachItemIn(i, pending)
  583. translator.buildStmt(ctx, &pending.item(i));
  584. pending.kill();
  585. }
  586. void optimize()
  587. {
  588. spotChildDatasets(false);
  589. combineConditions();
  590. optimizeAssigns();
  591. }
  592. IHqlExpression * getActionList()
  593. {
  594. OwnedHqlExpr ret = createActionList(pending);
  595. pending.kill();
  596. return ret.getClear();
  597. }
  598. protected:
  599. //Combine multiple conditional assigns, where the guard condition is the same.
  600. void combineConditions()
  601. {
  602. pending.combineConditions();
  603. }
  604. void spotChildDatasets(bool forceRoot)
  605. {
  606. if (!processed && translator.queryCommonUpChildGraphs())
  607. {
  608. HqlExprArray analyseExprs;
  609. ForEachItemIn(i, pending)
  610. {
  611. IHqlExpression & cur = pending.item(i);
  612. IHqlExpression * value = &cur;
  613. switch (value->getOperator())
  614. {
  615. case no_assign:
  616. value = value->queryChild(1);
  617. break;
  618. case no_alias:
  619. case no_skip:
  620. value = value->queryChild(0);
  621. break;
  622. }
  623. if (value)
  624. analyseExprs.append(*LINK(value));
  625. }
  626. NewChildDatasetSpotter spotter(translator, buildctx, forceRoot);
  627. if (spotter.analyseNeedsTransform(analyseExprs))
  628. {
  629. //This could be conditional on whether or not there is an unconditional candidate, but that would stop
  630. //the same expression being commoned up between two conditional branches.
  631. //So, only avoid if 1 conditional candidate used in a single location.
  632. bool worthHoisting = true;
  633. if (!forceRoot)
  634. {
  635. if (spotter.hasSingleConditionalCandidate())
  636. worthHoisting = false;
  637. }
  638. if (worthHoisting)
  639. {
  640. bool createSubQueryBeforeAll = forceRoot;
  641. spotter.transformAll(pending, createSubQueryBeforeAll);
  642. translator.traceExpressions("spotted child", pending);
  643. }
  644. }
  645. processed = true;
  646. }
  647. }
  648. virtual void optimizeAssigns() {}
  649. protected:
  650. HqlCppTranslator & translator;
  651. BuildCtx buildctx;
  652. StatementCollection pending;
  653. bool processed;
  654. };
  655. void HqlCppTranslator::optimizeBuildActionList(BuildCtx & ctx, IHqlExpression * exprs)
  656. {
  657. if ((exprs->getOperator() != no_actionlist) || !activeGraph)
  658. {
  659. buildStmt(ctx, exprs);
  660. return;
  661. }
  662. DelayedStatementExecutor delayed(*this, ctx);
  663. delayed.processStmts(exprs);
  664. delayed.flush(ctx);
  665. }
  666. //---------------------------------------------------------------------------
  667. static IHqlExpression * getExtractMatchingAssign(HqlExprArray & assigns, IHqlExpression * search, unsigned & expectedIndex, IHqlExpression * selfSelector)
  668. {
  669. if (assigns.isItem(expectedIndex))
  670. {
  671. IHqlExpression & candidate = assigns.item(expectedIndex);
  672. IHqlExpression * lhs = candidate.queryChild(0);
  673. IHqlExpression * candidateField = lhs->queryChild(1);
  674. if (candidateField == search)
  675. {
  676. OwnedHqlExpr ret;
  677. if (lhs->queryChild(0) == selfSelector)
  678. ret.set(&candidate);
  679. else
  680. {
  681. IHqlExpression * rhs = candidate.queryChild(1);
  682. ret.setown(createAssign(createSelectExpr(LINK(selfSelector), LINK(candidateField)), LINK(rhs)));
  683. }
  684. expectedIndex++;
  685. return ret.getClear();
  686. }
  687. }
  688. ForEachItemIn(idx, assigns)
  689. {
  690. IHqlExpression & assign = assigns.item(idx);
  691. #ifdef TRACE_ASSIGN_MATCH
  692. PrintLog("Next comparison:");
  693. x.clear().append("target(").append((unsigned)assign.queryChild(0)->queryChild(0)).append(":");
  694. x.appendf("%p", assign.queryChild(0)->queryChild(1)).append(") ");
  695. assign.queryChild(0)->toString(x);
  696. PrintLog(x.str());
  697. x.clear().append("search(").appendf("%p", search).append(") ");
  698. search->toString(x);
  699. PrintLog(x.str());
  700. #endif
  701. IHqlExpression * lhs = assign.queryChild(0);
  702. IHqlExpression * candidateField = lhs->queryChild(1);
  703. if (candidateField == search)
  704. {
  705. OwnedHqlExpr ret;
  706. if (lhs->queryChild(0) == selfSelector)
  707. ret.set(&assign);
  708. else
  709. {
  710. IHqlExpression * rhs = assign.queryChild(1);
  711. ret.setown(createAssign(createSelectExpr(LINK(selfSelector), LINK(candidateField)), LINK(rhs)));
  712. }
  713. expectedIndex = idx+1;
  714. return ret.getClear();
  715. }
  716. }
  717. return NULL;
  718. }
  719. class TransformBuilder : public DelayedStatementExecutor
  720. {
  721. public:
  722. TransformBuilder(HqlCppTranslator & _translator, BuildCtx & _ctx, IHqlExpression * _record, BoundRow * _self, HqlExprArray & _assigns) :
  723. DelayedStatementExecutor(_translator, _ctx), assigns(_assigns), record(_record), self(_self)
  724. {
  725. expectedIndex = 0;
  726. if (translator.recordContainsIfBlock(record))
  727. mapper.setown(new NestedHqlMapTransformer);
  728. }
  729. TransformBuilder(const TransformBuilder & other, BuildCtx & _ctx) :
  730. DelayedStatementExecutor(other.translator, _ctx), mapper(other.mapper), assigns(other.assigns), self(other.self)
  731. {
  732. expectedIndex = 0;
  733. }
  734. void doTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self);
  735. void buildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector);
  736. protected:
  737. virtual void checkAssigned() { }
  738. virtual void onIfBlock(IHqlExpression * expr) { }
  739. virtual void onMissingAssignment(IHqlExpression * expr)
  740. {
  741. StringBuffer s;
  742. expr->toString(s);
  743. throwError2(HQLERR_MissingTransformAssignXX, s.str(), expr);
  744. }
  745. void pushCondition(IHqlExpression * cond)
  746. {
  747. mapper->beginNestedScope();
  748. }
  749. void popCondition()
  750. {
  751. mapper->endNestedScope();
  752. }
  753. void buildTransform(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * parentSelector);
  754. void doBuildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector);
  755. public:
  756. Linked<NestedHqlMapTransformer> mapper;
  757. HqlExprArray & assigns;
  758. LinkedHqlExpr record;
  759. BoundRow * self;
  760. unsigned expectedIndex;
  761. };
  762. void TransformBuilder::buildTransform(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * parentSelector)
  763. {
  764. switch (expr->getOperator())
  765. {
  766. case no_ifblock:
  767. {
  768. onIfBlock(expr);
  769. flush(ctx);
  770. assertex(mapper != NULL);
  771. OwnedHqlExpr test = replaceSelector(expr->queryChild(0), querySelfReference(), parentSelector);
  772. OwnedHqlExpr foldedTest = mapper->transformRoot(test);
  773. foldedTest.setown(foldHqlExpression(foldedTest)); // can only contain references to self, so don't need to worry about other datasets in scope being messed up.
  774. OwnedHqlExpr sizeOfIfBlock = createValue(no_sizeof, makeIntType(4,false), createSelectExpr(LINK(parentSelector), LINK(expr)));
  775. IValue * mappedValue = foldedTest->queryValue();
  776. BuildCtx subctx(ctx);
  777. bool include = true;
  778. if (mappedValue)
  779. {
  780. //Associate the ifblock condition to avoid it being evaluated later when calculating the field offsets
  781. ctx.associateExpr(test, foldedTest);
  782. if (!mappedValue->getBoolValue())
  783. include = false;
  784. }
  785. else
  786. pushCondition(foldedTest);
  787. if (include)
  788. {
  789. translator.buildFilter(subctx, foldedTest);
  790. TransformBuilder childBuilder(*this, subctx);
  791. childBuilder.buildTransformChildren(subctx, expr->queryChild(1), parentSelector);
  792. childBuilder.flush(subctx);
  793. //This calculates the size of the previous block. It means that subsequent uses of the
  794. //offsets are cached - even if they are inside another ifblock().
  795. CHqlBoundExpr bound;
  796. translator.buildCachedExpr(ctx, sizeOfIfBlock, bound);
  797. }
  798. else
  799. {
  800. //This calculates the size of the previous block. It means that subsequent uses of the
  801. //offsets are cached - even if they are inside another ifblock().
  802. OwnedHqlExpr zero = getSizetConstant(0);
  803. ctx.associateExpr(sizeOfIfBlock, zero);
  804. }
  805. if (!mappedValue)
  806. popCondition();
  807. }
  808. break;
  809. case no_record:
  810. doBuildTransformChildren(ctx, expr, parentSelector);
  811. break;
  812. case no_field:
  813. {
  814. OwnedHqlExpr match = getExtractMatchingAssign(assigns, expr, expectedIndex, parentSelector);
  815. if (match)
  816. {
  817. processAssign(ctx, match);
  818. if (mapper && (match->getOperator() == no_assign))
  819. {
  820. IHqlExpression * rhs = match->queryChild(1);
  821. if (rhs->queryValue())
  822. {
  823. IHqlExpression * lhs = match->queryChild(0);
  824. OwnedHqlExpr cast = ensureExprType(rhs, lhs->queryType());
  825. mapper->setMapping(lhs, cast);
  826. }
  827. }
  828. return;
  829. }
  830. onMissingAssignment(expr);
  831. }
  832. break;
  833. case no_attr:
  834. case no_attr_expr:
  835. case no_attr_link:
  836. break;
  837. default:
  838. UNIMPLEMENTED;
  839. }
  840. }
  841. void TransformBuilder::doBuildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector)
  842. {
  843. ForEachChild(idx, record)
  844. buildTransform(ctx, record->queryChild(idx), parentSelector);
  845. }
  846. void TransformBuilder::buildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector)
  847. {
  848. assertex(parentSelector);
  849. expectedIndex = 0;
  850. doBuildTransformChildren(ctx, record, parentSelector);
  851. }
  852. void TransformBuilder::doTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self)
  853. {
  854. IHqlExpression * body = transform->queryBody(true);
  855. if (transform != body)
  856. {
  857. ErrorSeverityMapper::Scope saved(translator.queryLocalOnWarningMapper());
  858. switch (transform->getAnnotationKind())
  859. {
  860. case annotate_meta:
  861. translator.queryLocalOnWarningMapper().processMetaAnnotation(transform);
  862. break;
  863. case annotate_symbol:
  864. translator.queryLocalOnWarningMapper().setSymbol(transform);
  865. break;
  866. }
  867. doTransform(ctx, body, self);
  868. return;
  869. }
  870. if (!isKnownTransform(transform))
  871. {
  872. translator.doUserTransform(ctx, transform, self);
  873. return;
  874. }
  875. translator.filterExpandAssignments(ctx, this, assigns, transform);
  876. IHqlExpression * selfRecord = self->queryRecord();
  877. buildTransformChildren(ctx, selfRecord, self->querySelector());
  878. flush(ctx);
  879. checkAssigned();
  880. //If this is a blank record with the size "fixed" to 1, clear the byte so consistent and disk writes compress well
  881. if (isEmptyRecord(selfRecord) && selfRecord->hasAttribute(_nonEmpty_Atom))
  882. translator.buildClearRecord(ctx, self->querySelector(), selfRecord, 0);
  883. }
  884. class UpdateTransformBuilder : public TransformBuilder
  885. {
  886. friend class UnsafeSelectorReplacer;
  887. public:
  888. UpdateTransformBuilder(HqlCppTranslator & _translator, BuildCtx & _ctx, IHqlExpression * record, BoundRow * _self, IHqlExpression * _prevSelector, HqlExprArray & _assigns, bool _canRemoveLeadingAssigns) :
  889. TransformBuilder(_translator, _ctx, record, _self, _assigns), prevSelector(_prevSelector)
  890. {
  891. aliasInsertPos = 0;
  892. needToReassignAll = false;
  893. canRemoveLeadingAssigns = _canRemoveLeadingAssigns;
  894. }
  895. void ensureAlias(IHqlExpression * expr);
  896. inline bool isUnsafeSelector(IHqlExpression * expr) const
  897. {
  898. return needToReassignAll || unsafeSelectors.contains(*expr);
  899. }
  900. protected:
  901. virtual void checkAssigned() { }
  902. virtual void onIfBlock(IHqlExpression * expr) { throwUnexpected(); }
  903. virtual void onMissingAssignment(IHqlExpression * expr) {}
  904. virtual void optimizeAssigns();
  905. bool isSpecialAssignment(IHqlExpression * assign, node_operator op, IHqlExpression * previous) const;
  906. void optimizeAssigns(IHqlExpression * expr, IHqlExpression * parentSelector);
  907. void optimizeRecordAssigns(IHqlExpression * record, IHqlExpression * parentSelector);
  908. IHqlExpression * replaceUnsafeSelectors(IHqlExpression * rhs);
  909. void optimizeSpecialAssignments(IHqlExpression * expr, IHqlExpression * parentSelector);
  910. void optimizeRecordSpecialAssignments(IHqlExpression * expr, IHqlExpression * parentSelector);
  911. void protectAgainstLeaks(IHqlExpression * expr);
  912. void protectRecordAgainstLeaks(IHqlExpression * expr);
  913. protected:
  914. LinkedHqlExpr prevSelector;
  915. HqlExprArray unsafeSelectors;
  916. HqlExprArray preservedSelectors;
  917. unsigned aliasInsertPos;
  918. bool needToReassignAll;
  919. bool canRemoveLeadingAssigns;
  920. };
  921. void UpdateTransformBuilder::ensureAlias(IHqlExpression * expr)
  922. {
  923. if (!pending.contains(*expr))
  924. pending.add(*LINK(expr), aliasInsertPos++);
  925. }
  926. bool UpdateTransformBuilder::isSpecialAssignment(IHqlExpression * assign, node_operator op, IHqlExpression * previous) const
  927. {
  928. IHqlExpression * rhs = assign->queryChild(1);
  929. if (rhs->getOperator() != op)
  930. return false;
  931. if (rhs->queryChild(0) != previous)
  932. return false;
  933. return true;
  934. }
  935. void UpdateTransformBuilder::optimizeSpecialAssignments(IHqlExpression * expr, IHqlExpression * parentSelector)
  936. {
  937. switch (expr->getOperator())
  938. {
  939. case no_record:
  940. optimizeRecordSpecialAssignments(expr, parentSelector);
  941. break;
  942. case no_field:
  943. {
  944. //check for SELF.x := RIGHT.x <add-file> f(LEFT)
  945. node_operator newOp = no_none;
  946. OwnedHqlExpr previous = createSelectExpr(LINK(prevSelector), LINK(expr));
  947. OwnedHqlExpr match;
  948. if (expr->isDataset())
  949. {
  950. match.setown(getExtractMatchingAssign(pending, expr, expectedIndex, parentSelector));
  951. if (match && isSpecialAssignment(match, no_addfiles, previous))
  952. newOp = no_assign_addfiles;
  953. }
  954. if (newOp && pending.onlyOccursOnce(previous))
  955. {
  956. IHqlExpression * rhs = match->queryChild(1);
  957. OwnedHqlExpr newAssign = createValue(newOp, makeVoidType(), LINK(match->queryChild(0)), LINK(rhs->queryChild(1)));
  958. pending.replaceAssignment(*match, *newAssign);
  959. preservedSelectors.append(*LINK(previous));
  960. }
  961. }
  962. break;
  963. }
  964. }
  965. void UpdateTransformBuilder::optimizeRecordSpecialAssignments(IHqlExpression * record, IHqlExpression * parentSelector)
  966. {
  967. ForEachChild(idx, record)
  968. optimizeSpecialAssignments(record->queryChild(idx), parentSelector);
  969. }
  970. //Ensure all fields from SELF are cloned before they are overwritten.
  971. //If only fixed width fields have been updated so far then any fields not yet assigned can be used
  972. //If a variable width field has been updated all fields updated so far are invalid, and all field that
  973. //follow may have been overwritten => it will need an alias. For simplicity all fields are assumed tainted.
  974. void UpdateTransformBuilder::optimizeAssigns(IHqlExpression * expr, IHqlExpression * parentSelector)
  975. {
  976. switch (expr->getOperator())
  977. {
  978. case no_ifblock:
  979. throwUnexpected();
  980. case no_record:
  981. optimizeRecordAssigns(expr, parentSelector);
  982. break;
  983. case no_field:
  984. {
  985. OwnedHqlExpr match = getExtractMatchingAssign(pending, expr, expectedIndex, parentSelector);
  986. if (match)
  987. {
  988. IHqlExpression * source = match->queryChild(1);
  989. OwnedHqlExpr previous = createSelectExpr(LINK(prevSelector), LINK(expr));
  990. bool usesPrevious = (source != previous) && exprReferencesDataset(source, prevSelector);
  991. bool retainAssign = !canRemoveLeadingAssigns || needToReassignAll || usesPrevious || (match->getOperator() != no_assign) || isGraphDependent(source);
  992. if (retainAssign)
  993. {
  994. IHqlExpression * target = match->queryChild(0);
  995. //Variable offset => all subsequent fields need to be reassigned.
  996. ITypeInfo * type = expr->queryType();
  997. bool hasVariableSize = (type->getSize() == UNKNOWN_LENGTH);
  998. //Potential problems with fixed length strings. Otherwise it should be safe, or go via a temporary
  999. bool safeToAccessSelf = hasVariableSize || !isTypePassedByAddress(type); // not true for some fixed length strings, what else?
  1000. //Any access to this field now needs to go via a temporary
  1001. if (!safeToAccessSelf)
  1002. unsafeSelectors.append(*LINK(previous));
  1003. OwnedHqlExpr safeRhs = replaceUnsafeSelectors(source);
  1004. if (safeToAccessSelf)
  1005. unsafeSelectors.append(*LINK(previous));
  1006. if (hasVariableSize)
  1007. needToReassignAll = true;
  1008. if (safeRhs != source)
  1009. {
  1010. //MORE: Create no_plusequals, no_concat_equals
  1011. OwnedHqlExpr newAssign = createAssign(LINK(target), LINK(safeRhs));
  1012. unsigned pos = pending.find(*match);
  1013. assertex(pos != NotFound);
  1014. pending.replace(*newAssign.getClear(), pos);
  1015. }
  1016. }
  1017. else
  1018. {
  1019. preservedSelectors.append(*LINK(previous));
  1020. pending.zap(*match);
  1021. }
  1022. return;
  1023. }
  1024. }
  1025. break;
  1026. case no_attr:
  1027. case no_attr_expr:
  1028. case no_attr_link:
  1029. break;
  1030. default:
  1031. UNIMPLEMENTED;
  1032. }
  1033. }
  1034. void UpdateTransformBuilder::optimizeRecordAssigns(IHqlExpression * record, IHqlExpression * parentSelector)
  1035. {
  1036. ForEachChild(idx, record)
  1037. optimizeAssigns(record->queryChild(idx), parentSelector);
  1038. }
  1039. void UpdateTransformBuilder::protectAgainstLeaks(IHqlExpression * expr)
  1040. {
  1041. switch (expr->getOperator())
  1042. {
  1043. case no_record:
  1044. protectRecordAgainstLeaks(expr);
  1045. break;
  1046. case no_field:
  1047. {
  1048. if (hasLinkCountedModifier(expr))
  1049. {
  1050. OwnedHqlExpr previous = createSelectExpr(LINK(prevSelector), LINK(expr));
  1051. if (!preservedSelectors.contains(*previous))
  1052. {
  1053. OwnedHqlExpr owned = createAliasOwn(ensureOwned(previous), NULL);
  1054. ensureAlias(owned);
  1055. }
  1056. }
  1057. }
  1058. break;
  1059. }
  1060. }
  1061. void UpdateTransformBuilder::protectRecordAgainstLeaks(IHqlExpression * record)
  1062. {
  1063. ForEachChild(idx, record)
  1064. protectAgainstLeaks(record->queryChild(idx));
  1065. }
  1066. void UpdateTransformBuilder::optimizeAssigns()
  1067. {
  1068. expectedIndex = 0;
  1069. optimizeRecordSpecialAssignments(record, self->querySelector());
  1070. expectedIndex = 0;
  1071. optimizeRecordAssigns(record, self->querySelector());
  1072. protectRecordAgainstLeaks(record);
  1073. }
  1074. static HqlTransformerInfo unsafeSelectorReplacerInfo("UnsafeSelectorReplacer");
  1075. class UnsafeSelectorReplacer : public NewHqlTransformer
  1076. {
  1077. public:
  1078. UnsafeSelectorReplacer(UpdateTransformBuilder & _builder, IHqlExpression * _searchSelector)
  1079. : NewHqlTransformer(unsafeSelectorReplacerInfo), builder(_builder), searchSelector(_searchSelector)
  1080. {
  1081. }
  1082. inline IHqlExpression * getReplacement(IHqlExpression * expr)
  1083. {
  1084. //Yuk if the whole row is referenced the code is not going to be good!
  1085. if (expr == searchSelector)
  1086. return ensureAliased(expr);
  1087. if ((expr->getOperator() == no_select) && (expr->queryChild(0) == searchSelector))
  1088. {
  1089. if (builder.isUnsafeSelector(expr))
  1090. return ensureAliased(expr);
  1091. return LINK(expr);
  1092. }
  1093. return NULL;
  1094. }
  1095. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  1096. {
  1097. IHqlExpression * body = expr->queryBody(true);
  1098. if (expr == body)
  1099. {
  1100. IHqlExpression * replacement = getReplacement(expr);
  1101. if (replacement)
  1102. return replacement;
  1103. return NewHqlTransformer::createTransformed(expr);
  1104. }
  1105. OwnedHqlExpr transformed = transform(body);
  1106. return expr->cloneAnnotation(transformed);
  1107. }
  1108. virtual IHqlExpression * createTransformedSelector(IHqlExpression * expr)
  1109. {
  1110. IHqlExpression * replacement = getReplacement(expr);
  1111. if (replacement)
  1112. return replacement;
  1113. return NewHqlTransformer::createTransformedSelector(expr);
  1114. }
  1115. IHqlExpression * ensureAliased(IHqlExpression * expr)
  1116. {
  1117. OwnedHqlExpr alias = createAlias(expr, NULL);
  1118. builder.ensureAlias(alias);
  1119. return alias.getClear();
  1120. }
  1121. protected:
  1122. UpdateTransformBuilder & builder;
  1123. IHqlExpression * searchSelector;
  1124. };
  1125. IHqlExpression * UpdateTransformBuilder::replaceUnsafeSelectors(IHqlExpression * rhs)
  1126. {
  1127. UnsafeSelectorReplacer replacer(*this, prevSelector);
  1128. return replacer.transformRoot(rhs);
  1129. }
  1130. //---------------------------------------------------------------------------
  1131. void HqlCppTranslator::doFilterAssignment(BuildCtx & ctx, TransformBuilder * builder, HqlExprArray & assigns, IHqlExpression * cur)
  1132. {
  1133. node_operator op = cur->getOperator();
  1134. switch (op)
  1135. {
  1136. case no_assignall:
  1137. case no_newtransform:
  1138. case no_transform:
  1139. case no_alias_scope:
  1140. doFilterAssignments(ctx, builder, assigns, cur);
  1141. break;
  1142. case no_assign:
  1143. assigns.append(*LINK(cur));
  1144. break;
  1145. case no_assert:
  1146. case no_skip:
  1147. case no_alias:
  1148. if (builder)
  1149. builder->processAlias(ctx, cur);
  1150. else
  1151. buildStmt(ctx, cur);
  1152. break;
  1153. case no_attr:
  1154. case no_attr_link:
  1155. case no_attr_expr:
  1156. break;
  1157. default:
  1158. UNIMPLEMENTED;
  1159. }
  1160. }
  1161. void HqlCppTranslator::doFilterAssignments(BuildCtx & ctx, TransformBuilder * builder, HqlExprArray & assigns, IHqlExpression * expr)
  1162. {
  1163. if (expr->getOperator() == no_alias_scope)
  1164. {
  1165. ForEachChildFrom(i, expr, 1)
  1166. doFilterAssignment(ctx, builder, assigns, expr->queryChild(i));
  1167. doFilterAssignment(ctx, builder, assigns, expr->queryChild(0));
  1168. }
  1169. else
  1170. {
  1171. ForEachChild(i, expr)
  1172. doFilterAssignment(ctx, builder, assigns, expr->queryChild(i));
  1173. }
  1174. }
  1175. void HqlCppTranslator::filterExpandAssignments(BuildCtx & ctx, TransformBuilder * builder, HqlExprArray & assigns, IHqlExpression * rawExpr)
  1176. {
  1177. LinkedHqlExpr expr = rawExpr;
  1178. if (options.spotCSE)
  1179. expr.setown(spotScalarCSE(expr, NULL, queryOptions().spotCseInIfDatasetConditions));
  1180. traceExpression("transform cse", expr);
  1181. // expandAliases(ctx, expr);
  1182. doFilterAssignments(ctx, builder, assigns, expr);
  1183. }
  1184. void HqlCppTranslator::associateCounter(BuildCtx & ctx, IHqlExpression * counterExpr, const char * name)
  1185. {
  1186. if (counterExpr)
  1187. {
  1188. OwnedHqlExpr counterVar = createVariable(name, LINK(counterType));
  1189. ctx.associateExpr(counterExpr, counterVar);
  1190. }
  1191. }
  1192. unsigned HqlCppTranslator::getConsistentUID(IHqlExpression * ptr)
  1193. {
  1194. if (!ptr)
  1195. return 0;
  1196. // Allocate consistent numbers helps to regression check the generated code
  1197. if (recordIndexCache.find(ptr) == NotFound)
  1198. recordIndexCache.append(ptr);
  1199. return recordIndexCache.find(ptr)+1;
  1200. }
  1201. unsigned HqlCppTranslator::beginFunctionGetCppIndex(unsigned activityId, bool isChildActivity)
  1202. {
  1203. activitiesThisCpp++;
  1204. if (activitiesThisCpp > options.activitiesPerCpp)
  1205. {
  1206. //Allow 25% over the default number of activities per child in order to reduce the number of activities moved into
  1207. //the header file.
  1208. if (!isChildActivity || activitiesThisCpp > (options.activitiesPerCpp * 5 / 4))
  1209. {
  1210. curCppFile++;
  1211. activitiesThisCpp = 1;
  1212. code->cppInfo.append(* new CppFileInfo(activityId));
  1213. }
  1214. }
  1215. CppFileInfo & curCpp = code->cppInfo.tos();
  1216. if (activityId)
  1217. {
  1218. if (curCpp.minActivityId == 0)
  1219. curCpp.minActivityId = activityId;
  1220. curCpp.maxActivityId = activityId;
  1221. }
  1222. return curCppFile;
  1223. }
  1224. //---------------------------------------------------------------------------
  1225. static IHqlExpression * createResultAttribute(IHqlExpression * seq, IHqlExpression * name)
  1226. {
  1227. //if a named user output then set seq to the name so that workunit reads from the named symbol get commoned up correctly
  1228. if (name && !name->queryType()->isInteger() && (getIntValue(seq, -1) >= 0))
  1229. seq = name;
  1230. return createAttribute(resultAtom, LINK(seq), LINK(name));
  1231. }
  1232. static void associateRemoteResult(BuildCtx & ctx, ABoundActivity * table, IHqlExpression * seq, IHqlExpression * name)
  1233. {
  1234. OwnedHqlExpr attr = createResultAttribute(seq, name);
  1235. OwnedHqlExpr unknown = createUnknown(no_attr, NULL, NULL, LINK(table));
  1236. ctx.associateExpr(attr, unknown);
  1237. }
  1238. void HqlCppTranslator::associateRemoteResult(ActivityInstance & instance, IHqlExpression * seq, IHqlExpression * name)
  1239. {
  1240. ::associateRemoteResult(*activeGraphCtx, instance.table, seq, name);
  1241. if (name && targetRoxie())
  1242. {
  1243. OwnedHqlExpr attr = createResultAttribute(seq, name);
  1244. globalFiles.append(* new GlobalFileTracker(attr, instance.graphNode));
  1245. }
  1246. }
  1247. void HqlCppTranslator::queryAddResultDependancy(ABoundActivity & whoAmIActivity, IHqlExpression * seq, IHqlExpression * name)
  1248. {
  1249. if (activeGraphCtx)
  1250. {
  1251. //Because of extend, we need to find all the possible matches, not just the last one.
  1252. AssociationIterator iter(*activeGraphCtx);
  1253. OwnedHqlExpr attr = createResultAttribute(seq, name);
  1254. ForEach(iter)
  1255. {
  1256. HqlExprAssociation & cur = iter.get();
  1257. if (cur.represents == attr)
  1258. {
  1259. ABoundActivity * match = (ABoundActivity *)cur.queryExpr()->queryUnknownExtra();
  1260. IHqlExpression * whoAmI = whoAmIActivity.queryBound();
  1261. OwnedHqlExpr dependency = createAttribute(dependencyAtom, LINK(whoAmI), LINK(match->queryBound()));
  1262. if (!activeGraphCtx->queryMatchExpr(dependency))
  1263. {
  1264. activeGraphCtx->associateExpr(dependency, dependency);
  1265. addDependency(*activeGraphCtx, match, &whoAmIActivity, dependencyAtom);
  1266. }
  1267. }
  1268. }
  1269. if (name && targetRoxie())
  1270. registerGlobalUsage(attr);
  1271. }
  1272. }
  1273. bool HqlCppTranslator::tempRowRequiresFinalize(IHqlExpression * record) const
  1274. {
  1275. if (recordRequiresDestructor(record) || options.finalizeAllRows)
  1276. return true;
  1277. if (isVariableSizeRecord(record))
  1278. return true;
  1279. return false;
  1280. }
  1281. BoundRow * HqlCppTranslator::createRowBuilder(BuildCtx & ctx, BoundRow * targetRow)
  1282. {
  1283. IHqlExpression * record = targetRow->queryRecord();
  1284. IHqlExpression * boundTarget = targetRow->queryBound();
  1285. bool targetIsOwnedRow = hasWrapperModifier(boundTarget->queryType());
  1286. StringBuffer builderName, rowName;
  1287. getUniqueId(builderName.append("b"));
  1288. rowName.append(builderName).append(".row()");
  1289. if (!targetIsOwnedRow && isFixedWidthDataset(record) && !options.alwaysCreateRowBuilder)
  1290. {
  1291. BoundRow * self = bindSelf(ctx, targetRow->queryDataset(), boundTarget, NULL);
  1292. return LINK(self);
  1293. }
  1294. if (targetIsOwnedRow)
  1295. {
  1296. OwnedHqlExpr allocator = createRowAllocator(ctx, record);
  1297. StringBuffer s;
  1298. s.clear().append("RtlDynamicRowBuilder ").append(builderName).append("(");
  1299. generateExprCpp(s, allocator).append(");");
  1300. ctx.addQuoted(s);
  1301. BoundRow * self = bindSelf(ctx, targetRow->queryDataset(), builderName);
  1302. return LINK(self);
  1303. }
  1304. else
  1305. {
  1306. StringBuffer s;
  1307. s.clear().append("RtlStaticRowBuilder ").append(builderName).append("(");
  1308. generateExprCpp(s, boundTarget);
  1309. s.append(",").append(getMaxRecordSize(record)).append(");");
  1310. ctx.addQuoted(s);
  1311. OwnedHqlExpr builder = createVariable(builderName, makeBoolType());
  1312. BoundRow * self = bindSelf(ctx, targetRow->queryDataset(), builderName);
  1313. return LINK(self);
  1314. }
  1315. }
  1316. IHqlExpression * HqlCppTranslator::declareLinkedRowExpr(BuildCtx & ctx, IHqlExpression * record, bool isMember)
  1317. {
  1318. StringBuffer rowName;
  1319. getUniqueId(rowName.append('r'));
  1320. Owned<ITypeInfo> rowType = makeRowType(record->getType());
  1321. rowType.setown(makeAttributeModifier(makeWrapperModifier(rowType.getClear()), getLinkCountedAttr()));
  1322. if (isMember)
  1323. rowType.setown(makeModifier(rowType.getClear(), typemod_member, NULL));
  1324. OwnedHqlExpr boundRow = createVariable(rowName, LINK(rowType));
  1325. //Ugly, but necessary. Conditional temporary rows will be accessed in a lifetime outside of the scope they are
  1326. //evaluated in - so the declaration needs to be in a scope where they will not be freed. For the moment make
  1327. //this the outer most scope (within a function)
  1328. ctx.setNextPriority(BuildCtx::OutermostScopePrio);
  1329. ctx.addDeclare(boundRow);
  1330. return boundRow.getClear();
  1331. }
  1332. BoundRow * HqlCppTranslator::declareLinkedRow(BuildCtx & ctx, IHqlExpression * expr, bool isMember)
  1333. {
  1334. assertex(expr->isDatarow());
  1335. OwnedHqlExpr boundRow = declareLinkedRowExpr(ctx, expr->queryRecord(), isMember);
  1336. return createBoundRow(expr, boundRow);
  1337. }
  1338. BoundRow * HqlCppTranslator::declareStaticRow(BuildCtx & ctx, IHqlExpression * expr)
  1339. {
  1340. assertex(expr->isDatarow());
  1341. IHqlExpression * record = expr->queryRecord();
  1342. unsigned maxRecordSize = getMaxRecordSize(record);
  1343. StringBuffer rowName;
  1344. getUniqueId(rowName.append('r'));
  1345. Owned<ITypeInfo> rowType = makeRowType(record->getType());
  1346. BuildCtx * declarectx = &ctx;
  1347. if (maxRecordSize > options.maxLocalRowSize)
  1348. getInvariantMemberContext(ctx, &declarectx, NULL, false, false);
  1349. if (!declarectx->isSameLocation(ctx))
  1350. rowType.setown(makeModifier(rowType.getClear(), typemod_member, NULL));
  1351. else
  1352. declarectx->setNextPriority(BuildCtx::OutermostScopePrio);
  1353. OwnedHqlExpr boundRow = createVariable(rowName, LINK(rowType));
  1354. StringBuffer s;
  1355. declarectx->addQuoted(s.append("byte ").append(rowName).append("[").append(maxRecordSize).append("];"));
  1356. return createBoundRow(expr, boundRow);
  1357. }
  1358. BoundRow * HqlCppTranslator::declareTempRow(BuildCtx & ctx, BuildCtx & codectx, IHqlExpression * expr)
  1359. {
  1360. assertex(expr->isDatarow());
  1361. IHqlExpression * record = expr->queryRecord();
  1362. //if maxRecordSize is too large, and cannot store it in a class, then allocate a pointer to it dynamically.
  1363. unsigned maxRecordSize = getMaxRecordSize(record);
  1364. bool createRowDynamically = tempRowRequiresFinalize(record) || (maxRecordSize > options.maxLocalRowSize);
  1365. if (createRowDynamically)
  1366. {
  1367. return declareLinkedRow(ctx, expr, !ctx.isSameLocation(codectx));
  1368. }
  1369. else
  1370. {
  1371. return declareStaticRow(ctx, expr);
  1372. }
  1373. }
  1374. BoundRow * HqlCppTranslator::declareTempAnonRow(BuildCtx & ctx, BuildCtx & codectx, IHqlExpression * record)
  1375. {
  1376. OwnedHqlExpr anon = createRow(no_self, LINK(record->queryRecord()), createUniqueId());
  1377. return declareTempRow(ctx, codectx, anon);
  1378. }
  1379. void HqlCppTranslator::finalizeTempRow(BuildCtx & ctx, BoundRow * row, BoundRow * builder)
  1380. {
  1381. IHqlExpression * targetRow = row->queryBound();
  1382. bool targetIsOwnedRow = hasWrapperModifier(targetRow->queryType());
  1383. if (builder->queryBuilder() && targetIsOwnedRow)
  1384. {
  1385. OwnedHqlExpr createdRowSize = getRecordSize(builder->querySelector());
  1386. HqlExprArray args;
  1387. args.append(*LINK(builder->queryBuilder()));
  1388. args.append(*LINK(createdRowSize));
  1389. OwnedHqlExpr call = bindFunctionCall(finalizeRowClearId, args, targetRow->queryType());
  1390. CHqlBoundTarget target;
  1391. target.expr.set(targetRow);
  1392. buildExprAssign(ctx, target, call);
  1393. CHqlBoundExpr bound;
  1394. buildExpr(ctx, createdRowSize, bound);
  1395. OwnedHqlExpr sizeofTarget = createSizeof(row->querySelector());
  1396. ctx.associateExpr(sizeofTarget, bound);
  1397. }
  1398. ctx.removeAssociation(builder);
  1399. }
  1400. //---------------------------------------------------------------------------
  1401. bool GlobalFileTracker::checkMatch(IHqlExpression * searchFilename)
  1402. {
  1403. if (searchFilename->queryBody() == filename.get())
  1404. {
  1405. usageCount++;
  1406. return true;
  1407. }
  1408. return false;
  1409. }
  1410. void GlobalFileTracker::writeToGraph()
  1411. {
  1412. if (usageCount && graphNode)
  1413. addGraphAttributeInt(graphNode, "_globalUsageCount", usageCount);
  1414. }
  1415. //---------------------------------------------------------------------------
  1416. MetaInstance::MetaInstance(HqlCppTranslator & translator, IHqlExpression * _record, bool _isGrouped)
  1417. {
  1418. setMeta(translator, _record, _isGrouped);
  1419. }
  1420. void MetaInstance::setMeta(HqlCppTranslator & translator, IHqlExpression * _record, bool _isGrouped)
  1421. {
  1422. record = _record;
  1423. grouped = _isGrouped;
  1424. assertex(!record || record->getOperator() == no_record);
  1425. searchKey.setown(::getMetaUniqueKey(record, grouped));
  1426. StringBuffer s,recordBase;
  1427. appendUniqueId(recordBase, translator.getConsistentUID(searchKey));
  1428. metaName.set(s.clear().append("mi").append(recordBase).str());
  1429. instanceName.set(s.clear().append("mx").append(recordBase).str());
  1430. //MORE: This function is only used by the fvsource code - getResultRecordSizeEntry
  1431. //It seems a bit of a waste generating it for something used infrequently.
  1432. metaFactoryName.set(s.clear().append("mf").append(recordBase).str());
  1433. }
  1434. //---------------------------------------------------------------------------
  1435. unsigned LocationArray::findLocation(IHqlExpression * location)
  1436. {
  1437. ISourcePath * sourcePath = location->querySourcePath();
  1438. unsigned line = location->getStartLine();
  1439. ForEachItem(i)
  1440. {
  1441. IHqlExpression & cur = item(i);
  1442. if ((cur.querySourcePath() == sourcePath) && (cur.getStartLine() == line))
  1443. return i;
  1444. }
  1445. return NotFound;
  1446. }
  1447. bool LocationArray::queryNewLocation(IHqlExpression * location)
  1448. {
  1449. if (findLocation(location) != NotFound)
  1450. return false;
  1451. append(*LINK(location));
  1452. return true;
  1453. }
  1454. IHqlDelayedCodeGenerator * ABoundActivity::createOutputCountCallback()
  1455. {
  1456. return new DelayedUnsignedGenerator(outputCount);
  1457. }
  1458. enum { createPrio = 1000, inputPrio = 3000, readyPrio = 4000, goPrio = 5000, donePrio = 7000, destroyPrio = 9000 };
  1459. ActivityInstance::ActivityInstance(HqlCppTranslator & _translator, BuildCtx & ctx, ThorActivityKind _kind, IHqlExpression * _dataset, const char * _activityArgName) :
  1460. HqlExprAssociation(activeActivityMarkerExpr),
  1461. translator(_translator), classctx(ctx), startctx(ctx), createctx(ctx), nestedctx(ctx), onstartctx(ctx), numChildQueries(0)
  1462. {
  1463. dataset.set(_dataset);
  1464. kind = _kind;
  1465. node_operator op = dataset->getOperator();
  1466. isGrouped = isGroupedActivity(dataset);
  1467. isLocal = !isGrouped && isLocalActivity(dataset) && localChangesActivity(dataset) && !translator.targetHThor();
  1468. implementationClassName = NULL;
  1469. activityArgName.set(_activityArgName);
  1470. IHqlExpression * outputDataset = dataset;
  1471. if (outputDataset->isAction() && (getNumChildTables(outputDataset) == 1))
  1472. outputDataset = dataset->queryChild(0);
  1473. if (translator.targetRoxie())
  1474. {
  1475. if ((op == no_output) && dataset->hasAttribute(_spill_Atom) && queryRealChild(dataset, 1))
  1476. outputDataset = dataset->queryChild(0);
  1477. }
  1478. if ((op == no_setgraphresult) && translator.queryOptions().minimizeActivityClasses)
  1479. outputDataset = dataset->queryChild(0);
  1480. bool removeXpath = dataset->hasAttribute(noXpathAtom) || (op == no_output && translator.queryOptions().removeXpathFromOutput);
  1481. LinkedHqlExpr record = queryRecord(outputDataset);
  1482. if (removeXpath)
  1483. record.setown(removeAttributeFromFields(record, xpathAtom));
  1484. meta.setMeta(translator, record, ::isGrouped(outputDataset));
  1485. activityId = translator.nextActivityId();
  1486. StringBuffer s;
  1487. className.set(s.clear().append("cAc").append(activityId).str());
  1488. factoryName.set(s.clear().append("fAc").append(activityId).str());
  1489. instanceName.set(s.clear().append("iAc").append(activityId).str());
  1490. argsName.set(s.clear().append("oAc").append(activityId).str());
  1491. OwnedHqlExpr boundName = createVariable(instanceName, dataset->getType());
  1492. isMember = false;
  1493. instanceIsLocal = false;
  1494. classStmt = NULL;
  1495. classGroup = NULL;
  1496. classGroupStmt = NULL;
  1497. hasChildActivity = false;
  1498. initialGroupMarker = 0;
  1499. includedInHeader = false;
  1500. isCoLocal = false;
  1501. isNoAccess = false;
  1502. executedRemotely = translator.targetThor();// && !translator.isNeverDistributed(dataset);
  1503. containerActivity = NULL;
  1504. subgraph = queryActiveSubGraph(ctx);
  1505. onCreateStmt = NULL;
  1506. //count index and count disk need to be swapped to the new (much simpler) mechanism
  1507. //until then, they need to be special cased.
  1508. activityLocalisation = GraphNoAccess;
  1509. containerActivity = translator.queryCurrentActivity(ctx);
  1510. parentEvalContext.set(translator.queryEvalContext(ctx));
  1511. parentExtract.set(static_cast<ParentExtract*>(ctx.queryFirstAssociation(AssocExtract)));
  1512. bool optimizeParentAccess = translator.queryOptions().optimizeParentAccess;
  1513. if (parentExtract)
  1514. {
  1515. GraphLocalisation localisation = parentExtract->queryLocalisation();
  1516. activityLocalisation = translator.isAlwaysCoLocal() ? GraphCoLocal : queryActivityLocalisation(dataset, optimizeParentAccess);
  1517. if (activityLocalisation == GraphNoAccess)
  1518. isNoAccess = true;
  1519. else if (activityLocalisation == GraphNeverAccess)
  1520. activityLocalisation = GraphNoAccess;
  1521. if (translator.targetThor() && !translator.insideChildQuery(ctx))
  1522. executedRemotely = true;
  1523. else
  1524. executedRemotely = ((activityLocalisation == GraphNonLocal) || (localisation == GraphRemote));
  1525. isCoLocal = false;
  1526. if (containerActivity && !executedRemotely && (localisation != GraphNonLocal))
  1527. {
  1528. // if we supported GraphNonCoLocal this test would not be needed
  1529. if (activityLocalisation != GraphNoAccess)
  1530. isCoLocal = true;
  1531. }
  1532. //if top level activity within a query library then need to force access to the parent extract
  1533. if (!containerActivity && translator.insideLibrary())
  1534. {
  1535. //there should be no colocal activity (container = null)
  1536. if (activityLocalisation != GraphNoAccess)
  1537. activityLocalisation = GraphNonLocal;
  1538. }
  1539. if (activityLocalisation == GraphNoAccess)
  1540. parentExtract.clear();
  1541. if (isCoLocal)
  1542. colocalMember.setown(createVariable("colocal", makeVoidType()));
  1543. }
  1544. else
  1545. {
  1546. if (executedRemotely)
  1547. {
  1548. GraphLocalisation localisation = queryActivityLocalisation(dataset, optimizeParentAccess);
  1549. if ((kind == TAKsimpleaction) || (localisation == GraphNeverAccess) || (localisation == GraphNoAccess))
  1550. executedRemotely = false;
  1551. }
  1552. }
  1553. if (!parentExtract && (translator.getTargetClusterType() == RoxieCluster))
  1554. executedRemotely = isNonLocal(dataset, false);
  1555. unsigned containerId = 0;
  1556. if (containerActivity)
  1557. {
  1558. containerActivity->hasChildActivity = true;
  1559. containerId = containerActivity->activityId;
  1560. }
  1561. table = new ThorBoundActivity(dataset, boundName, activityId, containerId, translator.curSubGraphId(ctx), kind);
  1562. table->setActive(this);
  1563. }
  1564. ActivityInstance::~ActivityInstance()
  1565. {
  1566. table->setActive(nullptr);
  1567. table->Release();
  1568. }
  1569. void ActivityInstance::addBaseClass(const char * name, bool needLinkOverride)
  1570. {
  1571. baseClassExtra.append(", public ").append(name);
  1572. }
  1573. ABoundActivity * ActivityInstance::getBoundActivity()
  1574. {
  1575. return LINK(table);
  1576. }
  1577. BuildCtx & ActivityInstance::onlyEvalOnceContext()
  1578. {
  1579. return evalContext->onCreate.childctx;
  1580. }
  1581. bool ActivityInstance::isExternal()
  1582. {
  1583. return !isMember && !instanceIsLocal;
  1584. }
  1585. void ActivityInstance::addAttribute(const char * name, const char * value)
  1586. {
  1587. addGraphAttribute(graphNode, name, value);
  1588. }
  1589. void ActivityInstance::addAttributeInt(const char * name, __int64 value)
  1590. {
  1591. addGraphAttributeInt(graphNode, name, value);
  1592. }
  1593. void ActivityInstance::addAttributeBool(const char * name, bool value, bool alwaysAdd)
  1594. {
  1595. addGraphAttributeBool(graphNode, name, value, alwaysAdd);
  1596. }
  1597. void ActivityInstance::addAttribute(const char * name, IHqlExpression * expr)
  1598. {
  1599. StringBuffer temp;
  1600. IValue * value = expr->queryValue();
  1601. assertex(value);
  1602. value->getStringValue(temp);
  1603. addGraphAttribute(graphNode, name, temp);
  1604. }
  1605. void ActivityInstance::addSignedAttribute(IHqlExpression * signedAttr)
  1606. {
  1607. if (signedAttr)
  1608. {
  1609. StringBuffer buf;
  1610. getStringValue(buf, signedAttr->queryChild(0));
  1611. addAttribute("signedBy", buf.str());
  1612. }
  1613. }
  1614. void ActivityInstance::addLocationAttribute(IHqlExpression * location)
  1615. {
  1616. if (!translator.queryOptions().reportLocations || translator.queryOptions().obfuscateOutput)
  1617. return;
  1618. unsigned line = location->getStartLine();
  1619. if (line == 0)
  1620. return;
  1621. if (!locations.queryNewLocation(location))
  1622. return;
  1623. ISourcePath * sourcePath = location->querySourcePath();
  1624. unsigned column = location->getStartColumn();
  1625. StringBuffer s;
  1626. s.append(str(sourcePath)).append("(").append(line);
  1627. if (column)
  1628. s.append(",").append(column);
  1629. s.append(")");
  1630. addAttribute("definition", s.str());
  1631. }
  1632. void ActivityInstance::addNameAttribute(IHqlExpression * symbol)
  1633. {
  1634. if (translator.queryOptions().obfuscateOutput)
  1635. return;
  1636. //Not so sure about adding a location for a named symbol if there are other locations already present....
  1637. //We should probably perform some deduping instead.
  1638. addLocationAttribute(symbol);
  1639. IAtom * name = symbol->queryName();
  1640. if (!name)
  1641. return;
  1642. ForEachItemIn(i, names)
  1643. {
  1644. if (names.item(i).queryName() == name)
  1645. return;
  1646. }
  1647. names.append(*symbol);
  1648. addAttribute("name", str(name));
  1649. }
  1650. void ActivityInstance::removeAttribute(const char * name)
  1651. {
  1652. removeGraphAttribute(graphNode, name);
  1653. }
  1654. void ActivityInstance::processAnnotation(IHqlExpression * annotation)
  1655. {
  1656. switch (annotation->getAnnotationKind())
  1657. {
  1658. case annotate_meta:
  1659. {
  1660. unsigned i=0;
  1661. IHqlExpression * cur;
  1662. while ((cur = annotation->queryAnnotationParameter(i++)) != NULL)
  1663. {
  1664. IAtom * name = cur->queryName();
  1665. if (name == sectionAtom)
  1666. processSection(cur);
  1667. else if (name == hintAtom)
  1668. processHints(cur);
  1669. }
  1670. }
  1671. }
  1672. }
  1673. void ActivityInstance::processAnnotations(IHqlExpression * expr)
  1674. {
  1675. ForEachChild(iHint, expr)
  1676. {
  1677. IHqlExpression * cur = expr->queryChild(iHint);
  1678. if ((cur->queryName() == hintAtom) && cur->isAttribute())
  1679. processHints(cur);
  1680. }
  1681. IHqlExpression * cur = expr;
  1682. for (;;)
  1683. {
  1684. IHqlExpression * body = cur->queryBody(true);
  1685. if (cur == body)
  1686. break;
  1687. processAnnotation(cur);
  1688. cur = body;
  1689. }
  1690. }
  1691. void ActivityInstance::processHint(IHqlExpression * attr)
  1692. {
  1693. StringBuffer name;
  1694. StringBuffer value;
  1695. getHintNameValue(attr, name, value);
  1696. IPropertyTree * att = createPTree();
  1697. att->setProp("@name", name);
  1698. att->setProp("@value", value);
  1699. graphNode->addPropTree("hint", att);
  1700. }
  1701. void ActivityInstance::processSection(IHqlExpression * section)
  1702. {
  1703. if (!translator.queryOptions().obfuscateOutput)
  1704. {
  1705. StringBuffer sectionName;
  1706. getStringValue(sectionName, section->queryChild(0));
  1707. addAttribute("section", sectionName);
  1708. }
  1709. }
  1710. void ActivityInstance::processHints(IHqlExpression * hintAttr)
  1711. {
  1712. ForEachChild(i, hintAttr)
  1713. processHint(hintAttr->queryChild(i));
  1714. }
  1715. void ActivityInstance::changeActivityKind(ThorActivityKind newKind)
  1716. {
  1717. kind = newKind;
  1718. if (graphNode)
  1719. {
  1720. removeGraphAttribute(graphNode, "_kind");
  1721. addAttributeInt("_kind", kind);
  1722. }
  1723. if (table)
  1724. table->updateActivityKind(kind);
  1725. }
  1726. void ActivityInstance::setInternalSink(bool value)
  1727. {
  1728. if (value)
  1729. addAttributeBool("_internal", true);
  1730. else
  1731. removeAttribute("_internal");
  1732. }
  1733. static void getRecordSizeText(StringBuffer & out, IHqlExpression * record)
  1734. {
  1735. size32_t minSize = getMinRecordSize(record);
  1736. if (isVariableSizeRecord(record))
  1737. {
  1738. size32_t expectedSize = getExpectedRecordSize(record);
  1739. out.append(minSize).append("..");
  1740. if (maxRecordSizeUsesDefault(record))
  1741. out.append("?");
  1742. else
  1743. out.append(getMaxRecordSize(record, 0));
  1744. out.append("(").append(expectedSize).append(")");
  1745. }
  1746. else
  1747. out.append(minSize);
  1748. }
  1749. void ActivityInstance::createGraphNode(IPropertyTree * defaultSubGraph, bool alwaysExecuted)
  1750. {
  1751. IPropertyTree * parentGraphNode = subgraph ? subgraph->tree.get() : defaultSubGraph;
  1752. if (!parentGraphNode)
  1753. return;
  1754. HqlCppOptions const & options = translator.queryOptions();
  1755. assertex(kind < TAKlast);
  1756. graphNode.set(parentGraphNode->addPropTree("node", createPTree()));
  1757. graphNode->setPropInt64("@id", activityId);
  1758. if (!options.obfuscateOutput)
  1759. {
  1760. StringBuffer label;
  1761. if (isGrouped)
  1762. label.append("Grouped ");
  1763. else if (isLocal)
  1764. label.append("Local ");
  1765. label.append(getActivityText(kind));
  1766. graphNode->setProp("@label", graphLabel ? graphLabel.get() : label.str());
  1767. }
  1768. IHqlExpression * cur = dataset;
  1769. for (;;)
  1770. {
  1771. IHqlExpression * body = cur->queryBody(true);
  1772. if (cur == body)
  1773. break;
  1774. switch (cur->getAnnotationKind())
  1775. {
  1776. case annotate_symbol:
  1777. addNameAttribute(cur);
  1778. break;
  1779. case annotate_location:
  1780. addLocationAttribute(cur);
  1781. break;
  1782. }
  1783. cur = body;
  1784. }
  1785. addAttributeInt("_kind", kind);
  1786. addAttributeBool("grouped", isGrouped);
  1787. addAttributeBool("local", isLocal);
  1788. #ifdef _DEBUG
  1789. // assertex(dataset->isAction() == isActivitySink(kind));
  1790. #endif
  1791. if (dataset->isAction())
  1792. {
  1793. if (alwaysExecuted)
  1794. markSubGraphAsRoot(parentGraphNode);
  1795. else
  1796. addAttributeBool("_internal", true);
  1797. }
  1798. if (containerActivity)
  1799. addAttributeInt("_parentActivity", containerActivity->activityId);
  1800. if (parentExtract && isCoLocal)
  1801. addAttributeBool("coLocal", true);
  1802. if (isNoAccess)
  1803. addAttributeBool("noAccess", true);
  1804. if (dataset->hasAttribute(parallelAtom))
  1805. addAttributeInt("parallel", getIntValue(queryAttributeChild(dataset, parallelAtom, 0), -1));
  1806. if (hasOrderedAttribute(dataset))
  1807. addAttributeBool("ordered", isOrdered(dataset), true);
  1808. if (dataset->hasAttribute(algorithmAtom))
  1809. addAttribute("algorithm", queryAttributeChild(dataset, algorithmAtom, 0));
  1810. if (!options.obfuscateOutput)
  1811. {
  1812. if (graphEclText.length() == 0)
  1813. toECL(dataset->queryBody(), graphEclText, false, true);
  1814. elideString(graphEclText, MAX_GRAPH_ECL_LENGTH);
  1815. if (options.showEclInGraph)
  1816. {
  1817. if (strcmp(graphEclText.str(), "<>") != 0)
  1818. addAttribute("ecl", graphEclText.str());
  1819. }
  1820. if (options.showSeqInGraph)
  1821. {
  1822. IHqlExpression * selSeq = querySelSeq(dataset);
  1823. if (selSeq)
  1824. addAttributeInt("selSeq", selSeq->querySequenceExtra());
  1825. }
  1826. if (options.showMetaInGraph)
  1827. {
  1828. StringBuffer s;
  1829. if (translator.targetThor())
  1830. {
  1831. IHqlExpression * distribution = queryDistribution(dataset);
  1832. if (distribution && distribution->queryName() != localAtom)
  1833. addAttribute("metaDistribution", getExprECL(distribution, s.clear(), true).str());
  1834. }
  1835. IHqlExpression * grouping = queryGrouping(dataset);
  1836. if (grouping)
  1837. addAttribute("metaGrouping", getExprECL(grouping, s.clear(), true).str());
  1838. if (translator.targetThor())
  1839. {
  1840. IHqlExpression * globalSortOrder = queryGlobalSortOrder(dataset);
  1841. if (globalSortOrder)
  1842. addAttribute("metaGlobalSortOrder", getExprECL(globalSortOrder, s.clear(), true).str());
  1843. }
  1844. IHqlExpression * localSortOrder = queryLocalUngroupedSortOrder(dataset);
  1845. if (localSortOrder)
  1846. addAttribute("metaLocalSortOrder", getExprECL(localSortOrder, s.clear(), true).str());
  1847. IHqlExpression * groupSortOrder = queryGroupSortOrder(dataset);
  1848. if (groupSortOrder)
  1849. addAttribute("metaGroupSortOrder", getExprECL(groupSortOrder, s.clear(), true).str());
  1850. }
  1851. if (options.noteRecordSizeInGraph)
  1852. {
  1853. LinkedHqlExpr record = dataset->queryRecord();
  1854. if (!record && (getNumChildTables(dataset) == 1))
  1855. record.set(dataset->queryChild(0)->queryRecord());
  1856. if (record)
  1857. {
  1858. //In Thor the serialized record is the interesting value, so include that in the graph
  1859. if (translator.targetThor())
  1860. record.setown(getSerializedForm(record, diskAtom));
  1861. StringBuffer temp;
  1862. getRecordSizeText(temp, record);
  1863. addAttribute("recordSize", temp.str());
  1864. }
  1865. }
  1866. if (options.showRecordCountInGraph && !dataset->isAction())
  1867. {
  1868. StringBuffer text;
  1869. getRecordCountText(text, dataset);
  1870. addAttribute("predictedCount", text);
  1871. }
  1872. }
  1873. processAnnotations(dataset);
  1874. }
  1875. void ActivityInstance::moveDefinitionToHeader()
  1876. {
  1877. if (!includedInHeader)
  1878. {
  1879. //remove this class from the c++ file and include it in the header file instead
  1880. includedInHeader = true;
  1881. classGroupStmt->setIncluded(false);
  1882. addAttributeBool("helperinheader", true);
  1883. BuildCtx headerctx(*translator.code, parentHelpersAtom);
  1884. headerctx.addAlias(classStmt);
  1885. }
  1886. }
  1887. void ActivityInstance::noteChildActivityLocation(IHqlExpression * pass)
  1888. {
  1889. if (containerActivity && colocalMember)
  1890. containerActivity->noteChildActivityLocation(pass);
  1891. //A child helper has been generated in a different module =>
  1892. //remove this class from the c++ file and include it in the header file instead
  1893. if (translator.queryOptions().spanMultipleCpp && !includedInHeader && (pass != sourceFileSequence))
  1894. moveDefinitionToHeader();
  1895. }
  1896. void ActivityInstance::buildPrefix()
  1897. {
  1898. const HqlCppOptions & options = translator.queryOptions();
  1899. if (options.generateActivityThresholdCycles != 0)
  1900. startTime = get_cycles_now();
  1901. startDistance = querySearchDistance();
  1902. StringBuffer s;
  1903. sourceFileSequence.setown(getSizetConstant(translator.beginFunctionGetCppIndex(activityId, isChildActivity())));
  1904. if (containerActivity && colocalMember)
  1905. containerActivity->noteChildActivityLocation(sourceFileSequence);
  1906. classctx.set(helperAtom);
  1907. classGroupStmt = classctx.addGroupPass(sourceFileSequence);
  1908. classctx.associate(*this);
  1909. classGroup = classctx.addGroup();
  1910. if (!implementationClassName)
  1911. {
  1912. s.clear().append("struct ").append(className).append(" : public CThor").append(activityArgName).append("Arg").append(baseClassExtra);
  1913. classStmt = classctx.addQuotedCompound(s, ";");
  1914. if (subgraph)
  1915. classctx.associate(*subgraph);
  1916. //Generate functions in the order i) always callable ii) after create iii) after start
  1917. nestedctx.set(classctx);
  1918. nestedctx.addGroup();
  1919. createctx.set(classctx);
  1920. createctx.setNextDestructor();
  1921. createctx.addGroup();
  1922. startctx.set(createctx);
  1923. startctx.setNextDestructor();
  1924. startctx.addGroup();
  1925. createctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  1926. evalContext.setown(new ActivityEvalContext(translator, this, parentExtract, parentEvalContext, colocalMember, createctx, startctx));
  1927. classctx.associate(*evalContext);
  1928. //virtual void onCreate(ICodeContext * ctx, IHThorArg * colocalParent, MemoryBuffer * serializedCreate)
  1929. BuildCtx oncreatectx(createctx);
  1930. if (parentExtract && isCoLocal && containerActivity)
  1931. {
  1932. oncreatectx.addQuotedCompoundLiteral("virtual void onCreate(ICodeContext * _ctx, IHThorArg * _colocal, MemoryBuffer * in)");
  1933. oncreatectx.addQuoted(s.clear().append("colocal = (").append(containerActivity->className).append("*)_colocal;"));
  1934. }
  1935. else
  1936. {
  1937. onCreateStmt = oncreatectx.addQuotedCompoundLiteral("virtual void onCreate(ICodeContext * _ctx, IHThorArg *, MemoryBuffer * in)");
  1938. }
  1939. oncreatectx.associateExpr(insideOnCreateMarker, NULL);
  1940. oncreatectx.addQuotedLiteral("ctx = _ctx;");
  1941. evalContext->onCreate.createFunctionStructure(translator, oncreatectx, true, executedRemotely ? "serializeCreateContext" : NULL);
  1942. if (onCreateStmt)
  1943. onCreateStmt->finishedFramework();
  1944. onstartctx.set(startctx);
  1945. if (parentExtract)
  1946. {
  1947. onstartctx.addQuotedCompoundOpt("virtual void onStart(const byte * pe, MemoryBuffer * in)");
  1948. parentExtract->beginChildActivity(startctx, onstartctx, activityLocalisation, colocalMember, false, false, containerActivity);
  1949. }
  1950. else
  1951. {
  1952. onstartctx.addQuotedCompoundOpt("virtual void onStart(const byte *, MemoryBuffer * in)");
  1953. }
  1954. onstartctx.associateExpr(insideOnStartMarker, NULL);
  1955. evalContext->onStart.createFunctionStructure(translator, onstartctx, true, executedRemotely ? "serializeStartContext" : NULL);
  1956. if (colocalMember)
  1957. {
  1958. s.clear().append(containerActivity->className).append(" * colocal;");
  1959. classctx.addQuoted(s);
  1960. }
  1961. if (baseClassExtra.length())
  1962. {
  1963. nestedctx.addQuoted(s.clear().append("virtual void Link() const { CThor").append(activityArgName).append("Arg::Link(); }"));
  1964. nestedctx.addQuoted(s.clear().append("virtual bool Release() const { return CThor").append(activityArgName).append("Arg::Release(); }"));
  1965. }
  1966. // if (!isMember)
  1967. // classGroupStmt->setIncomplete(true);
  1968. }
  1969. else
  1970. {
  1971. s.clear().append("// use library for ").append(className);
  1972. classctx.addQuoted(s);
  1973. assertex(isExternal());
  1974. nestedctx.set(classctx);
  1975. createctx.set(classctx);
  1976. startctx.set(createctx);
  1977. initialGroupMarker = classGroup->numChildren();
  1978. }
  1979. }
  1980. void ActivityInstance::buildSuffix()
  1981. {
  1982. if (numChildQueries)
  1983. addAttributeInt("childQueries", numChildQueries);
  1984. //Paranoid check to ensure that library classes aren't used when member functions were required
  1985. if (implementationClassName && (initialGroupMarker != classGroup->numChildren()))
  1986. throwUnexpectedX("Implementation class created, but member functions generated");
  1987. const HqlCppOptions & options = translator.queryOptions();
  1988. if (classStmt && (options.spotComplexClasses || options.showActivitySizeInGraph))
  1989. {
  1990. //NOTE: The peephole optimizer means this is often vastly larger than the actual number of lines generated
  1991. unsigned approxSize = calcTotalChildren(classStmt);
  1992. if (options.spotComplexClasses && (approxSize >= options.complexClassesThreshold))
  1993. {
  1994. if ((options.complexClassesActivityFilter == 0) || (kind == options.complexClassesActivityFilter))
  1995. translator.WARNING2(CategoryEfficiency, HQLWRN_ComplexHelperClass, activityId, approxSize);
  1996. }
  1997. if (!options.obfuscateOutput && options.showActivitySizeInGraph)
  1998. addAttributeInt("approxClassSize", approxSize);
  1999. }
  2000. if (options.generateActivityThresholdCycles != 0)
  2001. {
  2002. cycle_t totalTime = get_cycles_now() - startTime;
  2003. cycle_t localTime = totalTime - nestedTime;
  2004. if (localTime > options.generateActivityThresholdCycles)
  2005. {
  2006. if (containerActivity)
  2007. containerActivity->nestedTime += totalTime;
  2008. unsigned __int64 generateTime = cycle_to_nanosec(localTime);
  2009. //Record as a statistic rather than a graph attribute to avoid stats iterators needing to walk the graph
  2010. //We could also record local and totalTime if they differ - but that would then need another stats kind
  2011. StringBuffer scope;
  2012. getScope(scope);
  2013. translator.wu()->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), SSTactivity, scope, StTimeGenerate, nullptr, generateTime, 1, 0, StatsMergeReplace);
  2014. }
  2015. }
  2016. unsigned __int64 searchDistance = querySearchDistance() - startDistance;
  2017. if (searchDistance > options.searchDistanceThreshold)
  2018. addAttributeInt("searchDistance", searchDistance);
  2019. // if (!isMember)
  2020. // classGroupStmt->setIncomplete(false);
  2021. if (parentExtract)
  2022. parentExtract->endChildActivity();
  2023. classctx.removeAssociation(this);
  2024. locations.kill();
  2025. names.kill();
  2026. if (isExternal())
  2027. {
  2028. BuildCtx globalctx(*translator.code, helperAtom);
  2029. globalctx.addGroupPass(sourceFileSequence);
  2030. if (implementationClassName)
  2031. {
  2032. //Meta is always the last parameter...
  2033. addConstructorMetaParameter();
  2034. StringBuffer s;
  2035. s.append("extern \"C\" ECL_API IHThorArg * ").append(factoryName).append("()");
  2036. globalctx.addQuotedFunction(s, true);
  2037. OwnedHqlExpr call = translator.bindFunctionCall(implementationClassName, constructorArgs);
  2038. //Don't call buildReturn because we're lying about the return type, and we don't want a boolean temporary created.
  2039. CHqlBoundExpr bound;
  2040. translator.buildExpr(globalctx, call, bound);
  2041. globalctx.addReturn(bound.expr);
  2042. //translator.buildReturn(globalctx, call);
  2043. }
  2044. else
  2045. {
  2046. StringBuffer s;
  2047. s.append("extern \"C\" ECL_API IHThorArg * ").append(factoryName).append("() { return new ").append(className).append("; }");
  2048. globalctx.addQuoted(s);
  2049. }
  2050. }
  2051. }
  2052. void ActivityInstance::buildMetaMember()
  2053. {
  2054. if (implementationClassName)
  2055. return;
  2056. translator.buildMetaInfo(meta);
  2057. if (meta.queryRecord())
  2058. {
  2059. StringBuffer s;
  2060. s.append("virtual IOutputMetaData * queryOutputMeta() { return &").append(meta.queryInstanceObject()).append("; }");
  2061. classctx.addQuoted(s);
  2062. }
  2063. }
  2064. void ActivityInstance::getScope(StringBuffer & scope) const
  2065. {
  2066. if (containerActivity)
  2067. {
  2068. containerActivity->getScope(scope);
  2069. scope.append(":");
  2070. }
  2071. else
  2072. {
  2073. scope.append(WorkflowScopePrefix).append(translator.curWfid).append(":");
  2074. if (translator.activeGraph)
  2075. scope.append(translator.activeGraph->name).append(":");
  2076. }
  2077. if (subgraph)
  2078. {
  2079. if (subgraph->graphId)
  2080. scope.append(ChildGraphScopePrefix).append(subgraph->graphId).append(":");
  2081. scope.append(SubGraphScopePrefix).append(subgraph->id).append(":");
  2082. }
  2083. scope.append(ActivityScopePrefix).append(activityId);
  2084. }
  2085. void ActivityInstance::addConstructorMetaParameter()
  2086. {
  2087. translator.buildMetaInfo(meta);
  2088. if (meta.queryRecord())
  2089. {
  2090. StringBuffer s;
  2091. s.append("&").append(meta.queryInstanceObject());
  2092. OwnedHqlExpr metaExpr = createQuoted(s.str(), makeBoolType());
  2093. constructorArgs.append(*metaExpr.getClear());
  2094. }
  2095. else if ((kind == TAKwhen_action) || (kind == TAKemptyaction))
  2096. {
  2097. constructorArgs.append(*createTranslatedOwned(createValue(no_nullptr, makeBoolType())));
  2098. }
  2099. }
  2100. ParentExtract * ActivityInstance::createNestedExtract()
  2101. {
  2102. if (!nestedExtract)
  2103. {
  2104. nestedExtract.setown(new ParentExtract(translator, PETnested, NULL, GraphCoLocal, evalContext));
  2105. nestedExtract->beginNestedExtract(startctx);
  2106. }
  2107. return LINK(nestedExtract);
  2108. }
  2109. //----------------------------------------------------------------------------------------------------
  2110. StringBuffer &expandLiteral(StringBuffer &s, const char *f)
  2111. {
  2112. const char * startLine = f;
  2113. char c;
  2114. s.append('"');
  2115. while ((c = *f++) != 0)
  2116. {
  2117. switch (c)
  2118. {
  2119. case '\t':
  2120. s.append("\\t");
  2121. break;
  2122. case '\r':
  2123. s.append("\\r");
  2124. break;
  2125. case '\n':
  2126. s.append("\\n\"\n\t\t\"");
  2127. startLine = f;
  2128. break;
  2129. case ',':
  2130. s.append(c);
  2131. if (f - startLine > 60)
  2132. {
  2133. s.append("\"\n\t\t\"");
  2134. startLine = f;
  2135. }
  2136. break;
  2137. case '\\':
  2138. case '\"':
  2139. case '\'':
  2140. s.append('\\');
  2141. // fall into...
  2142. default:
  2143. s.append(c);
  2144. break;
  2145. }
  2146. if (f - startLine > 120)
  2147. {
  2148. s.append("\"\n\t\t\"");
  2149. startLine = f;
  2150. }
  2151. }
  2152. return s.append("\"");
  2153. }
  2154. //---------------------------------------------------------------------------
  2155. ReferenceSelector::ReferenceSelector(HqlCppTranslator & _translator) : translator(_translator)
  2156. {
  2157. }
  2158. //---------------------------------------------------------------------------
  2159. /* In parms: _dataset, _path are NOT linked */
  2160. DatasetSelector::DatasetSelector(HqlCppTranslator & _translator, BoundRow * _row, IHqlExpression * _path)
  2161. : ReferenceSelector(_translator)
  2162. {
  2163. row = LINK(_row);
  2164. matchedDataset = false;
  2165. column = row->queryRootColumn();
  2166. column->Link();
  2167. path.set(_path);
  2168. if (!_path)
  2169. path.set(row->querySelector());
  2170. parent = NULL;
  2171. }
  2172. /* All in parms: NOT linked */
  2173. DatasetSelector::DatasetSelector(DatasetSelector * _parent, BoundRow * _row, AColumnInfo * _column, IHqlExpression * _path)
  2174. : ReferenceSelector(_parent->translator)
  2175. {
  2176. parent = LINK(_parent);
  2177. matchedDataset = _parent->matchedDataset;
  2178. column = LINK(_column);
  2179. path.set(_path);
  2180. row = LINK(_row);
  2181. }
  2182. DatasetSelector::~DatasetSelector()
  2183. {
  2184. ::Release(column);
  2185. ::Release(parent);
  2186. ::Release(row);
  2187. }
  2188. void DatasetSelector::assignTo(BuildCtx & ctx, const CHqlBoundTarget & target)
  2189. {
  2190. OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2191. if (mapped)
  2192. translator.buildExprAssign(ctx, target, mapped);
  2193. else
  2194. column->buildAssign(translator, ctx, this, target);
  2195. }
  2196. void DatasetSelector::buildAddress(BuildCtx & ctx, CHqlBoundExpr & target)
  2197. {
  2198. OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2199. if (mapped)
  2200. translator.buildAddress(ctx, mapped, target);
  2201. else
  2202. column->buildAddress(translator, ctx, this, target);
  2203. }
  2204. void DatasetSelector::buildClear(BuildCtx & ctx, int direction)
  2205. {
  2206. assertex(row->isModifyable());
  2207. column->buildClear(translator, ctx, this, direction);
  2208. }
  2209. bool DatasetSelector::isBinary()
  2210. {
  2211. return row->isBinary();
  2212. }
  2213. bool DatasetSelector::isRoot()
  2214. {
  2215. return parent == NULL;
  2216. }
  2217. /* _newCursor, _newColumn: not linked. newPathOwn: linked */
  2218. DatasetSelector * DatasetSelector::createChild(BoundRow * _newCursor, AColumnInfo * newColumn, IHqlExpression * newPath)
  2219. {
  2220. return new DatasetSelector(this, _newCursor, newColumn, newPath);
  2221. }
  2222. void DatasetSelector::get(BuildCtx & ctx, CHqlBoundExpr & bound)
  2223. {
  2224. OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2225. if (mapped)
  2226. translator.buildAnyExpr(ctx, mapped, bound);
  2227. else
  2228. column->buildExpr(translator, ctx, this, bound);
  2229. }
  2230. void DatasetSelector::getOffset(BuildCtx & ctx, CHqlBoundExpr & bound)
  2231. {
  2232. //OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2233. assertex(!row->isNonLocal());
  2234. column->buildOffset(translator, ctx, this, bound);
  2235. }
  2236. size32_t DatasetSelector::getContainerTrailingFixed()
  2237. {
  2238. assertex(!row->isNonLocal());
  2239. return column->getContainerTrailingFixed();
  2240. }
  2241. void DatasetSelector::getSize(BuildCtx & ctx, CHqlBoundExpr & bound)
  2242. {
  2243. //OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2244. assertex(!row->isNonLocal());
  2245. column->buildSizeOf(translator, ctx, this, bound);
  2246. }
  2247. bool DatasetSelector::isDataset()
  2248. {
  2249. switch (column->queryType()->getTypeCode())
  2250. {
  2251. case type_table:
  2252. case type_groupedtable:
  2253. return true;
  2254. }
  2255. return false;
  2256. }
  2257. bool DatasetSelector::isConditional()
  2258. {
  2259. return row->isConditional() || column->isConditional();
  2260. }
  2261. AColumnInfo * DatasetSelector::queryColumn()
  2262. {
  2263. return column;
  2264. }
  2265. BoundRow * DatasetSelector::queryRootRow()
  2266. {
  2267. return row;
  2268. }
  2269. IHqlExpression * DatasetSelector::queryExpr()
  2270. {
  2271. return path;
  2272. }
  2273. ITypeInfo * DatasetSelector::queryType()
  2274. {
  2275. if (parent)
  2276. return path->queryType();
  2277. return row->queryDataset()->queryType();
  2278. }
  2279. IHqlExpression * DatasetSelector::resolveChildDataset(IHqlExpression * searchDataset) const
  2280. {
  2281. searchDataset = searchDataset->queryNormalizedSelector();
  2282. IHqlExpression * compare = row->queryDataset()->queryNormalizedSelector();
  2283. if (searchDataset == compare)
  2284. return compare;
  2285. return NULL;
  2286. }
  2287. AColumnInfo * DatasetSelector::resolveField(IHqlExpression * search) const
  2288. {
  2289. AColumnInfo * nextColumn = column->lookupColumn(search);
  2290. if (nextColumn)
  2291. return nextColumn;
  2292. return NULL;
  2293. }
  2294. void DatasetSelector::set(BuildCtx & ctx, IHqlExpression * expr)
  2295. {
  2296. while (expr->getOperator() == no_compound)
  2297. {
  2298. translator.buildStmt(ctx, expr->queryChild(0));
  2299. expr = expr->queryChild(1);
  2300. }
  2301. assertex(row->isModifyable());
  2302. ITypeInfo * type = column->queryType();
  2303. if (!hasReferenceModifier(type))
  2304. {
  2305. switch (type->getTypeCode())
  2306. {
  2307. case type_row:
  2308. {
  2309. if (queryRecordType(queryType()) == expr->queryRecordType())
  2310. {
  2311. translator.buildRowAssign(ctx, this, expr);
  2312. }
  2313. else
  2314. {
  2315. Owned<IReferenceSelector> sourceRef = translator.buildNewRow(ctx, expr);
  2316. setRow(ctx, sourceRef);
  2317. }
  2318. return;
  2319. }
  2320. }
  2321. }
  2322. column->setColumn(translator, ctx, this, expr);
  2323. }
  2324. void DatasetSelector::setRow(BuildCtx & ctx, IReferenceSelector * rhs)
  2325. {
  2326. assertex(row->isModifyable());
  2327. column->setRow(translator, ctx, this, rhs);
  2328. }
  2329. void DatasetSelector::modifyOp(BuildCtx & ctx, IHqlExpression * expr, node_operator op)
  2330. {
  2331. assertex(row->isModifyable());
  2332. // IReferenceSelector * aliasedSelector = row->queryAlias();
  2333. // assertex(aliasedSelector);
  2334. if (column->modifyColumn(translator, ctx, this, expr, op))
  2335. return;
  2336. // OwnedHqlExpr sourceValue = aliasedSelector->queryRootRow()->bindToRow(path, row->querySelector());
  2337. OwnedHqlExpr sourceValue = LINK(path);
  2338. OwnedHqlExpr result;
  2339. switch (op)
  2340. {
  2341. case no_assign_addfiles:
  2342. result.setown(createDataset(no_addfiles, ensureOwned(sourceValue), LINK(expr)));
  2343. break;
  2344. #ifdef _THE_FOLLOWING_ARENT_YET_IMPLEMENTED_BUT_WOULD_BE_USEFUL
  2345. case no_assign_concat:
  2346. result.setown(createValue(no_concat, path->getType(), LINK(sourceValue), LINK(expr)));
  2347. break;
  2348. case no_assign_add:
  2349. result.setown(createValue(no_add, path->getType(), LINK(sourceValue), LINK(expr)));
  2350. break;
  2351. #endif
  2352. default:
  2353. throwError1(HQLERR_UnknownCompoundAssign, getOpString(op));
  2354. }
  2355. set(ctx, result);
  2356. }
  2357. void DatasetSelector::buildDeserialize(BuildCtx & ctx, IHqlExpression * helper, IAtom * serializeForm)
  2358. {
  2359. column->buildDeserialize(translator, ctx, this, helper, serializeForm);
  2360. }
  2361. void DatasetSelector::buildSerialize(BuildCtx & ctx, IHqlExpression * helper, IAtom * serializeForm)
  2362. {
  2363. column->buildSerialize(translator, ctx, this, helper, serializeForm);
  2364. }
  2365. /* In selector: not linked. Return: linked */
  2366. IReferenceSelector * DatasetSelector::select(BuildCtx & ctx, IHqlExpression * selectExpr)
  2367. {
  2368. // assertex(!isDataset());
  2369. OwnedHqlExpr selected;
  2370. //Optimize so don't create so many select expressions that already exist.
  2371. if (selectExpr->getOperator() != no_select)
  2372. selected.setown(createSelectExpr(LINK(path), LINK(selectExpr)));
  2373. else if (selectExpr->queryChild(0) == path)
  2374. selected.set(selectExpr);
  2375. else
  2376. selected.setown(createSelectExpr(LINK(path), LINK(selectExpr->queryChild(1))));
  2377. IHqlExpression * selectedField = selected->queryChild(1);
  2378. AColumnInfo * newColumn = resolveField(selectedField);
  2379. if (!newColumn)
  2380. {
  2381. //could be a dataset selector
  2382. IHqlExpression * selected = NULL;
  2383. if (!matchedDataset)
  2384. selected = resolveChildDataset(selectedField);
  2385. if (!selected)
  2386. {
  2387. #ifdef TraceTableFields
  2388. IHqlExpression * searchDataset = row->queryDataset(); // MORE what when children selected?
  2389. IHqlExpression * record = searchDataset->queryRecord()->queryBody();
  2390. unsigned numFields = record->numChildren();
  2391. unsigned idxc;
  2392. StringBuffer fields;
  2393. PrintLog("Fields:");
  2394. for (idxc = 0; idxc < numFields; idxc++)
  2395. {
  2396. IHqlExpression * field = record->queryChild(idxc);
  2397. IAtom * name = field->queryName();
  2398. fields.clear();
  2399. fields.appendf(" %20s [@%lx := %lx] ", name->str(), field, field->queryChild(0));
  2400. PrintLog(fields.str());
  2401. }
  2402. PrintLog("Search: %20s [@%lx])", selectedField->queryName()->str(),selectedField);
  2403. #endif
  2404. StringBuffer searchName, datasetName;
  2405. selectedField->toString(searchName);
  2406. if (path->queryName())
  2407. datasetName.append(path->queryName());
  2408. else
  2409. path->toString(datasetName);
  2410. throwError2(HQLERR_XDoesNotContainExpressionY, datasetName.str(), searchName.str());
  2411. }
  2412. DatasetSelector * next = createChild(row, column, selected);
  2413. next->matchedDataset = true;
  2414. return next;
  2415. }
  2416. return createChild(row, newColumn, selected);
  2417. }
  2418. BoundRow * DatasetSelector::getRow(BuildCtx & ctx)
  2419. {
  2420. if (isRoot())
  2421. return LINK(row);
  2422. CHqlBoundExpr bound;
  2423. buildAddress(ctx, bound);
  2424. Owned<ITypeInfo> type = makeReferenceModifier(LINK(queryType()));
  2425. OwnedHqlExpr address = createValue(no_implicitcast, type.getClear(), LINK(bound.expr));
  2426. return translator.createBoundRow(path, address);
  2427. }
  2428. IReferenceSelector * HqlCppTranslator::createSelfSelect(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr, IHqlExpression * rootSelector)
  2429. {
  2430. if (expr == rootSelector)
  2431. return LINK(target);
  2432. assertex(expr->getOperator() == no_select);
  2433. Owned<IReferenceSelector> parent = createSelfSelect(ctx, target, expr->queryChild(0), rootSelector);
  2434. return parent->select(ctx, expr);
  2435. }
  2436. void initBoundStringTarget(CHqlBoundTarget & target, ITypeInfo * type, const char * lenName, const char * dataName)
  2437. {
  2438. if (type->getSize() == UNKNOWN_LENGTH)
  2439. target.length.setown(createVariable(lenName, LINK(sizetType)));
  2440. target.expr.setown(createVariable(dataName, makeReferenceModifier(LINK(type))));
  2441. }
  2442. //---------------------------------------------------------------------------
  2443. GlobalClassBuilder::GlobalClassBuilder(HqlCppTranslator & _translator, BuildCtx & _ctx, const char * _className, const char * _baseName, const char * _accessorInterface)
  2444. : translator(_translator), classctx(_ctx), nestedctx(_ctx), startctx(_ctx), createctx(_ctx)
  2445. {
  2446. className.set(_className);
  2447. baseName.set(_baseName);
  2448. accessorInterface.set(_accessorInterface);
  2449. if (accessorInterface)
  2450. {
  2451. StringBuffer s;
  2452. accessorName.set(s.clear().append("cr").append(className).str());
  2453. }
  2454. onCreateStmt = NULL;
  2455. classStmt = NULL;
  2456. }
  2457. void GlobalClassBuilder::buildClass(unsigned priority)
  2458. {
  2459. StringBuffer s;
  2460. s.append("struct ").append(className);
  2461. if (baseName)
  2462. s.append(" : public ").append(baseName);
  2463. classctx.set(declareAtom);
  2464. if (priority)
  2465. classctx.setNextPriority(priority);
  2466. classStmt = classctx.addQuotedCompound(s, ";");
  2467. if (!baseName)
  2468. classctx.addQuotedLiteral("ICodeContext * ctx;");
  2469. classctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  2470. //Generate functions in the order i) always callable ii) after create iii) after start
  2471. nestedctx.set(classctx);
  2472. nestedctx.addGroup();
  2473. createctx.set(classctx);
  2474. createctx.setNextDestructor();
  2475. createctx.addGroup();
  2476. startctx.set(createctx);
  2477. evalContext.setown(new GlobalClassEvalContext(translator, parentExtract, parentEvalContext, createctx, startctx));
  2478. classctx.associate(*evalContext);
  2479. //virtual void onCreate(ICodeContext * ctx, IHThorArg * colocalParent, MemoryBuffer * serializedCreate)
  2480. BuildCtx oncreatectx(createctx);
  2481. onCreateStmt = oncreatectx.addQuotedCompoundLiteral("void onCreate(ICodeContext * _ctx)");
  2482. oncreatectx.associateExpr(insideOnCreateMarker, NULL);
  2483. oncreatectx.addQuotedLiteral("ctx = _ctx;");
  2484. evalContext->onCreate.createFunctionStructure(translator, oncreatectx, true, NULL);
  2485. onCreateStmt->finishedFramework();
  2486. }
  2487. void GlobalClassBuilder::completeClass(unsigned priority)
  2488. {
  2489. //MORE: This should be generated from a system function prototype somehow - so we can extend it to user functions later.
  2490. //arguments and parameters should also be configured similarly.
  2491. if (accessorInterface)
  2492. {
  2493. StringBuffer s, prototype;
  2494. prototype.append("extern ECL_API ").append(accessorInterface).append(" * ").append(accessorName).append("(ICodeContext * ctx, unsigned activityId)");
  2495. BuildCtx accessctx(classctx);
  2496. accessctx.set(declareAtom);
  2497. if (priority)
  2498. accessctx.setNextPriority(priority);
  2499. accessctx.addQuotedFunction(prototype, true);
  2500. accessctx.addQuoted(s.clear().append(className).append("* p = new ").append(className).append("(activityId); "));
  2501. accessctx.addQuotedLiteral("p->onCreate(ctx);");
  2502. accessctx.addQuotedLiteral("return p;");
  2503. if (translator.queryOptions().spanMultipleCpp)
  2504. {
  2505. BuildCtx protoctx(*translator.queryCode(), mainprototypesAtom);
  2506. protoctx.addQuoted(s.clear().append(prototype).append(";"));
  2507. }
  2508. }
  2509. }
  2510. //---------------------------------------------------------------------------
  2511. static bool expandThisPass(IHqlExpression * name, unsigned pass)
  2512. {
  2513. if (!name)
  2514. return pass == 1;
  2515. StringBuffer temp;
  2516. name->queryValue()->getStringValue(temp);
  2517. if (temp.length() && temp.charAt(0) =='@')
  2518. return pass == 0;
  2519. return pass == 1;
  2520. }
  2521. static bool anyXmlGeneratedForPass(IHqlExpression * expr, unsigned pass)
  2522. {
  2523. switch (expr->getOperator())
  2524. {
  2525. case no_field:
  2526. {
  2527. OwnedHqlExpr name;
  2528. extractXmlName(name, NULL, NULL, expr, NULL, false);
  2529. ITypeInfo * type = expr->queryType()->queryPromotedType();
  2530. switch (type->getTypeCode())
  2531. {
  2532. case type_row:
  2533. if (name)
  2534. return (pass == 1);
  2535. return anyXmlGeneratedForPass(queryRecord(type), pass);
  2536. case type_set:
  2537. return (pass==1);
  2538. case type_dictionary:
  2539. case type_table:
  2540. case type_groupedtable:
  2541. return (pass == 1);
  2542. default:
  2543. return expandThisPass(name, pass);
  2544. }
  2545. break;
  2546. }
  2547. case no_ifblock:
  2548. return anyXmlGeneratedForPass(expr->queryChild(1), pass);
  2549. case no_record:
  2550. {
  2551. ForEachChild(idx, expr)
  2552. if (anyXmlGeneratedForPass(expr->queryChild(idx), pass))
  2553. return true;
  2554. return false;
  2555. }
  2556. case no_attr:
  2557. case no_attr_expr:
  2558. case no_attr_link:
  2559. return false;
  2560. default:
  2561. UNIMPLEMENTED;
  2562. }
  2563. throwUnexpected(); // unreachable, but some compilers will complain about missing return
  2564. }
  2565. //---------------------------------------------------------------------------
  2566. bool HqlCppTranslator::insideOnCreate(BuildCtx & ctx)
  2567. {
  2568. return ctx.queryMatchExpr(insideOnCreateMarker) != NULL;
  2569. }
  2570. bool HqlCppTranslator::insideOnStart(BuildCtx & ctx)
  2571. {
  2572. return ctx.queryMatchExpr(insideOnStartMarker) != NULL;
  2573. }
  2574. bool HqlCppTranslator::getInvariantMemberContext(BuildCtx & ctx, BuildCtx * * declarectx, BuildCtx * * initctx, bool isIndependentMaybeShared, bool invariantEachStart)
  2575. {
  2576. EvalContext * instance = queryEvalContext(ctx);
  2577. if (instance)
  2578. return instance->getInvariantMemberContext(&ctx, declarectx, initctx, isIndependentMaybeShared, invariantEachStart);
  2579. return false;
  2580. }
  2581. void getMemberClassName(StringBuffer & className, const char * member)
  2582. {
  2583. className.append((char)toupper(member[0])).append(member+1).append("Class");
  2584. }
  2585. IHqlStmt * HqlCppTranslator::beginNestedClass(BuildCtx & ctx, const char * member, const char * bases, const char * memberExtra, ParentExtract * extract)
  2586. {
  2587. // ActivityInstance * activity = queryCurrentActivity(ctx);
  2588. // Owned<ParentExtract> nestedUse;
  2589. // if (activity)
  2590. // nestedUse.setown(extract ? LINK(extract) : activity->createNestedExtract());
  2591. StringBuffer begin,end;
  2592. StringBuffer className;
  2593. getMemberClassName(className, member);
  2594. begin.append("struct ").append((char)toupper(member[0])).append(member+1).append("Class");
  2595. if (bases)
  2596. begin.append(" : public ").append(bases);
  2597. end.append(" ").append(member).append(memberExtra).append(";");
  2598. IHqlStmt * stmt = ctx.addQuotedCompound(begin.str(), end.str());
  2599. stmt->setIncomplete(true);
  2600. OwnedHqlExpr colocalName = createVariable("activity", makeVoidType());
  2601. ActivityInstance * activity = queryCurrentActivity(ctx);
  2602. if (activity)
  2603. {
  2604. Owned<ParentExtract> nestedUse = extract ? LINK(extract) : activity->createNestedExtract();
  2605. NestedEvalContext * nested = new NestedEvalContext(*this, member, nestedUse, queryEvalContext(ctx), colocalName, ctx, ctx);
  2606. ctx.associateOwn(*nested);
  2607. nested->initContext();
  2608. }
  2609. return stmt;
  2610. }
  2611. void HqlCppTranslator::endNestedClass(IHqlStmt * stmt)
  2612. {
  2613. stmt->setIncomplete(false);
  2614. }
  2615. void HqlCppTranslator::doBuildFunctionReturn(BuildCtx & ctx, ITypeInfo * type, IHqlExpression * value)
  2616. {
  2617. bool returnByReference = false;
  2618. CHqlBoundTarget target;
  2619. OwnedHqlExpr returnValue;
  2620. switch (type->getTypeCode())
  2621. {
  2622. case type_varstring:
  2623. case type_varunicode:
  2624. if (type->getSize() == UNKNOWN_LENGTH)
  2625. break;
  2626. //fall through
  2627. case type_qstring:
  2628. case type_string:
  2629. case type_data:
  2630. case type_unicode:
  2631. case type_utf8:
  2632. case type_dictionary:
  2633. case type_table:
  2634. case type_groupedtable:
  2635. if (!hasStreamedModifier(type))
  2636. {
  2637. initBoundStringTarget(target, type, "__lenResult", "__result");
  2638. returnByReference = true;
  2639. }
  2640. break;
  2641. case type_row:
  2642. if (!hasLinkCountedModifier(type))
  2643. {
  2644. initBoundStringTarget(target, type, "__lenResult", "__result");
  2645. returnByReference = true;
  2646. }
  2647. break;
  2648. case type_transform:
  2649. {
  2650. OwnedHqlExpr dataset = createDataset(no_anon, LINK(::queryRecord(type)));
  2651. BoundRow * row = bindSelf(ctx, dataset, "__self");
  2652. target.expr.set(row->querySelector());
  2653. returnByReference = true;
  2654. //A transform also returns the size that was generated (which will be bound to a local variable)
  2655. returnValue.setown(getRecordSize(row->querySelector()));
  2656. break;
  2657. }
  2658. case type_set:
  2659. target.isAll.setown(createVariable("__isAllResult", makeBoolType()));
  2660. target.length.setown(createVariable("__lenResult", LINK(sizetType)));
  2661. target.expr.setown(createVariable("__result", makeReferenceModifier(LINK(type))));
  2662. returnByReference = true;
  2663. break;
  2664. }
  2665. if (returnByReference)
  2666. {
  2667. buildExprAssign(ctx, target, value);
  2668. if (returnValue)
  2669. buildReturn(ctx, returnValue);
  2670. }
  2671. else
  2672. buildReturn(ctx, value, type);
  2673. }
  2674. //MORE: Should have a generalized doBuildFunctionHeader(ctx, name, retType, HqlExprArray & parameters)
  2675. // for when we generate functions for aliases
  2676. void HqlCppTranslator::doBuildBoolFunction(BuildCtx & ctx, const char * name, bool value)
  2677. {
  2678. StringBuffer s;
  2679. s.append("virtual bool ").append(name).append("() { return ").append(TF[value]).append("; }");
  2680. ctx.addQuoted(s);
  2681. }
  2682. void HqlCppTranslator::doBuildDataFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2683. {
  2684. doBuildFunction(ctx, unknownDataType, name, value);
  2685. }
  2686. void HqlCppTranslator::doBuildStringFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2687. {
  2688. doBuildFunction(ctx, unknownStringType, name, value);
  2689. }
  2690. void HqlCppTranslator::doBuildVarStringFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2691. {
  2692. StringBuffer proto;
  2693. proto.append("virtual const char * ").append(name).append("()");
  2694. MemberFunction func(*this, ctx, proto, MFdynamicproto);
  2695. if (value)
  2696. buildReturn(func.ctx, value, constUnknownVarStringType);
  2697. else
  2698. func.ctx.addReturn(queryQuotedNullExpr());
  2699. }
  2700. void HqlCppTranslator::doBuildBoolFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2701. {
  2702. doBuildFunction(ctx, queryBoolType(), name, value);
  2703. }
  2704. void HqlCppTranslator::doBuildUnsignedFunction(BuildCtx & ctx, const char * name, unsigned value)
  2705. {
  2706. StringBuffer s;
  2707. s.append("virtual unsigned ").append(name).append("() { return ").append(value).append("; }");
  2708. ctx.addQuoted(s);
  2709. }
  2710. void HqlCppTranslator::doBuildSizetFunction(BuildCtx & ctx, const char * name, size32_t value)
  2711. {
  2712. StringBuffer s;
  2713. s.append("virtual size32_t ").append(name).append("() { return ").append(value).append("; }");
  2714. ctx.addQuoted(s);
  2715. }
  2716. void HqlCppTranslator::doBuildUnsignedFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2717. {
  2718. doBuildFunction(ctx, unsignedType, name, value);
  2719. }
  2720. void HqlCppTranslator::doBuildDoubleFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2721. {
  2722. Owned<ITypeInfo> type = makeRealType(8);
  2723. doBuildFunction(ctx, doubleType, name, value);
  2724. }
  2725. void HqlCppTranslator::doBuildUnsigned64Function(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2726. {
  2727. Owned<ITypeInfo> type = makeIntType(8, false);
  2728. doBuildFunction(ctx, type, name, value);
  2729. }
  2730. void HqlCppTranslator::doBuildUnsignedFunction(BuildCtx & ctx, const char * name, const char * value)
  2731. {
  2732. if (value)
  2733. {
  2734. StringBuffer s;
  2735. s.append("virtual unsigned ").append(name).append("() { return ").append(value).append("; }");
  2736. ctx.addQuoted(s);
  2737. }
  2738. }
  2739. void HqlCppTranslator::doBuildSignedFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2740. {
  2741. doBuildFunction(ctx, signedType, name, value);
  2742. }
  2743. void HqlCppTranslator::doBuildFunction(BuildCtx & ctx, ITypeInfo * type, const char * name, IHqlExpression * value)
  2744. {
  2745. if (value)
  2746. {
  2747. LinkedHqlExpr cseValue = value;
  2748. if (options.spotCSE)
  2749. cseValue.setown(spotScalarCSE(cseValue, NULL, queryOptions().spotCseInIfDatasetConditions));
  2750. if (false)
  2751. {
  2752. HqlExprArray parameters;
  2753. OwnedHqlExpr entrypoint = createAttribute(entrypointAtom, createConstant(name));
  2754. OwnedHqlExpr body = createValue(no_null, LINK(type), LINK(entrypoint));
  2755. OwnedHqlExpr formals = createSortList(parameters);
  2756. OwnedHqlExpr attrs = createAttribute(virtualAtom);
  2757. OwnedHqlExpr function = createFunctionDefinition(NULL, LINK(body), LINK(formals), NULL, LINK(attrs));
  2758. BuildCtx funcctx(ctx);
  2759. funcctx.addFunction(function);
  2760. doBuildFunctionReturn(funcctx, type, cseValue);
  2761. }
  2762. else
  2763. {
  2764. StringBuffer s, returnParameters;
  2765. s.append("virtual ");
  2766. generateFunctionReturnType(s, returnParameters, type, NULL, options.targetCompiler);
  2767. s.append(" ").append(name).append("(").append(returnParameters).append(")");
  2768. MemberFunction func(*this, ctx, s, MFdynamicproto);
  2769. doBuildFunctionReturn(func.ctx, type, cseValue);
  2770. }
  2771. }
  2772. }
  2773. void HqlCppTranslator::addFilenameConstructorParameter(ActivityInstance & instance, const char * name, IHqlExpression * expr)
  2774. {
  2775. OwnedHqlExpr folded = foldHqlExpression(expr);
  2776. instance.addConstructorParameter(folded);
  2777. noteFilename(instance, name, folded, false);
  2778. }
  2779. void HqlCppTranslator::buildFilenameFunction(ActivityInstance & instance, BuildCtx & classctx, const char * name, IHqlExpression * expr, bool isDynamic)
  2780. {
  2781. OwnedHqlExpr folded = foldHqlExpression(expr);
  2782. doBuildVarStringFunction(classctx, name, folded);
  2783. noteFilename(instance, name, folded, isDynamic);
  2784. }
  2785. void HqlCppTranslator::noteFilename(ActivityInstance & instance, const char * name, IHqlExpression * expr, bool isDynamic)
  2786. {
  2787. if (options.addFilesnamesToGraph)
  2788. {
  2789. StringBuffer propName;
  2790. const char * propNameBase = name;
  2791. if (memicmp(propNameBase, "get", 3) == 0)
  2792. propNameBase += 3;
  2793. else if (memicmp(propNameBase, "query", 3) == 0)
  2794. propNameBase += 5;
  2795. propName.append("_").append((char)tolower(*propNameBase)).append(propNameBase+1);
  2796. OwnedHqlExpr folded = foldHqlExpression(expr);
  2797. if (folded)
  2798. {
  2799. if (!folded->queryValue())
  2800. {
  2801. if (!isDynamic && !options.allowVariableRoxieFilenames && targetRoxie())
  2802. {
  2803. StringBuffer x;
  2804. folded->toString(x);
  2805. throwError1(HQLERR_RoxieExpectedConstantFilename, x.str());
  2806. }
  2807. }
  2808. else
  2809. {
  2810. StringBuffer propValue;
  2811. folded->queryValue()->getStringValue(propValue);
  2812. instance.addAttribute(propName, propValue);
  2813. }
  2814. }
  2815. if (isDynamic)
  2816. {
  2817. unsigned len = propName.length();
  2818. if ((len > 4) && (memicmp(propName.str() + len-4, "name", 4) == 0))
  2819. propName.setLength(len-4);
  2820. propName.append("_dynamic");
  2821. instance.addAttributeBool(propName.str(), true);
  2822. }
  2823. }
  2824. }
  2825. void HqlCppTranslator::buildRefFilenameFunction(ActivityInstance & instance, BuildCtx & classctx, const char * name, IHqlExpression * expr)
  2826. {
  2827. IHqlExpression * table = queryPhysicalRootTable(expr);
  2828. assertex(table);
  2829. IHqlExpression * filename = NULL;
  2830. switch (table->getOperator())
  2831. {
  2832. case no_keyindex:
  2833. filename = table->queryChild(2);
  2834. break;
  2835. case no_newkeyindex:
  2836. filename = table->queryChild(3);
  2837. break;
  2838. case no_table:
  2839. filename = table->queryChild(0);
  2840. break;
  2841. }
  2842. buildFilenameFunction(instance, classctx, name, filename, hasDynamicFilename(table));
  2843. }
  2844. void HqlCppTranslator::buildConnectInputOutput(BuildCtx & ctx, ActivityInstance * instance, ABoundActivity * table, unsigned outputIndex, unsigned inputIndex, const char * label, bool nWay)
  2845. {
  2846. #ifdef _GATHER_USAGE_STATS
  2847. activityCounts[table->queryActivityKind()][instance->kind]++;
  2848. #endif
  2849. outputIndex = table->nextOutputCount();
  2850. logGraphEdge(instance->querySubgraphNode(), table->queryActivityId(), instance->activityId, outputIndex, inputIndex, label, nWay);
  2851. }
  2852. void HqlCppTranslator::buildInstancePrefix(ActivityInstance * instance)
  2853. {
  2854. instance->buildPrefix();
  2855. activeActivities.append(*instance->getBoundActivity());
  2856. }
  2857. void HqlCppTranslator::buildInstanceSuffix(ActivityInstance * instance)
  2858. {
  2859. instance->buildMetaMember();
  2860. instance->buildSuffix();
  2861. activeActivities.pop();
  2862. }
  2863. IHqlExpression * HqlCppTranslator::getRecordSize(IHqlExpression * dataset)
  2864. {
  2865. IHqlExpression * ds = dataset->queryNormalizedSelector();
  2866. return createValue(no_sizeof, makeIntType(4, false), ensureActiveRow(ds));
  2867. }
  2868. /* In parms: not linked */
  2869. void HqlCppTranslator::getRecordSize(BuildCtx & ctx, IHqlExpression * dataset, CHqlBoundExpr & bound)
  2870. {
  2871. OwnedHqlExpr size = getRecordSize(dataset);
  2872. buildExpr(ctx, size, bound);
  2873. }
  2874. unsigned HqlCppTranslator::getMaxRecordSize(IHqlExpression * record)
  2875. {
  2876. if (!record)
  2877. return 0;
  2878. return ::getMaxRecordSize(record, options.maxRecordSize);
  2879. }
  2880. unsigned HqlCppTranslator::getCsvMaxLength(IHqlExpression * csvAttr)
  2881. {
  2882. if (options.testIgnoreMaxLength)
  2883. return 1;
  2884. HqlExprArray attrs;
  2885. if (csvAttr)
  2886. {
  2887. ForEachChild(idx, csvAttr)
  2888. csvAttr->queryChild(idx)->unwindList(attrs, no_comma);
  2889. }
  2890. IHqlExpression * maxLength = queryAttribute(maxLengthAtom, attrs);
  2891. if (maxLength)
  2892. return (unsigned)getIntValue(maxLength->queryChild(0), 0);
  2893. return MAX_CSV_RECORD_SIZE;
  2894. }
  2895. bool HqlCppTranslator::isFixedWidthDataset(IHqlExpression * dataset)
  2896. {
  2897. return isFixedSizeRecord(dataset->queryRecord());
  2898. }
  2899. void HqlCppTranslator::createAccessFunctions(StringBuffer & helperFunc, BuildCtx & ctx, unsigned prio, const char * interfaceName, const char * object)
  2900. {
  2901. helperFunc.append("q").append(object);
  2902. StringBuffer s;
  2903. s.clear().append(interfaceName).append(" & ").append(helperFunc).append("() { ");
  2904. s.append("return ").append(object).append("; ");
  2905. s.append("}");
  2906. if (prio)
  2907. ctx.setNextPriority(prio);
  2908. ctx.addQuoted(s);
  2909. s.clear().append("extern ").append(interfaceName).append(" & ").append(helperFunc).append("();");
  2910. BuildCtx protoctx(*code, mainprototypesAtom);
  2911. protoctx.addQuoted(s);
  2912. }
  2913. void HqlCppTranslator::ensureRowAllocator(StringBuffer & allocatorName, BuildCtx & ctx, IHqlExpression * record, IHqlExpression * activityId)
  2914. {
  2915. OwnedHqlExpr marker = createAttribute(rowAllocatorMarkerAtom, LINK(record->queryBody()), LINK(activityId));
  2916. HqlExprAssociation * match = ctx.queryMatchExpr(marker);
  2917. if (match)
  2918. {
  2919. generateExprCpp(allocatorName, match->queryExpr());
  2920. return;
  2921. }
  2922. StringBuffer uid;
  2923. getUniqueId(uid.append("alloc"));
  2924. BuildCtx subctx(ctx);
  2925. BuildCtx * declarectx = &subctx;
  2926. BuildCtx * callctx = &subctx;
  2927. if (!getInvariantMemberContext(ctx, &declarectx, &callctx, true, false))
  2928. {
  2929. //The following will not currently work because not all compound statements are correctly marked as
  2930. //complete/incomplete
  2931. //subctx.selectOutermostScope();
  2932. }
  2933. StringBuffer s;
  2934. s.append("Owned<IEngineRowAllocator> ").append(uid).append(";");
  2935. declarectx->addQuoted(s);
  2936. StringBuffer decl;
  2937. s.clear().append(uid).append(".setown(ctx->getRowAllocator(&");
  2938. buildMetaForRecord(s, record);
  2939. s.append(",");
  2940. generateExprCpp(s, activityId).append(")");
  2941. s.append(");");
  2942. callctx->addQuoted(s);
  2943. OwnedHqlExpr value = createVariable(uid.str(), makeBoolType());
  2944. declarectx->associateExpr(marker, value);
  2945. allocatorName.append(uid);
  2946. }
  2947. IHqlExpression * HqlCppTranslator::createRowAllocator(BuildCtx & ctx, IHqlExpression * record)
  2948. {
  2949. StringBuffer allocatorName;
  2950. OwnedHqlExpr curActivityId = getCurrentActivityId(ctx);
  2951. ensureRowAllocator(allocatorName, ctx, record, curActivityId);
  2952. return createQuoted(allocatorName, makeBoolType());
  2953. }
  2954. void HqlCppTranslator::buildMetaSerializerClass(BuildCtx & ctx, IHqlExpression * record, const char * serializerName, IAtom * serializeForm)
  2955. {
  2956. StringBuffer s;
  2957. GlobalClassBuilder serializer(*this, ctx, serializerName, "COutputRowSerializer", "IOutputRowSerializer");
  2958. serializer.buildClass(RowMetaPrio);
  2959. serializer.setIncomplete(true);
  2960. BuildCtx & classctx = serializer.classctx;
  2961. s.clear().append("inline ").append(serializerName).append("(unsigned _activityId) : COutputRowSerializer(_activityId) {}");
  2962. classctx.addQuoted(s);
  2963. OwnedHqlExpr id = createVariable("activityId", LINK(sizetType));
  2964. serializer.classctx.associateExpr(queryActivityIdMarker(), id);
  2965. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  2966. {
  2967. MemberFunction func(*this, serializer.startctx, "virtual void serialize(IRowSerializerTarget & out, const byte * self)");
  2968. OwnedHqlExpr helper = createVariable("out", makeBoolType());
  2969. BoundRow * row = bindTableCursor(func.ctx, dataset, "self");
  2970. OwnedHqlExpr size = getRecordSize(row->querySelector());
  2971. CHqlBoundExpr boundSize;
  2972. buildExpr(func.ctx, size, boundSize);
  2973. if (recordRequiresSerialization(record, serializeForm))
  2974. {
  2975. Owned<IReferenceSelector> selector = buildActiveRow(func.ctx, row->querySelector());
  2976. selector->buildSerialize(func.ctx, helper, serializeForm);
  2977. }
  2978. else
  2979. {
  2980. HqlExprArray args;
  2981. args.append(*LINK(helper));
  2982. args.append(*LINK(boundSize.expr));
  2983. args.append(*LINK(row->queryBound()));
  2984. OwnedHqlExpr call = bindTranslatedFunctionCall(serializerPutId, args);
  2985. func.ctx.addExpr(call);
  2986. }
  2987. }
  2988. serializer.setIncomplete(false);
  2989. serializer.completeClass(RowMetaPrio);
  2990. }
  2991. void HqlCppTranslator::buildMetaDeserializerClass(BuildCtx & ctx, IHqlExpression * record, const char * deserializerName, IAtom * serializeForm)
  2992. {
  2993. StringBuffer s;
  2994. GlobalClassBuilder deserializer(*this, ctx, deserializerName, "COutputRowDeserializer", "IOutputRowDeserializer");
  2995. deserializer.buildClass(RowMetaPrio);
  2996. deserializer.setIncomplete(true);
  2997. BuildCtx & classctx = deserializer.classctx;
  2998. s.clear().append("inline ").append(deserializerName).append("(unsigned _activityId) : COutputRowDeserializer(_activityId) {}");
  2999. classctx.addQuoted(s);
  3000. OwnedHqlExpr id = createVariable("activityId", LINK(sizetType));
  3001. deserializer.classctx.associateExpr(queryActivityIdMarker(), id);
  3002. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  3003. {
  3004. MemberFunction func(*this, deserializer.startctx, "virtual size32_t deserialize(ARowBuilder & crSelf, IRowDeserializerSource & in)");
  3005. BoundRow * row = bindSelf(func.ctx, dataset, "crSelf");
  3006. ensureRowAllocated(func.ctx, "crSelf");
  3007. OwnedHqlExpr helper = createVariable("in", makeBoolType());
  3008. Owned<IReferenceSelector> selector = buildActiveRow(func.ctx, row->querySelector());
  3009. selector->buildDeserialize(func.ctx, helper, serializeForm);
  3010. buildReturnRecordSize(func.ctx, row);
  3011. }
  3012. deserializer.setIncomplete(false);
  3013. deserializer.completeClass(RowMetaPrio);
  3014. }
  3015. bool HqlCppTranslator::buildMetaPrefetcherClass(BuildCtx & ctx, IHqlExpression * record, const char * prefetcherName)
  3016. {
  3017. StringBuffer s;
  3018. GlobalClassBuilder prefetcher(*this, ctx, prefetcherName, "CSourceRowPrefetcher", NULL);
  3019. prefetcher.buildClass(RowMetaPrio);
  3020. prefetcher.setIncomplete(true);
  3021. BuildCtx & classctx = prefetcher.classctx;
  3022. s.clear().append("inline ").append(prefetcherName).append("(unsigned _activityId) : CSourceRowPrefetcher(_activityId) {}");
  3023. classctx.addQuoted(s);
  3024. OwnedHqlExpr id = createVariable("activityId", LINK(sizetType));
  3025. prefetcher.classctx.associateExpr(queryActivityIdMarker(), id);
  3026. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  3027. bool ok;
  3028. {
  3029. MemberFunction func(*this, prefetcher.startctx, "virtual void readAhead(IRowDeserializerSource & in)");
  3030. OwnedHqlExpr helper = createVariable("in", makeBoolType());
  3031. ok = queryRecordOffsetMap(record, false)->buildReadAhead(*this, func.ctx, helper);
  3032. }
  3033. if (ok)
  3034. {
  3035. prefetcher.setIncomplete(false);
  3036. prefetcher.completeClass(RowMetaPrio);
  3037. }
  3038. else
  3039. prefetcher.setIncluded(false);
  3040. return ok;
  3041. }
  3042. IHqlExpression * HqlCppTranslator::getRtlFieldKey(IHqlExpression * expr, IHqlExpression * rowRecord)
  3043. {
  3044. /*
  3045. Most field information is context independent - which make life much easier, there are a few exceptions though:
  3046. type_bitfield. The offset within the bitfield, and whether the bitfield is the last in the block depend on the other adjacent bitfields.
  3047. type_alien. Because it can refer to self in the parameters to the type definition it is dependent on the containing record
  3048. no_ifblock: Again because it references no_self, it is context dependent.
  3049. Theoretically with an inline record definition for a field it might be possible to make an ifblock dependent on something other than the most
  3050. immediate parent record, but it would be extremely pathological, and probably wouldn't work in lots of other ways.
  3051. */
  3052. bool contextDependent = false;
  3053. LinkedHqlExpr extra = rowRecord;
  3054. switch (expr->getOperator())
  3055. {
  3056. case no_field:
  3057. switch (expr->queryType()->getTypeCode())
  3058. {
  3059. case type_bitfield:
  3060. {
  3061. ColumnToOffsetMap * map = queryRecordOffsetMap(rowRecord, false);
  3062. AColumnInfo * root = map->queryRootColumn();
  3063. CBitfieldInfo * resolved = static_cast<CBitfieldInfo *>(root->lookupColumn(expr));
  3064. assertex(resolved);
  3065. unsigned offset = resolved->queryBitfieldOffset();
  3066. bool isLastBitfield = resolved->queryIsLastBitfield();
  3067. Linked<ITypeInfo> fieldType = expr->queryType();
  3068. fieldType.setown(makeAttributeModifier(LINK(fieldType), createAttribute(bitfieldOffsetAtom, getSizetConstant(offset))));
  3069. if (isLastBitfield)
  3070. fieldType.setown(makeAttributeModifier(LINK(fieldType), createAttribute(isLastBitfieldAtom)));
  3071. HqlExprArray args;
  3072. unwindChildren(args, expr);
  3073. return createField(expr->queryId(), LINK(fieldType), args);
  3074. }
  3075. break;
  3076. case type_alien:
  3077. //actually too strict - some alien data types are not context dependent.
  3078. contextDependent = true;
  3079. break;
  3080. }
  3081. break;
  3082. case no_ifblock:
  3083. contextDependent = true;
  3084. break;
  3085. }
  3086. if (contextDependent)
  3087. return createAttribute(rtlFieldKeyMarkerAtom, LINK(expr), extra.getClear());
  3088. return LINK(expr);
  3089. }
  3090. unsigned HqlCppTranslator::buildRtlField(StringBuffer & instanceName, IHqlExpression * field, IHqlExpression * rowRecord)
  3091. {
  3092. OwnedHqlExpr fieldKey = getRtlFieldKey(field, rowRecord);
  3093. BuildCtx declarectx(*code, declareAtom);
  3094. HqlExprAssociation * match = declarectx.queryMatchExpr(fieldKey);
  3095. if (match)
  3096. {
  3097. IHqlExpression * mapped = match->queryExpr();
  3098. mapped->queryChild(0)->toString(instanceName);
  3099. return (unsigned)getIntValue(mapped->queryChild(1));
  3100. }
  3101. StringBuffer name;
  3102. unsigned typeFlags = 0;
  3103. unsigned fieldFlags = 0;
  3104. if (field->getOperator() == no_ifblock)
  3105. {
  3106. typeFlags = buildRtlIfBlockField(name, field, rowRecord);
  3107. }
  3108. else
  3109. {
  3110. Linked<ITypeInfo> fieldType = field->queryType();
  3111. switch (field->queryType()->getTypeCode())
  3112. {
  3113. case type_alien:
  3114. //MORE:::
  3115. break;
  3116. case type_row:
  3117. //Backward compatibility - should revisit
  3118. fieldType.set(fieldType->queryChildType());
  3119. break;
  3120. case type_bitfield:
  3121. //fieldKey contains a field with a type annotated with offsets/isLastBitfield
  3122. fieldType.set(fieldKey->queryType());
  3123. break;
  3124. }
  3125. StringBuffer xpathName, xpathItem;
  3126. switch (fieldType->getTypeCode())
  3127. {
  3128. case type_set:
  3129. extractXmlName(xpathName, &xpathItem, NULL, field, "Item", false);
  3130. break;
  3131. case type_dictionary:
  3132. case type_table:
  3133. case type_groupedtable:
  3134. extractXmlName(xpathName, &xpathItem, NULL, field, "Row", false);
  3135. //Following should be in the type processing, and the type should include the information
  3136. if (field->hasAttribute(sizeAtom) || field->hasAttribute(countAtom))
  3137. fieldFlags |= RFTMinvalidxml;
  3138. break;
  3139. default:
  3140. extractXmlName(xpathName, NULL, NULL, field, NULL, false);
  3141. break;
  3142. }
  3143. if (xpathName.length())
  3144. {
  3145. if (xpathName.charAt(0) == '@')
  3146. fieldFlags |= RFTMhasxmlattr;
  3147. if (checkXpathIsNonScalar(xpathName))
  3148. fieldFlags |= RFTMhasnonscalarxpath;
  3149. }
  3150. StringBuffer lowerName;
  3151. lowerName.append(field->queryName()).toLowerCase();
  3152. if (options.debugGeneratedCpp)
  3153. {
  3154. name.append("rf_");
  3155. convertToValidLabel(name, lowerName.str(), lowerName.length());
  3156. name.append("_").append(++nextFieldId);
  3157. }
  3158. else
  3159. name.append("rf").append(++nextFieldId);
  3160. //Format of the xpath field is (nested-item 0x01 repeated-item)
  3161. StringBuffer xpathFull, xpathCppText;
  3162. xpathFull.append(xpathName);
  3163. if (xpathItem.length())
  3164. xpathFull.append(xpathCompoundSeparatorChar).append(xpathItem);
  3165. if (strcmp(lowerName, xpathFull) != 0)
  3166. appendStringAsQuotedCPP(xpathCppText, xpathFull.length(), xpathFull.str(), false);
  3167. else
  3168. xpathCppText.append("NULL");
  3169. StringBuffer defaultInitializer;
  3170. IHqlExpression *defaultValue = queryAttributeChild(field, defaultAtom, 0);
  3171. if (defaultValue)
  3172. {
  3173. LinkedHqlExpr targetField = field;
  3174. if (fieldType->getTypeCode() == type_bitfield)
  3175. targetField.setown(createField(field->queryId(), LINK(fieldType->queryChildType()), NULL));
  3176. MemoryBuffer target;
  3177. if (createConstantField(target, targetField, defaultValue))
  3178. appendStringAsQuotedCPP(defaultInitializer, target.length(), target.toByteArray(), false);
  3179. else
  3180. throwError1(HQLERR_CouldNotGenerateDefault, str(field->queryName()));
  3181. }
  3182. StringBuffer definition;
  3183. StringBuffer typeName;
  3184. typeFlags |= buildRtlType(typeName, fieldType);
  3185. typeFlags |= fieldFlags;
  3186. definition.append("const RtlFieldStrInfo ").append(name).append("(\"").append(lowerName).append("\",").append(xpathCppText).append(",&").append(typeName);
  3187. if (fieldFlags || defaultInitializer.length())
  3188. definition.append(',').appendf("0x%x", fieldFlags);
  3189. if (defaultInitializer.length())
  3190. definition.append(',').append(defaultInitializer);
  3191. definition.append(");");
  3192. BuildCtx fieldctx(declarectx);
  3193. fieldctx.setNextPriority(TypeInfoPrio);
  3194. fieldctx.addQuoted(definition);
  3195. name.insert(0, "&");
  3196. }
  3197. OwnedHqlExpr nameExpr = createVariable(name.str(), makeBoolType());
  3198. OwnedHqlExpr mapped = createAttribute(fieldAtom, LINK(nameExpr), getSizetConstant(typeFlags));
  3199. declarectx.associateExpr(fieldKey, mapped);
  3200. instanceName.append(name);
  3201. return typeFlags;
  3202. }
  3203. unsigned HqlCppTranslator::buildRtlIfBlockField(StringBuffer & instanceName, IHqlExpression * ifblock, IHqlExpression * rowRecord)
  3204. {
  3205. StringBuffer typeName, s;
  3206. BuildCtx declarectx(*code, declareAtom);
  3207. //First generate a pseudo type entry for an ifblock.
  3208. unsigned fieldType = type_ifblock|RFTMcontainsifblock|RFTMnoserialize;
  3209. {
  3210. unsigned length = 0;
  3211. StringBuffer childTypeName;
  3212. unsigned childType = buildRtlRecordFields(childTypeName, ifblock->queryChild(1), rowRecord);
  3213. fieldType |= (childType & RFTMinherited);
  3214. StringBuffer className;
  3215. typeName.append("ty").append(++nextTypeId);
  3216. className.append("tyc").append(nextFieldId);
  3217. //The ifblock needs a unique instance of the class to evaluate the test
  3218. BuildCtx fieldclassctx(declarectx);
  3219. fieldclassctx.setNextPriority(TypeInfoPrio);
  3220. fieldclassctx.addQuotedCompound(s.clear().append("struct ").append(className).append(" : public RtlIfBlockTypeInfo"), ";");
  3221. fieldclassctx.addQuoted(s.clear().append(className).append("() : RtlIfBlockTypeInfo(0x").appendf("%x", fieldType).append(",").append(0).append(",").append(childTypeName).append(") {}"));
  3222. OwnedHqlExpr anon = createDataset(no_anon, LINK(rowRecord));
  3223. {
  3224. MemberFunction condfunc(*this, fieldclassctx, "virtual bool getCondition(const byte * self) const");
  3225. BoundRow * self = bindTableCursor(condfunc.ctx, anon, "self");
  3226. OwnedHqlExpr cond = self->bindToRow(ifblock->queryChild(0), querySelfReference());
  3227. buildReturn(condfunc.ctx, cond);
  3228. }
  3229. s.clear().append("const ").append(className).append(" ").append(typeName).append(";");
  3230. BuildCtx typectx(declarectx);
  3231. typectx.setNextPriority(TypeInfoPrio);
  3232. typectx.addQuoted(s);
  3233. }
  3234. StringBuffer name;
  3235. name.append("rf").append(++nextFieldId);
  3236. //Now generate a pseudo field for the ifblock
  3237. s.clear().append("const RtlFieldStrInfo ").append(name).append("(NULL, NULL,&").append(typeName).append(");");
  3238. BuildCtx fieldctx(declarectx);
  3239. fieldctx.setNextPriority(TypeInfoPrio);
  3240. fieldctx.addQuoted(s);
  3241. instanceName.append("&").append(name);
  3242. return fieldType;
  3243. }
  3244. unsigned HqlCppTranslator::expandRtlRecordFields(StringBuffer & fieldListText, IHqlExpression * record, IHqlExpression * rowRecord)
  3245. {
  3246. unsigned fieldType = 0;
  3247. ForEachChild(i, record)
  3248. {
  3249. IHqlExpression * cur = record->queryChild(i);
  3250. unsigned childType = 0;
  3251. switch (cur->getOperator())
  3252. {
  3253. case no_field:
  3254. case no_ifblock:
  3255. childType = buildRtlField(fieldListText, cur, rowRecord);
  3256. fieldListText.append(",");
  3257. break;
  3258. case no_record:
  3259. childType = expandRtlRecordFields(fieldListText, cur, rowRecord);
  3260. break;
  3261. }
  3262. fieldType |= (childType & RFTMinherited);
  3263. }
  3264. return fieldType;
  3265. }
  3266. unsigned HqlCppTranslator::buildRtlRecordFields(StringBuffer & instanceName, IHqlExpression * record, IHqlExpression * rowRecord)
  3267. {
  3268. StringBuffer fieldListText;
  3269. unsigned fieldFlags = expandRtlRecordFields(fieldListText, record, rowRecord);
  3270. StringBuffer name;
  3271. name.append("tl").append(++nextTypeId);
  3272. StringBuffer s;
  3273. s.append("const RtlFieldInfo * const ").append(name).append("[] = { ").append(fieldListText).append(" 0 };");
  3274. BuildCtx listctx(*code, declareAtom);
  3275. listctx.setNextPriority(TypeInfoPrio);
  3276. listctx.addQuoted(s);
  3277. instanceName.append(name);
  3278. return fieldFlags;
  3279. }
  3280. unsigned HqlCppTranslator::buildRtlType(StringBuffer & instanceName, ITypeInfo * type)
  3281. {
  3282. assertex(type);
  3283. if (type->getTypeCode() == type_record)
  3284. type = queryUnqualifiedType(type);
  3285. OwnedHqlExpr search = createVariable("t", LINK(type));
  3286. BuildCtx declarectx(*code, declareAtom);
  3287. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  3288. if (match)
  3289. {
  3290. IHqlExpression * value = match->queryExpr();
  3291. value->queryChild(0)->toString(instanceName);
  3292. return (unsigned)getIntValue(value->queryChild(1));
  3293. }
  3294. StringBuffer name, arguments;
  3295. if (options.debugGeneratedCpp)
  3296. {
  3297. StringBuffer ecl;
  3298. type->getECLType(ecl);
  3299. name.append("ty_");
  3300. convertToValidLabel(name, ecl.str(), ecl.length());
  3301. name.append("_").append(++nextTypeId);
  3302. }
  3303. else
  3304. name.append("ty").append(++nextTypeId);
  3305. FieldTypeInfoStruct info;
  3306. getFieldTypeInfo(info, type);
  3307. unsigned childType = 0;
  3308. switch (info.fieldType & RFTMkind)
  3309. {
  3310. case type_record:
  3311. {
  3312. IHqlExpression * record = ::queryRecord(type);
  3313. arguments.append(",");
  3314. StringBuffer fieldsInstance;
  3315. childType = buildRtlRecordFields(fieldsInstance, record, record);
  3316. arguments.append(fieldsInstance);
  3317. //The following code could be used to generate an extra list of fields with nested records expanded out,
  3318. //but it causes some queries to grow significantly, so not currently used.
  3319. #if 0
  3320. if (!recordContainsNestedRow(record))
  3321. {
  3322. arguments.append(fieldsInstance).append(",");
  3323. arguments.append(fieldsInstance);
  3324. }
  3325. else
  3326. {
  3327. arguments.append(fieldsInstance).append(",");
  3328. childType |= buildRtlRecordFields(arguments, record, record, true);
  3329. }
  3330. #endif
  3331. break;
  3332. }
  3333. case type_row:
  3334. {
  3335. arguments.append(",&");
  3336. childType = buildRtlType(arguments, ::queryRecordType(type));
  3337. break;
  3338. }
  3339. case type_table:
  3340. case type_groupedtable:
  3341. {
  3342. arguments.append(",&");
  3343. childType = buildRtlType(arguments, ::queryRecordType(type));
  3344. break;
  3345. }
  3346. case type_dictionary:
  3347. {
  3348. arguments.append(",&");
  3349. childType = buildRtlType(arguments, ::queryRecordType(type));
  3350. StringBuffer lookupHelperName;
  3351. buildDictionaryHashClass(::queryRecord(type), lookupHelperName);
  3352. arguments.append(",&").append(lookupHelperName.str());
  3353. break;
  3354. }
  3355. case type_set:
  3356. arguments.append(",&");
  3357. childType = buildRtlType(arguments, type->queryChildType());
  3358. break;
  3359. case type_unicode:
  3360. case type_varunicode:
  3361. case type_utf8:
  3362. arguments.append(", \"").append(info.locale).append("\"").toLowerCase();
  3363. break;
  3364. }
  3365. info.fieldType |= (childType & RFTMinherited);
  3366. StringBuffer definition;
  3367. definition.append("const ").append(info.className).append(" ").append(name).append("(0x").appendf("%x", info.fieldType).append(",").append(info.length).append(arguments).append(");");
  3368. BuildCtx typectx(declarectx);
  3369. typectx.setNextPriority(TypeInfoPrio);
  3370. typectx.addQuoted(definition);
  3371. OwnedHqlExpr nameExpr = createVariable(name.str(), makeVoidType());
  3372. OwnedHqlExpr mapped = createAttribute(fieldAtom, LINK(nameExpr), getSizetConstant(info.fieldType));
  3373. declarectx.associateExpr(search, mapped);
  3374. instanceName.append(name);
  3375. return info.fieldType;
  3376. }
  3377. void HqlCppTranslator::buildMetaInfo(MetaInstance & instance)
  3378. {
  3379. if (options.spanMultipleCpp)
  3380. {
  3381. StringBuffer queryFunctionName;
  3382. queryFunctionName.append("q").append(instance.instanceName).append("()");
  3383. instance.instanceObject.set(queryFunctionName);
  3384. }
  3385. BuildCtx declarectx(*code, declareAtom);
  3386. OwnedHqlExpr search = instance.getMetaUniqueKey();
  3387. // stop duplicate classes being generated.
  3388. // MORE: If this ever includes sorting/grouping, the dependence on a record will need to be revised
  3389. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  3390. if (match)
  3391. return;
  3392. bool savedContextAvailable = contextAvailable;
  3393. contextAvailable = false;
  3394. metas.append(*search.getLink());
  3395. StringBuffer s;
  3396. StringBuffer serializerName, deserializerName, prefetcherName, internalSerializerName, internalDeserializerName;
  3397. StringBuffer endText;
  3398. endText.append(" ").append(instance.instanceName).append(";");
  3399. BuildCtx metactx(declarectx);
  3400. IHqlExpression * record = instance.queryRecord();
  3401. unsigned flags = MDFhasserialize; // we always generate a serialize since
  3402. bool useTypeForXML = false;
  3403. if (instance.isGrouped())
  3404. flags |= MDFgrouped;
  3405. if (record)
  3406. flags |= MDFhasxml;
  3407. if (record)
  3408. {
  3409. if (recordRequiresDestructor(record))
  3410. flags |= MDFneeddestruct;
  3411. if (recordRequiresSerialization(record, diskAtom))
  3412. flags |= MDFneedserializedisk;
  3413. if (recordRequiresSerialization(record, internalAtom))
  3414. flags |= MDFneedserializeinternal;
  3415. const unsigned serializeFlags = (flags & MDFneedserializemask);
  3416. if ((serializeFlags == MDFneedserializemask) && !recordSerializationDiffers(record, diskAtom, internalAtom))
  3417. flags |= MDFdiskmatchesinternal;
  3418. if (maxRecordSizeUsesDefault(record))
  3419. flags |= MDFunknownmaxlength;
  3420. useTypeForXML = true;
  3421. }
  3422. if (instance.isGrouped())
  3423. {
  3424. MetaInstance ungroupedMeta(*this, record, false);
  3425. buildMetaInfo(ungroupedMeta);
  3426. s.append("struct ").append(instance.metaName).append(" : public ").append(ungroupedMeta.metaName);
  3427. metactx.setNextPriority(RowMetaPrio);
  3428. metactx.addQuotedCompound(s, endText.str());
  3429. doBuildUnsignedFunction(metactx, "getMetaFlags", flags);
  3430. }
  3431. else
  3432. {
  3433. //Serialization classes need to be generated for all meta information - because they may be called by parent row classes
  3434. //however, the CFixedOutputMetaData base class contains a default implementation - reducing the required code.
  3435. if (record && (isVariableSizeRecord(record) || (flags & MDFneedserializemask)))
  3436. {
  3437. //Base class provides a default variable width implementation
  3438. if (flags & MDFneedserializedisk)
  3439. {
  3440. serializerName.append("s").append(instance.metaName);
  3441. buildMetaSerializerClass(declarectx, record, serializerName.str(), diskAtom);
  3442. }
  3443. bool needInternalSerializer = ((flags & MDFneedserializeinternal) && recordSerializationDiffers(record, diskAtom, internalAtom));
  3444. if (needInternalSerializer)
  3445. {
  3446. internalSerializerName.append("si").append(instance.metaName);
  3447. buildMetaSerializerClass(declarectx, record, internalSerializerName.str(), internalAtom);
  3448. }
  3449. //MORE:
  3450. //still generate a deserialize for the variable width case because it offers protection
  3451. //against accessing out of bounds data
  3452. deserializerName.append("d").append(instance.metaName);
  3453. buildMetaDeserializerClass(declarectx, record, deserializerName.str(), diskAtom);
  3454. if (needInternalSerializer)
  3455. {
  3456. internalDeserializerName.append("di").append(instance.metaName);
  3457. buildMetaDeserializerClass(declarectx, record, internalDeserializerName.str(), internalAtom);
  3458. }
  3459. //The base class implements prefetch using the serialized meta so no need to generate...
  3460. if (!(flags & MDFneedserializemask))
  3461. {
  3462. prefetcherName.append("p").append(instance.metaName);
  3463. if (!buildMetaPrefetcherClass(declarectx, record, prefetcherName))
  3464. prefetcherName.clear();
  3465. }
  3466. }
  3467. s.append("struct ").append(instance.metaName).append(" : public ");
  3468. if (!record)
  3469. s.append("CActionOutputMetaData");
  3470. else if (isFixedSizeRecord(record))
  3471. s.append("CFixedOutputMetaData");
  3472. else
  3473. s.append("CVariableOutputMetaData");
  3474. metactx.setNextPriority(RowMetaPrio);
  3475. IHqlStmt * metaclass = metactx.addQuotedCompound(s, endText.str());
  3476. metaclass->setIncomplete(true);
  3477. if (record)
  3478. {
  3479. if (isFixedSizeRecord(record))
  3480. {
  3481. unsigned fixedSize = getMinRecordSize(record);
  3482. s.clear().append("inline ").append(instance.metaName).append("() : CFixedOutputMetaData(").append(fixedSize).append(") {}");
  3483. metactx.addQuoted(s);
  3484. }
  3485. else
  3486. {
  3487. unsigned minSize = getMinRecordSize(record);
  3488. unsigned maxLength = getMaxRecordSize(record);
  3489. if (maxLength < minSize)
  3490. reportError(queryLocation(record), ECODETEXT(HQLERR_MaximumSizeLessThanMinimum_XY), maxLength, minSize);
  3491. //These use a CVariableOutputMetaData base class instead, and trade storage for number of virtuals
  3492. s.clear().append("inline ").append(instance.metaName).append("() : CVariableOutputMetaData(").append(minSize).append(") {}");
  3493. metactx.addQuoted(s);
  3494. if (options.testIgnoreMaxLength)
  3495. maxLength = minSize;
  3496. MemberFunction getFunc(*this, metactx, "virtual size32_t getRecordSize(const void * data)");
  3497. s.clear().append("if (!data) return ").append(maxLength).append(";");
  3498. getFunc.ctx.addQuoted(s.str());
  3499. getFunc.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *)data;");
  3500. OwnedHqlExpr selfDs = createDataset(no_null, LINK(instance.queryRecord()));
  3501. BoundRow * selfRow = bindTableCursorOrRow(getFunc.ctx, selfDs, "left");
  3502. OwnedHqlExpr size = getRecordSize(selfRow->querySelector());
  3503. buildReturn(getFunc.ctx, size);
  3504. }
  3505. assertex(!instance.isGrouped());
  3506. StringBuffer typeName;
  3507. unsigned recordTypeFlags = buildRtlType(typeName, record->queryType());
  3508. s.clear().append("virtual const RtlTypeInfo * queryTypeInfo() const { return &").append(typeName).append("; }");
  3509. metactx.addQuoted(s);
  3510. if (record->numChildren() != 0)
  3511. {
  3512. if (!useTypeForXML || (recordTypeFlags & (RFTMinvalidxml|RFTMhasxmlattr)))
  3513. {
  3514. OwnedHqlExpr anon = createDataset(no_anon, LINK(instance.queryRecord()));
  3515. buildXmlSerialize(metactx, anon, "toXML", true);
  3516. }
  3517. }
  3518. generateMetaRecordSerialize(metactx, record, serializerName.str(), deserializerName.str(), internalSerializerName.str(), internalDeserializerName.str(), prefetcherName.str());
  3519. if (flags != (MDFhasserialize|MDFhasxml))
  3520. doBuildUnsignedFunction(metactx, "getMetaFlags", flags);
  3521. if (flags & MDFneedserializedisk)
  3522. {
  3523. OwnedHqlExpr serializedRecord = getSerializedForm(record, diskAtom);
  3524. MetaInstance serializedMeta(*this, serializedRecord, false);
  3525. buildMetaInfo(serializedMeta);
  3526. StringBuffer s;
  3527. s.append("virtual IOutputMetaData * querySerializedDiskMeta() { return &").append(serializedMeta.queryInstanceObject()).append("; }");
  3528. metactx.addQuoted(s);
  3529. }
  3530. }
  3531. metaclass->setIncomplete(false);
  3532. }
  3533. s.clear().append("extern \"C\" ECL_API IOutputMetaData * ").append(instance.metaFactoryName).append("() { ");
  3534. s.append(instance.instanceName).append(".Link(); ");
  3535. s.append("return &").append(instance.instanceName).append("; ");
  3536. s.append("}");
  3537. declarectx.setNextPriority(RowMetaPrio);
  3538. declarectx.addQuoted(s);
  3539. if (options.spanMultipleCpp)
  3540. {
  3541. StringBuffer temp;
  3542. createAccessFunctions(temp, declarectx, RowMetaPrio, "IOutputMetaData", instance.instanceName);
  3543. }
  3544. OwnedHqlExpr temp = createVariable(instance.metaName, makeVoidType());
  3545. declarectx.associateExpr(search, temp);
  3546. contextAvailable = savedContextAvailable;
  3547. }
  3548. class MetaMemberCallback
  3549. {
  3550. public:
  3551. MetaMemberCallback(HqlCppTranslator & _translator) : translator(_translator) {}
  3552. void callChildFunction(BuildCtx & ctx, IHqlExpression * selected)
  3553. {
  3554. MetaInstance childMeta(translator, selected->queryRecord(), false);
  3555. translator.buildMetaInfo(childMeta);
  3556. callChildFunction(ctx, selected, childMeta);
  3557. }
  3558. void walkRecord(BuildCtx & ctx, IHqlExpression * selector, IHqlExpression * record)
  3559. {
  3560. ForEachChild(i, record)
  3561. {
  3562. IHqlExpression * cur = record->queryChild(i);
  3563. switch (cur->getOperator())
  3564. {
  3565. case no_record:
  3566. walkRecord(ctx, selector, cur);
  3567. break;
  3568. case no_ifblock:
  3569. {
  3570. OwnedHqlExpr cond = replaceSelector(cur->queryChild(0), querySelfReference(), selector);
  3571. BuildCtx condctx(ctx);
  3572. translator.buildFilter(condctx, cond);
  3573. walkRecord(condctx, selector, cur->queryChild(1));
  3574. break;
  3575. }
  3576. case no_field:
  3577. {
  3578. ITypeInfo * type = cur->queryType();
  3579. switch (type->getTypeCode())
  3580. {
  3581. case type_alien:
  3582. //MORE: Allow for alien data types to have destructors.
  3583. break;
  3584. case type_row:
  3585. {
  3586. IHqlExpression * record = cur->queryRecord();
  3587. if (recordRequiresDestructor(record))
  3588. {
  3589. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  3590. callChildFunction(ctx, selected);
  3591. }
  3592. break;
  3593. }
  3594. case type_dictionary:
  3595. case type_table:
  3596. case type_groupedtable:
  3597. {
  3598. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  3599. IHqlExpression * record = cur->queryRecord();
  3600. if (cur->hasAttribute(_linkCounted_Atom))
  3601. {
  3602. //releaseRowset(ctx, count, rowset)
  3603. MetaInstance childMeta(translator, selected->queryRecord(), false);
  3604. translator.buildMetaInfo(childMeta);
  3605. processRowset(ctx, selected, childMeta);
  3606. }
  3607. else if (recordRequiresDestructor(record))
  3608. {
  3609. BuildCtx iterctx(ctx);
  3610. translator.buildDatasetIterate(iterctx, selected, false);
  3611. OwnedHqlExpr active = createRow(no_activerow, LINK(selected));
  3612. callChildFunction(iterctx, active);
  3613. }
  3614. break;
  3615. }
  3616. }
  3617. break;
  3618. }
  3619. }
  3620. }
  3621. }
  3622. protected:
  3623. virtual void callChildFunction(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta) = 0;
  3624. virtual void processRowset(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta) = 0;
  3625. protected:
  3626. HqlCppTranslator & translator;
  3627. };
  3628. class MetaDestructCallback : public MetaMemberCallback
  3629. {
  3630. public:
  3631. MetaDestructCallback(HqlCppTranslator & _translator) : MetaMemberCallback(_translator) {}
  3632. protected:
  3633. virtual void callChildFunction(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3634. {
  3635. HqlExprArray args;
  3636. args.append(*createQuoted(childMeta.queryInstanceObject(), makeBoolType()));
  3637. args.append(*LINK(selected));
  3638. translator.buildFunctionCall(ctx, destructMetaMemberId, args);
  3639. }
  3640. virtual void processRowset(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3641. {
  3642. HqlExprArray args;
  3643. args.append(*LINK(selected));
  3644. translator.buildFunctionCall(ctx, releaseRowsetId, args);
  3645. }
  3646. };
  3647. void HqlCppTranslator::doGenerateMetaDestruct(BuildCtx & ctx, IHqlExpression * selector, IHqlExpression * record)
  3648. {
  3649. MetaDestructCallback builder(*this);
  3650. builder.walkRecord(ctx, selector, record);
  3651. }
  3652. class MetaWalkIndirectCallback : public MetaMemberCallback
  3653. {
  3654. public:
  3655. MetaWalkIndirectCallback(HqlCppTranslator & _translator, IHqlExpression * _visitor)
  3656. : MetaMemberCallback(_translator), visitor(_visitor) {}
  3657. protected:
  3658. virtual void callChildFunction(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3659. {
  3660. HqlExprArray args;
  3661. args.append(*createQuoted(childMeta.queryInstanceObject(), makeBoolType()));
  3662. args.append(*LINK(selected));
  3663. args.append(*LINK(visitor));
  3664. translator.buildFunctionCall(ctx, walkIndirectMetaMemberId, args);
  3665. }
  3666. virtual void processRowset(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3667. {
  3668. HqlExprArray args;
  3669. args.append(*LINK(visitor));
  3670. args.append(*LINK(selected));
  3671. translator.buildFunctionCall(ctx, IIndirectMemberVisitor_visitRowsetId, args);
  3672. }
  3673. protected:
  3674. LinkedHqlExpr visitor;
  3675. };
  3676. class MetaChildMetaCallback
  3677. {
  3678. public:
  3679. MetaChildMetaCallback(HqlCppTranslator & _translator, IHqlStmt * _switchStmt)
  3680. : translator(_translator), switchStmt(_switchStmt)
  3681. {
  3682. nextIndex = 0;
  3683. }
  3684. void walkRecord(BuildCtx & ctx, IHqlExpression * record)
  3685. {
  3686. ForEachChild(i, record)
  3687. {
  3688. IHqlExpression * cur = record->queryChild(i);
  3689. switch (cur->getOperator())
  3690. {
  3691. case no_record:
  3692. walkRecord(ctx, cur);
  3693. break;
  3694. case no_ifblock:
  3695. walkRecord(ctx, cur->queryChild(1));
  3696. break;
  3697. case no_field:
  3698. {
  3699. ITypeInfo * type = cur->queryType();
  3700. switch (type->getTypeCode())
  3701. {
  3702. case type_row:
  3703. walkRecord(ctx, queryRecord(cur));
  3704. break;
  3705. case type_dictionary:
  3706. case type_table:
  3707. case type_groupedtable:
  3708. {
  3709. IHqlExpression * record = cur->queryRecord()->queryBody();
  3710. if (!visited.contains(*record))
  3711. {
  3712. BuildCtx condctx(ctx);
  3713. OwnedHqlExpr branch = getSizetConstant(nextIndex++);
  3714. OwnedHqlExpr childMeta = translator.buildMetaParameter(record);
  3715. OwnedHqlExpr ret = createValue(no_address, makeBoolType(), LINK(childMeta));
  3716. condctx.addCase(switchStmt, branch);
  3717. condctx.addReturn(ret);
  3718. visited.append(*record);
  3719. }
  3720. break;
  3721. }
  3722. }
  3723. break;
  3724. }
  3725. }
  3726. }
  3727. }
  3728. protected:
  3729. HqlCppTranslator & translator;
  3730. IHqlStmt * switchStmt;
  3731. HqlExprCopyArray visited;
  3732. unsigned nextIndex;
  3733. };
  3734. void HqlCppTranslator::generateMetaRecordSerialize(BuildCtx & ctx, IHqlExpression * record, const char * diskSerializerName, const char * diskDeserializerName, const char * internalSerializerName, const char * internalDeserializerName, const char * prefetcherName)
  3735. {
  3736. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  3737. if (recordRequiresDestructor(record))
  3738. {
  3739. MemberFunction func(*this, ctx, "virtual void destruct(byte * self)");
  3740. bindTableCursor(func.ctx, dataset, "self");
  3741. MetaDestructCallback builder(*this);
  3742. builder.walkRecord(func.ctx, dataset, record);
  3743. }
  3744. if (recordRequiresDestructor(record))
  3745. {
  3746. OwnedHqlExpr visitor = createVariable("visitor", makeBoolType()); // makeClassType("IIndirectMemberVisitor");
  3747. MemberFunction func(*this, ctx, "virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor)");
  3748. bindTableCursor(func.ctx, dataset, "self");
  3749. MetaWalkIndirectCallback builder(*this, visitor);
  3750. builder.walkRecord(func.ctx, dataset, record);
  3751. }
  3752. {
  3753. OwnedHqlExpr switchVar = createVariable("i", makeIntType(4, false));
  3754. MemberFunction func(*this, ctx, "virtual IOutputMetaData * queryChildMeta(unsigned i)");
  3755. BuildCtx switchctx(func.ctx);
  3756. IHqlStmt * switchStmt = switchctx.addSwitch(switchVar);
  3757. unsigned prevChildren = func.numStmts();
  3758. MetaChildMetaCallback builder(*this, switchStmt);
  3759. builder.walkRecord(func.ctx, record);
  3760. if (prevChildren != func.numStmts())
  3761. func.ctx.addReturn(queryQuotedNullExpr());
  3762. else
  3763. func.setIncluded(false);
  3764. }
  3765. if (diskSerializerName && *diskSerializerName)
  3766. {
  3767. BuildCtx serializectx(ctx);
  3768. serializectx.addQuotedFunction("virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId)");
  3769. StringBuffer s;
  3770. s.append("return cr").append(diskSerializerName).append("(ctx, activityId);");
  3771. serializectx.addQuoted(s);
  3772. }
  3773. if (diskDeserializerName && *diskDeserializerName)
  3774. {
  3775. BuildCtx deserializectx(ctx);
  3776. deserializectx.addQuotedFunction("virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId)");
  3777. StringBuffer s;
  3778. s.append("return cr").append(diskDeserializerName).append("(ctx, activityId);");
  3779. deserializectx.addQuoted(s);
  3780. }
  3781. if (internalSerializerName && *internalSerializerName)
  3782. {
  3783. BuildCtx serializectx(ctx);
  3784. serializectx.addQuotedFunction("virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId)");
  3785. StringBuffer s;
  3786. s.append("return cr").append(internalSerializerName).append("(ctx, activityId);");
  3787. serializectx.addQuoted(s);
  3788. }
  3789. if (internalDeserializerName && *internalDeserializerName)
  3790. {
  3791. BuildCtx deserializectx(ctx);
  3792. deserializectx.addQuotedFunction("virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId)");
  3793. StringBuffer s;
  3794. s.append("return cr").append(internalDeserializerName).append("(ctx, activityId);");
  3795. deserializectx.addQuoted(s);
  3796. }
  3797. if (prefetcherName && *prefetcherName)
  3798. {
  3799. BuildCtx deserializectx(ctx);
  3800. deserializectx.addQuotedFunction("virtual CSourceRowPrefetcher * doCreateDiskPrefetcher(unsigned activityId)");
  3801. StringBuffer s;
  3802. s.append("return new ").append(prefetcherName).append("(activityId);");
  3803. deserializectx.addQuoted(s);
  3804. }
  3805. }
  3806. IHqlExpression * HqlCppTranslator::buildMetaParameter(IHqlExpression * arg)
  3807. {
  3808. MetaInstance meta(*this, arg->queryRecord(), false);
  3809. buildMetaInfo(meta);
  3810. return createQuoted(meta.queryInstanceObject(), makeBoolType());
  3811. }
  3812. void HqlCppTranslator::buildMetaMember(BuildCtx & ctx, IHqlExpression * datasetOrRecord, bool grouped, const char * name)
  3813. {
  3814. MetaInstance meta(*this, ::queryRecord(datasetOrRecord), grouped);
  3815. StringBuffer s;
  3816. buildMetaInfo(meta);
  3817. s.append("virtual IOutputMetaData * ").append(name).append("() { return &").append(meta.queryInstanceObject()).append("; }");
  3818. ctx.addQuoted(s);
  3819. }
  3820. void HqlCppTranslator::buildMetaForRecord(StringBuffer & name, IHqlExpression * record)
  3821. {
  3822. MetaInstance meta(*this, record, false);
  3823. buildMetaInfo(meta);
  3824. name.append(meta.queryInstanceObject());
  3825. }
  3826. void HqlCppTranslator::buildMetaForSerializedRecord(StringBuffer & name, IHqlExpression * record, bool isGrouped)
  3827. {
  3828. if (isGrouped)
  3829. {
  3830. HqlExprArray args;
  3831. unwindChildren(args, record);
  3832. args.append(*createField(__eogId, makeBoolType(), NULL, NULL));
  3833. OwnedHqlExpr groupedRecord = record->clone(args);
  3834. buildMetaForRecord(name, groupedRecord);
  3835. }
  3836. else
  3837. buildMetaForRecord(name, record);
  3838. }
  3839. void HqlCppTranslator::ensureRowSerializer(StringBuffer & serializerName, BuildCtx & ctx, IHqlExpression * record, IAtom * format, IAtom * kind)
  3840. {
  3841. OwnedHqlExpr marker = createAttribute(serializerInstanceMarkerAtom, LINK(record->queryBody()), createAttribute(kind));
  3842. HqlExprAssociation * match = ctx.queryMatchExpr(marker);
  3843. if (match)
  3844. {
  3845. generateExprCpp(serializerName, match->queryExpr());
  3846. return;
  3847. }
  3848. StringBuffer uid;
  3849. getUniqueId(uid.append("ser"));
  3850. BuildCtx * declarectx = &ctx;
  3851. BuildCtx * callctx = &ctx;
  3852. getInvariantMemberContext(ctx, &declarectx, &callctx, true, false);
  3853. StringBuffer s;
  3854. const char * kindText = (kind == serializerAtom) ? "Serializer" : "Deserializer";
  3855. s.append("Owned<IOutputRow").append(kindText).append("> ").append(uid).append(";");
  3856. declarectx->addQuoted(s);
  3857. MetaInstance meta(*this, record, false);
  3858. buildMetaInfo(meta);
  3859. s.clear().append(uid).append(".setown(").append(meta.queryInstanceObject());
  3860. if (format == diskAtom)
  3861. s.append(".createDisk").append(kindText);
  3862. else if (format == internalAtom)
  3863. s.append(".createInternal").append(kindText);
  3864. else
  3865. throwUnexpected();
  3866. s.append("(ctx, ");
  3867. OwnedHqlExpr activityId = getCurrentActivityId(ctx);
  3868. generateExprCpp(s, activityId);
  3869. s.append("));");
  3870. callctx->addQuoted(s);
  3871. OwnedHqlExpr value = createVariable(uid.str(), makeBoolType());
  3872. declarectx->associateExpr(marker, value);
  3873. serializerName.append(uid);
  3874. }
  3875. void HqlCppTranslator::ensureRowPrefetcher(StringBuffer & prefetcherName, BuildCtx & ctx, IHqlExpression * record)
  3876. {
  3877. OwnedHqlExpr marker = createAttribute(prefetcherInstanceMarkerAtom, LINK(record->queryBody()));
  3878. HqlExprAssociation * match = ctx.queryMatchExpr(marker);
  3879. if (match)
  3880. {
  3881. generateExprCpp(prefetcherName, match->queryExpr());
  3882. return;
  3883. }
  3884. StringBuffer uid;
  3885. getUniqueId(uid.append("pf"));
  3886. BuildCtx * declarectx = &ctx;
  3887. BuildCtx * callctx = &ctx;
  3888. getInvariantMemberContext(ctx, &declarectx, &callctx, true, false);
  3889. StringBuffer s;
  3890. s.append("Owned<ISourceRowPrefetcher> ").append(uid).append(";");
  3891. declarectx->addQuoted(s);
  3892. MetaInstance meta(*this, record, false);
  3893. buildMetaInfo(meta);
  3894. s.clear().append(uid).append(".setown(").append(meta.queryInstanceObject());
  3895. s.append(".createDiskPrefetcher(ctx, ");
  3896. OwnedHqlExpr activityId = getCurrentActivityId(ctx);
  3897. generateExprCpp(s, activityId);
  3898. s.append("));");
  3899. callctx->addQuoted(s);
  3900. OwnedHqlExpr value = createVariable(uid.str(), makeBoolType());
  3901. declarectx->associateExpr(marker, value);
  3902. prefetcherName.append(uid);
  3903. }
  3904. IHqlExpression * HqlCppTranslator::createSerializer(BuildCtx & ctx, IHqlExpression * record, IAtom * form, IAtom * kind)
  3905. {
  3906. StringBuffer serializerName;
  3907. ensureRowSerializer(serializerName, ctx, record, form, kind);
  3908. return createQuoted(serializerName.str(), makeBoolType());
  3909. }
  3910. IHqlExpression * HqlCppTranslator::createResultName(IHqlExpression * name, bool expandLogicalName)
  3911. {
  3912. IHqlExpression * resultName = ::createResultName(name);
  3913. if (!expandLogicalName)
  3914. return resultName;
  3915. HqlExprArray args;
  3916. args.append(*resultName);
  3917. return bindFunctionCall(getExpandLogicalNameId, args);
  3918. }
  3919. bool HqlCppTranslator::registerGlobalUsage(IHqlExpression * filename)
  3920. {
  3921. bool matched = false;
  3922. ForEachItemIn(i, globalFiles)
  3923. {
  3924. if (globalFiles.item(i).checkMatch(filename))
  3925. matched = true;
  3926. }
  3927. return matched;
  3928. }
  3929. //---------------------------------------------------------------------------
  3930. IHqlExpression * HqlCppTranslator::convertBetweenCountAndSize(const CHqlBoundExpr & bound, bool getCount)
  3931. {
  3932. ITypeInfo * type = bound.expr->queryType();
  3933. if (getCount)
  3934. {
  3935. if (getIntValue(bound.length, 1) == 0)
  3936. return getSizetConstant(0);
  3937. }
  3938. else
  3939. {
  3940. if (getIntValue(bound.count, 1) == 0)
  3941. return getSizetConstant(0);
  3942. }
  3943. OwnedHqlExpr record;
  3944. switch (type->getTypeCode())
  3945. {
  3946. case type_dictionary:
  3947. case type_table:
  3948. case type_groupedtable:
  3949. record.set(bound.expr->queryRecord());
  3950. break;
  3951. case type_set:
  3952. case type_array:
  3953. {
  3954. ITypeInfo * elementType = type->queryChildType();
  3955. HqlExprArray fields;
  3956. fields.append(*createField(valueId, LINK(elementType), NULL));
  3957. record.setown(createRecord(fields));
  3958. break;
  3959. }
  3960. default:
  3961. UNIMPLEMENTED;
  3962. }
  3963. if (isFixedSizeRecord(record))
  3964. {
  3965. unsigned fixedSize = getMinRecordSize(record);
  3966. if (fixedSize == 0)
  3967. throwError(HQLERR_ZeroLengthIllegal);
  3968. if (type->getTypeCode() == type_groupedtable)
  3969. fixedSize++;
  3970. if (getCount)
  3971. {
  3972. if (fixedSize == 1)
  3973. return LINK(bound.length);
  3974. IValue * value = bound.length->queryValue();
  3975. if (value)
  3976. return getSizetConstant((unsigned)value->getIntValue()/fixedSize);
  3977. return createValue(no_div, LINK(sizetType), LINK(bound.length), getSizetConstant(fixedSize));
  3978. }
  3979. else
  3980. {
  3981. if (fixedSize == 1)
  3982. return LINK(bound.count);
  3983. IValue * value = bound.count->queryValue();
  3984. if (value)
  3985. return getSizetConstant((unsigned)value->getIntValue() * fixedSize);
  3986. return createValue(no_mul, LINK(sizetType), LINK(bound.count), getSizetConstant(fixedSize));
  3987. }
  3988. }
  3989. StringBuffer metaInstanceName, s;
  3990. buildMetaForSerializedRecord(metaInstanceName, record, (type->getTypeCode() == type_groupedtable));
  3991. HqlExprArray args;
  3992. IIdAtom * func;
  3993. if (getCount)
  3994. {
  3995. args.append(*getBoundSize(bound));
  3996. args.append(*LINK(bound.expr));
  3997. func = countRowsId;
  3998. }
  3999. else
  4000. {
  4001. args.append(*LINK(bound.count));
  4002. args.append(*LINK(bound.expr));
  4003. func = countToSizeId;
  4004. }
  4005. args.append(*createQuoted(s.clear().append("&").append(metaInstanceName), makeBoolType()));
  4006. return bindTranslatedFunctionCall(func, args);
  4007. }
  4008. //---------------------------------------------------------------------------
  4009. void HqlCppTranslator::noteResultDefined(BuildCtx & ctx, ActivityInstance * activityInstance, IHqlExpression * seq, IHqlExpression * name, bool alwaysExecuted)
  4010. {
  4011. unsigned graph = curGraphSequence();
  4012. assertex(graph);
  4013. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  4014. assertex(activeSubgraph);
  4015. if (isInternalSeq(seq))
  4016. {
  4017. internalResults.append(* new InternalResultTracker(name, activeSubgraph->tree, graph, activityInstance));
  4018. }
  4019. else if (alwaysExecuted)
  4020. {
  4021. assertex(activeSubgraph->tree->hasProp("att[@name=\"rootGraph\"]"));
  4022. }
  4023. }
  4024. void HqlCppTranslator::noteResultAccessed(BuildCtx & ctx, IHqlExpression * seq, IHqlExpression * name)
  4025. {
  4026. if (isInternalSeq(seq))
  4027. {
  4028. unsigned graph = curGraphSequence();
  4029. ForEachItemIn(i, internalResults)
  4030. {
  4031. if (internalResults.item(i).noteUse(name, graph))
  4032. {
  4033. //Can't currently break because the same result might be generated more than once
  4034. //if an expression ends up in two different graphs.
  4035. //break;
  4036. }
  4037. }
  4038. }
  4039. }
  4040. void HqlCppTranslator::buildGetResultInfo(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * boundTarget, const CHqlBoundTarget * targetAssign)
  4041. {
  4042. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  4043. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  4044. if (!name)
  4045. name = queryAttributeChild(expr, nameAtom, 0);
  4046. noteResultAccessed(ctx, seq, name);
  4047. if (insideLibrary())
  4048. {
  4049. SCMStringBuffer libraryName;
  4050. getOutputLibraryName(libraryName, wu());
  4051. StringBuffer storedName;
  4052. getStoredDescription(storedName, seq, name, true);
  4053. throwError2(HQLERR_LibraryNoWorkunitRead, libraryName.str(), storedName.str());
  4054. }
  4055. __int64 seqValue = seq->queryValue()->getIntValue();
  4056. assertex(!expr->hasAttribute(internalAtom) && !expr->hasAttribute(_internal_Atom));
  4057. bool expandLogical = (seqValue == ResultSequencePersist) && !expr->hasAttribute(_internal_Atom);
  4058. HqlExprArray args;
  4059. args.append(*createResultName(name, expandLogical));
  4060. args.append(*LINK(seq));
  4061. IIdAtom * func;
  4062. ITypeInfo * type = expr->queryType();
  4063. type_t ttc = type->getTypeCode();
  4064. OwnedITypeInfo overrideType;
  4065. switch(ttc)
  4066. {
  4067. case type_int: func = getResultIntId; break;
  4068. case type_swapint: func = getResultIntId; break;
  4069. case type_boolean: func = getResultBoolId; break;
  4070. case type_data: func = getResultDataId; break;
  4071. case type_dictionary:
  4072. case type_table:
  4073. case type_groupedtable:
  4074. case type_set:
  4075. //MORE: type_row...
  4076. {
  4077. OwnedHqlExpr record;
  4078. bool ensureSerialized = true;
  4079. if (ttc == type_dictionary)
  4080. {
  4081. record.set(::queryRecord(type));
  4082. //NB: The result type will be overridden when this function is bound
  4083. ensureSerialized = false;
  4084. overrideType.setown(setLinkCountedAttr(type, true));
  4085. func = getResultDictionaryId;
  4086. }
  4087. else if (ttc != type_set)
  4088. {
  4089. overrideType.set(type);
  4090. record.set(::queryRecord(type));
  4091. //NB: The result type (including grouping) will be overridden when this function is bound
  4092. func = getResultDatasetId;
  4093. bool defaultLCR = targetAssign ? hasLinkedRow(targetAssign->queryType()) : true;
  4094. if (hasLinkCountedModifier(type) || defaultLCR)
  4095. {
  4096. ensureSerialized = false;
  4097. args.append(*createRowAllocator(ctx, record));
  4098. args.append(*createConstant(isGrouped(expr)));
  4099. overrideType.setown(setLinkCountedAttr(overrideType, true));
  4100. func = getResultRowsetId;
  4101. }
  4102. }
  4103. else
  4104. {
  4105. overrideType.set(type);
  4106. ITypeInfo * elementType = type->queryChildType();
  4107. OwnedHqlExpr field = createField(valueId, LINK(elementType), NULL);
  4108. record.setown(createRecord(field));
  4109. func = getResultSetId;
  4110. }
  4111. if (ensureSerialized && record)
  4112. record.setown(getSerializedForm(record, diskAtom));
  4113. if (record && (seqValue == ResultSequenceStored))
  4114. {
  4115. StringBuffer s;
  4116. OwnedHqlExpr ds = createDataset(no_anon, LINK(record));
  4117. StringBuffer xmlInstanceName, xmlFactoryName;
  4118. bool usesContents = false;
  4119. getUniqueId(xmlInstanceName.append("xml"));
  4120. buildXmlReadTransform(ds, xmlFactoryName, usesContents);
  4121. OwnedHqlExpr curActivityId = getCurrentActivityId(ctx);
  4122. s.append("Owned<IXmlToRowTransformer> ").append(xmlInstanceName).append(" = ").append(xmlFactoryName).append("(ctx,");
  4123. generateExprCpp(s, curActivityId).append(");");
  4124. ctx.addQuoted(s);
  4125. args.append(*createQuoted(xmlInstanceName, makeBoolType()));
  4126. StringBuffer csvInstanceName;
  4127. if (canReadFromCsv(record))
  4128. {
  4129. buildCsvReadTransformer(ds, csvInstanceName, NULL);
  4130. csvInstanceName.insert(0, "&");
  4131. }
  4132. else
  4133. {
  4134. csvInstanceName.clear().append("0");
  4135. }
  4136. args.append(*createQuoted(csvInstanceName, makeBoolType()));
  4137. }
  4138. else
  4139. {
  4140. args.append(*createQuoted("0", makeBoolType()));
  4141. args.append(*createQuoted("0", makeBoolType()));
  4142. }
  4143. if (ttc == type_dictionary)
  4144. {
  4145. StringBuffer lookupHelperName;
  4146. buildDictionaryHashClass(expr->queryRecord(), lookupHelperName);
  4147. lookupHelperName.insert(0, "&"); // MORE: Should this be passed by reference instead - it isn't optional
  4148. args.append(*createQuoted(lookupHelperName.str(), makeBoolType()));
  4149. }
  4150. break;
  4151. }
  4152. case type_string:
  4153. {
  4154. func = getResultStringId;
  4155. if ((type->queryCharset()->queryName() != asciiAtom) || !targetAssign)
  4156. break;
  4157. ITypeInfo * targetType = targetAssign->queryType();
  4158. if ((targetType->getTypeCode() != type_string) || (targetType->getSize() == UNKNOWN_LENGTH) ||
  4159. (targetType->queryCharset() != type->queryCharset()))
  4160. break;
  4161. //more: if (options.checkOverflow && queryUnqualifiedType(targetType) != queryUnqualifiedType(type)
  4162. args.add(*targetAssign->getTranslatedExpr(), 0);
  4163. buildFunctionCall(ctx, getResultStringFId, args);
  4164. return;
  4165. }
  4166. case type_qstring: func = getResultStringId; break;
  4167. case type_varstring:func = getResultVarStringId; break;
  4168. case type_unicode: func = getResultUnicodeId; break;
  4169. case type_varunicode:func = getResultVarUnicodeId; break;
  4170. case type_utf8: func = getResultUnicodeId; break;
  4171. case type_real: func = getResultRealId; break;
  4172. case type_decimal:
  4173. {
  4174. //Special case - need to bind the first parameter..., since not calling buildExpr on the call.
  4175. //sequence is always a constant, so no need to bind.
  4176. CHqlBoundExpr boundName;
  4177. buildExpr(ctx, &args.item(0), boundName);
  4178. args.replace(*LINK(boundName.expr), 0);
  4179. const CHqlBoundTarget * getTarget = targetAssign;
  4180. CHqlBoundTarget tempTarget;
  4181. if (!getTarget)
  4182. {
  4183. getTarget = &tempTarget;
  4184. createTempFor(ctx, expr, tempTarget);
  4185. }
  4186. args.add(*createConstant((int)type->getSize()), 0);
  4187. args.add(*getSizetConstant(type->getPrecision()),1);
  4188. args.add(*createConstant(type->isSigned()),2);
  4189. args.add(*getPointer(getTarget->expr), 3);
  4190. callProcedure(ctx, getResultDecimalId, args);
  4191. if (boundTarget)
  4192. boundTarget->setFromTarget(*getTarget);
  4193. return;
  4194. }
  4195. case type_row: UNIMPLEMENTED; break; //should be translated to rawData.
  4196. default:
  4197. PrintLog("%d", ttc);
  4198. throwUnexpectedX("No getResult defined for this type");
  4199. break;
  4200. }
  4201. OwnedHqlExpr function = bindFunctionCall(func, args, overrideType);
  4202. switch (ttc)
  4203. {
  4204. case type_qstring:
  4205. {
  4206. Owned<ITypeInfo> qstrType = makeQStringType(UNKNOWN_LENGTH);
  4207. function.setown(ensureExprType(function, type));
  4208. break;
  4209. }
  4210. case type_string:
  4211. case type_varstring:
  4212. {
  4213. if (type->queryCollation()->queryName() != asciiAtom)
  4214. function.setown(ensureExprType(function, type));
  4215. break;
  4216. }
  4217. }
  4218. if (boundTarget)
  4219. buildExpr(ctx, function, *boundTarget);
  4220. else
  4221. buildExprAssign(ctx, *targetAssign, function);
  4222. }
  4223. void HqlCppTranslator::buildSetXmlSerializer(StringBuffer & helper, ITypeInfo * valueType)
  4224. {
  4225. BuildCtx declarectx(*code, declareAtom);
  4226. OwnedHqlExpr search = createQuoted("setXmlHelper", LINK(valueType));
  4227. // stop duplicate classes being generated.
  4228. // MORE: If this ever includes sorting/grouping, the dependence on a record will need to be revised
  4229. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  4230. if (match)
  4231. {
  4232. match->queryExpr()->toString(helper);
  4233. return;
  4234. }
  4235. StringBuffer helperclass;
  4236. unique_id_t id = getUniqueId();
  4237. appendUniqueId(helper.append("r2x"), id);
  4238. appendUniqueId(helperclass.append("cr2x"), id);
  4239. BuildCtx r2xctx(declarectx);
  4240. r2xctx.setNextPriority(XmlTransformerPrio);
  4241. StringBuffer s, endText;
  4242. s.append("struct ").append(helperclass).append(" : public ISetToXmlTransformer");
  4243. endText.append(" ").append(helper).append(";");
  4244. r2xctx.addQuotedCompound(s, endText.str());
  4245. CHqlBoundExpr boundValue;
  4246. boundValue.isAll.setown(createVariable("isAll", makeBoolType()));
  4247. boundValue.length.setown(createVariable("length", LINK(sizetType)));
  4248. boundValue.expr.setown(createVariable("self", makeReferenceModifier(LINK(valueType))));
  4249. {
  4250. MemberFunction func(*this, r2xctx, "virtual void toXML(bool isAll, size32_t length, const byte * self, IXmlWriter & out)");
  4251. OwnedHqlExpr itemName = createConstant("Item");
  4252. OwnedHqlExpr value = boundValue.getTranslatedExpr();
  4253. buildXmlSerializeSetValues(func.ctx, value, itemName, true);
  4254. }
  4255. if (options.spanMultipleCpp)
  4256. {
  4257. StringBuffer helperFunc;
  4258. createAccessFunctions(helperFunc, declarectx, XmlTransformerPrio, "ISetToXmlTransformer", helper);
  4259. helper.clear().append(helperFunc).append("()");
  4260. }
  4261. OwnedHqlExpr name = createVariable(helper, makeVoidType());
  4262. declarectx.associateExpr(search, name);
  4263. }
  4264. IWUResult * HqlCppTranslator::createWorkunitResult(int sequence, IHqlExpression * nameExpr)
  4265. {
  4266. switch(sequence)
  4267. {
  4268. case ResultSequenceStored:
  4269. {
  4270. assertex(nameExpr);
  4271. StringBuffer storedName;
  4272. getStringValue(storedName, nameExpr);
  4273. return wu()->updateVariableByName(storedName.str());
  4274. }
  4275. case ResultSequencePersist:
  4276. case ResultSequenceInternal:
  4277. case ResultSequenceOnce:
  4278. return NULL;
  4279. }
  4280. assertex(sequence >= 0);
  4281. StringBuffer resultName;
  4282. getStringValue(resultName, nameExpr);
  4283. if (resultName.length() == 0)
  4284. resultName.append("Result ").append(sequence+1);
  4285. Owned<IWUResult> result = wu()->updateResultBySequence(sequence);
  4286. result->setResultName(resultName);
  4287. return result.getClear();
  4288. }
  4289. void checkAppendXpathNamePrefix(StringArray &prefixes, const char *xpathName)
  4290. {
  4291. if (!xpathName || !*xpathName)
  4292. return;
  4293. if (*xpathName=='@')
  4294. xpathName++;
  4295. if (*xpathName==':')
  4296. return;
  4297. const char *colon = strchr(xpathName, ':');
  4298. if (!colon)
  4299. return;
  4300. StringAttr prefix;
  4301. prefix.set(xpathName, colon-xpathName);
  4302. if (prefixes.find(prefix.get())==NotFound)
  4303. prefixes.append(prefix);
  4304. }
  4305. void gatherXpathPrefixes(StringArray &prefixes, IHqlExpression * record)
  4306. {
  4307. ForEachChild(i, record)
  4308. {
  4309. IHqlExpression * cur = record->queryChild(i);
  4310. switch (cur->getOperator())
  4311. {
  4312. case no_field:
  4313. {
  4314. //don't need to be too picky about xpath field types, worst case if an xpath is too long, we end up with an extra prefix
  4315. StringBuffer xpathName, xpathItem;
  4316. extractXmlName(xpathName, &xpathItem, NULL, cur, NULL, false);
  4317. checkAppendXpathNamePrefix(prefixes, xpathName);
  4318. checkAppendXpathNamePrefix(prefixes, xpathItem);
  4319. ITypeInfo * type = cur->queryType();
  4320. switch (type->getTypeCode())
  4321. {
  4322. case type_row:
  4323. case type_dictionary:
  4324. case type_table:
  4325. case type_groupedtable:
  4326. gatherXpathPrefixes(prefixes, cur->queryRecord());
  4327. break;
  4328. }
  4329. break;
  4330. }
  4331. case no_ifblock:
  4332. gatherXpathPrefixes(prefixes, cur->queryChild(1));
  4333. break;
  4334. case no_record:
  4335. gatherXpathPrefixes(prefixes, cur);
  4336. break;
  4337. }
  4338. }
  4339. }
  4340. void addDatasetResultXmlNamespaces(IWUResult &result, HqlExprArray &xmlnsAttrs, IHqlExpression *record)
  4341. {
  4342. StringArray declaredPrefixes;
  4343. ForEachItemIn(idx, xmlnsAttrs)
  4344. {
  4345. IHqlExpression & xmlns = xmlnsAttrs.item(idx);
  4346. StringBuffer xmlnsPrefix;
  4347. StringBuffer xmlnsURI;
  4348. getUTF8Value(xmlnsPrefix, xmlns.queryChild(0));
  4349. getUTF8Value(xmlnsURI, xmlns.queryChild(1));
  4350. if (xmlnsURI.length())
  4351. {
  4352. if (xmlnsPrefix.length() && declaredPrefixes.find(xmlnsPrefix)==NotFound)
  4353. {
  4354. if (!validateXMLTag(xmlnsPrefix))
  4355. throwError1(HQLERR_InvalidXmlnsPrefix, xmlnsPrefix.str());
  4356. declaredPrefixes.append(xmlnsPrefix);
  4357. }
  4358. result.setResultXmlns(xmlnsPrefix, xmlnsURI);
  4359. }
  4360. }
  4361. StringArray usedPrefixes;
  4362. if (record)
  4363. gatherXpathPrefixes(usedPrefixes, record);
  4364. ForEachItemIn(p, usedPrefixes)
  4365. {
  4366. const char *prefix = usedPrefixes.item(p);
  4367. if (declaredPrefixes.find(prefix)==NotFound)
  4368. {
  4369. StringBuffer uri("urn:hpccsystems:ecl:unknown:");
  4370. uri.append(prefix);
  4371. result.setResultXmlns(prefix, uri);
  4372. }
  4373. }
  4374. }
  4375. void HqlCppTranslator::buildSetResultInfo(BuildCtx & ctx, IHqlExpression * originalExpr, IHqlExpression * value, ITypeInfo * type, bool isPersist, bool associateResult)
  4376. {
  4377. IHqlExpression * seq = queryAttributeChild(originalExpr, sequenceAtom, 0);
  4378. IHqlExpression * name = queryAttributeChild(originalExpr, namedAtom, 0);
  4379. if (insideLibrary())
  4380. {
  4381. SCMStringBuffer libraryName;
  4382. getOutputLibraryName(libraryName, wu());
  4383. StringBuffer storedName;
  4384. getStoredDescription(storedName, seq, name, true);
  4385. throwError2(HQLERR_LibraryNoWorkunitWrite, libraryName.str(), storedName.str());
  4386. }
  4387. ITypeInfo * resultType = type ? type->queryPromotedType() : value->queryType()->queryPromotedType();
  4388. Linked<ITypeInfo> schemaType = resultType;
  4389. type_t retType = schemaType->getTypeCode();
  4390. IIdAtom * func = NULL;
  4391. CHqlBoundExpr valueToSave;
  4392. LinkedHqlExpr castValue = value;
  4393. LinkedHqlExpr size;
  4394. switch(retType)
  4395. {
  4396. case type_int:
  4397. case type_swapint:
  4398. {
  4399. bool isSigned = schemaType->isSigned();
  4400. func = isSigned ? setResultIntId : setResultUIntId;
  4401. schemaType.setown(makeIntType(8, isSigned));
  4402. size.setown(getSizetConstant(schemaType->getSize()));
  4403. break;
  4404. }
  4405. case type_boolean: func = setResultBoolId; break;
  4406. case type_string: func = setResultStringId; schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL)); break;
  4407. case type_unicode: func = setResultUnicodeId; schemaType.setown(makeUnicodeType(UNKNOWN_LENGTH, 0)); break;
  4408. case type_utf8: func = setResultUnicodeId; schemaType.setown(makeUnicodeType(UNKNOWN_LENGTH, 0)); castValue.setown(ensureExprType(value, schemaType)); associateResult = false; break;
  4409. case type_qstring: func = setResultStringId; schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL)); break;
  4410. case type_data: func = setResultDataId; schemaType.setown(makeDataType(UNKNOWN_LENGTH)); break;
  4411. case type_varstring:func = setResultVarStringId; schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL)); break;
  4412. case type_varunicode:func = setResultVarUnicodeId; schemaType.setown(makeUnicodeType(UNKNOWN_LENGTH, 0)); break;
  4413. case type_real: func = setResultRealId; schemaType.setown(makeRealType(8)); break;
  4414. case type_decimal: func = setResultDecimalId; break;
  4415. case type_row:
  4416. {
  4417. CHqlBoundExpr boundLength;
  4418. OwnedHqlExpr serialized = ::ensureSerialized(value, diskAtom);
  4419. func = setResultRawId;
  4420. Owned<IReferenceSelector> ds = buildNewRow(ctx, serialized);
  4421. OwnedHqlExpr size = createSizeof(ds->queryExpr());
  4422. buildExpr(ctx, size, boundLength);
  4423. ds->buildAddress(ctx, valueToSave);
  4424. valueToSave.length.set(boundLength.expr);
  4425. valueToSave.expr.setown(createValue(no_typetransfer, makeDataType(UNKNOWN_LENGTH), LINK(valueToSave.expr)));
  4426. schemaType.set(schemaType->queryChildType());
  4427. break;
  4428. }
  4429. case type_set:
  4430. {
  4431. func = setResultSetId;
  4432. ITypeInfo * elementType = LINK(schemaType->queryChildType());
  4433. if (!elementType)
  4434. elementType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  4435. schemaType.setown(makeSetType(elementType));
  4436. }
  4437. break;
  4438. case type_dictionary:
  4439. case type_table:
  4440. case type_groupedtable:
  4441. {
  4442. throwUnexpected();
  4443. #if 0
  4444. HqlExprArray args;
  4445. args.append(*LINK(value));
  4446. args.append(*createAttribute(sequenceAtom, LINK(seq)));
  4447. if (name)
  4448. args.append(*createAttribute(nameAtom, LINK(name)));
  4449. OwnedHqlExpr createFile = createValue(no_output, makeVoidType(), args);
  4450. buildStmt(ctx, createFile);
  4451. // MORE - the file name should be a unique temporary...
  4452. // MORE - associate a logical name with it
  4453. // MORE - save the logical name in the workunit
  4454. #endif
  4455. return;
  4456. }
  4457. case type_any:
  4458. //Someone has used error instead of fail. Don't do anything....
  4459. if (value->getOperator() == no_fail)
  4460. {
  4461. buildStmt(ctx, value);
  4462. return;
  4463. }
  4464. //fall through
  4465. default:
  4466. PrintLog("%d", retType);
  4467. throwError(HQLERR_InvalidSetResultType);
  4468. }
  4469. HqlExprArray args;
  4470. if (!valueToSave.expr)
  4471. {
  4472. LinkedHqlExpr cseValue = castValue;
  4473. if (options.spotCSE)
  4474. cseValue.setown(spotScalarCSE(cseValue, NULL, queryOptions().spotCseInIfDatasetConditions));
  4475. if ((retType == type_set) && isComplexSet(resultType, castValue->isConstant()) && castValue->getOperator() == no_list && !isNullList(castValue))
  4476. {
  4477. CHqlBoundTarget tempTarget;
  4478. createTempFor(ctx, resultType, tempTarget, typemod_none, FormatBlockedDataset);
  4479. Owned<IHqlCppSetBuilder> builder = createTempSetBuilder(tempTarget.queryType()->queryChildType(), tempTarget.isAll);
  4480. builder->buildDeclare(ctx);
  4481. buildSetAssign(ctx, builder, castValue);
  4482. builder->buildFinish(ctx, tempTarget);
  4483. valueToSave.setFromTarget(tempTarget);
  4484. }
  4485. else
  4486. buildSimpleExpr(ctx, cseValue, valueToSave);
  4487. if (associateResult)
  4488. {
  4489. OwnedHqlExpr getResult = createGetResultFromSetResult(originalExpr);
  4490. ctx.associateExpr(getResult, valueToSave);
  4491. }
  4492. }
  4493. assertex(func);
  4494. OwnedHqlExpr nameText = createResultName(name, isPersist);
  4495. if (retType == type_decimal)
  4496. {
  4497. assertex(schemaType->getSize() != UNKNOWN_LENGTH);
  4498. //An ugly exception because it takes an arbitrary length decimal.
  4499. //This should be handled by having a decimal(unknown length) parameter to a function which passes size and precision
  4500. CHqlBoundExpr boundName;
  4501. buildExpr(ctx, nameText, boundName);
  4502. args.append(*LINK(boundName.expr));
  4503. args.append(*LINK(seq));
  4504. args.append(*getBoundSize(valueToSave));
  4505. args.append(*getSizetConstant(schemaType->getPrecision()));
  4506. args.append(*createConstant(schemaType->isSigned()));
  4507. args.append(*getPointer(valueToSave.expr));
  4508. buildTranslatedFunctionCall(ctx, func, args);
  4509. }
  4510. else
  4511. {
  4512. args.append(*nameText.getLink());
  4513. args.append(*LINK(seq));
  4514. args.append(*valueToSave.getTranslatedExpr());
  4515. if (func == setResultSetId)
  4516. {
  4517. StringBuffer helper, s;
  4518. buildSetXmlSerializer(helper, resultType);
  4519. s.clear().append("&").append(helper);
  4520. args.append(*createQuoted(s, makeBoolType()));
  4521. }
  4522. else if (func == setResultIntId || func == setResultUIntId)
  4523. args.append(*getSizetConstant(schemaType->getSize()));
  4524. buildFunctionCall(ctx, func, args);
  4525. }
  4526. if(wu())
  4527. {
  4528. HqlExprArray xmlnsAttrs;
  4529. gatherAttributes(xmlnsAttrs, xmlnsAtom, originalExpr);
  4530. Owned<IWUResult> result;
  4531. if (retType == type_row)
  4532. {
  4533. OwnedHqlExpr record = LINK(::queryRecord(schemaType));
  4534. if (originalExpr->hasAttribute(noXpathAtom))
  4535. record.setown(removeAttributeFromFields(record, xpathAtom));
  4536. result.setown(createDatasetResultSchema(seq, name, record, xmlnsAttrs, false, false, 0));
  4537. if (result)
  4538. result->setResultTotalRowCount(1);
  4539. }
  4540. else
  4541. {
  4542. // Bit of a mess - should split into two procedures
  4543. int sequence = (int) seq->queryValue()->getIntValue();
  4544. result.setown(createWorkunitResult(sequence, name));
  4545. if(result)
  4546. {
  4547. StringBuffer fieldName;
  4548. SCMStringBuffer resultName;
  4549. result->getResultName(resultName);
  4550. const char * cur = resultName.str();
  4551. while (*cur)
  4552. {
  4553. unsigned char c = *cur++;
  4554. if (isalnum(c) || (c == '_'))
  4555. fieldName.append(c);
  4556. else if (isspace(c))
  4557. fieldName.append('_');
  4558. }
  4559. addDatasetResultXmlNamespaces(*result, xmlnsAttrs, NULL);
  4560. MemoryBuffer schema;
  4561. schema.append(fieldName.str());
  4562. schemaType->serialize(schema);
  4563. schema.append("").append((unsigned char) type_void);
  4564. schema.append((unsigned)0);
  4565. result->setResultSchemaRaw(schema.length(), schema.toByteArray());
  4566. StringBuffer xml;
  4567. {
  4568. XmlSchemaBuilder xmlbuilder(false);
  4569. xmlbuilder.addField(fieldName, *schemaType, false);
  4570. xmlbuilder.getXml(xml);
  4571. }
  4572. addSchemaResource(sequence, resultName.str(), xml.length()+1, xml.str());
  4573. }
  4574. }
  4575. if (result)
  4576. {
  4577. ActivityInstance * activity = queryCurrentActivity(ctx);
  4578. if (activity)
  4579. {
  4580. const char * graphName = activeGraph->name;
  4581. result->setResultWriteLocation(graphName, activity->activityId);
  4582. }
  4583. IHqlExpression * format = originalExpr->queryAttribute(storedFieldFormatAtom);
  4584. if (format)
  4585. {
  4586. ForEachChild(i, format)
  4587. {
  4588. StringBuffer name;
  4589. StringBuffer value;
  4590. OwnedHqlExpr folded = foldHqlExpression(format->queryChild(i));
  4591. getHintNameValue(folded, name, value);
  4592. result->setResultFieldOpt(name, value);
  4593. }
  4594. }
  4595. }
  4596. }
  4597. }
  4598. void HqlCppTranslator::buildCompareClass(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4599. {
  4600. BuildCtx classctx(ctx);
  4601. IHqlStmt * classStmt = beginNestedClass(classctx, name, "ICompare");
  4602. {
  4603. MemberFunction func(*this, classctx, "virtual int docompare(const void * _left, const void * _right) const" OPTIMIZE_FUNCTION_ATTRIBUTE);
  4604. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  4605. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  4606. func.ctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4607. bindTableCursor(func.ctx, datasetLeft, "left", no_left, selSeq);
  4608. bindTableCursor(func.ctx, datasetRight, "right", no_right, selSeq);
  4609. if (orderExpr->getOperator() == no_order)
  4610. doBuildReturnCompare(func.ctx, orderExpr, no_order, false, false);
  4611. else
  4612. buildReturn(func.ctx, orderExpr);
  4613. }
  4614. endNestedClass(classStmt);
  4615. }
  4616. void HqlCppTranslator::buildCompareMemberLR(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4617. {
  4618. StringBuffer s;
  4619. s.clear().append("virtual ICompare * query").append(name).append("() { return &").append(name).append("; }");
  4620. ctx.addQuoted(s);
  4621. buildCompareClass(ctx, name, orderExpr, datasetLeft, datasetRight, selSeq);
  4622. }
  4623. void HqlCppTranslator::buildCompareMember(BuildCtx & ctx, const char * name, IHqlExpression * cond, const DatasetReference & dataset)
  4624. {
  4625. //MORE:Support multiple comparison fields.
  4626. IHqlExpression * datasetExpr = dataset.queryDataset();
  4627. OwnedHqlExpr seq = createDummySelectorSequence();
  4628. OwnedHqlExpr leftSelect = createSelector(no_left, datasetExpr, seq);
  4629. OwnedHqlExpr rightSelect = createSelector(no_right, datasetExpr, seq);
  4630. IHqlExpression * left = dataset.mapCompound(cond, leftSelect);
  4631. IHqlExpression * right = dataset.mapCompound(cond, rightSelect);
  4632. OwnedHqlExpr compare = createValue(no_order, LINK(signedType), left, right);
  4633. buildCompareMemberLR(ctx, name, compare, datasetExpr, datasetExpr, seq);
  4634. }
  4635. void HqlCppTranslator::buildCompareEqClass(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4636. {
  4637. BuildCtx classctx(ctx);
  4638. IHqlStmt * classStmt = beginNestedClass(classctx, name, "ICompareEq");
  4639. {
  4640. MemberFunction func(*this, classctx, "virtual bool match(const void * _left, const void * _right) const");
  4641. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  4642. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  4643. func.ctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4644. bindTableCursor(func.ctx, datasetLeft, "left", no_left, selSeq);
  4645. bindTableCursor(func.ctx, datasetRight, "right", no_right, selSeq);
  4646. if (orderExpr->getOperator() == no_order)
  4647. doBuildReturnCompare(func.ctx, orderExpr, no_eq, true, false);
  4648. else
  4649. buildReturn(func.ctx, orderExpr);
  4650. }
  4651. endNestedClass(classStmt);
  4652. }
  4653. void HqlCppTranslator::buildCompareEqMemberLR(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4654. {
  4655. StringBuffer s;
  4656. s.clear().append("virtual ICompareEq * query").append(name).append("() { return &").append(name).append("; }");
  4657. ctx.addQuoted(s);
  4658. buildCompareEqClass(ctx, name, orderExpr, datasetLeft, datasetRight, selSeq);
  4659. }
  4660. void HqlCppTranslator::buildNaryCompareClass(BuildCtx & ctx, const char * name, IHqlExpression * expr, IHqlExpression * dataset, IHqlExpression * selSeq, IHqlExpression * rowsid)
  4661. {
  4662. BuildCtx classctx(ctx);
  4663. IHqlStmt * classStmt = beginNestedClass(classctx, name, "INaryCompareEq");
  4664. {
  4665. MemberFunction func(*this, classctx, "virtual bool match(unsigned numRows, const void * * _rows) const");
  4666. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _rows[0];");
  4667. func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
  4668. func.ctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4669. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  4670. bindRows(func.ctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", false);
  4671. buildReturn(func.ctx, expr);
  4672. }
  4673. endNestedClass(classStmt);
  4674. }
  4675. void HqlCppTranslator::buildNaryCompareMember(BuildCtx & ctx, const char * name, IHqlExpression * expr, IHqlExpression * datasetLeft, IHqlExpression * selSeq, IHqlExpression * rowsid)
  4676. {
  4677. StringBuffer s;
  4678. s.clear().append("virtual INaryCompareEq * query").append(name).append("() { return &").append(name).append("; }");
  4679. ctx.addQuoted(s);
  4680. buildNaryCompareClass(ctx, name, expr, datasetLeft, selSeq, rowsid);
  4681. }
  4682. void HqlCppTranslator::buildCompareEqMember(BuildCtx & ctx, const char * name, IHqlExpression * cond, const DatasetReference & dataset)
  4683. {
  4684. //MORE:Support multiple comparison fields.
  4685. IHqlExpression * datasetExpr = dataset.queryDataset();
  4686. OwnedHqlExpr seq = createDummySelectorSequence();
  4687. OwnedHqlExpr leftSelect = createSelector(no_left, datasetExpr, seq);
  4688. OwnedHqlExpr rightSelect = createSelector(no_right, datasetExpr, seq);
  4689. IHqlExpression * left = dataset.mapCompound(cond, leftSelect);
  4690. IHqlExpression * right = dataset.mapCompound(cond, rightSelect);
  4691. OwnedHqlExpr compare = createValue(no_order, LINK(signedType), left, right);
  4692. buildCompareEqMemberLR(ctx, name, compare, datasetExpr, datasetExpr, seq);
  4693. }
  4694. void HqlCppTranslator::buildOrderedCompare(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * sorts, CHqlBoundExpr & bound, IHqlExpression * leftDataset, IHqlExpression * rightDataset)
  4695. {
  4696. //MORE: This needs to be more intelligent to deal with related datasets (child datasets will work ok).
  4697. //MORE: Should create a member function if a member of a class.
  4698. //Otherwise a function + generate an error if it uses fields outside of the context?
  4699. //Would also need to pass in parent cursors for a global function since parent will not be available.
  4700. //MORE:Support multiple comparison fields.
  4701. OwnedHqlExpr compare = createOrderFromSortList(DatasetReference(dataset), sorts, leftDataset, rightDataset);
  4702. buildTempExpr(ctx, compare, bound);
  4703. }
  4704. void HqlCppTranslator::buildHashClass(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, const DatasetReference & dataset)
  4705. {
  4706. StringBuffer s;
  4707. s.clear().append("virtual IHash * query").append(name).append("() { return &").append(name).append("; }");
  4708. ctx.addQuoted(s);
  4709. BuildCtx classctx(ctx);
  4710. IHqlStmt * classStmt = beginNestedClass(classctx, name, "IHash");
  4711. {
  4712. MemberFunction hashFunc(*this, classctx, "virtual unsigned hash(const void * _self)");
  4713. hashFunc.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *) _self;");
  4714. bindTableCursor(hashFunc.ctx, dataset.queryDataset(), "self", dataset.querySide(), dataset.querySelSeq());
  4715. OwnedITypeInfo returnType = makeIntType(4, false);
  4716. buildReturn(hashFunc.ctx, orderExpr, returnType);
  4717. }
  4718. endNestedClass(classStmt);
  4719. }
  4720. void HqlCppTranslator::buildCompareClass(BuildCtx & ctx, const char * name, IHqlExpression * sortList, const DatasetReference & dataset)
  4721. {
  4722. BuildCtx comparectx(ctx);
  4723. IHqlStmt * classStmt = beginNestedClass(comparectx, name, "ICompare");
  4724. {
  4725. MemberFunction func(*this, comparectx, "virtual int docompare(const void * _left, const void * _right) const" OPTIMIZE_FUNCTION_ATTRIBUTE);
  4726. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  4727. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  4728. func.ctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4729. buildReturnOrder(func.ctx, sortList, dataset);
  4730. }
  4731. endNestedClass(classStmt);
  4732. }
  4733. void HqlCppTranslator::buildHashOfExprsClass(BuildCtx & ctx, const char * name, IHqlExpression * cond, const DatasetReference & dataset, bool compareToSelf)
  4734. {
  4735. IHqlExpression * attr = compareToSelf ? createAttribute(internalAtom) : NULL;
  4736. OwnedHqlExpr hash = createValue(no_hash32, LINK(unsignedType), LINK(cond), attr);
  4737. buildHashClass(ctx, name, hash, dataset);
  4738. }
  4739. void HqlCppTranslator::buildDictionaryHashClass(IHqlExpression *record, StringBuffer &funcName)
  4740. {
  4741. BuildCtx declarectx(*code, declareAtom);
  4742. OwnedHqlExpr attr = createAttribute(lookupAtom, LINK(record));
  4743. HqlExprAssociation * match = declarectx.queryMatchExpr(attr);
  4744. if (match)
  4745. match->queryExpr()->toString(funcName);
  4746. else
  4747. {
  4748. StringBuffer lookupHelperName;
  4749. appendUniqueId(lookupHelperName.append("lu"), getConsistentUID(record));
  4750. BuildCtx classctx(declarectx);
  4751. classctx.setNextPriority(TypeInfoPrio);
  4752. IHqlStmt * classStmt = beginNestedClass(classctx, lookupHelperName, "IHThorHashLookupInfo");
  4753. OwnedHqlExpr searchRecord = getDictionarySearchRecord(record);
  4754. OwnedHqlExpr keyRecord = getDictionaryKeyRecord(record);
  4755. HqlExprArray keyedSourceFields;
  4756. HqlExprArray keyedDictFields;
  4757. OwnedHqlExpr source = createDataset(no_null, LINK(searchRecord));
  4758. DatasetReference sourceRef(source, no_none, NULL);
  4759. OwnedHqlExpr dict = createDataset(no_null, LINK(record));
  4760. DatasetReference dictRef(dict, no_none, NULL);
  4761. ForEachChild(idx, searchRecord)
  4762. {
  4763. IHqlExpression *child = searchRecord->queryChild(idx);
  4764. if (!child->isAttribute())
  4765. keyedSourceFields.append(*createSelectExpr(LINK(source->queryNormalizedSelector()), LINK(child)));
  4766. }
  4767. ForEachChild(idx2, keyRecord)
  4768. {
  4769. IHqlExpression *child = keyRecord->queryChild(idx2);
  4770. if (!child->isAttribute())
  4771. keyedDictFields.append(*createSelectExpr(LINK(dict->queryNormalizedSelector()), LINK(child)));
  4772. }
  4773. OwnedHqlExpr keyedSourceList = createValueSafe(no_sortlist, makeSortListType(NULL), keyedSourceFields);
  4774. OwnedHqlExpr keyedDictList = createValueSafe(no_sortlist, makeSortListType(NULL), keyedDictFields);
  4775. buildHashOfExprsClass(classctx, "HashLookup", keyedSourceList, sourceRef, false);
  4776. buildHashOfExprsClass(classctx, "Hash", keyedDictList, dictRef, false);
  4777. OwnedHqlExpr seq = createDummySelectorSequence();
  4778. OwnedHqlExpr leftSelect = createSelector(no_left, source, seq);
  4779. OwnedHqlExpr rightSelect = createSelector(no_right, dict, seq);
  4780. IHqlExpression * left = sourceRef.mapCompound(keyedSourceList, leftSelect);
  4781. IHqlExpression * right = dictRef.mapCompound(keyedDictList, rightSelect);
  4782. OwnedHqlExpr compare = createValue(no_order, LINK(signedType), left, right);
  4783. buildCompareMemberLR(classctx, "CompareLookup", compare, source, dict, seq);
  4784. buildCompareMember(classctx, "Compare", keyedDictList, dictRef);
  4785. endNestedClass(classStmt);
  4786. if (queryOptions().spanMultipleCpp)
  4787. {
  4788. createAccessFunctions(funcName, declarectx, BuildCtx::NormalPrio, "IHThorHashLookupInfo", lookupHelperName);
  4789. funcName.append("()");
  4790. }
  4791. else
  4792. funcName.append(lookupHelperName);
  4793. OwnedHqlExpr func = createVariable(funcName, makeVoidType());
  4794. declarectx.associateExpr(attr, func);
  4795. }
  4796. }
  4797. void HqlCppTranslator::buildDictionaryHashMember(BuildCtx & ctx, IHqlExpression *dictionary, const char * memberName)
  4798. {
  4799. StringBuffer lookupHelperName;
  4800. buildDictionaryHashClass(dictionary->queryRecord(), lookupHelperName);
  4801. BuildCtx funcctx(ctx);
  4802. StringBuffer s;
  4803. s.append("virtual IHThorHashLookupInfo * ").append(memberName).append("() { return &").append(lookupHelperName).append("; }");
  4804. funcctx.addQuoted(s);
  4805. }
  4806. //---------------------------------------------------------------------------
  4807. IHqlExpression * queryImplementationInterface(IHqlExpression * moduleFunc)
  4808. {
  4809. IHqlExpression * module = moduleFunc->queryChild(0);
  4810. IHqlExpression * library = module->queryAttribute(libraryAtom);
  4811. if (library)
  4812. return library->queryChild(0);
  4813. return moduleFunc;
  4814. }
  4815. bool isLibraryScope(IHqlExpression * expr)
  4816. {
  4817. while (expr->getOperator() == no_comma)
  4818. expr = expr->queryChild(1);
  4819. return expr->isScope();
  4820. }
  4821. bool HqlCppTranslator::prepareToGenerate(HqlQueryContext & query, WorkflowArray & actions, bool isEmbeddedLibrary)
  4822. {
  4823. bool createLibrary = isLibraryScope(query.expr);
  4824. if (createLibrary)
  4825. {
  4826. if (query.expr->getOperator() != no_funcdef)
  4827. throwError(HQLERR_LibraryMustBeFunctional);
  4828. ::Release(outputLibrary);
  4829. outputLibrary = NULL;
  4830. outputLibraryId.setown(createAttribute(graphAtom, getSizetConstant(nextActivityId())));
  4831. outputLibrary = new HqlCppLibraryImplementation(*this, queryImplementationInterface(query.expr), outputLibraryId, targetClusterType);
  4832. if (!isEmbeddedLibrary)
  4833. {
  4834. wu()->setLibraryInformation(wu()->queryJobName(), outputLibrary->getInterfaceHash(), getLibraryCRC(query.expr));
  4835. }
  4836. }
  4837. else
  4838. {
  4839. if (options.applyInstantEclTransformations)
  4840. query.expr.setown(doInstantEclTransformations(query.expr, options.applyInstantEclTransformationsLimit));
  4841. }
  4842. if (!transformGraphForGeneration(query, actions))
  4843. return false;
  4844. return true;
  4845. }
  4846. void HqlCppTranslator::updateClusterType()
  4847. {
  4848. const char * clusterTypeText="?";
  4849. switch (targetClusterType)
  4850. {
  4851. case ThorLCRCluster:
  4852. clusterTypeText = "thorlcr";
  4853. break;
  4854. case HThorCluster:
  4855. clusterTypeText = "hthor";
  4856. break;
  4857. case RoxieCluster:
  4858. clusterTypeText = "roxie";
  4859. break;
  4860. }
  4861. //ensure targetClusterType is consistently set in the work unit - so library code can use it.
  4862. wu()->setDebugValue("targetClusterType", clusterTypeText, true);
  4863. }
  4864. struct CountEntry : public CInterface
  4865. {
  4866. ThorActivityKind from;
  4867. ThorActivityKind to;
  4868. unsigned cnt;
  4869. };
  4870. int compareItems(CInterface * * _l, CInterface * * _r)
  4871. {
  4872. CountEntry * l = (CountEntry *)*_l;
  4873. CountEntry * r = (CountEntry *)*_r;
  4874. return (int)(r->cnt - l->cnt);
  4875. }
  4876. void dumpActivityCounts()
  4877. {
  4878. #ifdef _GATHER_USAGE_STATS
  4879. CIArray items;
  4880. for (unsigned i = TAKnone; i < TAKlast; i++)
  4881. {
  4882. for (unsigned j = TAKnone; j < TAKlast; j++)
  4883. {
  4884. if (activityCounts[i][j])
  4885. {
  4886. CountEntry & next = * new CountEntry;
  4887. next.from = (ThorActivityKind)i;
  4888. next.to = (ThorActivityKind)j;
  4889. next.cnt = activityCounts[i][j];
  4890. items.append(next);
  4891. }
  4892. }
  4893. }
  4894. items.sort(compareItems);
  4895. FILE * out = fopen("stats.txt", "w");
  4896. if (!out)
  4897. return;
  4898. fprintf(out, "-Count- Source -> Sink\n");
  4899. ForEachItemIn(k, items)
  4900. {
  4901. CountEntry & cur = (CountEntry &)items.item(k);
  4902. fprintf(out, "%8d %s -> %s\n", cur.cnt, getActivityText(cur.from), getActivityText(cur.to));
  4903. }
  4904. fclose(out);
  4905. #endif
  4906. }
  4907. bool HqlCppTranslator::buildCode(HqlQueryContext & query, const char * embeddedLibraryName, const char * embeddedGraphName)
  4908. {
  4909. WorkflowArray workflow;
  4910. bool ok = prepareToGenerate(query, workflow, (embeddedLibraryName != NULL));
  4911. if (ok)
  4912. {
  4913. //This is done late so that pickBestEngine has decided which engine we are definitely targeting.
  4914. if (!embeddedLibraryName)
  4915. updateClusterType();
  4916. if (insideLibrary())
  4917. {
  4918. //always do these checks for consistency
  4919. OwnedHqlExpr graph;
  4920. ForEachItemIn(i, workflow)
  4921. {
  4922. WorkflowItem & cur = workflow.item(i);
  4923. if (!cur.isFunction())
  4924. {
  4925. assertex(!graph);
  4926. HqlExprArray & exprs = cur.queryExprs();
  4927. assertex(exprs.ordinality() == 1);
  4928. graph.set(&exprs.item(0));
  4929. assertex(graph->getOperator() == no_thor);
  4930. }
  4931. }
  4932. //More: this should be cleaned up - with a flag in the workflow items to indicate a library graph instead...
  4933. if (embeddedLibraryName)
  4934. {
  4935. ForEachItemIn(i, workflow)
  4936. {
  4937. WorkflowItem & cur = workflow.item(i);
  4938. if (cur.isFunction())
  4939. {
  4940. OwnedHqlExpr function = cur.getFunction();
  4941. buildFunctionDefinition(function);
  4942. }
  4943. }
  4944. BuildCtx ctx(*code, goAtom);
  4945. buildLibraryGraph(ctx, graph, embeddedGraphName);
  4946. }
  4947. else
  4948. buildWorkflow(workflow);
  4949. }
  4950. else
  4951. buildWorkflow(workflow);
  4952. if (options.calculateComplexity)
  4953. {
  4954. cycle_t startCycles = get_cycles_now();
  4955. StringBuffer complexityText;
  4956. complexityText.append(getComplexity(workflow));
  4957. wu()->setDebugValue("__Calculated__Complexity__", complexityText, true);
  4958. if (options.timeTransforms)
  4959. noteFinishedTiming("compile:complexity", startCycles);
  4960. }
  4961. buildRowAccessors();
  4962. }
  4963. ::Release(outputLibrary);
  4964. outputLibrary = NULL;
  4965. outputLibraryId.clear();
  4966. return ok;
  4967. }
  4968. bool HqlCppTranslator::buildCpp(IHqlCppInstance & _code, HqlQueryContext & query)
  4969. {
  4970. if (!internalScope)
  4971. return false;
  4972. try
  4973. {
  4974. wu()->setCodeVersion(ACTIVITY_INTERFACE_VERSION,BUILD_TAG,LANGUAGE_VERSION);
  4975. cacheOptions();
  4976. if (options.obfuscateOutput)
  4977. {
  4978. Owned<IWUQuery> query = wu()->updateQuery();
  4979. query->setQueryText(NULL);
  4980. }
  4981. useLibrary(ECLRTL_LIB);
  4982. useInclude("eclrtl.hpp");
  4983. HqlExprArray internalLibraries;
  4984. query.expr.setown(separateLibraries(query.expr, internalLibraries));
  4985. //General internal libraries first, in dependency order
  4986. ForEachItemIn(i, internalLibraries)
  4987. {
  4988. IHqlExpression & cur = internalLibraries.item(i);
  4989. assertex(cur.getOperator() == no_funcdef);
  4990. IHqlExpression * moduleExpr = cur.queryChild(0);
  4991. IHqlExpression * definition = queryAttributeChild(moduleExpr, internalAtom, 0);
  4992. IHqlExpression * name = queryAttributeChild(moduleExpr, nameAtom, 0);
  4993. StringBuffer internalLibraryName;
  4994. name->queryValue()->getStringValue(internalLibraryName);
  4995. //Use a graph number that couldn't possibly clash with any graphs generated by the main query
  4996. StringBuffer embeddedGraphName;
  4997. embeddedGraphName.append("graph").append(EMBEDDED_GRAPH_DELTA+i+1);
  4998. overrideOptionsForLibrary();
  4999. HqlQueryContext libraryQuery;
  5000. libraryQuery.expr.set(definition);
  5001. if (!buildCode(libraryQuery, internalLibraryName.str(), embeddedGraphName.str()))
  5002. return false;
  5003. }
  5004. if (isLibraryScope(query.expr))
  5005. overrideOptionsForLibrary();
  5006. else
  5007. overrideOptionsForQuery();
  5008. if (!buildCode(query, NULL, NULL))
  5009. return false;
  5010. //Return early if iteratively generating the field usage statistics
  5011. if (getDebugFlag("generateFullFieldUsage", false))
  5012. return false;
  5013. #ifdef _GATHER_USAGE_STATS
  5014. if (getDebugFlag("dumpActivityCounts", false))
  5015. dumpActivityCounts();
  5016. #endif
  5017. ForEachItemIn(i1, globalFiles)
  5018. globalFiles.item(i1).writeToGraph();
  5019. //Have to submit graphs to work unit right at the end so that globalUsage counts etc. can be updated in them.
  5020. ForEachItemIn(i2, graphs)
  5021. {
  5022. GeneratedGraphInfo & cur = graphs.item(i2);
  5023. wu()->createGraph(cur.name, cur.label, GraphTypeActivities, cur.xgmml.getClear());
  5024. }
  5025. code->processIncludes();
  5026. if (options.peephole)
  5027. {
  5028. cycle_t startCycles = get_cycles_now();
  5029. peepholeOptimize(*code, *this);
  5030. if (options.timeTransforms)
  5031. noteFinishedTiming("compile:transform:peephole", startCycles);
  5032. }
  5033. }
  5034. catch (IException * e)
  5035. {
  5036. ensureWorkUnitUpdated();
  5037. if (e->errorCode() != HQLERR_ErrorAlreadyReported)
  5038. throw;
  5039. e->Release();
  5040. return false;
  5041. }
  5042. catch (...)
  5043. {
  5044. ensureWorkUnitUpdated();
  5045. throw;
  5046. }
  5047. ensureWorkUnitUpdated();
  5048. return true;
  5049. }
  5050. class WuTimingUpdater : implements ITimeReportInfo
  5051. {
  5052. public:
  5053. WuTimingUpdater(IWorkUnit * _wu) { wu = _wu; }
  5054. virtual void report(const char * scope, const char * description, const __int64 totaltime, const __int64 maxtime, const unsigned count)
  5055. {
  5056. StatisticScopeType scopeType = SSTcompilestage;
  5057. StatisticKind kind = StTimeTotalExecute;
  5058. wu->setStatistic(queryStatisticsComponentType(), queryStatisticsComponentName(), scopeType, scope, kind, description, totaltime, count, maxtime, StatsMergeReplace);
  5059. }
  5060. protected:
  5061. IWorkUnit * wu;
  5062. };
  5063. void HqlCppTranslator::ensureWorkUnitUpdated()
  5064. {
  5065. if (timeReporter)
  5066. {
  5067. WuTimingUpdater updater(wu());
  5068. timeReporter->report(updater);
  5069. }
  5070. }
  5071. double HqlCppTranslator::getComplexity(IHqlExpression * expr, ClusterType cluster)
  5072. {
  5073. double complexity = 0;
  5074. switch (expr->getOperator())
  5075. {
  5076. case no_sequential:
  5077. case no_comma:
  5078. case no_compound:
  5079. case no_parallel:
  5080. case no_actionlist:
  5081. case no_orderedactionlist:
  5082. break;
  5083. case no_thor:
  5084. {
  5085. OwnedHqlExpr resourced = getResourcedGraph(expr->queryChild(0), NULL);
  5086. lockTransformMutex();
  5087. complexity = getComplexity(resourced, targetClusterType);
  5088. unlockTransformMutex();
  5089. return complexity;
  5090. }
  5091. case no_subgraph:
  5092. return getComplexity(expr->queryChild(0), cluster);
  5093. case no_selfjoin:
  5094. case no_join:
  5095. if (isLocalActivity(expr) || !isThorCluster(cluster))
  5096. complexity = 1;
  5097. else
  5098. complexity = 5;
  5099. break;
  5100. case no_distribute:
  5101. if (isThorCluster(cluster))
  5102. complexity = 5;
  5103. break;
  5104. case no_subsort:
  5105. complexity = 1;
  5106. break;
  5107. case no_sort:
  5108. if (isLocalActivity(expr) || !isThorCluster(cluster))
  5109. complexity = 2;
  5110. else
  5111. complexity = 5;
  5112. break;
  5113. case no_ensureresult:
  5114. if (options.freezePersists)
  5115. return 0;
  5116. if (expr->queryChild(0)->queryType()->getTypeCode() == type_void)
  5117. return getComplexity(expr->queryChild(0), cluster);
  5118. //fall through..
  5119. case no_setresult:
  5120. {
  5121. if (cluster == NoCluster)
  5122. return 0.05;
  5123. return 1;
  5124. }
  5125. case no_split:
  5126. //Only count the parents of a splitter once
  5127. if (expr->queryTransformExtra())
  5128. return 0;
  5129. expr->setTransformExtraUnlinked(expr);
  5130. complexity = 1;
  5131. break;
  5132. case no_forcelocal:
  5133. return getComplexity(expr->queryChild(0), cluster);
  5134. default:
  5135. complexity = 1;
  5136. break;
  5137. }
  5138. ForEachChildActivity(i, expr)
  5139. complexity += getComplexity(queryChildActivity(expr, i), cluster);
  5140. return complexity;
  5141. }
  5142. double HqlCppTranslator::getComplexity(IHqlCppInstance & _code, IHqlExpression * exprlist)
  5143. {
  5144. WorkflowArray workflow;
  5145. HqlQueryContext query;
  5146. query.expr.set(exprlist);
  5147. if (!prepareToGenerate(query, workflow, false))
  5148. return 0;
  5149. return getComplexity(workflow);
  5150. }
  5151. double HqlCppTranslator::getComplexity(WorkflowArray & workflow)
  5152. {
  5153. double complexity = 0;
  5154. ForEachItemIn(i, workflow)
  5155. complexity += getComplexity(workflow.item(i).queryExprs());
  5156. return complexity;
  5157. }
  5158. double HqlCppTranslator::getComplexity(HqlExprArray & exprs)
  5159. {
  5160. double complexity = 0;
  5161. ForEachItemIn(idx, exprs)
  5162. complexity += getComplexity(&exprs.item(idx), NoCluster);
  5163. return complexity;
  5164. }
  5165. //---------------------------------------------------------------------------------------------------------------------
  5166. static int compareTrackedSourceByName(CInterface * const * _left, CInterface * const * _right)
  5167. {
  5168. SourceFieldUsage & left = static_cast<SourceFieldUsage &>(**_left);
  5169. SourceFieldUsage & right = static_cast<SourceFieldUsage &>(**_right);
  5170. const char * leftName = left.queryFilenameText();
  5171. const char * rightName = right.queryFilenameText();
  5172. return stricmp(leftName, rightName);
  5173. }
  5174. IPropertyTree * HqlCppTranslator::gatherFieldUsage(const char * variant, const IPropertyTree * exclude)
  5175. {
  5176. Owned<IPropertyTree> sources = createPTree("usedsources");
  5177. sources->setProp("@varient", variant);
  5178. trackedSources.sort(compareTrackedSourceByName);
  5179. ForEachItemIn(i, trackedSources)
  5180. {
  5181. IPropertyTree * next = trackedSources.item(i).createReport(options.reportFieldUsage || options.recordFieldUsage, exclude);
  5182. if (next)
  5183. sources->addPropTree(next->queryName(), next);
  5184. }
  5185. return sources.getClear();
  5186. }
  5187. SourceFieldUsage * HqlCppTranslator::querySourceFieldUsage(IHqlExpression * expr)
  5188. {
  5189. if (!(options.reportFieldUsage || options.recordFieldUsage || options.reportFileUsage) || !expr)
  5190. return NULL;
  5191. if (expr->hasAttribute(_spill_Atom) || expr->hasAttribute(jobTempAtom))
  5192. return NULL;
  5193. OwnedHqlExpr normalized = removeAttribute(expr, _uid_Atom);
  5194. IHqlExpression * original = normalized->queryAttribute(_original_Atom);
  5195. if (original)
  5196. {
  5197. OwnedHqlExpr normalTable = removeAttribute(original->queryChild(0), _uid_Atom);
  5198. OwnedHqlExpr normalOriginal = replaceChild(original, 0, normalTable);
  5199. normalized.setown(replaceOwnedAttribute(normalized, normalOriginal.getClear()));
  5200. }
  5201. ForEachItemIn(i, trackedSources)
  5202. {
  5203. SourceFieldUsage & cur = trackedSources.item(i);
  5204. if (cur.matches(normalized))
  5205. return &cur;
  5206. }
  5207. SourceFieldUsage * next = new SourceFieldUsage(normalized);
  5208. trackedSources.append(*next);
  5209. return next;
  5210. }
  5211. void HqlCppTranslator::noteAllFieldsUsed(IHqlExpression * expr)
  5212. {
  5213. SourceFieldUsage * match = querySourceFieldUsage(expr);
  5214. if (match)
  5215. match->noteAll();
  5216. }
  5217. void HqlCppTranslator::writeFieldUsage(const char * targetDir, IPropertyTree * source, const char * variant)
  5218. {
  5219. if (source)
  5220. {
  5221. StringBuffer fullname;
  5222. addDirectoryPrefix(fullname, targetDir).append(soName).append("_fieldusage");
  5223. if (variant)
  5224. fullname.append("_").append(variant);
  5225. fullname.append(".xml");
  5226. saveXML(fullname, source);
  5227. Owned<IWUQuery> query = wu()->updateQuery();
  5228. associateLocalFile(query, FileTypeXml, fullname, "FieldUsage", 0);
  5229. }
  5230. }
  5231. void HqlCppTranslator::generateStatistics(const char * targetDir, const char * variant)
  5232. {
  5233. if (options.reportFieldUsage || options.reportFileUsage)
  5234. {
  5235. Owned<IPropertyTree> sources = gatherFieldUsage(variant, NULL);
  5236. writeFieldUsage(targetDir, sources, NULL);
  5237. }
  5238. if (options.recordFieldUsage)
  5239. {
  5240. Owned<IPropertyTree> sources = gatherFieldUsage(variant, NULL);
  5241. wu()->noteFieldUsage(LINK(sources));
  5242. }
  5243. }
  5244. //---------------------------------------------------------------------------------------------------------------------
  5245. BoundRow * HqlCppTranslator::resolveDatasetRequired(BuildCtx & ctx, IHqlExpression * expr)
  5246. {
  5247. BoundRow * cursor = resolveSelectorDataset(ctx, expr);
  5248. if (!cursor)
  5249. {
  5250. StringBuffer tablename;
  5251. tablename.append(expr->queryName());
  5252. if (tablename.length() == 0)
  5253. getExprECL(expr, tablename);
  5254. if (ctx.queryFirstAssociation(AssocCursor))
  5255. throwError1(HQLERR_CouldNotFindDataset, tablename.str());
  5256. throwError1(HQLERR_CouldNotAnyDatasetX, tablename.str());
  5257. }
  5258. return cursor;
  5259. }
  5260. IReferenceSelector * HqlCppTranslator::buildActiveReference(BuildCtx & ctx, IHqlExpression * expr)
  5261. {
  5262. ITypeInfo * type = expr->queryType();
  5263. assertex(type);
  5264. switch (type->getTypeCode())
  5265. {
  5266. case type_row:
  5267. return buildActiveRow(ctx, expr);
  5268. }
  5269. return buildReference(ctx, expr);
  5270. }
  5271. IReferenceSelector * HqlCppTranslator::createReferenceSelector(BoundRow * cursor, IHqlExpression * path)
  5272. {
  5273. return new DatasetSelector(*this, cursor, path);
  5274. }
  5275. IReferenceSelector * HqlCppTranslator::createReferenceSelector(BoundRow * cursor)
  5276. {
  5277. return new DatasetSelector(*this, cursor, cursor->querySelector());
  5278. }
  5279. IReferenceSelector * HqlCppTranslator::buildReference(BuildCtx & ctx, IHqlExpression * expr)
  5280. {
  5281. ITypeInfo * type = expr->queryType();
  5282. assertex(type);
  5283. switch (type->getTypeCode())
  5284. {
  5285. case type_row:
  5286. return buildNewRow(ctx, expr);
  5287. }
  5288. const node_operator op = expr->getOperator();
  5289. switch (op)
  5290. {
  5291. case no_variable:
  5292. case no_field:
  5293. case no_ifblock:
  5294. throwUnexpectedOp(op);
  5295. case no_select:
  5296. {
  5297. IHqlExpression * ds = expr->queryChild(0);
  5298. #ifdef _DEBUG
  5299. //Here to make tracing easier in a debugger
  5300. IHqlExpression * field = expr->queryChild(1);
  5301. #endif
  5302. Owned<IReferenceSelector> selector;
  5303. if (isNewSelector(expr))
  5304. {
  5305. //could optimize selection from a project of an in-scope dataset.
  5306. if (((ds->getOperator() == no_newusertable) || (ds->getOperator() == no_hqlproject)) &&
  5307. isAlwaysActiveRow(ds->queryChild(0)))
  5308. {
  5309. //MORE: could optimize selection from a project of an in-scope dataset.
  5310. }
  5311. selector.setown(buildNewRow(ctx, ds));
  5312. }
  5313. else
  5314. selector.setown(buildActiveRow(ctx, ds));
  5315. return selector->select(ctx, expr);
  5316. }
  5317. }
  5318. BoundRow * cursor = resolveDatasetRequired(ctx, expr);
  5319. IReferenceSelector * alias = cursor->queryAlias();
  5320. if (alias)
  5321. return LINK(alias);
  5322. IHqlExpression * dataset = cursor->queryDataset();
  5323. return createReferenceSelector(cursor, dataset);
  5324. }
  5325. ABoundActivity * HqlCppTranslator::buildActivity(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  5326. {
  5327. checkAbort();
  5328. ErrorSeverityMapper::Scope saved(*localOnWarnings);
  5329. //Process any annotations first - but still pass the original expr to the doBuildActivtyXXX functions.
  5330. IHqlExpression * cur = expr;
  5331. for (;;)
  5332. {
  5333. IHqlExpression * body = cur->queryBody(true);
  5334. if (cur == body)
  5335. break;
  5336. switch (cur->getAnnotationKind())
  5337. {
  5338. case annotate_meta:
  5339. localOnWarnings->processMetaAnnotation(cur); // state restored by OnWarningStateBlock
  5340. break;
  5341. case annotate_symbol:
  5342. {
  5343. #ifdef SPOT_POTENTIAL_COMMON_ACTIVITIES
  5344. if (cur->getStartLine() && cur->queryName()->str()[0] != '_')
  5345. {
  5346. unsigned match = savedActivityLocations.findLocation(cur);
  5347. if (match == NotFound)
  5348. {
  5349. savedActivityLocations.append(*LINK(cur));
  5350. savedActivities.append(*LINK(expr));
  5351. }
  5352. else
  5353. {
  5354. debugFindFirstDifference(cur, &savedActivities.item(match));
  5355. //MORE: Could add some kind of comment.
  5356. }
  5357. }
  5358. #endif
  5359. localOnWarnings->setSymbol(cur);
  5360. break;
  5361. }
  5362. }
  5363. cur = body;
  5364. }
  5365. if (isCompoundSource(expr))
  5366. {
  5367. OwnedHqlExpr mapped = normalizeAnyDatasetAliases(expr);
  5368. if (mapped != expr)
  5369. return buildActivity(ctx, mapped, isRoot);
  5370. }
  5371. ABoundActivity * result;
  5372. try
  5373. {
  5374. node_operator op = expr->getOperator();
  5375. switch (op)
  5376. {
  5377. case no_merge:
  5378. result = doBuildActivityMerge(ctx, expr);
  5379. break;
  5380. case no_nwaymerge:
  5381. result = doBuildActivityNWayMerge(ctx, expr);
  5382. break;
  5383. case no_mergejoin:
  5384. case no_nwayjoin:
  5385. result = doBuildActivityNWayMergeJoin(ctx, expr);
  5386. break;
  5387. case no_rowsetrange:
  5388. result = doBuildActivityRowsetRange(ctx, expr);
  5389. break;
  5390. case no_rowsetindex:
  5391. result = doBuildActivityRowsetIndex(ctx, expr);
  5392. break;
  5393. case no_datasetlist:
  5394. {
  5395. OwnedHqlExpr allExpr = createValue(no_all, makeSetType(LINK(sizetType)));
  5396. result = doBuildActivityRowsetRange(ctx, expr, expr, allExpr);
  5397. break;
  5398. }
  5399. case no_addfiles:
  5400. // result = doBuildActivityChildDataset(ctx, expr);
  5401. // break;
  5402. result = doBuildActivityConcat(ctx, expr);
  5403. break;
  5404. case no_regroup:
  5405. result = doBuildActivityRegroup(ctx, expr);
  5406. break;
  5407. case no_nonempty:
  5408. result = doBuildActivityNonEmpty(ctx, expr);
  5409. break;
  5410. case no_combine:
  5411. result = doBuildActivityCombine(ctx, expr);
  5412. break;
  5413. case no_combinegroup:
  5414. result = doBuildActivityCombineGroup(ctx, expr);
  5415. break;
  5416. case no_rollupgroup:
  5417. result = doBuildActivityRollupGroup(ctx, expr);
  5418. break;
  5419. case no_filtergroup:
  5420. result = doBuildActivityFilterGroup(ctx, expr);
  5421. break;
  5422. case no_cachealias:
  5423. result = doBuildActivityCacheAlias(ctx, expr);
  5424. break;
  5425. case no_cloned:
  5426. result = doBuildActivityCloned(ctx, expr);
  5427. break;
  5428. case no_distribute:
  5429. case no_assertdistributed:
  5430. result = doBuildActivityDistribute(ctx, expr);
  5431. break;
  5432. case no_keyeddistribute:
  5433. result = doBuildActivityKeyedDistribute(ctx, expr);
  5434. break;
  5435. case no_select:
  5436. if (isNewSelector(expr))
  5437. result = doBuildActivitySelectNew(ctx, expr);
  5438. else
  5439. result = doBuildActivityChildDataset(ctx, expr);
  5440. break;
  5441. //Items in this list need to also be in the list inside doBuildActivityChildDataset
  5442. case no_call:
  5443. case no_externalcall:
  5444. if (expr->isAction())
  5445. result = doBuildActivityAction(ctx, expr, isRoot);
  5446. else if (expr->isDatarow())
  5447. result = doBuildActivityCreateRow(ctx, expr, false);
  5448. else if (hasStreamedModifier(expr->queryType()))
  5449. {
  5450. result = doBuildActivityStreamedCall(ctx, expr);
  5451. }
  5452. else if (hasLinkCountedModifier(expr->queryType()))
  5453. {
  5454. result = doBuildActivityLinkedRawChildDataset(ctx, expr);
  5455. }
  5456. else
  5457. result = doBuildActivityChildDataset(ctx, expr);
  5458. break;
  5459. case no_left:
  5460. case no_right:
  5461. case no_top:
  5462. case no_activetable:
  5463. case no_id2blob:
  5464. case no_typetransfer:
  5465. case no_rows:
  5466. case no_xmlproject:
  5467. case no_libraryinput:
  5468. case no_translated:
  5469. if (expr->isDatarow())
  5470. result = doBuildActivityCreateRow(ctx, expr, false);
  5471. else
  5472. result = doBuildActivityChildDataset(ctx, expr);
  5473. break;
  5474. case no_compound_inline:
  5475. result = doBuildActivityChildDataset(ctx, expr->queryChild(0));
  5476. break;
  5477. case no_dataset_from_transform:
  5478. result = doBuildActivityCountTransform(ctx, expr);
  5479. break;
  5480. case no_table:
  5481. result = doBuildActivityTable(ctx, expr);
  5482. break;
  5483. case no_compound_diskread:
  5484. result = doBuildActivityDiskRead(ctx, expr);
  5485. break;
  5486. case no_compound_diskaggregate:
  5487. case no_compound_diskcount:
  5488. result = doBuildActivityDiskAggregate(ctx, expr);
  5489. break;
  5490. case no_compound_diskgroupaggregate:
  5491. result = doBuildActivityDiskGroupAggregate(ctx, expr);
  5492. break;
  5493. case no_compound_disknormalize:
  5494. result = doBuildActivityDiskNormalize(ctx, expr);
  5495. break;
  5496. case no_compound_childread:
  5497. case no_compound_childnormalize:
  5498. result = doBuildActivityChildNormalize(ctx, expr);
  5499. break;
  5500. case no_compound_childaggregate:
  5501. case no_compound_childcount:
  5502. result = doBuildActivityChildAggregate(ctx, expr);
  5503. break;
  5504. case no_compound_childgroupaggregate:
  5505. result = doBuildActivityChildGroupAggregate(ctx, expr);
  5506. break;
  5507. case no_compound_selectnew:
  5508. result = doBuildActivityCompoundSelectNew(ctx, expr);
  5509. break;
  5510. case no_denormalize:
  5511. case no_denormalizegroup:
  5512. result = doBuildActivityDenormalize(ctx, expr);
  5513. break;
  5514. case no_datasetfromrow:
  5515. {
  5516. OwnedHqlExpr row = expr->cloneAllAnnotations(expr->queryChild(0)); // preserve any position information....
  5517. if (worthGeneratingRowAsSingleActivity(row))
  5518. result = doBuildActivityCreateRow(ctx, row, false);
  5519. else
  5520. result = buildCachedActivity(ctx, row);
  5521. break;
  5522. }
  5523. case no_datasetfromdictionary:
  5524. result = doBuildActivityChildDataset(ctx, expr);
  5525. break;
  5526. case no_temptable:
  5527. result = doBuildActivityTempTable(ctx, expr);
  5528. break;
  5529. case no_inlinetable:
  5530. result = doBuildActivityInlineTable(ctx, expr);
  5531. break;
  5532. case no_temprow:
  5533. throwUnexpected();
  5534. break;
  5535. case no_workunit_dataset:
  5536. if (targetRoxie() && queryCurrentActivity(ctx))
  5537. result = doBuildActivityChildDataset(ctx, expr);
  5538. else
  5539. result = doBuildActivityWorkunitRead(ctx, expr);
  5540. break;
  5541. case no_fail:
  5542. if (expr->isAction())
  5543. result = doBuildActivityAction(ctx, expr, isRoot);
  5544. else
  5545. result = doBuildActivitySideEffect(ctx, expr, isRoot, true);
  5546. break;
  5547. case no_null:
  5548. if (expr->isDatarow())
  5549. result = doBuildActivityCreateRow(ctx, expr, false);
  5550. else
  5551. result = doBuildActivityNull(ctx, expr, isRoot);
  5552. break;
  5553. case no_split:
  5554. result = doBuildActivitySplit(ctx, expr);
  5555. break;
  5556. case no_apply:
  5557. result = doBuildActivityApply(ctx, expr, isRoot);
  5558. break;
  5559. case no_output:
  5560. result = doBuildActivityOutput(ctx, expr, isRoot);
  5561. break;
  5562. case no_extractresult:
  5563. case no_setresult:
  5564. result = doBuildActivitySetResult(ctx, expr, isRoot);
  5565. break;
  5566. case no_returnresult:
  5567. result = doBuildActivityReturnResult(ctx, expr, isRoot);
  5568. break;
  5569. case no_getgraphresult:
  5570. //Use the get graph result activity if we are generating the correct level graph.
  5571. //otherwise it needs to be serialized from the parent activity
  5572. {
  5573. IHqlExpression * graphId = expr->queryChild(1);
  5574. bool canAccessResultDirectly = isCurrentActiveGraph(ctx, graphId);
  5575. if (!canAccessResultDirectly)
  5576. {
  5577. //Sometimes results for the parent graph can be accessed from a child graph (e.g., loops).
  5578. //The test for Thor is temporary - roxie and hthor should both allow access to outer results
  5579. //from inside a loop.
  5580. //In fact roxie/hthor could access parent results directly from a child query if the parent
  5581. //activity is always on the master. (Thor could if it knew to access the entire result.)
  5582. if (getTargetClusterType() == ThorLCRCluster)
  5583. {
  5584. ParentExtract * extract = static_cast<ParentExtract*>(ctx.queryFirstAssociation(AssocExtract));
  5585. if (extract)
  5586. canAccessResultDirectly = extract->areGraphResultsAccessible(graphId);
  5587. }
  5588. else if (getTargetClusterType() == HThorCluster)
  5589. {
  5590. //Only create the activity for results from parent graphs, not from siblings
  5591. if (matchActiveGraph(ctx, graphId))
  5592. canAccessResultDirectly = true;
  5593. }
  5594. }
  5595. if (canAccessResultDirectly)
  5596. result = doBuildActivityGetGraphResult(ctx, expr);
  5597. else
  5598. result = doBuildActivityChildDataset(ctx, expr);
  5599. break;
  5600. }
  5601. case no_getgraphloopresult:
  5602. //Use the get graph result activity if we are generating the correct level graph.
  5603. //otherwise it needs to be serialized from the parent activity
  5604. {
  5605. if (isCurrentActiveGraph(ctx, expr->queryChild(1)))
  5606. result = doBuildActivityGetGraphLoopResult(ctx, expr);
  5607. else
  5608. throwError(HQLERR_GraphInputAccessedChild);
  5609. break;
  5610. }
  5611. case no_setgraphresult:
  5612. case no_spillgraphresult:
  5613. result = doBuildActivitySetGraphResult(ctx, expr, isRoot);
  5614. break;
  5615. case no_setgraphloopresult:
  5616. result = doBuildActivitySetGraphLoopResult(ctx, expr);
  5617. break;
  5618. case no_spill:
  5619. result = doBuildActivitySpill(ctx, expr);
  5620. break;
  5621. case no_buildindex:
  5622. result = doBuildActivityOutputIndex(ctx, expr, isRoot);
  5623. break;
  5624. case no_distribution:
  5625. result = doBuildActivityDistribution(ctx, expr, isRoot);
  5626. break;
  5627. case no_keydiff:
  5628. result = doBuildActivityKeyDiff(ctx, expr, isRoot);
  5629. break;
  5630. case no_keypatch:
  5631. result = doBuildActivityKeyPatch(ctx, expr, isRoot);
  5632. break;
  5633. case no_if:
  5634. result = doBuildActivityIf(ctx, expr, isRoot);
  5635. break;
  5636. case no_case:
  5637. case no_map:
  5638. result = doBuildActivityCase(ctx, expr, isRoot);
  5639. break;
  5640. case no_quantile:
  5641. result = doBuildActivityQuantile(ctx, expr);
  5642. break;
  5643. case no_chooseds:
  5644. case no_choose:
  5645. result = doBuildActivityChoose(ctx, expr, isRoot);
  5646. break;
  5647. case no_iterate:
  5648. result = doBuildActivityIterate(ctx, expr);
  5649. break;
  5650. case no_process:
  5651. result = doBuildActivityProcess(ctx, expr);
  5652. break;
  5653. case no_group:
  5654. //Special case group(subsort) which will be mapped to group(group(sort(group))) to remove
  5655. //the redundant group
  5656. if (!options.supportsSubSortActivity && (expr->queryChild(0)->getOperator() == no_subsort))
  5657. {
  5658. IHqlExpression * subsort = expr->queryChild(0);
  5659. OwnedHqlExpr groupedSort = convertSubSortToGroupedSort(subsort);
  5660. assertex(groupedSort->getOperator() == no_group);
  5661. OwnedHqlExpr newGroup = replaceChild(expr, 0, groupedSort->queryChild(0));
  5662. result = doBuildActivityGroup(ctx, newGroup);
  5663. }
  5664. else
  5665. result = doBuildActivityGroup(ctx, expr);
  5666. break;
  5667. case no_cogroup:
  5668. case no_assertgrouped:
  5669. result = doBuildActivityGroup(ctx, expr);
  5670. break;
  5671. case no_normalize:
  5672. result = doBuildActivityNormalize(ctx, expr);
  5673. break;
  5674. case no_normalizegroup:
  5675. result = doBuildActivityNormalizeGroup(ctx, expr);
  5676. break;
  5677. case no_distributed:
  5678. {
  5679. IHqlExpression * in = expr->queryChild(0);
  5680. if (isGrouped(in))
  5681. {
  5682. Owned<ABoundActivity> boundInput = buildCachedActivity(ctx, in);
  5683. result = doBuildActivityUngroup(ctx, expr, boundInput);
  5684. }
  5685. else
  5686. result = buildCachedActivity(ctx, in);
  5687. break;
  5688. }
  5689. case no_sorted:
  5690. case no_preservemeta:
  5691. case no_unordered:
  5692. case no_grouped:
  5693. case no_nofold:
  5694. case no_nohoist:
  5695. case no_nocombine:
  5696. case no_globalscope:
  5697. case no_thisnode:
  5698. case no_forcegraph:
  5699. case no_keyed:
  5700. result = buildCachedActivity(ctx, expr->queryChild(0));
  5701. break;
  5702. case no_dataset_alias:
  5703. if (!expr->hasAttribute(_normalized_Atom))
  5704. {
  5705. OwnedHqlExpr uniqueChild = normalizeDatasetAlias(expr);
  5706. result = buildCachedActivity(ctx, uniqueChild);
  5707. }
  5708. else
  5709. result = buildCachedActivity(ctx, expr->queryChild(0));
  5710. break;
  5711. case no_alias_scope:
  5712. case no_alias:
  5713. result = buildCachedActivity(ctx, expr->queryChild(0));
  5714. break;
  5715. case no_section:
  5716. result = doBuildActivitySection(ctx, expr);
  5717. break;
  5718. case no_sectioninput:
  5719. result = doBuildActivitySectionInput(ctx, expr);
  5720. break;
  5721. case no_forcelocal:
  5722. result = doBuildActivityForceLocal(ctx, expr);
  5723. break;
  5724. case no_preload:
  5725. {
  5726. StringBuffer s;
  5727. DBGLOG("%s", getExprECL(expr, s).str());
  5728. throwError(HQLERR_TooComplicatedToPreload);
  5729. }
  5730. case no_sub:
  5731. result = doBuildActivitySub(ctx, expr);
  5732. break;
  5733. case no_subsort:
  5734. if (!options.supportsSubSortActivity)
  5735. {
  5736. OwnedHqlExpr groupedSort = convertSubSortToGroupedSort(expr);
  5737. result = buildCachedActivity(ctx, groupedSort);
  5738. }
  5739. else
  5740. result = doBuildActivitySort(ctx, expr);
  5741. break;
  5742. case no_sort:
  5743. case no_cosort:
  5744. case no_topn:
  5745. case no_assertsorted:
  5746. result = doBuildActivitySort(ctx, expr);
  5747. break;
  5748. case no_dedup:
  5749. result = doBuildActivityDedup(ctx, expr);
  5750. break;
  5751. case no_enth:
  5752. result = doBuildActivityEnth(ctx, expr);
  5753. break;
  5754. case no_pipe:
  5755. result = doBuildActivityPipeThrough(ctx, expr);
  5756. break;
  5757. case no_sample:
  5758. result = doBuildActivitySample(ctx, expr);
  5759. break;
  5760. case no_filter:
  5761. result = doBuildActivityFilter(ctx, expr);
  5762. break;
  5763. case no_limit:
  5764. result = doBuildActivityLimit(ctx, expr);
  5765. break;
  5766. case no_catchds:
  5767. result = doBuildActivityCatch(ctx, expr);
  5768. break;
  5769. case no_keyedlimit:
  5770. {
  5771. traceExpression("keyed fail", expr);
  5772. StringBuffer s;
  5773. getExprECL(expr->queryChild(1), s);
  5774. throwError1(HQLERR_KeyedLimitNotKeyed, s.str());
  5775. }
  5776. case no_index:
  5777. case no_selectnth:
  5778. result = doBuildActivitySelectNth(ctx, expr);
  5779. break;
  5780. case no_selectmap:
  5781. result = doBuildActivityCreateRow(ctx, expr, false);
  5782. break;
  5783. case no_join:
  5784. case no_selfjoin:
  5785. result = doBuildActivityJoin(ctx, expr);
  5786. break;
  5787. case no_fetch:
  5788. case no_compound_fetch:
  5789. result = doBuildActivityFetch(ctx, expr);
  5790. break;
  5791. case no_rollup:
  5792. result = doBuildActivityRollup(ctx, expr);
  5793. break;
  5794. case no_hqlproject:
  5795. case no_transformascii:
  5796. case no_transformebcdic:
  5797. case no_projectrow:
  5798. result = doBuildActivityProject(ctx, expr);
  5799. break;
  5800. case no_createrow:
  5801. result = doBuildActivityCreateRow(ctx, expr, false);
  5802. break;
  5803. case no_newusertable:
  5804. result = doBuildActivityProject(ctx, expr);
  5805. break;
  5806. case no_aggregate:
  5807. case no_newaggregate:
  5808. case no_throughaggregate:
  5809. result = doBuildActivityAggregate(ctx, expr);
  5810. break;
  5811. case no_metaactivity:
  5812. if (expr->hasAttribute(pullAtom))
  5813. result = doBuildActivityPullActivity(ctx, expr);
  5814. else if (expr->hasAttribute(traceAtom))
  5815. result = doBuildActivityTraceActivity(ctx, expr);
  5816. else
  5817. throwUnexpected();
  5818. break;
  5819. case no_choosen:
  5820. result = doBuildActivityFirstN(ctx, expr);
  5821. break;
  5822. case no_choosesets:
  5823. result = doBuildActivityChooseSets(ctx, expr);
  5824. break;
  5825. case no_newkeyindex:
  5826. case no_compound_indexread:
  5827. result = doBuildActivityIndexRead(ctx, expr);
  5828. break;
  5829. case no_compound_indexcount:
  5830. case no_compound_indexaggregate:
  5831. result = doBuildActivityIndexAggregate(ctx, expr);
  5832. break;
  5833. case no_compound_indexgroupaggregate:
  5834. result = doBuildActivityIndexGroupAggregate(ctx, expr);
  5835. break;
  5836. case no_compound_indexnormalize:
  5837. result = doBuildActivityIndexNormalize(ctx, expr);
  5838. break;
  5839. case no_compound:
  5840. buildStmt(ctx, expr->queryChild(0));
  5841. result = buildCachedActivity(ctx, expr->queryChild(1));
  5842. break;
  5843. case no_newparse:
  5844. result = doBuildActivityParse(ctx, expr);
  5845. break;
  5846. case no_newxmlparse:
  5847. result = doBuildActivityXmlParse(ctx, expr);
  5848. break;
  5849. case no_httpcall:
  5850. result = doBuildActivityHTTP(ctx, expr, (expr->isAction()), isRoot);
  5851. break;
  5852. case no_newsoapcall:
  5853. case no_newsoapcall_ds:
  5854. case no_newsoapaction_ds:
  5855. result = doBuildActivitySOAP(ctx, expr, (expr->isAction()), isRoot);
  5856. break;
  5857. case no_parallel:
  5858. case no_sequential:
  5859. case no_actionlist:
  5860. case no_orderedactionlist:
  5861. result = doBuildActivitySequentialParallel(ctx, expr, isRoot);
  5862. break;
  5863. case no_activerow:
  5864. result = doBuildActivityCreateRow(ctx, expr, false);
  5865. break;
  5866. case no_assert_ds:
  5867. result = doBuildActivityAssert(ctx, expr);
  5868. break;
  5869. case no_loop:
  5870. result = doBuildActivityLoop(ctx, expr);
  5871. break;
  5872. case no_graphloop:
  5873. result = doBuildActivityGraphLoop(ctx, expr);
  5874. break;
  5875. case no_allnodes:
  5876. result = doBuildActivityRemote(ctx, expr, isRoot);
  5877. break;
  5878. case no_libraryselect:
  5879. result = doBuildActivityLibrarySelect(ctx, expr);
  5880. break;
  5881. case no_libraryscopeinstance:
  5882. result = doBuildActivityLibraryInstance(ctx, expr);
  5883. break;
  5884. case no_serialize:
  5885. case no_deserialize:
  5886. result = doBuildActivitySerialize(ctx, expr);
  5887. break;
  5888. case no_definesideeffect:
  5889. result = doBuildActivityDefineSideEffect(ctx, expr);
  5890. break;
  5891. case no_callsideeffect:
  5892. result = doBuildActivityCallSideEffect(ctx, expr);
  5893. break;
  5894. case no_executewhen:
  5895. result = doBuildActivityExecuteWhen(ctx, expr, isRoot);
  5896. break;
  5897. case no_param:
  5898. throwUnexpectedX("Create Parameter as an activity");
  5899. case no_thor:
  5900. UNIMPLEMENTED;
  5901. break;
  5902. case no_stepped:
  5903. throwError(HQLERR_SteppedNotImplemented);
  5904. default:
  5905. if (expr->isAction())
  5906. return doBuildActivityAction(ctx, expr, isRoot);
  5907. if (expr->isDatarow())
  5908. {
  5909. return doBuildActivityCreateRow(ctx, expr, false);
  5910. }
  5911. else
  5912. {
  5913. UNIMPLEMENTED_XY("Activity", getOpString(op));
  5914. }
  5915. }
  5916. }
  5917. catch (IError *)
  5918. {
  5919. throw;
  5920. }
  5921. catch (IException * e)
  5922. {
  5923. IHqlExpression * location = queryActiveActivityLocation();
  5924. if (location)
  5925. {
  5926. IError * error = annotateExceptionWithLocation(e, location);
  5927. e->Release();
  5928. throw error;
  5929. }
  5930. throw;
  5931. }
  5932. return result;
  5933. }
  5934. ABoundActivity * HqlCppTranslator::buildCachedActivity(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  5935. {
  5936. switch (expr->getOperator())
  5937. {
  5938. case no_split:
  5939. case no_libraryscopeinstance:
  5940. {
  5941. ActivityAssociation * match = static_cast<ActivityAssociation *>(ctx.queryAssociation(expr, AssocActivity, NULL));
  5942. if (match)
  5943. return LINK(match->activity);
  5944. break;
  5945. }
  5946. case no_if:
  5947. {
  5948. if (options.recreateMapFromIf && !expr->isAction())
  5949. {
  5950. OwnedHqlExpr converted = combineIfsToMap(expr);
  5951. if (converted)
  5952. return buildCachedActivity(ctx, converted);
  5953. }
  5954. break;
  5955. }
  5956. }
  5957. //NB: ActivityExprStack is purely used for improving the error reporting
  5958. activityExprStack.append(*LINK(expr));
  5959. try
  5960. {
  5961. //Don't modify aliases in child queries - otherwise they can fail to match the aliases generated in the parent
  5962. OwnedHqlExpr optimized = insideChildOrLoopGraph(ctx) ? LINK(expr) : optimizeActivityAliasReferences(expr);
  5963. ThorBoundActivity * bound = (ThorBoundActivity *)buildActivity(ctx, optimized, isRoot);
  5964. activityExprStack.pop();
  5965. ActivityAssociation * table = new ActivityAssociation(expr->queryBody(), bound);
  5966. ctx.associateOwn(*table);
  5967. return bound;
  5968. }
  5969. catch (IException *)
  5970. {
  5971. activityExprStack.pop();
  5972. throw;
  5973. }
  5974. }
  5975. void HqlCppTranslator::buildRootActivity(BuildCtx & ctx, IHqlExpression * expr)
  5976. {
  5977. ErrorSeverityMapper::Scope saved(*localOnWarnings);
  5978. ::Release(buildCachedActivity(ctx, expr, true));
  5979. }
  5980. void HqlCppTranslator::buildRecordSerializeExtract(BuildCtx & ctx, IHqlExpression * memoryRecord)
  5981. {
  5982. OwnedHqlExpr serializedRecord = getSerializedForm(memoryRecord, diskAtom);
  5983. OwnedHqlExpr serializedDataset = createDataset(no_null, LINK(serializedRecord));
  5984. OwnedHqlExpr memoryDataset = createDataset(no_anon, LINK(memoryRecord));
  5985. MetaInstance meta(*this, memoryRecord, false);
  5986. buildMetaInfo(meta);
  5987. if (recordTypesMatch(memoryRecord, serializedRecord))
  5988. {
  5989. StringBuffer s;
  5990. if (isFixedRecordSize(memoryRecord))
  5991. {
  5992. ctx.addQuoted(s.append("size32_t size = ").append(getFixedRecordSize(memoryRecord)).append(";"));
  5993. }
  5994. else
  5995. {
  5996. ctx.addQuoted(s.append("size32_t size = ").append(meta.queryInstanceObject()).append(".getRecordSize(_left);"));
  5997. }
  5998. ctx.addQuotedLiteral("byte * self = crSelf.ensureCapacity(size, NULL);");
  5999. ctx.addQuotedLiteral("memcpy(crSelf.row(), _left, size);");
  6000. ctx.addQuotedLiteral("return size;");
  6001. }
  6002. else
  6003. {
  6004. ctx.addQuotedLiteral("const byte * left = (const byte *)_left;");
  6005. BoundRow * self = bindSelf(ctx, serializedDataset, "crSelf");
  6006. BoundRow * left = bindTableCursor(ctx, memoryDataset, "left");
  6007. OwnedHqlExpr rhs = ensureActiveRow(left->querySelector());
  6008. OwnedHqlExpr serializedRow = ::ensureSerialized(rhs, diskAtom); // Ensure this is always accessed as disk serialized
  6009. buildAssign(ctx, self->querySelector(), serializedRow);
  6010. buildReturnRecordSize(ctx, self);
  6011. }
  6012. }
  6013. //---------------------------------------------------------------------------
  6014. BoundRow * HqlCppTranslator::bindTableCursor(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq)
  6015. {
  6016. IHqlExpression * record = dataset->queryRecord();
  6017. bool useRowAccessor = useRowAccessorClass(record, side == no_self);
  6018. BoundRow * cursor = createTableCursor(dataset, bound, useRowAccessor, side, selSeq);
  6019. if (useRowAccessor)
  6020. cursor->prepareAccessor(*this, ctx);
  6021. ctx.associateOwn(*cursor);
  6022. return cursor;
  6023. }
  6024. BoundRow * HqlCppTranslator::bindTableCursor(BuildCtx & ctx, IHqlExpression * dataset, const char * name, bool isLinkCounted, node_operator side, IHqlExpression * selSeq)
  6025. {
  6026. Owned<ITypeInfo> type = makeRowReferenceType(dataset);
  6027. if (isLinkCounted)
  6028. type.setown(makeAttributeModifier(type.getClear(), getLinkCountedAttr()));
  6029. Owned<IHqlExpression> bound = createVariable(name, type.getClear());
  6030. return bindTableCursor(ctx, dataset, bound, side, selSeq);
  6031. }
  6032. BoundRow * HqlCppTranslator::rebindTableCursor(BuildCtx & ctx, IHqlExpression * dataset, BoundRow * row, node_operator side, IHqlExpression * selSeq)
  6033. {
  6034. BoundRow * cursor = recreateTableCursor(dataset, row, side, selSeq);
  6035. ctx.associateOwn(*cursor);
  6036. return cursor;
  6037. }
  6038. BoundRow * HqlCppTranslator::createTableCursor(IHqlExpression * dataset, IHqlExpression * bound, bool useAccessorClass, node_operator side, IHqlExpression * selSeq)
  6039. {
  6040. return new BoundRow(dataset, bound, NULL, queryRecordOffsetMap(dataset->queryRecord(), useAccessorClass), side, selSeq);
  6041. }
  6042. BoundRow * HqlCppTranslator::recreateTableCursor(IHqlExpression * dataset, BoundRow * row, node_operator side, IHqlExpression * selSeq)
  6043. {
  6044. ColumnToOffsetMap * columnMap = queryRecordOffsetMap(row->queryRecord(), false);
  6045. return new BoundRow(dataset, row->queryBound(), nullptr, columnMap, side, selSeq);
  6046. }
  6047. BoundRow * HqlCppTranslator::bindXmlTableCursor(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq, bool translateVirtuals)
  6048. {
  6049. Owned<ColumnToOffsetMap> xmlMap = new XmlColumnToOffsetMap(dataset->queryRecord(), getDefaultMaxRecordSize(), translateVirtuals);
  6050. xmlMap->init(recordMap);
  6051. BoundRow * cursor = new BoundRow(dataset, bound, NULL, xmlMap, side, selSeq);
  6052. ctx.associateOwn(*cursor);
  6053. return cursor;
  6054. }
  6055. BoundRow * HqlCppTranslator::bindXmlTableCursor(BuildCtx & ctx, IHqlExpression * dataset, const char * name, node_operator side, IHqlExpression * selSeq, bool translateVirtuals)
  6056. {
  6057. OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(NULL));
  6058. // OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(dataset));
  6059. return bindXmlTableCursor(ctx, dataset, bound, side, selSeq, translateVirtuals);
  6060. }
  6061. BoundRow * HqlCppTranslator::bindCsvTableCursor(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq, bool translateVirtuals, IAtom * encoding)
  6062. {
  6063. Owned<ColumnToOffsetMap> csvMap = new CsvColumnToOffsetMap(dataset->queryRecord(), getDefaultMaxRecordSize(), translateVirtuals, encoding);
  6064. csvMap->init(recordMap);
  6065. BoundRow * cursor = new BoundRow(dataset, bound, NULL, csvMap, side, selSeq);
  6066. ctx.associateOwn(*cursor);
  6067. return cursor;
  6068. }
  6069. BoundRow * HqlCppTranslator::bindCsvTableCursor(BuildCtx & ctx, IHqlExpression * dataset, const char * name, node_operator side, IHqlExpression * selSeq, bool translateVirtuals, IAtom * encoding)
  6070. {
  6071. OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(NULL));
  6072. // OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(dataset));
  6073. return bindCsvTableCursor(ctx, dataset, bound, side, selSeq, translateVirtuals, encoding);
  6074. }
  6075. BoundRow * HqlCppTranslator::bindSelf(BuildCtx & ctx, IHqlExpression * dataset, const char * builderName)
  6076. {
  6077. StringBuffer bound;
  6078. bound.append(builderName).append(".row()");
  6079. BoundRow * row = bindTableCursor(ctx, dataset, bound, false, no_self, NULL);
  6080. OwnedHqlExpr builder = createVariable(builderName, makeBoolType());
  6081. row->setBuilder(builder);
  6082. return row;
  6083. }
  6084. BoundRow * HqlCppTranslator::bindSelf(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * expr, IHqlExpression * builder)
  6085. {
  6086. BoundRow * row = bindTableCursor(ctx, dataset, expr, no_self, NULL);
  6087. row->setBuilder(builder);
  6088. return row;
  6089. }
  6090. BoundRow * HqlCppTranslator::bindRow(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * bound)
  6091. {
  6092. BoundRow * row = createBoundRow(expr, bound);
  6093. ctx.associateOwn(*row);
  6094. return row;
  6095. }
  6096. BoundRow * HqlCppTranslator::bindRow(BuildCtx & ctx, IHqlExpression * expr, const char * name)
  6097. {
  6098. Owned<IHqlExpression> bound = createVariable(name, makeRowReferenceType(NULL));
  6099. return bindRow(ctx, expr, bound);
  6100. }
  6101. BoundRow * HqlCppTranslator::bindTableCursorOrRow(BuildCtx & ctx, IHqlExpression * expr, const char * name)
  6102. {
  6103. if (expr->getOperator() == no_activerow)
  6104. expr = expr->queryChild(0);
  6105. if (expr->isDatarow())
  6106. return bindRow(ctx, expr, name);
  6107. else
  6108. return bindTableCursor(ctx, expr, name);
  6109. }
  6110. BoundRow * HqlCppTranslator::createBoundRow(IHqlExpression * dataset, IHqlExpression * bound)
  6111. {
  6112. bool useAccessor = false;
  6113. IHqlExpression * accessor = NULL;
  6114. return new BoundRow(dataset->queryBody(), bound, accessor, queryRecordOffsetMap(dataset->queryRecord(), (accessor != NULL)));
  6115. }
  6116. BoundRow * HqlCppTranslator::bindSelectorAsSelf(BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * expr)
  6117. {
  6118. BoundRow * rootRow = selector->queryRootRow();
  6119. if (!rootRow->queryBuilder())
  6120. {
  6121. if (options.alwaysCreateRowBuilder || !isFixedWidthDataset(rootRow->queryRecord()))
  6122. UNIMPLEMENTED_X("expected a row builder");
  6123. }
  6124. if (selector->isRoot())
  6125. {
  6126. if (rootRow->querySide() == no_self)
  6127. {
  6128. //No need to associate since it is already present in the context
  6129. //ctx.associate(*rootRow);
  6130. return rootRow;
  6131. }
  6132. return bindSelf(ctx, expr, rootRow->queryBound(), rootRow->queryBuilder());
  6133. }
  6134. //Need to bind a delta address to a new variable.
  6135. if (!rootRow->queryBuilder())
  6136. UNIMPLEMENTED_X("expected a row builder");
  6137. CHqlBoundExpr offset;
  6138. selector->getOffset(ctx, offset);
  6139. CHqlBoundExpr address;
  6140. selector->buildAddress(ctx, address);
  6141. OwnedHqlExpr row = createValue(no_typetransfer, makeReferenceModifier(LINK(selector->queryType())), LINK(address.expr));
  6142. unsigned trailingFixed = selector->getContainerTrailingFixed();
  6143. StringBuffer builderName;
  6144. {
  6145. getUniqueId(builderName.append("b"));
  6146. StringBuffer s;
  6147. s.append("RtlNestedRowBuilder ").append(builderName).append("(");
  6148. generateExprCpp(s, rootRow->queryBuilder()).append(",");
  6149. generateExprCpp(s, offset.expr).append(",").append(trailingFixed).append(");");
  6150. ctx.addQuoted(s);
  6151. }
  6152. BoundRow * selfRow = bindSelf(ctx, expr, builderName);
  6153. selfRow->setAlias(selector);
  6154. return selfRow;
  6155. }
  6156. void HqlCppTranslator::finishSelf(BuildCtx & ctx, BoundRow * self, BoundRow * target)
  6157. {
  6158. if (target)
  6159. {
  6160. OwnedHqlExpr sizeofSelf = createSizeof(self->querySelector());
  6161. CHqlBoundExpr bound;
  6162. buildExpr(ctx, sizeofSelf, bound);
  6163. OwnedHqlExpr sizeofTarget = createSizeof(target->querySelector());
  6164. ctx.associateExpr(sizeofTarget, bound);
  6165. }
  6166. }
  6167. void HqlCppTranslator::ensureRowAllocated(BuildCtx & ctx, const char * builder)
  6168. {
  6169. StringBuffer s;
  6170. s.append(builder).append(".getSelf();");
  6171. ctx.addQuoted(s);
  6172. }
  6173. void HqlCppTranslator::ensureRowAllocated(BuildCtx & ctx, BoundRow * row)
  6174. {
  6175. assertex(row->queryBuilder());
  6176. StringBuffer s;
  6177. generateExprCpp(s, row->queryBuilder()).append(".getSelf();");
  6178. ctx.addQuoted(s);
  6179. }
  6180. //---------------------------------------------------------------------------
  6181. BoundRow * HqlCppTranslator::bindSelectorAsRootRow(BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * expr)
  6182. {
  6183. BoundRow * rootRow = selector->queryRootRow();
  6184. assertex(!rootRow->queryBuilder());
  6185. if (selector->isRoot())
  6186. {
  6187. ctx.associate(*rootRow);
  6188. return rootRow;
  6189. }
  6190. //Need to bind a delta address to a new variable.
  6191. CHqlBoundExpr address;
  6192. selector->buildAddress(ctx, address);
  6193. OwnedHqlExpr row = createValue(no_typetransfer, makeReferenceModifier(LINK(selector->queryType())), LINK(address.expr));
  6194. BoundRow * childRow = bindTableCursor(ctx, expr, row);
  6195. childRow->setAlias(selector);
  6196. return childRow;
  6197. }
  6198. //---------------------------------------------------------------------------
  6199. BoundRow * HqlCppTranslator::resolveSelectorDataset(BuildCtx & ctx, IHqlExpression * dataset)
  6200. {
  6201. return static_cast<BoundRow *>(ctx.queryAssociation(dataset->queryNormalizedSelector(), AssocCursor, NULL));
  6202. }
  6203. //---------------------------------------------------------------------------
  6204. void HqlCppTranslator::addDependency(BuildCtx & ctx, ABoundActivity * sourceActivity, IPropertyTree * sinkGraphTree, ABoundActivity * sinkActivity, IAtom * kind, const char * label, unsigned inputIndex, int whenId)
  6205. {
  6206. IPropertyTree * graphTree = NULL;
  6207. if (sinkActivity->queryGraphId() == sourceActivity->queryGraphId())
  6208. {
  6209. if (targetHThor())
  6210. throwError1(HQLERR_DependencyWithinGraph, sinkActivity->queryGraphId());
  6211. graphTree = sinkGraphTree;
  6212. }
  6213. unsigned outputIndex = 0;
  6214. if (kind != childAtom)
  6215. outputIndex = sourceActivity->nextOutputCount();
  6216. StringBuffer idText;
  6217. idText.append(sourceActivity->queryActivityId()).append('_').append(sinkActivity->queryActivityId());
  6218. IPropertyTree *edge = createPTree();
  6219. edge->setProp("@id", idText.str());
  6220. if (label)
  6221. edge->setProp("@label", label);
  6222. if (targetRoxie())
  6223. {
  6224. if (outputIndex)
  6225. addGraphAttributeInt(edge, "_sourceIndex", outputIndex);
  6226. }
  6227. if (inputIndex)
  6228. addGraphAttributeInt(edge, "_targetIndex", inputIndex);
  6229. if (kind == childAtom)
  6230. {
  6231. addGraphAttributeBool(edge, "_childGraph", true);
  6232. }
  6233. else if (kind == dependencyAtom)
  6234. {
  6235. addGraphAttributeBool(edge, "_dependsOn", true);
  6236. }
  6237. else if (sourceActivity->queryContainerId() != sinkActivity->queryContainerId())
  6238. {
  6239. //mark as a dependency if the source and target aren't at the same depth
  6240. addGraphAttributeBool(edge, "_dependsOn", true);
  6241. }
  6242. if (whenId)
  6243. addGraphAttributeInt(edge, "_when", whenId);
  6244. if (graphTree)
  6245. {
  6246. edge->setPropInt64("@target", sinkActivity->queryActivityId());
  6247. edge->setPropInt64("@source", sourceActivity->queryActivityId());
  6248. graphTree->addPropTree("edge", edge);
  6249. }
  6250. else
  6251. {
  6252. edge->setPropInt64("@target", sinkActivity->queryGraphId());
  6253. edge->setPropInt64("@source", sourceActivity->queryGraphId());
  6254. addGraphAttributeInt(edge, "_sourceActivity", sourceActivity->queryActivityId());
  6255. addGraphAttributeInt(edge, "_targetActivity", sinkActivity->queryActivityId());
  6256. activeGraph->xgmml->addPropTree("edge", edge);
  6257. }
  6258. }
  6259. void HqlCppTranslator::addDependency(BuildCtx & ctx, ABoundActivity * element, ABoundActivity * dependent, IAtom * kind, const char * label)
  6260. {
  6261. unsigned whenId = 0;
  6262. addDependency(ctx, element, NULL, dependent, kind, label, 0, whenId);
  6263. }
  6264. void HqlCppTranslator::addDependency(BuildCtx & ctx, ABoundActivity * element, ActivityInstance * instance, IAtom * kind, const char * label)
  6265. {
  6266. unsigned whenId = 0;
  6267. addDependency(ctx, element, instance->querySubgraphNode(), instance->queryBoundActivity(), kind, label, 0, whenId);
  6268. }
  6269. void HqlCppTranslator::addActionConnection(BuildCtx & ctx, ABoundActivity * element, ActivityInstance * instance, IAtom * kind, const char * label, unsigned inputIndex, int whenId)
  6270. {
  6271. addDependency(ctx, element, instance->querySubgraphNode(), instance->queryBoundActivity(), kind, label, inputIndex, whenId);
  6272. }
  6273. void HqlCppTranslator::buildClearRecord(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * record, int direction)
  6274. {
  6275. Owned<IReferenceSelector> selector = buildActiveRow(ctx, dataset);
  6276. selector->buildClear(ctx, direction);
  6277. }
  6278. IHqlExpression * HqlCppTranslator::getClearRecordFunction(IHqlExpression * record, int direction)
  6279. {
  6280. assertex(record);
  6281. IHqlExpression * dirExpr = getSizetConstant((size32_t)direction);
  6282. OwnedHqlExpr search = createAttribute(__clearHelperAtom, LINK(record->queryBody()), dirExpr);
  6283. BuildCtx declarectx(*code, declareAtom);
  6284. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  6285. if (match)
  6286. return LINK(match->queryExpr());
  6287. StringBuffer functionName;
  6288. getUniqueId(functionName.append("clearRow"));
  6289. BuildCtx clearctx(declarectx);
  6290. StringBuffer s;
  6291. s.append("size32_t ").append(functionName).append("(ARowBuilder & crSelf, IResourceContext * ctx)");
  6292. clearctx.setNextPriority(RowMetaPrio);
  6293. {
  6294. MemberFunction clearFunc(*this, clearctx, s, MFdynamicproto);
  6295. clearFunc.setIncomplete(true);
  6296. OwnedHqlExpr dataset = createDataset(no_anon, LINK(record));
  6297. BoundRow * cursor = bindSelf(clearFunc.ctx, dataset, "crSelf");
  6298. ensureRowAllocated(clearFunc.ctx, "crSelf");
  6299. buildClearRecord(clearFunc.ctx, cursor->querySelector(), record, direction);
  6300. buildReturnRecordSize(clearFunc.ctx, cursor);
  6301. clearFunc.setIncomplete(false);
  6302. }
  6303. if (options.spanMultipleCpp)
  6304. {
  6305. s.clear().append("extern size32_t ").append(functionName).append("(ARowBuilder & crSelf, IResourceContext * ctx);");
  6306. BuildCtx protoctx(*code, mainprototypesAtom);
  6307. protoctx.addQuoted(s);
  6308. }
  6309. OwnedHqlExpr temp = createVariable(functionName, makeVoidType());
  6310. declarectx.associateExpr(search, temp);
  6311. return temp.getLink();
  6312. }
  6313. void HqlCppTranslator::buildClearRecordMember(BuildCtx & ctx, const char * name, IHqlExpression * dataset)
  6314. {
  6315. BuildCtx clearCtx(ctx);
  6316. StringBuffer s;
  6317. s.append("virtual size32_t createDefault").append(name).append("(ARowBuilder & crSelf)");
  6318. if (dataset && dataset->queryRecord()->numChildren())
  6319. {
  6320. OwnedHqlExpr func = getClearRecordFunction(dataset->queryRecord());
  6321. generateExprCpp(s.append(" { return "), func).append("(crSelf, ctx); }");
  6322. clearCtx.addQuoted(s);
  6323. }
  6324. else
  6325. clearCtx.addQuoted(s.append(" { return 0; }"));
  6326. }
  6327. void HqlCppTranslator::doBuildExprEvaluate(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6328. {
  6329. IHqlExpression * dataset = expr->queryChild(0);
  6330. IHqlExpression * field = expr->queryChild(1);
  6331. BoundRow * boundRow = resolveSelectorDataset(ctx, dataset);
  6332. if (boundRow)
  6333. {
  6334. //E.g. EVALUATE(LEFT, attribute). Need to make sure field refs are unambiguous.
  6335. BuildCtx subctx(ctx);
  6336. subctx.addGroup();
  6337. bindTableCursor(subctx, boundRow->queryDataset(), boundRow->queryBound());
  6338. buildExpr(subctx, field, tgt);
  6339. }
  6340. else
  6341. {
  6342. switch (dataset->queryType()->getTypeCode())
  6343. {
  6344. case type_row:
  6345. BuildCtx subctx(ctx);
  6346. subctx.addGroup();
  6347. Owned<IReferenceSelector> selector = buildNewRow(subctx, dataset);
  6348. Owned<BoundRow> boundRow = selector->getRow(subctx);
  6349. //subctx.associateOwn???
  6350. bindTableCursor(subctx, boundRow->queryDataset(), boundRow->queryBound());
  6351. buildExpr(subctx, field, tgt);
  6352. return;
  6353. }
  6354. throwError(HQLERR_EvaluateTableNotInScope);
  6355. }
  6356. }
  6357. void HqlCppTranslator::doBuildExprCounter(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6358. {
  6359. if (buildExprInCorrectContext(ctx, expr, tgt, false))
  6360. return;
  6361. throwError(HQLERR_CounterNotValid);
  6362. }
  6363. //---------------------------------------------------------------------------
  6364. void HqlCppTranslator::doBuildSerialize(BuildCtx & ctx, IIdAtom * name, IHqlExpression * length, CHqlBoundExpr & bound, const char * bufferName)
  6365. {
  6366. HqlExprArray args;
  6367. if (length)
  6368. args.append(*LINK(length));
  6369. else
  6370. {
  6371. args.append(*getBoundSize(bound));
  6372. }
  6373. args.append(*getPointer(bound.expr));
  6374. args.append(*createVariable(bufferName, makeBoolType()));
  6375. callProcedure(ctx, name, args);
  6376. }
  6377. void HqlCppTranslator::ensureSerialized(const CHqlBoundTarget & variable, BuildCtx & serializectx, BuildCtx & deserializectx, const char * inBufferName, const char * outBufferName, IAtom * serializeForm)
  6378. {
  6379. CHqlBoundExpr value;
  6380. value.setFromTarget(variable);
  6381. while (isCast(value.expr))
  6382. value.expr.set(value.expr->queryChild(0));
  6383. ITypeInfo * type = value.expr->queryType();
  6384. if ((type->getSize() == UNKNOWN_LENGTH) || hasLinkCountedModifier(type) || hasWrapperModifier(type))
  6385. {
  6386. HqlExprArray serializeArgs;
  6387. serializeArgs.append(*value.getTranslatedExpr());
  6388. HqlExprArray deserializeArgs;
  6389. IIdAtom * serializeName;
  6390. IIdAtom * deserializeName;
  6391. OwnedITypeInfo serializedType;
  6392. type_t tc = type->getTypeCode();
  6393. switch (tc)
  6394. {
  6395. case type_varstring:
  6396. serializeName = serializeCStringXId;
  6397. deserializeName = deserializeCStringXId;
  6398. break;
  6399. case type_string:
  6400. serializeName = serializeStringXId;
  6401. deserializeName = deserializeStringXId;
  6402. break;
  6403. case type_data:
  6404. serializeName = serializeDataXId;
  6405. deserializeName = deserializeDataXId;
  6406. break;
  6407. case type_set:
  6408. serializeName = serializeSetId;
  6409. deserializeName = deserializeSetId;
  6410. break;
  6411. case type_qstring:
  6412. serializeName = serializeQStrXId;
  6413. deserializeName = deserializeQStrXId;
  6414. break;
  6415. case type_unicode:
  6416. serializeName = serializeUnicodeXId;
  6417. deserializeName = deserializeUnicodeXId;
  6418. break;
  6419. case type_varunicode:
  6420. serializeName = serializeUnicodeXId;
  6421. deserializeName = deserializeVUnicodeXId;
  6422. break;
  6423. case type_utf8:
  6424. serializeName = serializeUtf8XId;
  6425. deserializeName = deserializeUtf8XId;
  6426. break;
  6427. case type_dictionary:
  6428. case type_table:
  6429. case type_groupedtable:
  6430. {
  6431. IHqlExpression * record = ::queryRecord(type);
  6432. if (hasLinkCountedModifier(type))
  6433. {
  6434. deserializeArgs.append(*createSerializer(deserializectx, record, serializeForm, deserializerAtom));
  6435. serializeArgs.append(*createSerializer(serializectx, record, serializeForm, serializerAtom));
  6436. if (tc == type_dictionary)
  6437. {
  6438. serializeName = serializeDictionaryXId;
  6439. deserializeName = deserializeDictionaryXId;
  6440. }
  6441. else if (tc == type_groupedtable)
  6442. {
  6443. serializeName = serializeGroupedRowsetXId;
  6444. deserializeName = deserializeGroupedRowsetXId;
  6445. }
  6446. else
  6447. {
  6448. serializeName = serializeRowsetXId;
  6449. deserializeName = deserializeRowsetXId;
  6450. }
  6451. }
  6452. else
  6453. {
  6454. assertex(!recordRequiresSerialization(record, serializeForm));
  6455. if (tc == type_dictionary)
  6456. {
  6457. throwUnexpected();
  6458. }
  6459. else if (tc == type_groupedtable)
  6460. {
  6461. serializeName = serializeGroupedDatasetXId;
  6462. deserializeName = deserializeGroupedDatasetXId;
  6463. }
  6464. else
  6465. {
  6466. serializeName = serializeDatasetXId;
  6467. deserializeName = deserializeDatasetXId;
  6468. }
  6469. }
  6470. serializedType.set(type);
  6471. break;
  6472. }
  6473. case type_row:
  6474. {
  6475. IHqlExpression * record = ::queryRecord(type);
  6476. assertex(hasWrapperModifier(type));
  6477. serializeArgs.append(*createSerializer(serializectx, record, serializeForm, serializerAtom));
  6478. serializeArgs.append(*createVariable(outBufferName, makeBoolType()));
  6479. buildFunctionCall(serializectx, serializeRowId, serializeArgs);
  6480. deserializeArgs.append(*createSerializer(deserializectx, record, serializeForm, deserializerAtom));
  6481. deserializeArgs.append(*createVariable(inBufferName, makeBoolType()));
  6482. Owned<ITypeInfo> resultType = makeReferenceModifier(makeAttributeModifier(makeRowType(record->getType()), getLinkCountedAttr()));
  6483. OwnedHqlExpr call = bindFunctionCall(deserializeRowId, deserializeArgs, resultType);
  6484. buildExprAssign(deserializectx, variable, call);
  6485. return;
  6486. }
  6487. default:
  6488. UNIMPLEMENTED;
  6489. }
  6490. serializeArgs.append(*createVariable(outBufferName, makeBoolType()));
  6491. deserializeArgs.append(*createVariable(inBufferName, makeBoolType()));
  6492. buildFunctionCall(serializectx, serializeName, serializeArgs);
  6493. OwnedHqlExpr deserializeCall = bindFunctionCall(deserializeName, deserializeArgs, serializedType);
  6494. buildExprAssign(deserializectx, variable, deserializeCall);
  6495. }
  6496. else
  6497. {
  6498. OwnedHqlExpr length;
  6499. switch (type->getTypeCode())
  6500. {
  6501. case type_int:
  6502. case type_swapint:
  6503. case type_packedint:
  6504. switch (type->getSize())
  6505. {
  6506. case 3: case 5: case 6: case 7:
  6507. if (isLittleEndian(type))
  6508. buildClear(deserializectx, variable);
  6509. else
  6510. {
  6511. unsigned newSize = (type->getSize() == 3) ? 4 : 8;
  6512. length.setown(getSizetConstant(newSize));
  6513. }
  6514. break;
  6515. }
  6516. break;
  6517. case type_row:
  6518. {
  6519. //MORE: This will cause problems if rows are dynamically allocated
  6520. if (hasReferenceModifier(type))
  6521. length.setown(getSizetConstant(sizeof(void*)));
  6522. else
  6523. {
  6524. IHqlExpression * record = ::queryRecord(type);
  6525. length.setown(getSizetConstant(getMaxRecordSize(record)));
  6526. }
  6527. break;
  6528. }
  6529. case type_bitfield:
  6530. UNIMPLEMENTED;
  6531. }
  6532. doBuildSerialize(serializectx, serializeRawId, length, value, outBufferName);
  6533. doBuildSerialize(deserializectx, deserializeRawId, length, value, inBufferName);
  6534. }
  6535. }
  6536. void HqlCppTranslator::ensureSerialized(BuildCtx & ctx, const CHqlBoundTarget & variable)
  6537. {
  6538. EvalContext * instance = queryEvalContext(ctx);
  6539. assertex(instance);
  6540. instance->tempCompatiablityEnsureSerialized(variable);
  6541. }
  6542. bool HqlCppTranslator::checkGetResultContext(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6543. {
  6544. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  6545. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  6546. if (!name)
  6547. name = queryAttributeChild(expr, nameAtom, 0);
  6548. if (!contextAvailable)
  6549. {
  6550. StringBuffer s;
  6551. getStoredDescription(s, seq, name, true);
  6552. ::throwError1(HQLERR_InvalidAcessStoredVariable, s.str());
  6553. }
  6554. if (!insideOnCreate(ctx) && !ctx.queryMatchExpr(globalContextMarkerExpr) && !matchesConstantValue(seq, ResultSequenceOnce))
  6555. {
  6556. if (queryEvalContext(ctx))
  6557. {
  6558. doBuildAliasValue(ctx, expr, tgt, NULL);
  6559. return true;
  6560. }
  6561. StringBuffer s;
  6562. getStoredDescription(s, seq, name, true);
  6563. ::throwError1(HQLERR_CannotAccessStoredVariable, s.str());
  6564. }
  6565. if (ctx.getMatchExpr(expr, tgt))
  6566. return true;
  6567. //Use top activity, rather than queryCurrentActivity() - since we want the dependency to the child (for graph display)
  6568. if (activeActivities.ordinality())
  6569. queryAddResultDependancy(activeActivities.tos(), seq, name);
  6570. else if (name && targetRoxie())
  6571. {
  6572. OwnedHqlExpr attr = createResultAttribute(seq, name);
  6573. registerGlobalUsage(attr);
  6574. }
  6575. return false;
  6576. }
  6577. void HqlCppTranslator::doBuildExprGetResult(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6578. {
  6579. if (checkGetResultContext(ctx, expr, tgt))
  6580. return;
  6581. ITypeInfo * exprType = expr->queryType();
  6582. CHqlBoundTarget tempTarget;
  6583. createTempFor(ctx, exprType, tempTarget, typemod_none, FormatLinkedDataset);
  6584. buildGetResultInfo(ctx, expr, NULL, &tempTarget);
  6585. tgt.setFromTarget(tempTarget);
  6586. ctx.associateExpr(expr, tgt);
  6587. }
  6588. void HqlCppTranslator::doBuildAssignGetResult(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6589. {
  6590. CHqlBoundExpr bound;
  6591. if (checkGetResultContext(ctx, expr, bound))
  6592. {
  6593. assign(ctx, target, bound);
  6594. return;
  6595. }
  6596. buildGetResultInfo(ctx, expr, NULL, &target);
  6597. }
  6598. void HqlCppTranslator::pushCluster(BuildCtx & ctx, IHqlExpression * cluster)
  6599. {
  6600. HqlExprArray args;
  6601. args.append(*LINK(cluster));
  6602. buildFunctionCall(ctx, selectClusterId, args);
  6603. StringBuffer clusterText;
  6604. getStringValue(clusterText, cluster);
  6605. if (clusterText.length())
  6606. ctxCallback->noteCluster(clusterText.str());
  6607. }
  6608. void HqlCppTranslator::popCluster(BuildCtx & ctx)
  6609. {
  6610. HqlExprArray args;
  6611. callProcedure(ctx, restoreClusterId, args);
  6612. }
  6613. void HqlCppTranslator::doBuildStmtSetResult(BuildCtx & ctx, IHqlExpression * expr)
  6614. {
  6615. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  6616. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  6617. IHqlExpression * persist = expr->queryAttribute(_workflowPersist_Atom);
  6618. IHqlExpression * cluster = expr->queryAttribute(clusterAtom);
  6619. BuildCtx subctx(ctx);
  6620. LinkedHqlExpr value;
  6621. if (expr->getOperator() == no_extractresult)
  6622. {
  6623. IHqlExpression * ds = expr->queryChild(0);
  6624. OwnedHqlExpr row = removeDatasetWrapper(ds);
  6625. OwnedHqlExpr newDs = (row->getOperator() == no_activerow) ? LINK(row) : createRow(no_newrow, LINK(row));
  6626. value.setown(replaceSelector(expr->queryChild(1), ds, newDs));
  6627. }
  6628. else
  6629. value.set(expr->queryChild(0));
  6630. if (matchesConstantValue(seq, ResultSequenceStored) || matchesConstantValue(seq, ResultSequencePersist))
  6631. {
  6632. StringBuffer text;
  6633. text.append("Create ");
  6634. getStoredDescription(text, seq, name, true);
  6635. graphLabel.set(text.str());
  6636. }
  6637. if (insideChildQuery(ctx))
  6638. {
  6639. StringBuffer description;
  6640. getStoredDescription(description, seq, name, true);
  6641. reportWarning(CategoryUnusual, SeverityError, queryLocation(expr), ECODETEXT(HQLWRN_OutputScalarInsideChildQuery), description.str());
  6642. }
  6643. if (cluster)
  6644. pushCluster(subctx, cluster->queryChild(0));
  6645. switch (value->queryType()->getTypeCode())
  6646. {
  6647. case type_void:
  6648. {
  6649. buildStmt(subctx, value);
  6650. IHqlExpression * result = queryBoolExpr(true);
  6651. if (expr->queryAttribute(checkpointAtom))
  6652. {
  6653. IHqlExpression * search = value;
  6654. if (search->getOperator() == no_thor)
  6655. search = search->queryChild(0);
  6656. if ((search->getOperator() == no_output) && search->queryChild(1))
  6657. {
  6658. BuildCtx atendctx(*code, goAtom);
  6659. atendctx.setNextDestructor();
  6660. HqlExprArray args;
  6661. args.append(*LINK(search->queryChild(1)));
  6662. callProcedure(atendctx, deleteFileId, args);
  6663. }
  6664. }
  6665. if (!expr->hasAttribute(noSetAtom))
  6666. buildSetResultInfo(subctx, expr, result, NULL, (persist != NULL), false);
  6667. }
  6668. break;
  6669. case type_set:
  6670. {
  6671. ITypeInfo * setType = NULL;
  6672. IHqlExpression * original = queryAttributeChild(expr, _original_Atom, 0);
  6673. if (original)
  6674. setType = original->queryType();
  6675. OwnedHqlExpr normalized = normalizeListCasts(value);
  6676. buildSetResultInfo(subctx, expr, normalized, setType, (persist != NULL), true);
  6677. break;
  6678. }
  6679. case type_dictionary:
  6680. case type_table:
  6681. case type_groupedtable:
  6682. switch (value->getOperator())
  6683. {
  6684. case no_null:
  6685. {
  6686. HqlExprArray args;
  6687. args.append(*createResultName(name, false));
  6688. args.append(*LINK(seq));
  6689. args.append(*createValue(no_translated, makeSetType(NULL), createValue(no_nullptr, makeSetType(NULL)), getSizetConstant(0)));
  6690. args.append(*createTranslatedOwned(createValue(no_nullptr, makeBoolType())));
  6691. buildFunctionCall(subctx, setResultSetId, args);
  6692. HqlExprArray xmlnsAttrs;
  6693. gatherAttributes(xmlnsAttrs, xmlnsAtom, expr);
  6694. Owned<IWUResult> result = createDatasetResultSchema(seq, name, value->queryRecord(), xmlnsAttrs, true, false, 0);
  6695. break;
  6696. }
  6697. default:
  6698. assertex(!"Should never occur - should have been transformed to an OUTPUT()");
  6699. }
  6700. break;
  6701. default:
  6702. buildSetResultInfo(subctx, expr, value, NULL, (persist != NULL), true);
  6703. break;
  6704. }
  6705. if (cluster)
  6706. popCluster(subctx);
  6707. if (matchesConstantValue(seq, ResultSequenceStored) || matchesConstantValue(seq, ResultSequencePersist))
  6708. graphLabel.clear();
  6709. }
  6710. static bool isFilePersist(IHqlExpression * expr)
  6711. {
  6712. for (;;)
  6713. {
  6714. switch (expr->getOperator())
  6715. {
  6716. case no_thor:
  6717. expr = expr->queryChild(0);
  6718. break;
  6719. case no_compound:
  6720. expr = expr->queryChild(1);
  6721. break;
  6722. case no_output:
  6723. return isFileOutput(expr);
  6724. case no_actionlist:
  6725. case no_orderedactionlist:
  6726. expr = expr->queryChild(expr->numChildren()-1);
  6727. break;
  6728. default:
  6729. return false;
  6730. }
  6731. }
  6732. }
  6733. IHqlExpression * HqlCppTranslator::calculatePersistInputCrc(BuildCtx & ctx, IHqlExpression * expr)
  6734. {
  6735. DependenciesUsed dependencies(true);
  6736. gatherDependencies(expr, dependencies, GatherAll);
  6737. dependencies.removeInternalReads();
  6738. return calculatePersistInputCrc(ctx, dependencies);
  6739. }
  6740. IHqlExpression * HqlCppTranslator::calculatePersistInputCrc(BuildCtx & ctx, DependenciesUsed & dependencies)
  6741. {
  6742. Owned<ITypeInfo> crcType = makeIntType(8, false);
  6743. OwnedHqlExpr zero = createNullExpr(crcType);
  6744. if ((dependencies.tablesRead.ordinality() == 0) && (dependencies.resultsRead.ordinality() == 0))
  6745. return zero.getClear();
  6746. OwnedHqlExpr crcExpr = ctx.getTempDeclare(crcType, zero);
  6747. ForEachItemIn(idx1, dependencies.tablesRead)
  6748. {
  6749. IHqlExpression & cur = dependencies.tablesRead.item(idx1);
  6750. HqlExprArray args;
  6751. args.append(OLINK(cur));
  6752. args.append(*LINK(crcExpr));
  6753. OwnedHqlExpr function = bindFunctionCall(getDatasetHashId, args);
  6754. buildAssignToTemp(ctx, crcExpr, function);
  6755. }
  6756. ForEachItemIn(idx2, dependencies.resultsRead)
  6757. {
  6758. IHqlExpression & cur = dependencies.resultsRead.item(idx2);
  6759. IHqlExpression * seq = cur.queryChild(0);
  6760. IHqlExpression * name = cur.queryChild(1);
  6761. IHqlExpression * wuid = cur.queryChild(2);
  6762. if (name->isAttribute())
  6763. {
  6764. assertex(name->queryName() == wuidAtom);
  6765. wuid = name;
  6766. name = NULL;
  6767. }
  6768. //Not sure if we need to do this if the result is internal. Leave on for the moment.
  6769. //if (seq->queryValue()->getIntValue() != ResultSequenceInternal)
  6770. bool expandLogical = matchesConstantValue(seq, ResultSequencePersist) && !cur.hasAttribute(_internal_Atom);
  6771. HqlExprArray args;
  6772. if (wuid)
  6773. args.append(*LINK(wuid->queryChild(0)));
  6774. args.append(*createResultName(name, expandLogical));
  6775. args.append(*LINK(seq));
  6776. OwnedHqlExpr call = bindFunctionCall(wuid ? getExternalResultHashId : getResultHashId, args);
  6777. OwnedHqlExpr value = createValue(no_bxor, crcExpr->getType(), LINK(crcExpr), ensureExprType(call, crcExpr->queryType()));
  6778. buildAssignToTemp(ctx, crcExpr, value);
  6779. }
  6780. return crcExpr.getClear();
  6781. }
  6782. void HqlCppTranslator::doBuildStmtEnsureResult(BuildCtx & ctx, IHqlExpression * expr)
  6783. {
  6784. IHqlExpression * value = expr->queryChild(0);
  6785. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  6786. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  6787. OwnedHqlExpr resultName = ::createResultName(name);
  6788. resultName.setown(ensureExprType(resultName, unknownVarStringType));
  6789. HqlExprArray args;
  6790. args.append(*LINK(resultName));
  6791. args.append(*LINK(seq));
  6792. OwnedHqlExpr checkExists = createValue(no_not, makeBoolType(), bindFunctionCall(isResultId, args));
  6793. if ((value->getOperator() == no_thor) && (value->queryChild(0)->getOperator() == no_output))
  6794. {
  6795. IHqlExpression * filename = queryRealChild(value->queryChild(0), 1);
  6796. if (filename)
  6797. {
  6798. args.append(*LINK(filename));
  6799. OwnedHqlExpr fileExists = createValue(no_not, makeBoolType(), bindFunctionCall(fileExistsId, args));
  6800. checkExists.setown(createBoolExpr(no_or, checkExists.getClear(), fileExists.getClear()));
  6801. }
  6802. }
  6803. BuildCtx subctx(ctx);
  6804. buildFilter(subctx, checkExists);
  6805. doBuildStmtSetResult(subctx, expr);
  6806. }
  6807. //---------------------------------------------------------------------------
  6808. void HqlCppTranslator::doBuildEvalOnce(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * bound)
  6809. {
  6810. IHqlExpression * value = expr->queryChild(0);
  6811. CHqlBoundExpr result;
  6812. doBuildAliasValue(ctx, value, result, NULL);
  6813. if (target)
  6814. {
  6815. OwnedHqlExpr translated = result.getTranslatedExpr();
  6816. buildExprAssign(ctx, *target, translated);
  6817. }
  6818. else if (bound)
  6819. bound->set(result);
  6820. }
  6821. //---------------------------------------------------------------------------
  6822. void HqlCppTranslator::doBuildExprSizeof(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6823. {
  6824. if (ctx.getMatchExpr(expr, tgt))
  6825. return;
  6826. IHqlExpression * child = expr->queryChild(0);
  6827. ITypeInfo * type = child->queryType();
  6828. if (expr->hasAttribute(maxAtom))
  6829. {
  6830. if (type)
  6831. {
  6832. unsigned size = UNKNOWN_LENGTH;
  6833. switch (type->getTypeCode())
  6834. {
  6835. case type_dictionary:
  6836. case type_table:
  6837. case type_groupedtable:
  6838. case type_record:
  6839. case type_row:
  6840. {
  6841. OwnedHqlExpr record = getSerializedForm(child->queryRecord(), diskAtom);
  6842. if (isFixedSizeRecord(record))
  6843. size = getMinRecordSize(record);
  6844. else
  6845. size = getMaxRecordSize(record);
  6846. }
  6847. break;
  6848. case type_alien:
  6849. {
  6850. IHqlAlienTypeInfo * alien = queryAlienType(type);
  6851. size = alien->getMaxSize();
  6852. break;
  6853. }
  6854. default:
  6855. size = type->getSize();
  6856. break;
  6857. }
  6858. if (size == UNKNOWN_LENGTH)
  6859. throwError(HQLERR_CouldNotDetermineMaxSize);
  6860. tgt.expr.setown(getSizetConstant(size));
  6861. return;
  6862. }
  6863. }
  6864. if (expr->hasAttribute(minAtom))
  6865. {
  6866. if (type)
  6867. {
  6868. unsigned size = UNKNOWN_LENGTH;
  6869. switch (type->getTypeCode())
  6870. {
  6871. case type_dictionary:
  6872. case type_table:
  6873. case type_groupedtable:
  6874. case type_record:
  6875. case type_row:
  6876. {
  6877. OwnedHqlExpr record = getSerializedForm(child->queryRecord(), diskAtom);
  6878. size = getMinRecordSize(record);
  6879. }
  6880. break;
  6881. default:
  6882. size = type->getSize();
  6883. break;
  6884. }
  6885. if (size == UNKNOWN_LENGTH)
  6886. throwError(HQLERR_CouldNotDetermineMinSize);
  6887. tgt.expr.setown(getSizetConstant(size));
  6888. return;
  6889. }
  6890. }
  6891. #if 0
  6892. IHqlExpression * limitExpr = expr->queryChild(1);
  6893. if (limitExpr)
  6894. {
  6895. OwnedHqlExpr other = createValue(no_sizeof, expr->getType(), LINK(child));
  6896. HqlExprAssociation * match = ctx.getMatchExpr(other);
  6897. if (match)
  6898. {
  6899. tgt.expr.set(match->expr);
  6900. return;
  6901. }
  6902. }
  6903. #endif
  6904. // Size calculation needs to only come in to play if the field/record can't be found in scope
  6905. // otherwise sizeof(field) is wrong if it is inside an ifblock.
  6906. Owned<IReferenceSelector> selector;
  6907. try
  6908. {
  6909. selector.setown(buildReference(ctx, child));
  6910. selector->getSize(ctx, tgt);
  6911. //cache non-constant values in a temporary variable...
  6912. if (!tgt.expr->queryValue())
  6913. {
  6914. if (!isSimpleLength(tgt.expr))
  6915. {
  6916. IHqlExpression * temp = ctx.getTempDeclare(expr->queryType(), tgt.expr);
  6917. tgt.expr.setown(temp);
  6918. }
  6919. ctx.associateExpr(expr, tgt);
  6920. }
  6921. }
  6922. catch (IException * e)
  6923. {
  6924. switch (child->getOperator())
  6925. {
  6926. case no_translated:
  6927. {
  6928. CHqlBoundExpr bound;
  6929. buildExpr(ctx, child, bound);
  6930. tgt.expr.setown(getBoundSize(bound));
  6931. return;
  6932. }
  6933. }
  6934. // Size calculation needs to only come in to play if the field/record can't be found in scope
  6935. // otherwise sizeof(field) is wrong if it is inside an ifblock.
  6936. if (type)
  6937. {
  6938. if (type->getTypeCode() == type_alien)
  6939. {
  6940. IHqlAlienTypeInfo * alien = queryAlienType(type);
  6941. type = alien->queryPhysicalType();
  6942. }
  6943. switch (type->getTypeCode())
  6944. {
  6945. case type_dictionary:
  6946. case type_table:
  6947. case type_groupedtable:
  6948. case type_record:
  6949. case type_row:
  6950. {
  6951. e->Release();
  6952. OwnedHqlExpr record = getSerializedForm(child->queryRecord(), diskAtom);
  6953. if (isFixedSizeRecord(record))
  6954. {
  6955. tgt.expr.setown(getSizetConstant(getMinRecordSize(record)));
  6956. return;
  6957. }
  6958. throwError(HQLERR_CannotDetermineSizeVar);
  6959. }
  6960. break;
  6961. case type_void:
  6962. break;
  6963. default:
  6964. if ((type->getSize() != UNKNOWN_LENGTH) && (!selector || !selector->isConditional()))
  6965. {
  6966. tgt.expr.setown(getSizetConstant(type->getSize()));
  6967. e->Release();
  6968. return;
  6969. }
  6970. }
  6971. }
  6972. throw; // really an internal error - the parse should not have let it through....
  6973. }
  6974. }
  6975. void HqlCppTranslator::doBuildExprRowDiff(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, IHqlExpression * leftSelector, IHqlExpression * rightRecord, IHqlExpression * rightSelector, StringBuffer & selectorText, bool isCount)
  6976. {
  6977. switch (expr->getOperator())
  6978. {
  6979. case no_field:
  6980. {
  6981. IIdAtom * id = expr->queryId();
  6982. IHqlSimpleScope * rightScope = rightRecord->querySimpleScope();
  6983. OwnedHqlExpr match = rightScope ? rightScope->lookupSymbol(id) : NULL;
  6984. if (!match)
  6985. return;
  6986. OwnedHqlExpr left = createSelectExpr(LINK(leftSelector), LINK(expr));
  6987. OwnedHqlExpr right = createSelectExpr(LINK(rightSelector), LINK(match));
  6988. ITypeInfo * leftType = expr->queryType()->queryPromotedType();
  6989. switch (leftType->getTypeCode())
  6990. {
  6991. case type_record:
  6992. case type_row:
  6993. {
  6994. StringBuffer subSelectorText;
  6995. subSelectorText.append(selectorText).append(expr->queryName()).append(".");
  6996. IHqlExpression * record = ::queryRecord(leftType);
  6997. doBuildExprRowDiff(ctx, target, record, left, right->queryRecord(), right, subSelectorText, isCount);
  6998. return;
  6999. }
  7000. break;
  7001. case type_dictionary:
  7002. case type_table:
  7003. case type_groupedtable:
  7004. {
  7005. StringBuffer typeName;
  7006. getFriendlyTypeStr(leftType, typeName);
  7007. throwError2(HQLERR_UnsupportedRowDiffType, typeName.str(), str(expr->queryId()));
  7008. }
  7009. }
  7010. StringBuffer fullName;
  7011. fullName.append(selectorText).append(str(id));
  7012. ITypeInfo * rightType = right->queryType()->queryPromotedType();
  7013. if (!leftType->assignableFrom(rightType))
  7014. throwError1(HQLERR_MismatchRowDiffType, fullName.str());
  7015. Owned<ITypeInfo> compareType = ::getPromotedECLType(leftType, rightType);
  7016. OwnedHqlExpr test = createBoolExpr(no_ne, ensureExprType(left, compareType), ensureExprType(right, compareType));
  7017. HqlExprArray args;
  7018. CHqlBoundExpr bound;
  7019. buildExpr(ctx, test, bound);
  7020. StringBuffer specialText;
  7021. generateExprCpp(specialText, target.length).append(",");
  7022. generateExprCpp(specialText, target.expr).append(".refextendstr()");
  7023. OwnedHqlExpr special = createQuoted(specialText.str(), makeBoolType());
  7024. BuildCtx condctx(ctx);
  7025. IHqlStmt * cond = condctx.addFilter(bound.expr);
  7026. //if differ...
  7027. args.append(*LINK(special));
  7028. if (isCount)
  7029. args.append(*createConstant(",1"));
  7030. else
  7031. {
  7032. StringBuffer temp;
  7033. temp.append(",").append(fullName);
  7034. args.append(*createConstant(temp));
  7035. }
  7036. buildFunctionCall(condctx, concatExtendId, args);
  7037. //else if same...
  7038. if (isCount)
  7039. {
  7040. condctx.selectElse(cond);
  7041. args.append(*LINK(special));
  7042. args.append(*createConstant(",0"));
  7043. buildFunctionCall(condctx, concatExtendId, args);
  7044. }
  7045. break;
  7046. }
  7047. case no_ifblock:
  7048. {
  7049. doBuildExprRowDiff(ctx, target, expr->queryChild(1), leftSelector, rightRecord, rightSelector, selectorText, isCount);
  7050. break;
  7051. }
  7052. case no_record:
  7053. {
  7054. ForEachChild(idx, expr)
  7055. doBuildExprRowDiff(ctx, target, expr->queryChild(idx), leftSelector, rightRecord, rightSelector, selectorText, isCount);
  7056. break;
  7057. }
  7058. case no_attr:
  7059. case no_attr_expr:
  7060. case no_attr_link:
  7061. break;
  7062. default:
  7063. UNIMPLEMENTED;
  7064. }
  7065. }
  7066. IHqlExpression * HqlCppTranslator::queryRecord(BuildCtx & ctx, IHqlExpression * expr)
  7067. {
  7068. return expr->queryRecord();
  7069. }
  7070. void HqlCppTranslator::doBuildExprRowDiff(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7071. {
  7072. CHqlBoundTarget tempTarget;
  7073. createTempFor(ctx, expr, tempTarget);
  7074. StringBuffer selectorText;
  7075. IHqlExpression * left = expr->queryChild(0);
  7076. IHqlExpression * leftRecord = queryRecord(ctx, left);
  7077. IHqlExpression * right = expr->queryChild(1);
  7078. IHqlExpression * rightRecord = queryRecord(ctx, right);
  7079. ctx.addAssign(tempTarget.length, queryZero());
  7080. doBuildExprRowDiff(ctx, tempTarget, leftRecord, left, rightRecord, right, selectorText, expr->hasAttribute(countAtom));
  7081. OwnedHqlExpr result = createValue(no_substring, LINK(unknownStringType), tempTarget.getTranslatedExpr(), createValue(no_rangefrom, makeVoidType(), createConstant(2)));
  7082. buildExpr(ctx, result, tgt);
  7083. }
  7084. //---------------------------------------------------------------------------
  7085. ABoundActivity * HqlCppTranslator::doBuildActivityCacheAlias(BuildCtx & ctx, IHqlExpression * expr)
  7086. {
  7087. IHqlExpression * dataset = expr->queryChild(1);
  7088. return buildCachedActivity(ctx, dataset);
  7089. }
  7090. //---------------------------------------------------------------------------
  7091. // no_cloned
  7092. ABoundActivity * HqlCppTranslator::doBuildActivityCloned(BuildCtx & ctx, IHqlExpression * expr)
  7093. {
  7094. IHqlExpression * dataset = expr->queryChild(0);
  7095. return buildCachedActivity(ctx, dataset);
  7096. }
  7097. //---------------------------------------------------------------------------
  7098. // no_addfiles
  7099. static void unwindAddFiles(HqlExprArray & args, IHqlExpression * expr, bool reqIsOrdered, bool isOrderedPull)
  7100. {
  7101. if ((expr->getOperator() == no_addfiles) && (isOrdered(expr) == reqIsOrdered) && (expr->hasAttribute(pullAtom) == isOrderedPull))
  7102. {
  7103. unwindAddFiles(args, expr->queryChild(0), reqIsOrdered, isOrderedPull);
  7104. unwindAddFiles(args, expr->queryChild(1), reqIsOrdered, isOrderedPull);
  7105. }
  7106. else
  7107. args.append(*LINK(expr));
  7108. }
  7109. static IHqlExpression * queryRootConcatActivity(IHqlExpression * expr)
  7110. {
  7111. for (;;)
  7112. {
  7113. node_operator curOp = expr->getOperator();
  7114. switch (curOp)
  7115. {
  7116. case no_nofold:
  7117. case no_section:
  7118. case no_sectioninput:
  7119. case no_preservemeta:
  7120. case no_nocombine:
  7121. case no_forcegraph:
  7122. break;
  7123. default:
  7124. return expr;
  7125. }
  7126. expr = expr->queryChild(0);
  7127. }
  7128. }
  7129. ABoundActivity * HqlCppTranslator::doBuildActivityConcat(BuildCtx & ctx, IHqlExpression * expr)
  7130. {
  7131. HqlExprArray inExprs;
  7132. bool ordered = isOrdered(expr);
  7133. bool orderedPull = expr->hasAttribute(pullAtom);
  7134. unwindAddFiles(inExprs, expr, ordered, orderedPull);
  7135. //If all coming from disk, probably better to pull them in order.
  7136. bool allFromDisk = options.orderDiskFunnel;
  7137. CIArray bound;
  7138. ForEachItemIn(idx, inExprs)
  7139. {
  7140. IHqlExpression * cur = &inExprs.item(idx);
  7141. bound.append(*buildCachedActivity(ctx, cur));
  7142. cur = queryRootConcatActivity(cur);
  7143. switch (cur->getOperator())
  7144. {
  7145. case no_compound_diskread:
  7146. case no_compound_disknormalize:
  7147. case no_compound_diskaggregate:
  7148. case no_compound_diskcount:
  7149. case no_compound_diskgroupaggregate:
  7150. break;
  7151. case no_temptable:
  7152. case no_inlinetable:
  7153. case no_temprow:
  7154. case no_datasetfromrow:
  7155. case no_projectrow:
  7156. case no_createrow:
  7157. case no_typetransfer:
  7158. break;
  7159. case no_table:
  7160. switch (cur->queryChild(2)->getOperator())
  7161. {
  7162. case no_thor: case no_flat:
  7163. break;
  7164. default:
  7165. allFromDisk = false;
  7166. break;
  7167. }
  7168. break;
  7169. default:
  7170. allFromDisk = false;
  7171. break;
  7172. }
  7173. }
  7174. if (orderedPull || (allFromDisk && !targetRoxie()))
  7175. ordered = true;
  7176. if (!expr->hasAttribute(orderedAtom) && insideChildQuery(ctx))
  7177. ordered = true;
  7178. bool useImplementationClass = options.minimizeActivityClasses && targetRoxie();
  7179. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfunnel, expr, "Funnel");
  7180. if (useImplementationClass)
  7181. instance->setImplementationClass(newFunnelArgId);
  7182. buildActivityFramework(instance);
  7183. buildInstancePrefix(instance);
  7184. if (!useImplementationClass)
  7185. {
  7186. if (ordered)
  7187. doBuildBoolFunction(instance->classctx, "isOrdered", true);
  7188. if (orderedPull)
  7189. doBuildBoolFunction(instance->classctx, "pullSequentially", orderedPull);
  7190. }
  7191. else
  7192. {
  7193. instance->addConstructorParameter(queryBoolExpr(ordered));
  7194. instance->addConstructorParameter(queryBoolExpr(orderedPull));
  7195. }
  7196. buildInstanceSuffix(instance);
  7197. ForEachItemIn(idx2, bound)
  7198. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  7199. return instance->getBoundActivity();
  7200. }
  7201. ABoundActivity * HqlCppTranslator::doBuildActivityMerge(BuildCtx & ctx, IHqlExpression * expr)
  7202. {
  7203. CIArrayOf<ABoundActivity> inputs;
  7204. ForEachChild(idx, expr)
  7205. {
  7206. IHqlExpression *cur = expr->queryChild(idx);
  7207. if (!cur->isAttribute())
  7208. inputs.append(*buildCachedActivity(ctx, cur));
  7209. }
  7210. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKmerge, expr, "Merge");
  7211. buildActivityFramework(instance);
  7212. buildInstancePrefix(instance);
  7213. IHqlExpression * dataset = expr->queryChild(0);
  7214. IHqlExpression * sortAttr = expr->queryAttribute(sortedAtom);
  7215. HqlExprArray sorts;
  7216. unwindChildren(sorts, sortAttr);
  7217. if (sorts.ordinality() != 0)
  7218. {
  7219. OwnedHqlExpr sortOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  7220. instance->startctx.addQuotedLiteral("virtual ICompare * queryCompare() { return &compare; }");
  7221. DatasetReference dsRef(dataset, no_activetable, NULL);
  7222. buildCompareClass(instance->nestedctx, "compare", sortOrder, dsRef);
  7223. if (!instance->isLocal)
  7224. generateSerializeKey(instance->nestedctx, no_none, dsRef, sorts, !instance->isChildActivity(), true);
  7225. }
  7226. else
  7227. throwError(HQLERR_InputMergeNotSorted);
  7228. if (expr->hasAttribute(dedupAtom))
  7229. doBuildBoolFunction(instance->classctx, "dedup", true);
  7230. buildInstanceSuffix(instance);
  7231. ForEachItemIn(idx2, inputs)
  7232. buildConnectInputOutput(ctx, instance, &inputs.item(idx2), 0, idx2);
  7233. return instance->getBoundActivity();
  7234. }
  7235. ABoundActivity * HqlCppTranslator::doBuildActivityRegroup(BuildCtx & ctx, IHqlExpression * expr)
  7236. {
  7237. HqlExprArray inExprs;
  7238. expr->unwindList(inExprs, no_regroup);
  7239. CIArray bound;
  7240. ForEachItemIn(idx, inExprs)
  7241. {
  7242. IHqlExpression & cur = inExprs.item(idx);
  7243. if (!cur.isAttribute())
  7244. bound.append(*buildCachedActivity(ctx, &cur));
  7245. }
  7246. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKregroup, expr, "Regroup");
  7247. buildActivityFramework(instance);
  7248. buildInstancePrefix(instance);
  7249. buildInstanceSuffix(instance);
  7250. ForEachItemIn(idx2, bound)
  7251. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  7252. return instance->getBoundActivity();
  7253. }
  7254. static void unwindNonEmpty(HqlExprCopyArray & args, IHqlExpression * expr, bool isLocal)
  7255. {
  7256. if ((expr->getOperator() == no_nonempty) && (expr->hasAttribute(localAtom) == isLocal))
  7257. {
  7258. ForEachChild(i, expr)
  7259. unwindNonEmpty(args, expr->queryChild(i), isLocal);
  7260. }
  7261. else
  7262. args.append(*expr);
  7263. }
  7264. ABoundActivity * HqlCppTranslator::doBuildActivityNonEmpty(BuildCtx & ctx, IHqlExpression * expr)
  7265. {
  7266. HqlExprCopyArray inExprs;
  7267. unwindNonEmpty(inExprs, expr, expr->hasAttribute(localAtom));
  7268. CIArray bound;
  7269. ForEachItemIn(idx, inExprs)
  7270. {
  7271. IHqlExpression * cur = &inExprs.item(idx);
  7272. if (!cur->isAttribute())
  7273. bound.append(*buildCachedActivity(ctx, cur));
  7274. }
  7275. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnonempty, expr, "NonEmpty");
  7276. buildActivityFramework(instance);
  7277. buildInstancePrefix(instance);
  7278. buildInstanceSuffix(instance);
  7279. ForEachItemIn(idx2, bound)
  7280. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  7281. return instance->getBoundActivity();
  7282. }
  7283. ABoundActivity * HqlCppTranslator::doBuildActivitySplit(BuildCtx & ctx, IHqlExpression * expr)
  7284. {
  7285. IHqlExpression * dataset = expr->queryChild(0);
  7286. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7287. bool useImplementationClass = options.minimizeActivityClasses;
  7288. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsplit, expr, "Split");
  7289. if (useImplementationClass)
  7290. instance->setImplementationClass(newSplitArgId);
  7291. buildActivityFramework(instance);
  7292. buildInstancePrefix(instance);
  7293. //IHqlExpression * numWays = expr->queryChild(1);
  7294. OwnedHqlExpr numWaysCallback = createUnknown(no_callback, LINK(sizetType), countAtom, instance->createOutputCountCallback());
  7295. OwnedHqlExpr numWays = createTranslated(numWaysCallback);
  7296. bool balanced = expr->hasAttribute(balancedAtom);
  7297. if (!useImplementationClass)
  7298. {
  7299. if (!matchesConstantValue(numWays, 2))
  7300. doBuildUnsignedFunction(instance->classctx, "numBranches", numWays);
  7301. if (balanced)
  7302. doBuildBoolFunction(instance->classctx, "isBalanced", true);
  7303. }
  7304. else
  7305. {
  7306. instance->addConstructorParameter(numWays);
  7307. instance->addConstructorParameter(queryBoolExpr(balanced));
  7308. }
  7309. buildInstanceSuffix(instance);
  7310. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7311. return instance->getBoundActivity();
  7312. }
  7313. ABoundActivity * HqlCppTranslator::doBuildActivitySpill(BuildCtx & ctx, IHqlExpression * expr)
  7314. {
  7315. return doBuildActivityOutput(ctx, expr, false);
  7316. }
  7317. bool HqlCppTranslator::isCurrentActiveGraph(BuildCtx & ctx, IHqlExpression * graphTag)
  7318. {
  7319. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7320. assertex(activeSubgraph);
  7321. return (graphTag == activeSubgraph->graphTag);
  7322. }
  7323. IHqlExpression * HqlCppTranslator::createLoopSubquery(IHqlExpression * dataset, IHqlExpression * selSeq, IHqlExpression * rowsid, IHqlExpression * body, IHqlExpression * filter, IHqlExpression * again, IHqlExpression * counter, bool multiInstance, unsigned & loopAgainResult)
  7324. {
  7325. //Now need to generate the body of the loop.
  7326. //output dataset is result 0
  7327. //input dataset is fed in using result 1
  7328. //counter (if required) is fed in using <result-2>[0].counter;
  7329. ChildGraphExprBuilder graphBuilder(2);
  7330. IHqlExpression * graphid = graphBuilder.queryRepresents();
  7331. LinkedHqlExpr transformedBody = body;
  7332. LinkedHqlExpr transformedAgain = again;
  7333. //Result 1 is the input dataset.
  7334. HqlExprArray args;
  7335. args.append(*LINK(dataset->queryRecord()));
  7336. args.append(*LINK(graphid));
  7337. args.append(*getSizetConstant(1));
  7338. if (isGrouped(dataset))
  7339. args.append(*createAttribute(groupedAtom));
  7340. args.append(*createAttribute(_loop_Atom));
  7341. if (multiInstance)
  7342. args.append(*createAttribute(_streaming_Atom));
  7343. if (targetThor()) // MORE: && !isChildQuery(ctx)..
  7344. args.append(*createAttribute(_distributed_Atom));
  7345. OwnedHqlExpr inputResult= createDataset(no_getgraphresult, args);
  7346. //Result 2 is the counter - if present
  7347. OwnedHqlExpr counterResult;
  7348. if (counter)
  7349. {
  7350. OwnedHqlExpr select = createCounterAsGraphResult(counter, graphid, 2);
  7351. transformedBody.setown(replaceExpression(transformedBody, counter, select));
  7352. if (transformedAgain)
  7353. {
  7354. //The COUNTER for the global termination condition is whether to execute iteration COUNTER, 1=1st iter
  7355. //Since we're evaluating the condition in the previous iteration it needs to be increased by 1.
  7356. OwnedHqlExpr nextCounter = adjustValue(select, 1);
  7357. transformedAgain.setown(replaceExpression(transformedAgain, counter, nextCounter));
  7358. }
  7359. graphBuilder.addInput();
  7360. }
  7361. //first create the result...
  7362. //Need to replace ROWS(LEFT) with the result1
  7363. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  7364. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(left), LINK(rowsid));
  7365. transformedBody.setown(replaceExpression(transformedBody, rowsExpr, inputResult));
  7366. OwnedHqlExpr result = createValue(no_setgraphresult, makeVoidType(), LINK(transformedBody), LINK(graphid), getSizetConstant(0), createAttribute(_loop_Atom));
  7367. graphBuilder.addAction(result);
  7368. if (transformedAgain)
  7369. {
  7370. LinkedHqlExpr nextLoopDataset = transformedBody;
  7371. if (filter)
  7372. {
  7373. //If there is a loop filter then the global condition is applied to dataset filtered by that.
  7374. OwnedHqlExpr mappedFilter = replaceSelector(filter, left, nextLoopDataset);
  7375. nextLoopDataset.setown(createDataset(no_filter, nextLoopDataset.getClear(), LINK(mappedFilter)));
  7376. }
  7377. transformedAgain.setown(replaceExpression(transformedAgain, rowsExpr, nextLoopDataset));
  7378. loopAgainResult = graphBuilder.addInput();
  7379. //MORE: Add loopAgainResult as an attribute on the no_childquery rather than using a reference parameter
  7380. OwnedHqlExpr againResult = convertScalarToGraphResult(transformedAgain, queryBoolType(), graphid, loopAgainResult);
  7381. graphBuilder.addAction(againResult);
  7382. }
  7383. return graphBuilder.getGraph();
  7384. }
  7385. ABoundActivity * HqlCppTranslator::doBuildActivityLoop(BuildCtx & ctx, IHqlExpression * expr)
  7386. {
  7387. IHqlExpression * dataset = expr->queryChild(0);
  7388. IHqlExpression * count = queryRealChild(expr, 1);
  7389. IHqlExpression * filter = queryRealChild(expr, 2);
  7390. IHqlExpression * loopCond = queryRealChild(expr, 3);
  7391. IHqlExpression * body = expr->queryChild(4);
  7392. assertex(body->getOperator() == no_loopbody);
  7393. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  7394. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  7395. IHqlExpression * selSeq = querySelSeq(expr);
  7396. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7397. ThorActivityKind kind = TAKnone;
  7398. //LOOP(dataset, count[, rowFilter])
  7399. //LOOP(dataset, <dataset-filter>, <rowfilter>)
  7400. //LOOP(dataset, <dataset-filter|rowfilter>
  7401. if (count)
  7402. kind = TAKloopcount;
  7403. else if (loopCond)
  7404. kind = TAKloopdataset;
  7405. else
  7406. kind = TAKlooprow;
  7407. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "Loop");
  7408. buildActivityFramework(instance);
  7409. buildInstancePrefix(instance);
  7410. if (filter)
  7411. {
  7412. MemberFunction func(*this, instance->startctx, "virtual bool sendToLoop(unsigned counter, const void * _self)");
  7413. func.ctx.addQuotedLiteral("unsigned char * self = (unsigned char *) _self;");
  7414. associateCounter(func.ctx, counter, "counter");
  7415. bindTableCursor(func.ctx, dataset, "self", no_left, selSeq);
  7416. buildReturn(func.ctx, filter);
  7417. }
  7418. if (count)
  7419. doBuildUnsignedFunction(instance->startctx, "numIterations", count);
  7420. if (loopCond)
  7421. {
  7422. MemberFunction func(*this, instance->startctx, "virtual bool loopAgain(unsigned counter, unsigned numRows, const void * * _rows)");
  7423. func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
  7424. associateCounter(func.ctx, counter, "counter");
  7425. bindRows(func.ctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  7426. buildReturn(func.ctx, loopCond);
  7427. }
  7428. IHqlExpression * loopFirst = queryAttributeChild(expr, _loopFirst_Atom, 0);
  7429. if (loopFirst)
  7430. doBuildBoolFunction(instance->startctx, "loopFirstTime", loopFirst);
  7431. IHqlExpression * parallel = expr->queryAttribute(parallelAtom);
  7432. if (parallel && (targetHThor() || !count || loopCond))
  7433. parallel = NULL;
  7434. if (parallel)
  7435. {
  7436. IHqlExpression * numThreads = parallel->queryChild(0);
  7437. if (numThreads)
  7438. doBuildUnsignedFunction(instance->startctx, "defaultParallelIterations", numThreads);
  7439. }
  7440. StringBuffer flags;
  7441. if (counter) flags.append("|LFcounter");
  7442. if (parallel) flags.append("|LFparallel");
  7443. if (filter) flags.append("|LFfiltered");
  7444. if (loopFirst) flags.append("|LFnewloopagain");
  7445. if (flags.length())
  7446. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  7447. {
  7448. MemberFunction func(*this, instance->startctx, "virtual void createParentExtract(rtlRowBuilder & builder)");
  7449. //Now need to generate the body of the loop.
  7450. unsigned loopAgainResult = 0;
  7451. OwnedHqlExpr childquery = createLoopSubquery(dataset, selSeq, rowsid, body->queryChild(0), filter, loopCond, counter, (parallel != NULL), loopAgainResult);
  7452. ChildGraphBuilder builder(*this, childquery);
  7453. unique_id_t loopId = builder.buildLoopBody(func.ctx, (parallel != NULL), getBoolAttribute(expr, fewAtom));
  7454. instance->addAttributeInt("_loopid", loopId);
  7455. if (loopAgainResult)
  7456. doBuildUnsignedFunction(instance->startctx, "loopAgainResult", loopAgainResult);
  7457. }
  7458. buildInstanceSuffix(instance);
  7459. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7460. return instance->getBoundActivity();
  7461. }
  7462. //---------------------------------------------------------------------------
  7463. ABoundActivity * HqlCppTranslator::doBuildActivityGraphLoop(BuildCtx & ctx, IHqlExpression * expr)
  7464. {
  7465. IHqlExpression * dataset = expr->queryChild(0);
  7466. IHqlExpression * count = expr->queryChild(1);
  7467. IHqlExpression * body = expr->queryChild(2);
  7468. assertex(body->getOperator() == no_loopbody);
  7469. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  7470. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  7471. IHqlExpression * selSeq = querySelSeq(expr);
  7472. IHqlExpression * parallel = expr->queryAttribute(parallelAtom);
  7473. if (parallel && targetHThor())
  7474. parallel = NULL;
  7475. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7476. ThorActivityKind kind = parallel ? TAKparallelgraphloop : TAKgraphloop;
  7477. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "GraphLoop");
  7478. buildActivityFramework(instance);
  7479. buildInstancePrefix(instance);
  7480. doBuildUnsignedFunction(instance->startctx, "numIterations", count);
  7481. StringBuffer flags;
  7482. if (counter) flags.append("|GLFcounter");
  7483. if (parallel) flags.append("|GLFparallel");
  7484. if (flags.length())
  7485. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  7486. {
  7487. MemberFunction func(*this, instance->startctx, "virtual void createParentExtract(rtlRowBuilder & builder)");
  7488. //Now need to generate the body of the loop.
  7489. //output dataset is result 0
  7490. //input dataset is fed in using result 1
  7491. //counter (if required) is fed in using result 2[0].counter;
  7492. unique_id_t loopId = buildGraphLoopSubgraph(func.ctx, dataset, selSeq, rowsid, body->queryChild(0), counter, (parallel != NULL), getBoolAttribute(expr, fewAtom));
  7493. instance->addAttributeInt("_loopid", loopId);
  7494. }
  7495. buildInstanceSuffix(instance);
  7496. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7497. return instance->getBoundActivity();
  7498. }
  7499. //---------------------------------------------------------------------------
  7500. ABoundActivity * HqlCppTranslator::doBuildActivityRemote(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  7501. {
  7502. IHqlExpression * child = expr->queryChild(0);
  7503. if (targetHThor() || (targetThor() && !insideChildQuery(ctx)))
  7504. {
  7505. if (!options.alwaysAllowAllNodes)
  7506. throwError(HQLERR_RemoteNoMeaning);
  7507. }
  7508. if (isGrouped(child))
  7509. throwError(HQLERR_RemoteGrouped);
  7510. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKremotegraph, expr, "Remote");
  7511. buildActivityFramework(instance, isRoot);
  7512. buildInstancePrefix(instance);
  7513. IHqlExpression * dataset = expr->queryChild(0);
  7514. IHqlExpression * rowlimit = expr->queryAttribute(rowLimitAtom);
  7515. if (rowlimit)
  7516. {
  7517. doBuildUnsigned64Function(instance->startctx, "getRowLimit", rowlimit->queryChild(0));
  7518. IHqlExpression * fail = queryChildOperator(no_fail, rowlimit);
  7519. if (fail)
  7520. {
  7521. MemberFunction func(*this, instance->startctx, "virtual void onLimitExceeded()");
  7522. buildStmt(func.ctx, fail);
  7523. }
  7524. }
  7525. {
  7526. MemberFunction func(*this, instance->startctx, "virtual void createParentExtract(rtlRowBuilder & builder)");
  7527. //output dataset is result 0
  7528. unique_id_t remoteId = buildRemoteSubgraph(func.ctx, dataset);
  7529. instance->addAttributeInt("_graphid", remoteId);
  7530. }
  7531. buildInstanceSuffix(instance);
  7532. return instance->getBoundActivity();
  7533. }
  7534. //---------------------------------------------------------------------------
  7535. // no_update
  7536. void HqlCppTranslator::doBuildStmtUpdate(BuildCtx & ctx, IHqlExpression * expr)
  7537. {
  7538. // MJH - CODE TO DO UPDATE GOES HERE
  7539. PrintLog("in HqlCppTranslator::doBuildStmtUpdate()");
  7540. }
  7541. IHqlExpression * HqlCppTranslator::createClearRowCall(BuildCtx & ctx, BoundRow * self)
  7542. {
  7543. IHqlExpression * record = self->querySelector()->queryRecord();
  7544. OwnedHqlExpr clearFunc = getClearRecordFunction(record, 0);
  7545. StringBuffer s;
  7546. ensureContextAvailable(ctx);
  7547. IHqlExpression * boundRow = self->queryBound();
  7548. OwnedHqlExpr rowPointer = getPointer(boundRow);
  7549. generateExprCpp(s, clearFunc).append("(");
  7550. if (self->queryBuilder())
  7551. {
  7552. generateExprCpp(s, self->queryBuilder());
  7553. }
  7554. else
  7555. {
  7556. StringBuffer builderName;
  7557. getUniqueId(builderName.append("rb"));
  7558. StringBuffer temp;
  7559. temp.append("RtlStaticRowBuilder ").append(builderName).append("(");
  7560. if (ctx.queryMatchExpr(constantMemberMarkerExpr))
  7561. temp.append("(byte *)");
  7562. generateExprCpp(temp, rowPointer);
  7563. temp.append(",").append(getMaxRecordSize(record)).append(");");
  7564. ctx.addQuoted(temp);
  7565. s.append(builderName);
  7566. }
  7567. s.append(", ctx)");
  7568. return createQuoted(s.str(), makeVoidType());
  7569. }
  7570. void HqlCppTranslator::associateSkipReturnMarker(BuildCtx & ctx, IHqlExpression * value, BoundRow * self)
  7571. {
  7572. ctx.associateExpr(skipReturnMarker, value);
  7573. }
  7574. void HqlCppTranslator::doBuildStmtSkip(BuildCtx & ctx, IHqlExpression * expr, bool * canReachFollowing)
  7575. {
  7576. HqlExprAssociation * match = ctx.queryMatchExpr(skipActionMarker);
  7577. IHqlExpression * cond = expr->queryChild(0);
  7578. if (cond && cond->isRecord())
  7579. cond = NULL;
  7580. if (canReachFollowing)
  7581. *canReachFollowing = true;
  7582. BuildCtx subctx(ctx);
  7583. if (match)
  7584. {
  7585. IHqlCodeCallback * callback = static_cast<IHqlCodeCallback *>(match->queryExpr()->queryUnknownExtra());
  7586. if (cond)
  7587. buildFilter(subctx, cond);
  7588. callback->buildCode(*this, subctx);
  7589. }
  7590. else
  7591. {
  7592. match = ctx.queryMatchExpr(skipReturnMarker);
  7593. if (match)
  7594. {
  7595. if (cond)
  7596. buildFilteredReturn(ctx, cond, match->queryExpr());
  7597. else
  7598. {
  7599. buildReturn(ctx, match->queryExpr());
  7600. if (canReachFollowing)
  7601. *canReachFollowing = false;
  7602. }
  7603. }
  7604. else
  7605. throwError(HQLERR_SkipNotValidHere);
  7606. }
  7607. }
  7608. void HqlCppTranslator::doBuildStmtAssert(BuildCtx & ctx, IHqlExpression * expr)
  7609. {
  7610. if (!options.checkAsserts)
  7611. return;
  7612. IHqlExpression * cond = expr->queryChild(0);
  7613. LinkedHqlExpr locationAttr = expr->queryAttribute(_location_Atom);
  7614. if (!locationAttr)
  7615. {
  7616. IHqlExpression * activeNamedActivity = queryActiveNamedActivity();
  7617. if (activeNamedActivity)
  7618. {
  7619. ISourcePath * sourcePath = activeNamedActivity->querySourcePath();
  7620. if (sourcePath)
  7621. locationAttr.setown(createLocationAttr(sourcePath, 0, 0, 0));
  7622. }
  7623. }
  7624. LinkedHqlExpr msg = queryRealChild(expr, 1);
  7625. if (!msg)
  7626. msg.setown(createDefaultAssertMessage(cond));
  7627. if (expr->hasAttribute(constAtom))
  7628. {
  7629. IValue * condValue = cond->queryValue();
  7630. assertex(condValue && msg->queryValue());
  7631. if (condValue->getBoolValue())
  7632. return;
  7633. StringBuffer msgText;
  7634. getStringValue(msgText, msg);
  7635. reportErrorDirect(locationAttr, ERR_ASSERTION_FAILS, msgText.str(), false);
  7636. return;
  7637. }
  7638. BuildCtx condctx(ctx);
  7639. OwnedHqlExpr inverse = getInverse(cond);
  7640. buildFilter(condctx, inverse);
  7641. OwnedHqlExpr action;
  7642. HqlExprArray args;
  7643. args.append(*getSizetConstant(ERR_ASSERTION_FAILS));
  7644. args.append(*LINK(msg));
  7645. ECLlocation location;
  7646. if (locationAttr)
  7647. location.extractLocationAttr(locationAttr);
  7648. if (location.sourcePath)
  7649. {
  7650. const char * filename = str(location.sourcePath);
  7651. if (options.reportAssertFilenameTail)
  7652. filename = pathTail(filename);
  7653. args.append(*createConstant(filename));
  7654. }
  7655. else
  7656. args.append(*getNullStringPointer(true));
  7657. args.append(*getSizetConstant(location.lineno));
  7658. args.append(*getSizetConstant(location.column));
  7659. args.append(*createConstant(expr->hasAttribute(failAtom)));
  7660. action.setown(bindFunctionCall(addWorkunitAssertFailureId, args));
  7661. buildStmt(condctx, action);
  7662. }
  7663. void HqlCppTranslator::doBuildStmtCluster(BuildCtx & ctx, IHqlExpression * expr)
  7664. {
  7665. pushCluster(ctx, expr->queryChild(1));
  7666. buildStmt(ctx, expr->queryChild(0));
  7667. popCluster(ctx);
  7668. }
  7669. //---------------------------------------------------------------------------
  7670. // no_apply
  7671. void HqlCppTranslator::doBuildSequenceFunc(BuildCtx & ctx, IHqlExpression * seq, bool ignoreInternal)
  7672. {
  7673. if (ignoreInternal && isInternalSeq(seq))
  7674. return;
  7675. //virtual unsigned getSequence() = 0;
  7676. StringBuffer s;
  7677. s.append("virtual int getSequence() { return ");
  7678. if (seq)
  7679. generateExprCpp(s, seq);
  7680. else
  7681. s.append("-1");
  7682. s.append("; }");
  7683. ctx.addQuoted(s);
  7684. }
  7685. class ApplyStmtBuilder
  7686. {
  7687. public:
  7688. ApplyStmtBuilder(HqlCppTranslator & _translator) : translator(_translator) {}
  7689. // ~ApplyStmtBuilder() { assertex(!builder); } // don't do this because throwing exceptions inside destructors is very messy
  7690. void flush(BuildCtx & ctx)
  7691. {
  7692. if (builder)
  7693. {
  7694. OwnedHqlExpr childquery = builder->getGraph(no_orderedactionlist);
  7695. translator.buildStmt(ctx, childquery);
  7696. builder.clear();
  7697. }
  7698. }
  7699. bool requiresGraph(BuildCtx & ctx, IHqlExpression * expr)
  7700. {
  7701. if (!expr) return false;
  7702. switch (expr->getOperator())
  7703. {
  7704. case NO_ACTION_REQUIRES_GRAPH:
  7705. return true;
  7706. case no_parallel:
  7707. case no_sequential:
  7708. case no_actionlist:
  7709. case no_orderedactionlist:
  7710. case no_compound:
  7711. {
  7712. ForEachChild(idx, expr)
  7713. {
  7714. if (requiresGraph(ctx, expr->queryChild(idx)))
  7715. return true;
  7716. }
  7717. break;
  7718. }
  7719. case no_if:
  7720. return requiresGraph(ctx, expr->queryChild(1)) || requiresGraph(ctx, expr->queryChild(2));
  7721. }
  7722. return false;
  7723. }
  7724. void addGraphStmt(BuildCtx & ctx, IHqlExpression * expr)
  7725. {
  7726. if (!builder)
  7727. builder.setown(new ChildGraphExprBuilder(0));
  7728. builder->addAction(expr);
  7729. }
  7730. void buildStmt(BuildCtx & ctx, IHqlExpression * expr)
  7731. {
  7732. node_operator op = expr->getOperator();
  7733. switch (expr->getOperator())
  7734. {
  7735. case NO_ACTION_REQUIRES_GRAPH:
  7736. addGraphStmt(ctx, expr);
  7737. break;
  7738. case no_parallel:
  7739. case no_sequential:
  7740. case no_actionlist:
  7741. case no_orderedactionlist:
  7742. case no_compound:
  7743. {
  7744. ForEachChild(idx, expr)
  7745. {
  7746. buildStmt(ctx, expr->queryChild(idx));
  7747. if (op == no_sequential)
  7748. flush(ctx);
  7749. }
  7750. break;
  7751. }
  7752. case no_attr:
  7753. case no_attr_link:
  7754. case no_attr_expr:
  7755. break;
  7756. case no_if:
  7757. if (requiresGraph(ctx, expr))
  7758. addGraphStmt(ctx, expr);
  7759. else
  7760. translator.buildStmt(ctx, expr);
  7761. break;
  7762. default:
  7763. translator.buildStmt(ctx, expr);
  7764. break;
  7765. }
  7766. }
  7767. protected:
  7768. HqlCppTranslator & translator;
  7769. Owned<ChildGraphExprBuilder> builder;
  7770. };
  7771. ABoundActivity * HqlCppTranslator::doBuildActivityApply(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  7772. {
  7773. StringBuffer s;
  7774. IHqlExpression * dataset = expr->queryChild(0);
  7775. IHqlExpression * start = expr->queryAttribute(beforeAtom);
  7776. IHqlExpression * end = expr->queryAttribute(afterAtom);
  7777. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7778. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKapply, expr, "Apply");
  7779. buildActivityFramework(instance, isRoot);
  7780. buildInstancePrefix(instance);
  7781. doBuildSequenceFunc(instance->classctx, querySequence(expr), false);
  7782. ApplyStmtBuilder builder(*this);
  7783. {
  7784. MemberFunction func(*this, instance->startctx, "virtual void apply(const void * _self)");
  7785. s.clear().append("unsigned char * self = (unsigned char *) _self;");
  7786. func.ctx.addQuoted(s);
  7787. bindTableCursor(func.ctx, dataset, "self");
  7788. unsigned max = expr->numChildren();
  7789. for (unsigned i=1; i < max; i++)
  7790. builder.buildStmt(func.ctx, expr->queryChild(i));
  7791. builder.flush(func.ctx);
  7792. }
  7793. if (start)
  7794. {
  7795. MemberFunction func(*this, instance->startctx, "virtual void start()");
  7796. builder.buildStmt(func.ctx, start->queryChild(0));
  7797. builder.flush(func.ctx);
  7798. }
  7799. if (end)
  7800. {
  7801. MemberFunction func(*this, instance->startctx, "virtual void end()");
  7802. builder.buildStmt(func.ctx, end->queryChild(0));
  7803. builder.flush(func.ctx);
  7804. }
  7805. buildInstanceSuffix(instance);
  7806. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7807. return instance->getBoundActivity();
  7808. }
  7809. //---------------------------------------------------------------------------
  7810. //-- no_thor --
  7811. ActivityInstance * HqlCppTranslator::queryCurrentActivity(BuildCtx & ctx)
  7812. {
  7813. return static_cast<ActivityInstance *>(ctx.queryFirstAssociation(AssocActivityInstance));
  7814. }
  7815. bool HqlCppTranslator::insideActivityRemoteSerialize(BuildCtx & ctx)
  7816. {
  7817. ActivityInstance * activeActivity = queryCurrentActivity(ctx);
  7818. return activeActivity && activeActivity->requiresRemoteSerialize();
  7819. }
  7820. unique_id_t HqlCppTranslator::queryCurrentActivityId(BuildCtx & ctx)
  7821. {
  7822. ActivityInstance * activeActivity = queryCurrentActivity(ctx);
  7823. if (activeActivity)
  7824. return activeActivity->activityId;
  7825. HqlExprAssociation * match = ctx.queryMatchExpr(queryActivityIdMarker());
  7826. if (match)
  7827. return getIntValue(match->queryExpr());
  7828. return 0;
  7829. }
  7830. IHqlExpression * HqlCppTranslator::getCurrentActivityId(BuildCtx & ctx)
  7831. {
  7832. ActivityInstance * activeActivity = queryCurrentActivity(ctx);
  7833. if (activeActivity)
  7834. return getSizetConstant(activeActivity->activityId);
  7835. HqlExprAssociation * match = ctx.queryMatchExpr(queryActivityIdMarker());
  7836. if (match)
  7837. return LINK(match->queryExpr());
  7838. return getSizetConstant(0);
  7839. }
  7840. bool HqlCppTranslator::insideRemoteGraph(BuildCtx & ctx)
  7841. {
  7842. //Dubious... how about a remote child query?
  7843. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7844. if (!activeSubgraph)
  7845. return false;
  7846. return (activeSubgraph->type == SubGraphRemote);
  7847. }
  7848. bool HqlCppTranslator::insideChildOrLoopGraph(BuildCtx & ctx)
  7849. {
  7850. FilteredAssociationIterator iter(ctx, AssocSubGraph);
  7851. ForEach(iter)
  7852. {
  7853. SubGraphInfo & cur = static_cast<SubGraphInfo &>(iter.get());
  7854. if ((cur.type == SubGraphChild) || (cur.type == SubGraphLoop))
  7855. return true;
  7856. }
  7857. return false;
  7858. }
  7859. bool HqlCppTranslator::insideChildQuery(BuildCtx & ctx)
  7860. {
  7861. ParentExtract * extract = static_cast<ParentExtract*>(ctx.queryFirstAssociation(AssocExtract));
  7862. if (extract)
  7863. return extract->insideChildQuery();
  7864. EvalContext * instance = queryEvalContext(ctx);
  7865. if (instance)
  7866. return instance->insideChildQuery();
  7867. return false;
  7868. }
  7869. unsigned HqlCppTranslator::curSubGraphId(BuildCtx & ctx)
  7870. {
  7871. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7872. return activeSubgraph ? activeSubgraph->id : 0;
  7873. }
  7874. unsigned HqlCppTranslator::doBuildThorChildSubGraph(BuildCtx & ctx, IHqlExpression * expr, SubGraphType kind, unsigned reservedId, IHqlExpression * graphTag)
  7875. {
  7876. //NB: Need to create the graph in the correct order so the references to property trees we retain
  7877. // remain live..
  7878. unsigned thisId = reservedId ? reservedId : nextActivityId();
  7879. unsigned graphId = thisId;
  7880. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7881. IPropertyTree * node = createPTree("node");
  7882. if (activeSubgraph)
  7883. {
  7884. if (!graphTag)
  7885. graphTag = activeSubgraph->graphTag;
  7886. node = activeSubgraph->tree->addPropTree("node", node);
  7887. if (activeSubgraph->graphTag == graphTag)
  7888. graphId = activeSubgraph->graphId;
  7889. }
  7890. else
  7891. node = activeGraph->xgmml->addPropTree("node", node);
  7892. node->setPropInt("@id", thisId);
  7893. IPropertyTree * graphAttr = node->addPropTree("att", createPTree("att"));
  7894. IPropertyTree * subGraph = graphAttr->addPropTree("graph", createPTree("graph"));
  7895. Owned<SubGraphInfo> graphInfo = new SubGraphInfo(subGraph, thisId, graphId, graphTag, kind);
  7896. ctx.associate(*graphInfo);
  7897. IHqlExpression * numResultsAttr = expr->queryAttribute(numResultsAtom);
  7898. if (numResultsAttr)
  7899. addGraphAttributeInt(subGraph, "_numResults", getIntValue(numResultsAttr->queryChild(0), 0));
  7900. if (expr->hasAttribute(multiInstanceAtom))
  7901. subGraph->setPropBool("@multiInstance", true);
  7902. if (expr->hasAttribute(delayedAtom))
  7903. subGraph->setPropBool("@delayed", true);
  7904. if (expr->queryAttribute(childAtom))
  7905. subGraph->setPropBool("@child", true);
  7906. if (expr->hasAttribute(sequentialAtom))
  7907. subGraph->setPropBool("@sequential", true);
  7908. if (kind == SubGraphLoop)
  7909. subGraph->setPropBool("@loopBody", true);
  7910. if (insideChildOrLoopGraph(ctx))
  7911. {
  7912. graphAttr->setProp("@name", "_kind");
  7913. graphAttr->setPropInt("@value", TAKsubgraph);
  7914. ActivityInstance * curActivityInstance = queryCurrentActivity(ctx);
  7915. if (curActivityInstance)
  7916. addGraphAttributeInt(node, "_parentActivity", curActivityInstance->activityId);
  7917. }
  7918. OwnedHqlExpr idExpr = createConstant((__int64)thisId);
  7919. ctx.associateExpr(expr, idExpr);
  7920. if (thisId == options.subgraphToRegenerate)
  7921. {
  7922. StringBuffer ecl;
  7923. regenerateECL(expr, ecl);
  7924. ecl.replaceString("\r","");
  7925. fputs(ecl.str(), stdout);
  7926. fflush(stdout);
  7927. }
  7928. BuildCtx subctx(ctx);
  7929. ForEachChild(idx, expr)
  7930. {
  7931. IHqlExpression * cur = expr->queryChild(idx);
  7932. switch (cur->getOperator())
  7933. {
  7934. case no_subgraph:
  7935. doBuildThorChildSubGraph(ctx, cur, SubGraphChild, 0, graphTag);
  7936. break;
  7937. case no_attr:
  7938. case no_attr_expr:
  7939. case no_attr_link:
  7940. break;
  7941. default:
  7942. buildRootActivity(subctx, cur);
  7943. break;
  7944. }
  7945. }
  7946. ctx.removeAssociation(graphInfo);
  7947. return thisId;
  7948. }
  7949. unsigned HqlCppTranslator::doBuildThorSubGraph(BuildCtx & ctx, IHqlExpression * expr, SubGraphType kind, unsigned reservedId, IHqlExpression * graphTag)
  7950. {
  7951. BuildCtx graphctx(ctx);
  7952. graphctx.addGroup();
  7953. bool needToCreateGraph = !activeGraph;
  7954. if (!graphTag && outputLibraryId)
  7955. graphTag = outputLibraryId;
  7956. if (needToCreateGraph)
  7957. beginGraph();
  7958. unsigned thisId = doBuildThorChildSubGraph(graphctx, expr, kind, reservedId, graphTag);
  7959. if (needToCreateGraph)
  7960. endGraph();
  7961. return thisId;
  7962. }
  7963. void HqlCppTranslator::beginGraph(const char * _graphName)
  7964. {
  7965. if (activeGraph)
  7966. throwError(HQLERR_NestedThorNodes);
  7967. graphSeqNumber++;
  7968. StringBuffer graphName;
  7969. if (!_graphName)
  7970. graphName.append("graph").append(graphSeqNumber);
  7971. else
  7972. graphName.append(_graphName);
  7973. activeGraph.setown(new GeneratedGraphInfo(graphName, graphLabel));
  7974. graphLabel.clear();
  7975. if (insideLibrary())
  7976. activeGraph->xgmml->setPropBool("@library", true);
  7977. if (curWfid)
  7978. activeGraph->xgmml->setPropInt("@wfid", curWfid);
  7979. }
  7980. void HqlCppTranslator::endGraph()
  7981. {
  7982. graphs.append(*activeGraph.getClear());
  7983. }
  7984. void HqlCppTranslator::clearGraph()
  7985. {
  7986. activeGraph.clear();
  7987. }
  7988. /*
  7989. Tricky getting this in the correct order, problems are:
  7990. 1. generally best to move limits over projects and everything else
  7991. 2. Don't move a limit over a project if that will be part of a compound disk/index read.
  7992. 3. Need to make sure preloaded items aren't messed up by the resourcing.
  7993. 4. Resourcing ensures that shared items are explicitly shared if needed, it also ensures that
  7994. index-reads are not shared if it would be inefficient.
  7995. 5. Worth optimizing the graph before resourcing because it may move split points - e.g.,
  7996. moving a filter/choosen over a sort/spill greatly reducing the time taken.
  7997. 6. Optimizing may move items over conditions which can improve the executed code. E.g.,
  7998. where it allows a limit to be added to something.
  7999. */
  8000. IHqlExpression * HqlCppTranslator::optimizeCompoundSource(IHqlExpression * expr, unsigned flags)
  8001. {
  8002. CompoundSourceTransformer transformer(*this, flags);
  8003. return transformer.process(expr);
  8004. }
  8005. IHqlExpression * HqlCppTranslator::optimizeGraphPostResource(IHqlExpression * expr, unsigned csfFlags, bool projectBeforeSpill, bool insideChildQuery)
  8006. {
  8007. LinkedHqlExpr resourced = expr;
  8008. // Second attempt to spot compound disk reads - this time of spill files for thor.
  8009. resourced.setown(optimizeCompoundSource(resourced, csfFlags));
  8010. //MORE: This call (enabled by -fparanoid) isn't correct when this is processing a child query
  8011. checkNormalized(resourced);
  8012. //insert projects after compound created...
  8013. if (options.optimizeResourcedProjects)
  8014. {
  8015. OwnedHqlExpr optimized = insertImplicitProjects(*this, resourced.get(), projectBeforeSpill);
  8016. traceExpression("AfterResourcedImplicit", resourced);
  8017. checkNormalized(optimized);
  8018. if (optimized != resourced)
  8019. resourced.setown(optimizeCompoundSource(optimized, csfFlags));
  8020. }
  8021. //Now call the optimizer again - the main purpose is to move projects over limits and into compound index/disk reads
  8022. if (options.optimizeGraph)
  8023. {
  8024. traceExpression("BeforeOptimize2", resourced);
  8025. resourced.setown(optimizeHqlExpression(queryErrorProcessor(), resourced, getOptimizeFlags(insideChildQuery)|HOOcompoundproject));
  8026. traceExpression("AfterOptimize2", resourced);
  8027. }
  8028. resourced.setown(optimizeCompoundSource(resourced, csfFlags));
  8029. return resourced.getClear();
  8030. }
  8031. IHqlExpression * HqlCppTranslator::getResourcedGraph(IHqlExpression * expr, IHqlExpression * graphIdExpr)
  8032. {
  8033. LinkedHqlExpr resourced = expr;
  8034. unsigned csfFlags = CSFindex|options.optimizeDiskFlag;
  8035. if (!targetRoxie())
  8036. csfFlags |= CSFcompoundSpill;
  8037. //Convert queries on preloaded into compound activities - before resourcing so keyed gets done correctly
  8038. checkNormalized(expr);
  8039. traceExpression("BeforeCompound", resourced);
  8040. if (true)
  8041. resourced.setown(optimizeCompoundSource(resourced, CSFpreload|csfFlags));
  8042. //Check to see if fields can be removed - this helps LOOP bodies, but also seems to help situations where hoisting
  8043. //expressions prevents child expressions from preventing fields from being removed.
  8044. //Perform before the optimizeHqlExpression() so decisions about reducing row sizes are accurate
  8045. traceExpression("BeforeImplicitProjectGraph", resourced);
  8046. resourced.setown(insertImplicitProjects(*this, resourced, false));
  8047. // Call optimizer before resourcing so items get moved over conditions, and remove other items
  8048. // which would otherwise cause extra spills.
  8049. traceExpression("BeforeOptimize", resourced);
  8050. unsigned optFlags = getOptimizeFlags(false);
  8051. checkNormalized(resourced);
  8052. if (options.optimizeGraph)
  8053. {
  8054. resourced.setown(optimizeHqlExpression(queryErrorProcessor(), resourced, optFlags|HOOfiltersharedproject));
  8055. //have the following on an "aggressive fold" option? If no_selects extract constants it can be quite impressive (jholt22.hql)
  8056. //resourced.setown(foldHqlExpression(resourced));
  8057. }
  8058. traceExpression("AfterOptimize", resourced);
  8059. checkNormalized(resourced);
  8060. resourced.setown(convertSetResultToExtract(resourced));
  8061. traceExpression("After ConvertSetResultToExtract", resourced);
  8062. checkNormalized(resourced);
  8063. if (true)
  8064. resourced.setown(optimizeCompoundSource(resourced, CSFpreload|csfFlags));
  8065. //Now resource the graph....
  8066. unsigned numNodes = 0;
  8067. if (options.specifiedClusterSize != 0)
  8068. numNodes = options.specifiedClusterSize;
  8069. traceExpression("BeforeResourcing", resourced);
  8070. cycle_t startCycles = get_cycles_now();
  8071. if (outputLibraryId)
  8072. {
  8073. unsigned numResults = outputLibrary->numResultsUsed();
  8074. resourced.setown(resourceLibraryGraph(*this, resourced, targetClusterType, numNodes, outputLibraryId, numResults));
  8075. resourced.setown(appendAttribute(resourced, multiInstanceAtom)); // since can be called from multiple places.
  8076. }
  8077. else
  8078. resourced.setown(resourceThorGraph(*this, resourced, targetClusterType, numNodes, graphIdExpr));
  8079. if (!resourced)
  8080. return NULL;
  8081. if (options.timeTransforms)
  8082. noteFinishedTiming("compile:resource graph", startCycles);
  8083. traceExpression("AfterResourcing", resourced);
  8084. if (options.regressionTest)
  8085. checkDependencyConsistency(resourced);
  8086. checkNormalized(resourced);
  8087. bool createGraphResults = (outputLibraryId != 0) || options.alwaysUseGraphResults;
  8088. resourced.setown(optimizeGraphPostResource(resourced, csfFlags, options.optimizeSpillProject && !createGraphResults, false));
  8089. if (options.optimizeSpillProject)
  8090. {
  8091. resourced.setown(convertSpillsToActivities(resourced, createGraphResults));
  8092. resourced.setown(optimizeGraphPostResource(resourced, csfFlags, false, false));
  8093. }
  8094. checkNormalized(resourced);
  8095. //Finally create a couple of special compound activities.
  8096. //e.g., filtered fetch, limited keyed join
  8097. {
  8098. CompoundActivityTransformer transformer(targetClusterType);
  8099. resourced.setown(transformer.transformRoot(resourced));
  8100. traceExpression("AfterCompoundActivity", resourced);
  8101. }
  8102. resourced.setown(spotTableInvariant(resourced));
  8103. traceExpression("TableInvariant", resourced);
  8104. checkNormalized(resourced);
  8105. return resourced.getClear();
  8106. }
  8107. void HqlCppTranslator::doBuildThorGraph(BuildCtx & ctx, IHqlExpression * expr)
  8108. {
  8109. assertex(expr->queryType()->getTypeCode() == type_void);
  8110. if (outputLibrary)
  8111. buildLibraryGraph(ctx, expr, NULL);
  8112. else
  8113. {
  8114. beginGraph();
  8115. unsigned id = 0;
  8116. OwnedHqlExpr graphTag = createAttribute(graphAtom, createUniqueId());
  8117. OwnedHqlExpr resourced = getResourcedGraph(expr->queryChild(0), graphTag);
  8118. if (resourced)
  8119. {
  8120. traceExpression("beforeGenerate", resourced);
  8121. BuildCtx graphctx(ctx);
  8122. graphctx.addGroup();
  8123. Owned<SubGraphInfo> graphInfo = new SubGraphInfo(activeGraph->xgmml, 0, 0, graphTag, SubGraphRoot);
  8124. graphctx.associate(*graphInfo);
  8125. activeGraphCtx = &graphctx;
  8126. buildStmt(graphctx, resourced);
  8127. activeGraphCtx = NULL;
  8128. graphctx.removeAssociation(graphInfo);
  8129. HqlExprArray args;
  8130. args.append(*createConstant(activeGraph->name));
  8131. args.append(*createConstant(targetThor()));
  8132. args.append(*createConstant(0));
  8133. args.append(*createValue(no_nullptr, makeReferenceModifier(makeRowType(queryNullRecord()->getType()))));
  8134. callProcedure(ctx, executeGraphId, args);
  8135. }
  8136. endGraph();
  8137. }
  8138. }
  8139. void HqlCppTranslator::buildReturnCsvValue(BuildCtx & ctx, IHqlExpression * _expr)
  8140. {
  8141. LinkedHqlExpr expr = _expr;
  8142. IValue * value = expr->queryValue();
  8143. if (value && isUnicodeType(value->queryType()))
  8144. {
  8145. StringBuffer temp;
  8146. value->getUTF8Value(temp);
  8147. expr.setown(createConstant(createStringValue(temp.str(), temp.length())));
  8148. }
  8149. buildReturn(ctx, expr, constUnknownVarStringType);
  8150. }
  8151. void HqlCppTranslator::buildCsvListFunc(BuildCtx & classctx, const char * func, IHqlExpression * value, const char * defaultValue)
  8152. {
  8153. StringBuffer s;
  8154. s.clear().append("virtual const char * ").append(func).append("(unsigned idx)");
  8155. MemberFunction csvFunc(*this, classctx, s, MFdynamicproto);
  8156. if (value || defaultValue)
  8157. {
  8158. OwnedHqlExpr idxVar = createVariable("idx", LINK(unsignedType));
  8159. if (!value || !isEmptyList(value))
  8160. {
  8161. IHqlStmt * caseStmt = csvFunc.ctx.addSwitch(idxVar);
  8162. if (value)
  8163. {
  8164. if (!value->isList())
  8165. {
  8166. OwnedHqlExpr label = createConstant((__int64)0);
  8167. csvFunc.ctx.addCase(caseStmt, label);
  8168. buildReturnCsvValue(csvFunc.ctx, value);
  8169. }
  8170. else
  8171. {
  8172. ForEachChild(idx, value)
  8173. {
  8174. OwnedHqlExpr label = createConstant((__int64)idx);
  8175. csvFunc.ctx.addCase(caseStmt, label);
  8176. buildReturnCsvValue(csvFunc.ctx, value->queryChild(idx));
  8177. }
  8178. }
  8179. }
  8180. else
  8181. {
  8182. unsigned entry = 0;
  8183. const char * start = defaultValue;
  8184. for (;;)
  8185. {
  8186. const char * end = strchr(start, '|');
  8187. if (!end) end = start+strlen(start);
  8188. s.clear().append("case ").append(entry++).append(": return ");
  8189. appendStringAsQuotedCPP(s, end-start, start, false);
  8190. s.append(";");
  8191. csvFunc.ctx.addQuoted(s);
  8192. if (!*end)
  8193. break;
  8194. start = end+1;
  8195. }
  8196. }
  8197. csvFunc.ctx.addDefault(caseStmt);
  8198. }
  8199. }
  8200. csvFunc.ctx.addReturn(queryQuotedNullExpr());
  8201. }
  8202. static void expandDefaultString(StringBuffer & out, IHqlExpression * value, const char * defaultValue, IAtom * encoding)
  8203. {
  8204. //If there are multiple alternatives use the first in the list as the default
  8205. if (value && value->getOperator() == no_list)
  8206. value = value->queryChild(0);
  8207. if (value && value->queryValue())
  8208. {
  8209. if (encoding == unicodeAtom)
  8210. getUTF8Value(out, value);
  8211. else
  8212. value->queryValue()->getStringValue(out);
  8213. }
  8214. else
  8215. out.append(defaultValue);
  8216. }
  8217. static IHqlExpression * forceToCorrectEncoding(IHqlExpression * expr, IAtom * encoding)
  8218. {
  8219. //This is ugly. Really it should cast to a varutf8 type - but that isn't implemented. So instead it
  8220. //casts it to a utf8, type transfers it to a string, and then casts that to a varstring!
  8221. //Reimplement if varutf8 is ever implemented.
  8222. if (expr && (encoding == unicodeAtom))
  8223. {
  8224. if (expr->isList())
  8225. {
  8226. assertex(expr->getOperator() == no_list);
  8227. HqlExprArray args;
  8228. ForEachChild(i, expr)
  8229. {
  8230. IHqlExpression * value = expr->queryChild(i);
  8231. args.append(*forceToCorrectEncoding(value, encoding));
  8232. }
  8233. return expr->clone(args);
  8234. }
  8235. else if (!isNumericType(expr->queryType()))
  8236. {
  8237. OwnedHqlExpr cast = ensureExprType(expr, unknownUtf8Type);
  8238. OwnedHqlExpr transfer = createValue(no_typetransfer, LINK(unknownStringType), LINK(cast));
  8239. OwnedHqlExpr recast = ensureExprType(transfer, unknownVarStringType);
  8240. return foldHqlExpression(recast);
  8241. }
  8242. }
  8243. return LINK(expr);
  8244. }
  8245. void HqlCppTranslator::buildCsvParameters(BuildCtx & subctx, IHqlExpression * csvAttr, IHqlExpression * record, bool isReading)
  8246. {
  8247. HqlExprArray attrs;
  8248. if (csvAttr)
  8249. unwindChildren(attrs, csvAttr);
  8250. BuildCtx classctx(subctx);
  8251. StringBuffer s;
  8252. IHqlStmt * classStmt = beginNestedClass(classctx, "csv", "ICsvParameters");
  8253. doBuildBoolFunction(classctx, "queryEBCDIC", queryAttribute(ebcdicAtom, attrs)!=NULL);
  8254. bool singleHeader = false;
  8255. bool manyHeader = false;
  8256. IHqlExpression * headerAttr = queryAttribute(headingAtom, attrs);
  8257. IHqlExpression * terminatorAttr = queryAttribute(terminatorAtom, attrs);
  8258. IHqlExpression * separatorAttr = queryAttribute(separatorAtom, attrs);
  8259. IHqlExpression * escapeAttr = queryAttribute(escapeAtom, attrs);
  8260. IHqlExpression * quoteAttr = queryAttribute(quoteAtom, attrs);
  8261. LinkedHqlExpr terminator = terminatorAttr ? terminatorAttr->queryChild(0) : nullptr;
  8262. LinkedHqlExpr separator = separatorAttr ? separatorAttr->queryChild(0) : nullptr;
  8263. LinkedHqlExpr escape = escapeAttr ? escapeAttr->queryChild(0) : nullptr;
  8264. LinkedHqlExpr quote = quoteAttr ? quoteAttr->queryChild(0) : nullptr;
  8265. IAtom * encoding = queryCsvEncoding(csvAttr);
  8266. if (headerAttr)
  8267. {
  8268. LinkedHqlExpr header = queryRealChild(headerAttr, 0);
  8269. if (header)
  8270. {
  8271. header.setown(forceToCorrectEncoding(header, encoding));
  8272. if (header->queryType()->isInteger())
  8273. {
  8274. classctx.addQuotedLiteral("virtual const char * getHeader() { return NULL; }");
  8275. doBuildUnsignedFunction(classctx, "queryHeaderLen", header);
  8276. }
  8277. else
  8278. {
  8279. doBuildVarStringFunction(classctx, "getHeader", header);
  8280. classctx.addQuotedLiteral("virtual unsigned queryHeaderLen() { return 1; }");
  8281. }
  8282. }
  8283. else
  8284. {
  8285. StringBuffer names;
  8286. if (!isReading)
  8287. {
  8288. StringBuffer comma;
  8289. expandDefaultString(comma, separator, ",", encoding);
  8290. expandFieldNames(queryErrorProcessor(), names, record, comma.str(), queryAttributeChild(headerAttr, formatAtom, 0));
  8291. expandDefaultString(names, terminator, "\n", encoding);
  8292. }
  8293. OwnedHqlExpr namesExpr = createConstant(names.str());
  8294. doBuildVarStringFunction(classctx, "getHeader", namesExpr);
  8295. classctx.addQuotedLiteral("virtual unsigned queryHeaderLen() { return 1; }");
  8296. }
  8297. if (isReading)
  8298. {
  8299. manyHeader = headerAttr->hasAttribute(manyAtom) && !headerAttr->hasAttribute(singleAtom);
  8300. singleHeader = !manyHeader;
  8301. }
  8302. else
  8303. {
  8304. if (queryRealChild(headerAttr, 1))
  8305. doBuildVarStringFunction(classctx, "getFooter", headerAttr->queryChild(1));
  8306. if (headerAttr->hasAttribute(singleAtom))
  8307. singleHeader = true;
  8308. else
  8309. manyHeader = true;
  8310. }
  8311. }
  8312. else
  8313. {
  8314. classctx.addQuotedLiteral("virtual const char * getHeader() { return NULL; }");
  8315. classctx.addQuotedLiteral("virtual unsigned queryHeaderLen() { return 0; }");
  8316. }
  8317. doBuildSizetFunction(classctx, "queryMaxSize", getCsvMaxLength(csvAttr));
  8318. quote.setown(forceToCorrectEncoding(quote, encoding));
  8319. separator.setown(forceToCorrectEncoding(separator, encoding));
  8320. terminator.setown(forceToCorrectEncoding(terminator, encoding));
  8321. escape.setown(forceToCorrectEncoding(escape, encoding));
  8322. buildCsvListFunc(classctx, "getQuote", quote, isReading ? "\"" : NULL);
  8323. buildCsvListFunc(classctx, "getSeparator", separator, ",");
  8324. buildCsvListFunc(classctx, "getTerminator", terminator, isReading ? "\r\n|\n" : "\n");
  8325. buildCsvListFunc(classctx, "getEscape", escape, NULL);
  8326. StringBuffer flags;
  8327. if (!quoteAttr) flags.append("|defaultQuote");
  8328. if (!separatorAttr) flags.append("|defaultSeparate");
  8329. if (!terminatorAttr) flags.append("|defaultTerminate");
  8330. if (!escapeAttr) flags.append("|defaultEscape");
  8331. if (singleHeader) flags.append("|singleHeaderFooter");
  8332. if (manyHeader) flags.append("|manyHeaderFooter");
  8333. if (queryAttribute(noTrimAtom, attrs)) flags.append("|preserveWhitespace");
  8334. if (flags.length() == 0) flags.append("|0");
  8335. doBuildUnsignedFunction(classctx, "getFlags", flags.str()+1);
  8336. endNestedClass(classStmt);
  8337. subctx.addQuotedLiteral("virtual ICsvParameters * queryCsvParameters() { return &csv; }");
  8338. }
  8339. void HqlCppTranslator::buildCsvWriteScalar(BuildCtx & ctx, IHqlExpression * expr, IAtom * encoding)
  8340. {
  8341. ITypeInfo * type = expr->queryType()->queryPromotedType();
  8342. type_t tc = type->getTypeCode();
  8343. LinkedHqlExpr value = expr;
  8344. IIdAtom * func;
  8345. if (type->isInteger() || tc == type_boolean)
  8346. {
  8347. if (type->isSigned())
  8348. func = writeSignedId;
  8349. else
  8350. func = writeUnsignedId;
  8351. }
  8352. else if (tc == type_real)
  8353. func = writeRealId;
  8354. else if (tc == type_utf8)
  8355. {
  8356. func = writeUtf8Id;
  8357. value.setown(createValue(no_trim, makeUtf8Type(UNKNOWN_LENGTH, NULL), LINK(value)));
  8358. }
  8359. else if (isUnicodeType(type))
  8360. {
  8361. func = writeUnicodeId;
  8362. value.setown(createValue(no_trim, makeUnicodeType(UNKNOWN_LENGTH, NULL), LINK(value)));
  8363. }
  8364. else
  8365. {
  8366. func = writeStringId;
  8367. value.setown(createValue(no_trim, LINK(unknownStringType), ensureExprType(value, unknownStringType)));
  8368. }
  8369. if (encoding == asciiAtom)
  8370. {
  8371. func = writeStringId;
  8372. Owned<ITypeInfo> type = makeStringType(UNKNOWN_LENGTH, getCharset(asciiAtom), NULL);
  8373. value.setown(ensureExprType(value, type));
  8374. }
  8375. else if (encoding == ebcdicAtom)
  8376. {
  8377. func = writeEbcdicId;
  8378. Owned<ITypeInfo> type = makeStringType(UNKNOWN_LENGTH, getCharset(ebcdicAtom), NULL);
  8379. value.setown(ensureExprType(value, type));
  8380. }
  8381. else if (encoding == unicodeAtom)
  8382. {
  8383. func = writeUnicodeId;
  8384. Owned<ITypeInfo> type = makeUnicodeType(UNKNOWN_LENGTH, NULL);
  8385. value.setown(ensureExprType(value, type));
  8386. }
  8387. HqlExprArray args;
  8388. args.append(*createVariable("out", makeBoolType()));
  8389. args.append(*LINK(value));
  8390. buildFunctionCall(ctx, func, args);
  8391. }
  8392. void HqlCppTranslator::buildCsvWriteTransform(BuildCtx & subctx, IHqlExpression * expr, IHqlExpression * selector, IAtom * encoding)
  8393. {
  8394. switch (expr->getOperator())
  8395. {
  8396. case no_field:
  8397. {
  8398. ITypeInfo * type = expr->queryType()->queryPromotedType();
  8399. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(expr));
  8400. if (type->getTypeCode() == type_row)
  8401. {
  8402. buildCsvWriteTransform(subctx, expr->queryRecord(), selected, encoding);
  8403. break;
  8404. }
  8405. if (expr->isDataset())
  8406. {
  8407. //May as well output datasets in csv in some way - a count followed by the expanded fields...
  8408. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(subctx, selected);
  8409. CHqlBoundExpr boundCount;
  8410. cursor->buildCount(subctx, boundCount);
  8411. OwnedHqlExpr translatedCount = boundCount.getTranslatedExpr();
  8412. buildCsvWriteScalar(subctx, translatedCount, encoding);
  8413. BuildCtx loopctx(subctx);
  8414. cursor->buildIterateLoop(loopctx, false);
  8415. buildCsvWriteTransform(loopctx, expr->queryRecord(), selected, encoding);
  8416. return;
  8417. }
  8418. else if (type->getTypeCode() == type_set)
  8419. {
  8420. BuildCtx condctx(subctx);
  8421. Owned<IHqlCppSetCursor> cursor = createSetSelector(condctx, selected);
  8422. CHqlBoundExpr isAll;
  8423. cursor->buildIsAll(condctx, isAll);
  8424. IHqlStmt * stmt = condctx.addFilter(isAll.expr);
  8425. OwnedHqlExpr allText = createConstant("ALL");
  8426. buildCsvWriteScalar(condctx, allText, encoding);
  8427. condctx.selectElse(stmt);
  8428. CHqlBoundExpr boundCurElement;
  8429. cursor->buildIterateLoop(condctx, boundCurElement, false);
  8430. OwnedHqlExpr curElement = boundCurElement.getTranslatedExpr();
  8431. buildCsvWriteScalar(condctx, curElement, encoding);
  8432. }
  8433. else
  8434. buildCsvWriteScalar(subctx, selected, encoding);
  8435. break;
  8436. }
  8437. case no_ifblock:
  8438. {
  8439. OwnedHqlExpr cond = replaceSelector(expr->queryChild(0), querySelfReference(), selector);
  8440. BuildCtx condctx(subctx);
  8441. buildFilter(condctx, cond);
  8442. buildCsvWriteTransform(condctx, expr->queryChild(1), selector, encoding);
  8443. break;
  8444. }
  8445. case no_record:
  8446. {
  8447. ForEachChild(idx, expr)
  8448. buildCsvWriteTransform(subctx, expr->queryChild(idx), selector, encoding);
  8449. break;
  8450. }
  8451. case no_attr:
  8452. case no_attr_expr:
  8453. case no_attr_link:
  8454. break;
  8455. }
  8456. }
  8457. void HqlCppTranslator::buildCsvWriteTransform(BuildCtx & subctx, IHqlExpression * dataset, IAtom * encoding)
  8458. {
  8459. MemberFunction func(*this, subctx, "void writeRow(const byte * self, ITypedOutputStream * out)");
  8460. BoundRow * cursor = bindTableCursor(func.ctx, dataset, "self");
  8461. buildCsvWriteTransform(func.ctx, dataset->queryRecord(), cursor->querySelector(), encoding);
  8462. }
  8463. void HqlCppTranslator::buildExpiryHelper(BuildCtx & ctx, IHqlExpression * expireAttr)
  8464. {
  8465. if (expireAttr)
  8466. {
  8467. LinkedHqlExpr num = expireAttr->queryChild(0);
  8468. if (!num)
  8469. num.setown(getSizetConstant(options.defaultExpiry));
  8470. doBuildUnsignedFunction(ctx, "getExpiryDays", num);
  8471. }
  8472. }
  8473. void HqlCppTranslator::buildEncryptHelper(BuildCtx & ctx, IHqlExpression * encryptAttr, const char * funcname)
  8474. {
  8475. if (encryptAttr)
  8476. {
  8477. if (!funcname) funcname = "getEncryptKey";
  8478. doBuildDataFunction(ctx, funcname, encryptAttr->queryChild(0));
  8479. }
  8480. }
  8481. void HqlCppTranslator::buildUpdateHelper(BuildCtx & ctx, ActivityInstance & instance, IHqlExpression * input, IHqlExpression * updateAttr)
  8482. {
  8483. if (updateAttr)
  8484. {
  8485. MemberFunction func(*this, ctx, "virtual void getUpdateCRCs(unsigned & eclCrc, unsigned __int64 & totalCRC)");
  8486. OwnedHqlExpr eclCrcVar = createVariable("eclCrc", LINK(unsignedType));
  8487. OwnedHqlExpr totalCrcVar = createVariable("totalCRC", makeIntType(8, false));
  8488. IHqlExpression * originalCrc = updateAttr->queryChild(0);
  8489. DependenciesUsed dependencies(true);
  8490. IHqlExpression * filesRead = updateAttr->queryAttribute(_files_Atom);
  8491. if (filesRead)
  8492. {
  8493. ForEachChild(i, filesRead)
  8494. dependencies.tablesRead.append(*getNormalizedFilename(filesRead->queryChild(i)));
  8495. }
  8496. IHqlExpression * resultsRead = updateAttr->queryAttribute(_results_Atom);
  8497. if (resultsRead)
  8498. unwindChildren(dependencies.resultsRead, resultsRead);
  8499. OwnedHqlExpr crcExpr = calculatePersistInputCrc(func.ctx, dependencies);
  8500. buildAssignToTemp(func.ctx, eclCrcVar, originalCrc);
  8501. buildAssignToTemp(func.ctx, totalCrcVar, crcExpr);
  8502. if (!updateAttr->hasAttribute(alwaysAtom))
  8503. instance.addAttributeBool("_updateIfChanged", true);
  8504. }
  8505. }
  8506. void HqlCppTranslator::buildClusterHelper(BuildCtx & ctx, IHqlExpression * expr)
  8507. {
  8508. IHqlExpression * cluster = expr->queryAttribute(clusterAtom);
  8509. if (!cluster)
  8510. return;
  8511. MemberFunction func(*this, ctx, "virtual const char * getCluster(unsigned idx)");
  8512. BuildCtx switchctx(func.ctx);
  8513. OwnedHqlExpr var = createVariable("idx", LINK(unsignedType));
  8514. IHqlStmt * switchStmt = switchctx.addSwitch(var);
  8515. unsigned count = 0;
  8516. ForEachChild(i, cluster)
  8517. {
  8518. IHqlExpression * cur = queryRealChild(cluster, i);
  8519. if (cur)
  8520. {
  8521. BuildCtx casectx(switchctx);
  8522. OwnedHqlExpr label = getSizetConstant(count++);
  8523. casectx.addCase(switchStmt, label);
  8524. buildReturn(casectx, cur, constUnknownVarStringType);
  8525. // I think this is wrong: it forces the arguments of the CLUSTER on OUTPUT/BUILDINDEX to by topology clusters (i.e. query destinations) instead of thor clusters (i.e. file destinations)
  8526. //if (logger)
  8527. //{
  8528. // OwnedHqlExpr folded = foldHqlExpression(cur);
  8529. // if (folded->queryValue())
  8530. // {
  8531. // StringBuffer clusterText;
  8532. // folded->queryValue()->getStringValue(clusterText);
  8533. // logger->noteCluster(clusterText.str());
  8534. // }
  8535. //}
  8536. }
  8537. }
  8538. func.ctx.addReturn(queryQuotedNullExpr());
  8539. }
  8540. void HqlCppTranslator::buildRecordEcl(BuildCtx & subctx, IHqlExpression * dataset, const char * methodName, bool removeXpath)
  8541. {
  8542. StringBuffer eclFuncName;
  8543. StringBuffer s;
  8544. //Ensure the ECL for the record reflects its serialized form, not the internal form
  8545. OwnedHqlExpr record = getSerializedForm(dataset->queryRecord(), diskAtom);
  8546. if (removeXpath)
  8547. record.setown(removeAttributeFromFields(record, xpathAtom));
  8548. appendUniqueId(eclFuncName.append("ecl"), getConsistentUID(record));
  8549. BuildCtx declarectx(*code, declareAtom);
  8550. OwnedHqlExpr attr = createAttribute(eclAtom, LINK(record));
  8551. HqlExprAssociation * match = declarectx.queryMatchExpr(attr);
  8552. if (!match)
  8553. {
  8554. StringBuffer eclText;
  8555. getRecordECL(record, eclText);
  8556. BuildCtx funcctx(declarectx);
  8557. funcctx.setNextPriority(EclTextPrio);
  8558. s.append("const char * ").append(eclFuncName).append("(ICodeContext * ctx)");
  8559. funcctx.addQuotedFunction(s, true);
  8560. OwnedHqlExpr v = addStringLiteral(eclText);
  8561. funcctx.addReturn(v);
  8562. OwnedHqlExpr temp = createVariable(eclFuncName.str(), makeVoidType());
  8563. declarectx.associateExpr(attr, temp);
  8564. if (options.spanMultipleCpp)
  8565. {
  8566. s.clear().append("extern const char * ").append(eclFuncName).append("(ICodeContext * ctx);");
  8567. BuildCtx protoctx(*code, mainprototypesAtom);
  8568. protoctx.addQuoted(s);
  8569. }
  8570. }
  8571. s.clear().append("virtual const char * ").append(methodName).append("() { return ").append(eclFuncName).append("(ctx); }");
  8572. subctx.addQuoted(s);
  8573. }
  8574. void HqlCppTranslator::buildFormatCrcFunction(BuildCtx & ctx, const char * name, IHqlExpression * dataset, IHqlExpression * expr, unsigned payloadDelta)
  8575. {
  8576. IHqlExpression * payload = expr ? expr->queryAttribute(_payload_Atom) : NULL;
  8577. OwnedHqlExpr exprToCrc = getSerializedForm(dataset->queryRecord(), diskAtom);
  8578. unsigned payloadSize = 1;
  8579. if (payload)
  8580. payloadSize = (unsigned)getIntValue(payload->queryChild(0)) + payloadDelta;
  8581. //FILEPOSITION(FALSE) means we have counted 1 too many in the payload
  8582. if (!getBoolAttribute(expr, filepositionAtom, true))
  8583. payloadSize--;
  8584. exprToCrc.setown(createComma(exprToCrc.getClear(), getSizetConstant(payloadSize)));
  8585. traceExpression("crc:", exprToCrc);
  8586. OwnedHqlExpr crc = getSizetConstant(getExpressionCRC(exprToCrc));
  8587. doBuildUnsignedFunction(ctx, name, crc);
  8588. }
  8589. static void createOutputIndexRecord(HqlMapTransformer & mapper, HqlExprArray & fields, IHqlExpression * record, bool hasFileposition, bool allowTranslate)
  8590. {
  8591. unsigned numFields = record->numChildren();
  8592. unsigned max = hasFileposition ? numFields-1 : numFields;
  8593. for (unsigned idx=0; idx < max; idx++)
  8594. {
  8595. IHqlExpression * cur = record->queryChild(idx);
  8596. IHqlExpression * newField = NULL;
  8597. switch (cur->getOperator())
  8598. {
  8599. case no_attr:
  8600. case no_attr_link:
  8601. case no_attr_expr:
  8602. newField = LINK(cur);
  8603. break;
  8604. case no_ifblock:
  8605. {
  8606. HqlExprArray newFields;
  8607. createOutputIndexRecord(mapper, newFields, cur->queryChild(1), false, false);
  8608. newField = createValue(no_ifblock, makeNullType(), mapper.transformRoot(cur->queryChild(0)), createRecord(newFields));
  8609. break;
  8610. }
  8611. case no_record:
  8612. {
  8613. HqlExprArray newFields;
  8614. createOutputIndexRecord(mapper, newFields, cur, false, allowTranslate);
  8615. newField = createRecord(newFields);
  8616. break;
  8617. }
  8618. case no_field:
  8619. if (cur->hasAttribute(blobAtom))
  8620. {
  8621. newField = createField(cur->queryId(), makeIntType(8, false), NULL, NULL);
  8622. }
  8623. else if (allowTranslate)
  8624. {
  8625. if (cur->isDatarow() && !isInPayload())
  8626. {
  8627. HqlMapTransformer childMapper;
  8628. HqlExprArray newFields;
  8629. createOutputIndexRecord(childMapper, newFields, cur->queryRecord(), false, allowTranslate);
  8630. OwnedHqlExpr newRecord = createRecord(newFields);
  8631. HqlExprArray args;
  8632. unwindChildren(args, cur);
  8633. newField = createField(cur->queryId(), newRecord->getType(), args);
  8634. }
  8635. else
  8636. {
  8637. OwnedHqlExpr select = createSelectExpr(getActiveTableSelector(), LINK(cur));
  8638. OwnedHqlExpr value = getHozedKeyValue(select);
  8639. ITypeInfo * newType = value->getType();
  8640. newField = createField(cur->queryId(), newType, NULL, extractFieldAttrs(cur));
  8641. //Now set up the mappings for ifblocks
  8642. OwnedHqlExpr selfSelect = createSelectExpr(LINK(querySelfReference()), LINK(cur));
  8643. OwnedHqlExpr physicalSelect = createSelectExpr(LINK(querySelfReference()), LINK(newField));
  8644. OwnedHqlExpr keyValue = convertIndexPhysical2LogicalValue(cur, physicalSelect, true);
  8645. mapper.setMapping(selfSelect, keyValue);
  8646. }
  8647. }
  8648. else
  8649. newField = LINK(cur);
  8650. break;
  8651. }
  8652. fields.append(*newField);
  8653. }
  8654. }
  8655. static void createOutputIndexTransform(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * tgtRecord, IHqlExpression * srcRecord, IHqlExpression* srcDataset, bool hasFileposition, bool allowTranslate)
  8656. {
  8657. unsigned numFields = srcRecord->numChildren();
  8658. unsigned max = hasFileposition ? numFields-1 : numFields;
  8659. for (unsigned idx=0; idx < max; idx++)
  8660. {
  8661. IHqlExpression * cur = srcRecord->queryChild(idx);
  8662. IHqlExpression * curNew = tgtRecord->queryChild(idx);
  8663. switch (cur->getOperator())
  8664. {
  8665. case no_ifblock:
  8666. createOutputIndexTransform(assigns, self, curNew->queryChild(1), cur->queryChild(1), srcDataset, false, false);
  8667. break;
  8668. case no_record:
  8669. createOutputIndexTransform(assigns, self, curNew, cur, srcDataset, false, allowTranslate);
  8670. break;
  8671. case no_field:
  8672. {
  8673. OwnedHqlExpr select = createSelectExpr(LINK(srcDataset), LINK(cur));
  8674. OwnedHqlExpr value;
  8675. if (cur->hasAttribute(blobAtom))
  8676. {
  8677. value.setown(createValue(no_blob2id, curNew->getType(), LINK(select)));
  8678. }
  8679. else if (cur->isDatarow() && !isInPayload())
  8680. {
  8681. OwnedHqlExpr childSelf = createSelectExpr(LINK(self), LINK(curNew));
  8682. createOutputIndexTransform(assigns, childSelf, curNew->queryRecord(), cur->queryRecord(), select, false, allowTranslate);
  8683. }
  8684. else
  8685. {
  8686. if (allowTranslate)
  8687. value.setown(getHozedKeyValue(select));
  8688. else
  8689. value.set(select);
  8690. }
  8691. if (value)
  8692. assigns.append(*createAssign(createSelectExpr(LINK(self), LINK(curNew)), LINK(value)));
  8693. break;
  8694. }
  8695. }
  8696. }
  8697. }
  8698. void HqlCppTranslator::doBuildIndexOutputTransform(BuildCtx & ctx, IHqlExpression * record, SharedHqlExpr & rawRecord, bool hasFileposition, IHqlExpression * maxlength)
  8699. {
  8700. OwnedHqlExpr srcDataset = createDataset(no_anon, LINK(record));
  8701. HqlExprArray fields;
  8702. HqlExprArray assigns;
  8703. HqlMapTransformer mapper;
  8704. createOutputIndexRecord(mapper, fields, record, hasFileposition, true);
  8705. OwnedHqlExpr newRecord = createRecord(fields);
  8706. rawRecord.set(newRecord);
  8707. OwnedHqlExpr self = getSelf(newRecord);
  8708. createOutputIndexTransform(assigns, self, newRecord, record, srcDataset, hasFileposition, true);
  8709. OwnedHqlExpr tgtDataset = createDataset(no_anon, newRecord.getLink());
  8710. {
  8711. OwnedHqlExpr transform = createValue(no_newtransform, makeTransformType(newRecord->getType()), assigns);
  8712. MemberFunction func(*this, ctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IBlobCreator * blobs, unsigned __int64 & filepos)");
  8713. ensureRowAllocated(func.ctx, "crSelf");
  8714. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  8715. associateBlobHelper(func.ctx, srcDataset, "blobs");
  8716. BoundRow * selfCursor = bindSelf(func.ctx, tgtDataset, "crSelf");
  8717. bindTableCursor(func.ctx, srcDataset, "left");
  8718. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  8719. doTransform(func.ctx, transform, selfCursor);
  8720. OwnedHqlExpr fposVar = createVariable("filepos", makeIntType(8, false));
  8721. OwnedHqlExpr fposValue;
  8722. if (hasFileposition)
  8723. fposValue.setown(createSelectExpr(LINK(srcDataset), LINK(queryLastField(record))));
  8724. else
  8725. fposValue.setown(getSizetConstant(0));
  8726. buildAssignToTemp(func.ctx, fposVar, fposValue);
  8727. buildReturnRecordSize(func.ctx, selfCursor);
  8728. }
  8729. buildMetaMember(ctx, tgtDataset, false, "queryDiskRecordSize");
  8730. size32_t maxRecordSize = 32767;
  8731. if (isVariableSizeRecord(newRecord))
  8732. {
  8733. if (maxlength)
  8734. {
  8735. maxRecordSize = (size32_t)getIntValue(maxlength->queryChild(0), 0);
  8736. if (maxRecordSize == 0)
  8737. maxRecordSize = getMaxRecordSize(newRecord);
  8738. }
  8739. }
  8740. else
  8741. maxRecordSize = getMinRecordSize(newRecord);
  8742. doBuildUnsignedFunction(ctx, "getMaxKeySize", maxRecordSize);
  8743. if (maxRecordSize > KEYBUILD_MAXLENGTH)
  8744. throwError2(HQLERR_MaxlengthExceedsLimit, maxRecordSize, KEYBUILD_MAXLENGTH);
  8745. }
  8746. class TranslatorMaxSizeCallback : public IMaxSizeCallback
  8747. {
  8748. public:
  8749. enum { sizeofFposField = 8 };
  8750. TranslatorMaxSizeCallback(HqlCppTranslator & _translator) : translator(_translator) {}
  8751. virtual size32_t getMaxSize(IHqlExpression * record)
  8752. {
  8753. bool isKnownSize, usedDefaultMaxSize;
  8754. size32_t maxSize = getMaxRecordSize(record, translator.getDefaultMaxRecordSize(), isKnownSize, usedDefaultMaxSize);
  8755. if (usedDefaultMaxSize)
  8756. maxSize += sizeofFposField; //adjust maximum size for the fileposition, so consistent with raw record size
  8757. return maxSize;
  8758. }
  8759. protected:
  8760. HqlCppTranslator & translator;
  8761. };
  8762. IDefRecordElement * HqlCppTranslator::createMetaRecord(IHqlExpression * record)
  8763. {
  8764. TranslatorMaxSizeCallback callback(*this);
  8765. return ::createMetaRecord(record, &callback);
  8766. }
  8767. IHqlExpression * HqlCppTranslator::getSerializedLayoutFunction(IHqlExpression * record, unsigned numKeyedFields)
  8768. {
  8769. OwnedHqlExpr serializedRecord = getSerializedForm(record, diskAtom);
  8770. OwnedHqlExpr search = createAttribute(indexLayoutMarkerAtom, LINK(serializedRecord), getSizetConstant(numKeyedFields));
  8771. BuildCtx declarectx(*code, declareAtom);
  8772. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  8773. if (match)
  8774. return LINK(match->queryExpr());
  8775. //Modify the record, so that blob fields are tagged as represented as they are in the index
  8776. OwnedHqlExpr indexRecord = annotateIndexBlobs(serializedRecord);
  8777. Owned<IDefRecordElement> re = createMetaRecord(indexRecord);
  8778. if (!re)
  8779. return NULL;
  8780. StringBuffer functionName;
  8781. getUniqueId(functionName.append("getLayout"));
  8782. BuildCtx layoutctx(declarectx);
  8783. StringBuffer s;
  8784. s.append("void ").append(functionName).append("(size32_t & __lenResult, void * & __result, IResourceContext * ctx)");
  8785. layoutctx.setNextPriority(RowMetaPrio);
  8786. layoutctx.addQuotedFunction(s, true);
  8787. Owned<IDefRecordMeta> meta = createDefRecordMeta(re, numKeyedFields);
  8788. MemoryBuffer serialized;
  8789. serializeRecordMeta(serialized, meta, true);
  8790. OwnedHqlExpr metaExpr = createConstant(createDataValue(serialized.toByteArray(), serialized.length()));
  8791. Owned<ITypeInfo> type = makeDataType(UNKNOWN_LENGTH);
  8792. doBuildFunctionReturn(layoutctx, type, metaExpr);
  8793. if (options.showMetaText)
  8794. {
  8795. s.clear().append("/*").newline();
  8796. getRecordMetaAsString(s, meta);
  8797. s.append("*/");
  8798. layoutctx.addQuoted(s.str());
  8799. }
  8800. if (options.spanMultipleCpp)
  8801. {
  8802. s.clear().append("extern void ").append(functionName).append("(size32_t & __lenResult, void * & __result, IResourceContext * ctx);");
  8803. BuildCtx protoctx(*code, mainprototypesAtom);
  8804. protoctx.addQuoted(s);
  8805. }
  8806. OwnedHqlExpr temp = createVariable(functionName, makeVoidType());
  8807. declarectx.associateExpr(search, temp);
  8808. return temp.getLink();
  8809. }
  8810. void HqlCppTranslator::buildSerializedLayoutMember(BuildCtx & ctx, IHqlExpression * record, const char * name, unsigned numKeyedFields)
  8811. {
  8812. OwnedHqlExpr func = getSerializedLayoutFunction(record, numKeyedFields);
  8813. if (func)
  8814. {
  8815. StringBuffer s;
  8816. s.append("virtual bool ").append(name).append("(size32_t & __lenResult, void * & __result) { ");
  8817. generateExprCpp(s, func).append("(__lenResult, __result, ctx); return true; }");
  8818. ctx.addQuoted(s);
  8819. }
  8820. }
  8821. ABoundActivity * HqlCppTranslator::doBuildActivityOutputIndex(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  8822. {
  8823. ensureDiskAccessAllowed(expr);
  8824. IHqlExpression * dataset = expr->queryChild(0);
  8825. IHqlExpression * filename = queryRealChild(expr, 1);
  8826. IHqlExpression * record = dataset->queryRecord();
  8827. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  8828. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKindexwrite, expr, "IndexWrite");
  8829. buildActivityFramework(instance, isRoot);
  8830. buildInstancePrefix(instance);
  8831. //virtual const char * getFileName() { return "x.d00"; }
  8832. buildFilenameFunction(*instance, instance->startctx, "getFileName", filename, hasDynamicFilename(expr));
  8833. //virtual unsigned getFlags() = 0;
  8834. IHqlExpression * updateAttr = expr->queryAttribute(updateAtom);
  8835. IHqlExpression * compressAttr = expr->queryAttribute(compressedAtom);
  8836. IHqlExpression * widthExpr = queryAttributeChild(expr, widthAtom, 0);
  8837. bool hasTLK = !expr->hasAttribute(noRootAtom);
  8838. bool hasFileposition = getBoolAttribute(expr, filepositionAtom, true);
  8839. bool singlePart = expr->hasAttribute(fewAtom);
  8840. if (matchesConstantValue(widthExpr, 1))
  8841. {
  8842. singlePart = true;
  8843. widthExpr = NULL;
  8844. }
  8845. StringBuffer s;
  8846. StringBuffer flags;
  8847. if (expr->hasAttribute(overwriteAtom)) flags.append("|TIWoverwrite");
  8848. if (expr->hasAttribute(noOverwriteAtom)) flags.append("|TIWnooverwrite");
  8849. if (expr->hasAttribute(backupAtom)) flags.append("|TIWbackup");
  8850. if (!filename->isConstant()) flags.append("|TIWvarfilename");
  8851. if (singlePart) flags.append("|TIWsmall");
  8852. if (updateAttr) flags.append("|TIWupdatecrc");
  8853. if (updateAttr && !updateAttr->queryAttribute(alwaysAtom)) flags.append("|TIWupdate");
  8854. if (!hasTLK && !singlePart) flags.append("|TIWlocal");
  8855. if (expr->hasAttribute(expireAtom)) flags.append("|TIWexpires");
  8856. if (expr->hasAttribute(maxLengthAtom)) flags.append("|TIWmaxlength");
  8857. if (compressAttr)
  8858. {
  8859. if (compressAttr->hasAttribute(rowAtom)) flags.append("|TIWrowcompress");
  8860. if (!compressAttr->hasAttribute(lzwAtom)) flags.append("|TIWnolzwcompress");
  8861. }
  8862. if (widthExpr) flags.append("|TIWhaswidth");
  8863. if (flags.length())
  8864. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  8865. IHqlExpression * indexNameAttr = expr->queryAttribute(indexAtom);
  8866. if (indexNameAttr)
  8867. buildFilenameFunction(*instance, instance->startctx, "getDistributeIndexName", indexNameAttr->queryChild(0), hasDynamicFilename(expr));
  8868. buildExpiryHelper(instance->createctx, expr->queryAttribute(expireAtom));
  8869. buildUpdateHelper(instance->createctx, *instance, dataset, updateAttr);
  8870. buildClusterHelper(instance->classctx, expr);
  8871. // virtual unsigned getKeyedSize()
  8872. HqlExprArray fields;
  8873. unwindChildren(fields, record);
  8874. removeAttributes(fields);
  8875. fields.popn(numPayloadFields(expr));
  8876. OwnedHqlExpr keyedRecord = createRecord(fields); // must be fixed length => no maxlength
  8877. if (expr->hasAttribute(_payload_Atom))
  8878. instance->classctx.addQuoted(s.clear().append("virtual unsigned getKeyedSize() { return ").append(getFixedRecordSize(keyedRecord)).append("; }"));
  8879. else
  8880. instance->classctx.addQuoted(s.clear().append("virtual unsigned getKeyedSize() { return (unsigned) -1; }"));
  8881. //virtual const char * queryRecordECL() = 0;
  8882. buildRecordEcl(instance->createctx, dataset, "queryRecordECL", false);
  8883. doBuildSequenceFunc(instance->classctx, querySequence(expr), false);
  8884. HqlExprArray xmlnsAttrs;
  8885. gatherAttributes(xmlnsAttrs, xmlnsAtom, expr);
  8886. Owned<IWUResult> result = createDatasetResultSchema(querySequence(expr), queryResultName(expr), dataset->queryRecord(), xmlnsAttrs, false, true, fields.ordinality());
  8887. if (expr->hasAttribute(setAtom))
  8888. {
  8889. MemberFunction func(*this, instance->startctx, "virtual bool getIndexMeta(size32_t & lenName, char * & name, size32_t & lenValue, char * & value, unsigned idx)");
  8890. CHqlBoundTarget nameTarget, valueTarget;
  8891. initBoundStringTarget(nameTarget, unknownStringType, "lenName", "name");
  8892. //more should probably be utf-8 rather than string
  8893. initBoundStringTarget(valueTarget, unknownStringType, "lenValue", "value");
  8894. OwnedHqlExpr idxVar = createVariable("idx", LINK(sizetType));
  8895. BuildCtx casectx(func.ctx);
  8896. IHqlStmt * switchStmt = casectx.addSwitch(idxVar);
  8897. unsigned count = 0;
  8898. ForEachChild(i, expr)
  8899. {
  8900. IHqlExpression * cur = expr->queryChild(i);
  8901. if (cur->isAttribute() && cur->queryName() == setAtom)
  8902. {
  8903. OwnedHqlExpr label = getSizetConstant(count++);
  8904. casectx.addCase(switchStmt, label);
  8905. buildExprAssign(casectx, nameTarget, cur->queryChild(0));
  8906. buildExprAssign(casectx, valueTarget, cur->queryChild(1));
  8907. buildReturn(casectx, queryBoolExpr(true));
  8908. }
  8909. }
  8910. buildReturn(func.ctx, queryBoolExpr(false));
  8911. }
  8912. OwnedHqlExpr rawRecord;
  8913. doBuildIndexOutputTransform(instance->startctx, record, rawRecord, hasFileposition, expr->queryAttribute(maxLengthAtom));
  8914. buildFormatCrcFunction(instance->classctx, "getFormatCrc", rawRecord, expr, 0);
  8915. if (compressAttr && compressAttr->hasAttribute(rowAtom))
  8916. {
  8917. if (!isFixedWidthDataset(rawRecord))
  8918. throwError(HQLERR_RowCompressRequireFixedSize);
  8919. }
  8920. if (!expr->hasAttribute(fixedAtom))
  8921. buildSerializedLayoutMember(instance->classctx, record, "getIndexLayout", fields.ordinality());
  8922. if (widthExpr)
  8923. {
  8924. doBuildUnsignedFunction(instance->startctx, "getWidth", widthExpr);
  8925. if (!hasTLK)
  8926. {
  8927. HqlExprArray sorts;
  8928. gatherIndexBuildSortOrder(sorts, expr, options.sortIndexPayload);
  8929. OwnedHqlExpr sortOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  8930. instance->startctx.addQuotedLiteral("virtual ICompare * queryCompare() { return &compare; }");
  8931. DatasetReference dsRef(dataset);
  8932. buildCompareClass(instance->nestedctx, "compare", sortOrder, dsRef);
  8933. }
  8934. }
  8935. buildInstanceSuffix(instance);
  8936. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  8937. instance->addSignedAttribute(expr->queryAttribute(_signed_Atom));
  8938. OwnedHqlExpr dependency = createAttribute(fileAtom, getNormalizedFilename(filename));
  8939. Owned<ABoundActivity> bound = instance->getBoundActivity();
  8940. OwnedHqlExpr boundUnknown = createUnknown(no_attr, NULL, NULL, LINK(bound));
  8941. ctx.associateExpr(dependency, boundUnknown);
  8942. return instance->getBoundActivity();
  8943. }
  8944. void HqlCppTranslator::buildCsvWriteMembers(ActivityInstance * instance, IHqlExpression * dataset, IHqlExpression * csvAttr)
  8945. {
  8946. buildCsvParameters(instance->nestedctx, csvAttr, dataset->queryRecord(), false);
  8947. buildCsvWriteTransform(instance->startctx, dataset, queryCsvEncoding(csvAttr));
  8948. }
  8949. void HqlCppTranslator::buildXmlWriteMembers(ActivityInstance * instance, IHqlExpression * dataset, IHqlExpression * xmlAttr)
  8950. {
  8951. buildXmlSerialize(instance->startctx, dataset, "toXML", false);
  8952. IHqlExpression * rowAttr = xmlAttr->queryAttribute(rowAtom);
  8953. if (rowAttr)
  8954. doBuildVarStringFunction(instance->startctx, "getXmlIteratorPath", rowAttr->queryChild(0));
  8955. IHqlExpression * headerAttr = xmlAttr->queryAttribute(headingAtom);
  8956. if (headerAttr)
  8957. {
  8958. doBuildVarStringFunction(instance->startctx, "getHeader", headerAttr->queryChild(0));
  8959. doBuildVarStringFunction(instance->startctx, "getFooter", headerAttr->queryChild(1));
  8960. }
  8961. StringBuffer xmlFlags;
  8962. if (xmlAttr->hasAttribute(trimAtom))
  8963. xmlFlags.append("|XWFtrim");
  8964. if (xmlAttr->hasAttribute(optAtom))
  8965. xmlFlags.append("|XWFopt");
  8966. if (xmlFlags.length())
  8967. {
  8968. StringBuffer s;
  8969. s.append("virtual unsigned getXmlFlags() { return ").append(xmlFlags.str()+1).append("; }");
  8970. instance->classctx.addQuoted(s);
  8971. }
  8972. }
  8973. ABoundActivity * HqlCppTranslator::doBuildActivityOutput(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  8974. {
  8975. IHqlExpression * dataset = expr->queryChild(0);
  8976. IHqlExpression * rawFilename = queryRealChild(expr, 1);
  8977. if (dataset->isDictionary())
  8978. {
  8979. //OUTPUT(dictionary,,'filename') should never be generated - it should go via a dataset
  8980. assertex(!rawFilename);
  8981. return doBuildActivityDictionaryWorkunitWrite(ctx, expr, isRoot);
  8982. }
  8983. if (!rawFilename)
  8984. return doBuildActivityOutputWorkunit(ctx, expr, isRoot);
  8985. OwnedHqlExpr filename = foldHqlExpression(rawFilename);
  8986. IHqlExpression * program = queryRealChild(expr, 2);
  8987. IHqlExpression * csvAttr = expr->queryAttribute(csvAtom);
  8988. bool isJson = false;
  8989. IHqlExpression * xmlAttr = expr->queryAttribute(xmlAtom);
  8990. if (!xmlAttr)
  8991. {
  8992. xmlAttr = expr->queryAttribute(jsonAtom);
  8993. if (xmlAttr)
  8994. isJson=true;
  8995. }
  8996. LinkedHqlExpr expireAttr = expr->queryAttribute(expireAtom);
  8997. IHqlExpression * seq = querySequence(expr);
  8998. IHqlExpression *pipe = NULL;
  8999. if (program)
  9000. {
  9001. if (program->getOperator()==no_pipe)
  9002. pipe = program->queryChild(0);
  9003. }
  9004. else if (filename->getOperator()==no_pipe)
  9005. pipe = filename->queryChild(0);
  9006. if (pipe && expr->hasAttribute(_disallowed_Atom))
  9007. throwError(HQLERR_PipeNotAllowed);
  9008. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9009. ThorActivityKind kind = TAKdiskwrite;
  9010. const char * activityArgName = "DiskWrite";
  9011. if (expr->getOperator() == no_spill)
  9012. {
  9013. kind = TAKspill;
  9014. activityArgName = "Spill";
  9015. }
  9016. else if (pipe)
  9017. {
  9018. kind = TAKpipewrite;
  9019. activityArgName = "PipeWrite";
  9020. }
  9021. else if (csvAttr)
  9022. {
  9023. kind = TAKcsvwrite;
  9024. activityArgName = "CsvWrite";
  9025. }
  9026. else if (xmlAttr)
  9027. {
  9028. kind = (isJson) ? TAKjsonwrite : TAKxmlwrite;
  9029. activityArgName = "XmlWrite";
  9030. }
  9031. bool useImplementationClass = options.minimizeActivityClasses && targetRoxie() && expr->hasAttribute(_spill_Atom);
  9032. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, activityArgName);
  9033. //Output to a variable filename is either a user result, or a computed workflow spill, both need evaluating.
  9034. if (useImplementationClass)
  9035. instance->setImplementationClass(newMemorySpillSplitArgId);
  9036. if ((kind == TAKdiskwrite) && filename->queryValue())
  9037. {
  9038. StringBuffer s;
  9039. s.append(getActivityText(kind));
  9040. if (expr->hasAttribute(_spill_Atom))
  9041. s.append("\nSpill File");
  9042. else
  9043. filename->toString(s.append("\n"));
  9044. instance->graphLabel.set(s.str());
  9045. }
  9046. if (pipe)
  9047. {
  9048. if (csvAttr)
  9049. instance->addBaseClass("IHThorCsvWriteExtra", true);
  9050. else if (xmlAttr)
  9051. instance->addBaseClass("IHThorXmlWriteExtra", true);
  9052. }
  9053. buildActivityFramework(instance, isRoot && !isInternalSeq(seq));
  9054. buildInstancePrefix(instance);
  9055. noteResultDefined(ctx, instance, seq, filename, isRoot);
  9056. //virtual const char * getFileName() { return "x.d00"; }
  9057. OwnedHqlExpr tempCount;
  9058. if (expr->hasAttribute(_spill_Atom) || expr->hasAttribute(jobTempAtom))
  9059. {
  9060. IPropertyTree * graphNode = NULL;
  9061. if (targetRoxie() && expr->hasAttribute(jobTempAtom))
  9062. graphNode = instance->graphNode;
  9063. GlobalFileTracker * tracker = new GlobalFileTracker(filename, graphNode);
  9064. globalFiles.append(*tracker);
  9065. OwnedHqlExpr callback = createUnknown(no_callback, LINK(unsignedType), globalAtom, LINK(tracker));
  9066. tempCount.setown(createTranslated(callback));
  9067. }
  9068. if (!useImplementationClass)
  9069. {
  9070. if (pipe)
  9071. {
  9072. //MORE or pipe name is dependent on the input dataset - !constant is not sufficient
  9073. if (expr->hasAttribute(repeatAtom))
  9074. {
  9075. //virtual const char * getPipeProgram() { return "grep"; }
  9076. instance->startctx.addQuotedLiteral("virtual const char * getPipeProgram() { return NULL; }");
  9077. MemberFunction func(*this, instance->startctx, "virtual char * getNameFromRow(const void * _self)");
  9078. func.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *) _self;");
  9079. bindTableCursor(func.ctx, dataset, "self");
  9080. buildReturn(func.ctx, pipe, unknownVarStringType);
  9081. }
  9082. else
  9083. {
  9084. //virtual const char * getPipeProgram() { return "grep"; }
  9085. MemberFunction func(*this, instance->startctx, "virtual const char * getPipeProgram()");
  9086. buildReturn(func.ctx, pipe, unknownVarStringType);
  9087. }
  9088. if (csvAttr)
  9089. instance->classctx.addQuotedLiteral("virtual IHThorCsvWriteExtra * queryCsvOutput() { return this; }");
  9090. if (xmlAttr)
  9091. instance->classctx.addQuotedLiteral("virtual IHThorXmlWriteExtra * queryXmlOutput() { return this; }");
  9092. StringBuffer flags;
  9093. if (expr->hasAttribute(repeatAtom))
  9094. flags.append("|TPFrecreateeachrow");
  9095. if (expr->hasAttribute(optAtom))
  9096. flags.append("|TPFnofail");
  9097. if (csvAttr)
  9098. flags.append("|TPFwritecsvtopipe");
  9099. if (xmlAttr)
  9100. flags.append("|TPFwritexmltopipe");
  9101. if (flags.length())
  9102. doBuildUnsignedFunction(instance->classctx, "getPipeFlags", flags.str()+1);
  9103. }
  9104. else
  9105. {
  9106. bool constFilename = true;
  9107. //virtual const char * getFileName() = 0;
  9108. if (filename && filename->getOperator() != no_pipe)
  9109. {
  9110. bool isDynamic = expr->hasAttribute(resultAtom) || hasDynamicFilename(expr);
  9111. buildFilenameFunction(*instance, instance->startctx, "getFileName", filename, isDynamic);
  9112. if (!filename->isConstant())
  9113. constFilename = false;
  9114. }
  9115. else
  9116. {
  9117. MemberFunction func(*this, instance->startctx, "virtual const char * getFileName()");
  9118. func.ctx.addReturn(queryQuotedNullExpr());
  9119. }
  9120. //Expire if explicit, or if a persisted output, and persists default to expiring
  9121. bool expires = expireAttr || (expr->hasAttribute(_workflowPersist_Atom) && options.expirePersists);
  9122. if (expires && !expireAttr && options.defaultPersistExpiry)
  9123. expireAttr.setown(createExprAttribute(expireAtom, getSizetConstant(options.defaultPersistExpiry)));
  9124. //virtual unsigned getFlags() = 0;
  9125. IHqlExpression * updateAttr = expr->queryAttribute(updateAtom);
  9126. StringBuffer s;
  9127. StringBuffer flags;
  9128. if (expr->hasAttribute(_spill_Atom)) flags.append("|TDXtemporary");
  9129. if (expr->hasAttribute(groupedAtom)) flags.append("|TDXgrouped");
  9130. if (expr->hasAttribute(compressedAtom)) flags.append("|TDWnewcompress");
  9131. if (expr->hasAttribute(__compressed__Atom)) flags.append("|TDXcompress");
  9132. if (expr->hasAttribute(extendAtom)) flags.append("|TDWextend");
  9133. if (expr->hasAttribute(overwriteAtom)) flags.append("|TDWoverwrite");
  9134. if (expr->hasAttribute(noOverwriteAtom)) flags.append("|TDWnooverwrite");
  9135. if (expr->hasAttribute(_workflowPersist_Atom)) flags.append("|TDWpersist");
  9136. if (expr->hasAttribute(_noReplicate_Atom)) flags.append("|TDWnoreplicate");
  9137. if (expr->hasAttribute(backupAtom)) flags.append("|TDWbackup");
  9138. if (expr->hasAttribute(resultAtom)) flags.append("|TDWowned|TDWresult");
  9139. if (expr->hasAttribute(ownedAtom)) flags.append("|TDWowned");
  9140. if (!constFilename) flags.append("|TDXvarfilename");
  9141. if (hasDynamicFilename(expr)) flags.append("|TDXdynamicfilename");
  9142. if (expr->hasAttribute(jobTempAtom)) flags.append("|TDXjobtemp");
  9143. if (updateAttr) flags.append("|TDWupdatecrc");
  9144. if (updateAttr && !updateAttr->queryAttribute(alwaysAtom)) flags.append("|TDWupdate");
  9145. if (expires) flags.append("|TDWexpires");
  9146. if (flags.length())
  9147. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  9148. //virtual const char * queryRecordECL() = 0;
  9149. buildRecordEcl(instance->createctx, dataset, "queryRecordECL", expr->hasAttribute(noXpathAtom));
  9150. buildExpiryHelper(instance->createctx, expireAttr);
  9151. buildUpdateHelper(instance->createctx, *instance, dataset, updateAttr);
  9152. }
  9153. doBuildSequenceFunc(instance->classctx, seq, true);
  9154. if (tempCount)
  9155. {
  9156. if ((kind != TAKspill) || !matchesConstantValue(tempCount, 1))
  9157. {
  9158. MemberFunction func(*this, instance->classctx, "virtual unsigned getTempUsageCount()");
  9159. buildReturn(func.ctx, tempCount, unsignedType);
  9160. }
  9161. }
  9162. IHqlExpression * outputRecord = instance->meta.queryRecord();
  9163. OwnedHqlExpr outputDs = createDataset(no_null, LINK(outputRecord));
  9164. HqlExprArray xmlnsAttrs;
  9165. gatherAttributes(xmlnsAttrs, xmlnsAtom, expr);
  9166. bool createTransformer = (kind != TAKcsvwrite) && (kind != TAKxmlwrite) && (kind != TAKjsonwrite);
  9167. Owned<IWUResult> result = createDatasetResultSchema(seq, queryResultName(expr), outputRecord, xmlnsAttrs, createTransformer, true, 0);
  9168. if (expr->hasAttribute(resultAtom))
  9169. result->setResultRowLimit(-1);
  9170. //Remove virtual attributes from the record, so the crc will be compatible with the disk read record
  9171. OwnedHqlExpr noVirtualRecord = removeVirtualAttributes(dataset->queryRecord());
  9172. buildFormatCrcFunction(instance->classctx, "getFormatCrc", noVirtualRecord, NULL, 0);
  9173. bool grouped = isGrouped(dataset);
  9174. bool ignoreGrouped = !expr->hasAttribute(groupedAtom);
  9175. if ((kind != TAKspill) || (dataset->queryType() != expr->queryType()) || (grouped && ignoreGrouped))
  9176. buildMetaMember(instance->classctx, dataset, grouped && !ignoreGrouped, "queryDiskRecordSize");
  9177. buildClusterHelper(instance->classctx, expr);
  9178. //Both csv write and pipe with csv/xml format
  9179. if (csvAttr)
  9180. buildCsvWriteMembers(instance, outputDs, csvAttr);
  9181. if (xmlAttr)
  9182. buildXmlWriteMembers(instance, outputDs, xmlAttr);
  9183. buildEncryptHelper(instance->startctx, expr->queryAttribute(encryptAtom));
  9184. }
  9185. else
  9186. {
  9187. assertex(tempCount.get() && !hasDynamic(expr));
  9188. instance->addConstructorParameter(tempCount);
  9189. addFilenameConstructorParameter(*instance, "getFileName", filename);
  9190. }
  9191. instance->addSignedAttribute(expr->queryAttribute(_signed_Atom));
  9192. instance->addAttributeBool("_isSpill", expr->hasAttribute(_spill_Atom));
  9193. if (targetRoxie())
  9194. instance->addAttributeBool("_isSpillGlobal", expr->hasAttribute(jobTempAtom));
  9195. buildInstanceSuffix(instance);
  9196. if (boundDataset)
  9197. {
  9198. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9199. }
  9200. OwnedHqlExpr dependency = createAttribute(fileAtom, getNormalizedFilename(filename));
  9201. Owned<ABoundActivity> bound = instance->getBoundActivity();
  9202. OwnedHqlExpr boundUnknown = createUnknown(no_attr, NULL, NULL, LINK(bound));
  9203. activeGraphCtx->associateExpr(dependency, boundUnknown);
  9204. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  9205. if (name)
  9206. associateRemoteResult(*instance, seq, name);
  9207. return instance->getBoundActivity();
  9208. }
  9209. void HqlCppTranslator::addSchemaField(IHqlExpression *field, MemoryBuffer &schema, IHqlExpression *selector)
  9210. {
  9211. IAtom * name = field->queryName();
  9212. StringBuffer schemaName;
  9213. if (name)
  9214. {
  9215. schemaName.append(str(name));
  9216. }
  9217. else
  9218. {
  9219. schemaName.append("unknown_name");
  9220. getUniqueId(schemaName);
  9221. }
  9222. schemaName.toLowerCase();
  9223. StringBuffer funcname;
  9224. Linked<ITypeInfo> schemaType = queryUnqualifiedType(field->queryType());
  9225. switch(schemaType->getTypeCode())
  9226. {
  9227. case type_alien:
  9228. case type_enumerated:
  9229. schemaType.set(schemaType->queryChildType());
  9230. break;
  9231. case type_bitfield:
  9232. schemaType.set(schemaType->queryPromotedType());
  9233. //fall through;
  9234. case type_dictionary:
  9235. case type_table:
  9236. case type_groupedtable:
  9237. case type_row:
  9238. schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL));
  9239. break;
  9240. }
  9241. schema.append(schemaName.str());
  9242. schemaType->serialize(schema);
  9243. }
  9244. void HqlCppTranslator::doAddSchemaFields(IHqlExpression * record, MemoryBuffer &schema, IHqlExpression *selector)
  9245. {
  9246. assertex(record->getOperator() == no_record);
  9247. ForEachChild(idx, record)
  9248. {
  9249. IHqlExpression *field = record->queryChild(idx);
  9250. switch (field->getOperator())
  9251. {
  9252. case no_ifblock:
  9253. doAddSchemaFields(field->queryChild(1), schema, selector);
  9254. break;
  9255. case no_record:
  9256. doAddSchemaFields(field, schema, selector);
  9257. break;
  9258. case no_field:
  9259. if (field->isDatarow())
  9260. {
  9261. // MORE - should I record this nesting in the schema?
  9262. // MORE - this does not yet work...
  9263. OwnedHqlExpr subselector = createSelectExpr(LINK(selector), LINK(field));
  9264. doAddSchemaFields(field->queryRecord(), schema, subselector);
  9265. }
  9266. else
  9267. addSchemaField(field, schema, selector);
  9268. break;
  9269. }
  9270. }
  9271. }
  9272. void HqlCppTranslator::getRecordECL(IHqlExpression * deserializedRecord, StringBuffer & eclText)
  9273. {
  9274. OwnedHqlExpr record = getSerializedForm(deserializedRecord, diskAtom);
  9275. if ((options.maxRecordSize != MAX_RECORD_SIZE) && maxRecordSizeUsesDefault(record))
  9276. {
  9277. //Add an explicit record size if default max record size
  9278. size32_t maxSize = getMaxRecordSize(record);
  9279. HqlExprArray args;
  9280. unwindChildren(args, record);
  9281. args.append(*createExprAttribute(maxLengthAtom, getSizetConstant(maxSize)));
  9282. OwnedHqlExpr annotatedRecord = record->clone(args);
  9283. ::getRecordECL(annotatedRecord, eclText);
  9284. }
  9285. else
  9286. ::getRecordECL(record, eclText);
  9287. }
  9288. void HqlCppTranslator::addSchemaFields(IHqlExpression * record, MemoryBuffer &schema, IHqlExpression *selector)
  9289. {
  9290. doAddSchemaFields(record, schema, selector);
  9291. schema.append("").append((unsigned char) type_void);
  9292. StringBuffer eclText;
  9293. getRecordECL(record, eclText);
  9294. schema.append((unsigned)eclText.length());
  9295. schema.append(eclText.length(), eclText.str()); // could compress at this point...
  9296. }
  9297. void HqlCppTranslator::addSchemaResource(int seq, const char * name, IHqlExpression * record, unsigned keyedCount)
  9298. {
  9299. StringBuffer xml;
  9300. getRecordXmlSchema(xml, record, true, keyedCount);
  9301. addSchemaResource(seq, name, xml.length()+1, xml.str());
  9302. }
  9303. void HqlCppTranslator::addSchemaResource(int seq, const char * name, unsigned len, const char * schemaXml)
  9304. {
  9305. Owned<IPropertyTree> manifestEntry = createPTree("Resource");
  9306. manifestEntry->setProp("@name", name);
  9307. manifestEntry->setPropInt("@seq", seq);
  9308. code->addCompressResource("RESULT_XSD", len, schemaXml, manifestEntry);
  9309. }
  9310. void HqlCppTranslator::finalizeResources()
  9311. {
  9312. }
  9313. IWUResult * HqlCppTranslator::createDatasetResultSchema(IHqlExpression * sequenceExpr, IHqlExpression * name, IHqlExpression * record, HqlExprArray &xmlnsAttrs, bool createTransformer, bool isFile, unsigned keyedCount)
  9314. {
  9315. //Some spills have no sequence attached
  9316. if (!sequenceExpr)
  9317. return NULL;
  9318. int sequence = (int)getIntValue(sequenceExpr);
  9319. Owned<IWUResult> result = createWorkunitResult(sequence, name);
  9320. if (!result)
  9321. return NULL;
  9322. addDatasetResultXmlNamespaces(*result, xmlnsAttrs, record);
  9323. MemoryBuffer schema;
  9324. OwnedHqlExpr self = getSelf(record);
  9325. addSchemaFields(record, schema, self);
  9326. SCMStringBuffer resultName;
  9327. result->getResultName(resultName);
  9328. addSchemaResource(sequence, resultName.str(), record, keyedCount);
  9329. result->setResultSchemaRaw(schema.length(), schema.toByteArray());
  9330. result->setResultScalar(false);
  9331. OwnedHqlExpr serialRecord = getSerializedForm(record, diskAtom);
  9332. OwnedHqlExpr ds = createDataset(no_anon, LINK(serialRecord));
  9333. MetaInstance meta(*this, serialRecord, false);
  9334. buildMetaInfo(meta);
  9335. result->setResultRecordSizeEntry(meta.metaFactoryName);
  9336. if (createTransformer)
  9337. {
  9338. OwnedHqlExpr noVirtualRecord = removeVirtualAttributes(serialRecord);
  9339. Owned<IHqlExpression> transformedRecord = getFileViewerRecord(noVirtualRecord, false);
  9340. if (transformedRecord)
  9341. {
  9342. OwnedHqlExpr ds = createDataset(no_anon, LINK(noVirtualRecord));
  9343. OwnedHqlExpr seq = createDummySelectorSequence();
  9344. OwnedHqlExpr leftSelect = createSelector(no_left, ds, seq);
  9345. OwnedHqlExpr transform = getSimplifiedTransform(transformedRecord, noVirtualRecord, leftSelect);
  9346. OwnedHqlExpr tds = createDataset(no_anon, LINK(transformedRecord));
  9347. StringBuffer s, name;
  9348. getUniqueId(name.append("tf"));
  9349. BuildCtx transformctx(*code, declareAtom);
  9350. transformctx.setNextPriority(RecordTranslatorPrio);
  9351. s.clear().append("extern \"C\" ECL_API size32_t ").append(name).append("(ARowBuilder & crSelf, const byte * src)");
  9352. MemberFunction tranformFunc(*this, transformctx, s, MFdynamicproto);
  9353. BoundRow * selfCursor = bindSelf(tranformFunc.ctx, tds, "crSelf");
  9354. bindTableCursor(tranformFunc.ctx, ds, "src", no_left, seq);
  9355. associateSkipReturnMarker(tranformFunc.ctx, queryZero(), selfCursor);
  9356. ensureRowAllocated(tranformFunc.ctx, "crSelf");
  9357. doTransform(tranformFunc.ctx, transform, selfCursor);
  9358. buildReturnRecordSize(tranformFunc.ctx, selfCursor);
  9359. result->setResultTransformerEntry(name.str());
  9360. }
  9361. }
  9362. return result.getClear();
  9363. }
  9364. //-------------------------------------------------------------------------------------------------------------------
  9365. void HqlCppTranslator::buildXmlSerializeSetValues(BuildCtx & ctx, IHqlExpression * value, IHqlExpression * itemName, bool includeAll)
  9366. {
  9367. OwnedHqlExpr simpleValue = simplifyFixedLengthList(value);
  9368. BuildCtx subctx(ctx);
  9369. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, simpleValue);
  9370. if (includeAll)
  9371. {
  9372. CHqlBoundExpr isAll;
  9373. cursor->buildIsAll(ctx, isAll);
  9374. IHqlStmt * stmt = subctx.addFilter(isAll.expr);
  9375. HqlExprArray args;
  9376. args.append(*createVariable("out", makeBoolType()));
  9377. callProcedure(subctx, outputXmlSetAllId, args);
  9378. subctx.selectElse(stmt);
  9379. }
  9380. buildXmlSerializeBeginArray(subctx, itemName);
  9381. {
  9382. BuildCtx loopctx(subctx);
  9383. CHqlBoundExpr boundCurElement;
  9384. cursor->buildIterateLoop(loopctx, boundCurElement, false);
  9385. OwnedHqlExpr curElement = boundCurElement.getTranslatedExpr();
  9386. buildXmlSerializeScalar(loopctx, curElement, itemName);
  9387. }
  9388. buildXmlSerializeEndArray(subctx, itemName);
  9389. }
  9390. void HqlCppTranslator::buildXmlSerializeBeginNested(BuildCtx & ctx, IHqlExpression * name, bool doIndent)
  9391. {
  9392. if (name)
  9393. {
  9394. HqlExprArray args;
  9395. args.append(*createVariable("out", makeBoolType()));
  9396. args.append(*LINK(name));
  9397. args.append(*createConstant(false));
  9398. callProcedure(ctx, outputXmlBeginNestedId, args);
  9399. }
  9400. }
  9401. void HqlCppTranslator::buildXmlSerializeEndNested(BuildCtx & ctx, IHqlExpression * name)
  9402. {
  9403. if (name)
  9404. {
  9405. HqlExprArray args;
  9406. args.append(*createVariable("out", makeBoolType()));
  9407. args.append(*LINK(name));
  9408. callProcedure(ctx, outputXmlEndNestedId, args);
  9409. }
  9410. }
  9411. void HqlCppTranslator::buildXmlSerializeBeginArray(BuildCtx & ctx, IHqlExpression * name)
  9412. {
  9413. if (name)
  9414. {
  9415. HqlExprArray args;
  9416. args.append(*createVariable("out", makeBoolType()));
  9417. args.append(*LINK(name));
  9418. callProcedure(ctx, outputXmlBeginArrayId, args);
  9419. }
  9420. }
  9421. void HqlCppTranslator::buildXmlSerializeEndArray(BuildCtx & ctx, IHqlExpression * name)
  9422. {
  9423. if (name)
  9424. {
  9425. HqlExprArray args;
  9426. args.append(*createVariable("out", makeBoolType()));
  9427. args.append(*LINK(name));
  9428. callProcedure(ctx, outputXmlEndArrayId, args);
  9429. }
  9430. }
  9431. void HqlCppTranslator::buildXmlSerializeSet(BuildCtx & ctx, IHqlExpression * field, IHqlExpression * value)
  9432. {
  9433. OwnedHqlExpr name, itemName;
  9434. extractXmlName(name, &itemName, NULL, field, "Item", false);
  9435. HqlExprArray args;
  9436. buildXmlSerializeBeginNested(ctx, name, false);
  9437. buildXmlSerializeSetValues(ctx, value, itemName, (name != NULL));
  9438. buildXmlSerializeEndNested(ctx, name);
  9439. }
  9440. void HqlCppTranslator::buildXmlSerializeDataset(BuildCtx & ctx, IHqlExpression * field, IHqlExpression * value, HqlExprArray * assigns)
  9441. {
  9442. OwnedHqlExpr name, rowName;
  9443. extractXmlName(name, &rowName, NULL, field, "Row", false);
  9444. HqlExprArray args;
  9445. buildXmlSerializeBeginNested(ctx, name, false);
  9446. buildXmlSerializeBeginArray(ctx, rowName);
  9447. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, value);
  9448. BuildCtx subctx(ctx);
  9449. BoundRow * sourceRow = cursor->buildIterateLoop(subctx, false);
  9450. buildXmlSerializeBeginNested(subctx, rowName, true);
  9451. StringBuffer boundRowText;
  9452. generateExprCpp(boundRowText, sourceRow->queryBound());
  9453. buildXmlSerializeUsingMeta(subctx, field, boundRowText.str());
  9454. buildXmlSerializeEndNested(subctx, rowName);
  9455. buildXmlSerializeEndArray(ctx, rowName);
  9456. buildXmlSerializeEndNested(ctx, name);
  9457. }
  9458. void HqlCppTranslator::buildXmlSerializeScalar(BuildCtx & ctx, IHqlExpression * selected, IHqlExpression * name)
  9459. {
  9460. ITypeInfo * type = selected->queryType()->queryPromotedType();
  9461. LinkedHqlExpr value = selected;
  9462. LinkedHqlExpr size;
  9463. IIdAtom * func;
  9464. switch (type->getTypeCode())
  9465. {
  9466. case type_boolean:
  9467. func = outputXmlBoolId;
  9468. break;
  9469. case type_string:
  9470. case type_varstring:
  9471. func = outputXmlStringId;
  9472. break;
  9473. case type_qstring:
  9474. func = outputXmlQStringId;
  9475. break;
  9476. case type_data:
  9477. func = outputXmlDataId;
  9478. break;
  9479. case type_unicode:
  9480. case type_varunicode:
  9481. func = outputXmlUnicodeId;
  9482. break;
  9483. case type_utf8:
  9484. func = outputXmlUtf8Id;
  9485. break;
  9486. case type_real:
  9487. func = outputXmlRealId;
  9488. break;
  9489. case type_int:
  9490. case type_swapint:
  9491. case type_packedint:
  9492. case type_bitfield:
  9493. size.setown(getSizetConstant(type->getSize()));
  9494. if (type->isSigned())
  9495. func = outputXmlIntId;
  9496. else
  9497. func = outputXmlUIntId;
  9498. break;
  9499. case type_decimal:
  9500. value.setown(ensureExprType(value, unknownStringType));
  9501. func = outputXmlStringId;
  9502. break;
  9503. default:
  9504. UNIMPLEMENTED;
  9505. }
  9506. HqlExprArray args;
  9507. args.append(*createVariable("out", makeBoolType()));
  9508. args.append(*value.getLink());
  9509. if (size)
  9510. args.append(*LINK(size));
  9511. if (name)
  9512. args.append(*LINK(name));
  9513. else
  9514. args.append(*getNullStringPointer(true));
  9515. buildFunctionCall(ctx, func, args);
  9516. }
  9517. void HqlCppTranslator::buildXmlSerialize(BuildCtx & subctx, IHqlExpression * expr, IHqlExpression * selector, HqlExprArray * assigns, unsigned pass, unsigned & expectedIndex)
  9518. {
  9519. if (anyXmlGeneratedForPass(expr, pass))
  9520. {
  9521. switch (expr->getOperator())
  9522. {
  9523. case no_field:
  9524. {
  9525. OwnedHqlExpr name;
  9526. extractXmlName(name, NULL, NULL, expr, NULL, false);
  9527. LinkedHqlExpr value;
  9528. OwnedHqlExpr selected;
  9529. ITypeInfo * type = expr->queryType()->queryPromotedType();
  9530. if (assigns)
  9531. {
  9532. OwnedHqlExpr match = getExtractMatchingAssign(*assigns, expr, expectedIndex, selector);
  9533. if (!match)
  9534. {
  9535. StringBuffer s;
  9536. expr->toString(s);
  9537. throwError2(HQLERR_MissingTransformAssignXX, s.str(), expr);
  9538. }
  9539. selected.set(match->queryChild(0));
  9540. value.setown(ensureExprType(match->queryChild(1), type));
  9541. }
  9542. else
  9543. {
  9544. selected.setown(createSelectExpr(LINK(selector), LINK(expr)));
  9545. value.set(selected);
  9546. }
  9547. switch (type->getTypeCode())
  9548. {
  9549. case type_row:
  9550. {
  9551. IHqlExpression * record = queryOriginalRecord(type);
  9552. buildXmlSerializeBeginNested(subctx, name, false);
  9553. if (assigns)
  9554. {
  9555. if (value->getOperator() == no_createrow)
  9556. {
  9557. HqlExprArray childAssigns;
  9558. filterExpandAssignments(subctx, NULL, childAssigns, value->queryChild(0));
  9559. OwnedHqlExpr childSelf = createSelector(no_self, value, NULL);
  9560. if (name)
  9561. buildXmlSerialize(subctx, record, childSelf, &childAssigns);
  9562. else
  9563. buildXmlSerialize(subctx, record, childSelf, &childAssigns, pass, expectedIndex);
  9564. }
  9565. else
  9566. {
  9567. CHqlBoundExpr bound;
  9568. Owned<IReferenceSelector> ref = buildNewRow(subctx, value);
  9569. if (name)
  9570. buildXmlSerialize(subctx, record, value, NULL);
  9571. else
  9572. buildXmlSerialize(subctx, record, value, NULL, pass, expectedIndex);
  9573. }
  9574. }
  9575. else
  9576. {
  9577. if (name)
  9578. buildXmlSerialize(subctx, record, selected, assigns);
  9579. else
  9580. buildXmlSerialize(subctx, record, selected, assigns, pass, expectedIndex);
  9581. }
  9582. buildXmlSerializeEndNested(subctx, name);
  9583. return;
  9584. }
  9585. break;
  9586. case type_set:
  9587. buildXmlSerializeSet(subctx, expr, value);
  9588. break;
  9589. case type_dictionary:
  9590. case type_table:
  9591. case type_groupedtable:
  9592. buildXmlSerializeDataset(subctx, expr, value, assigns);
  9593. break;
  9594. default:
  9595. buildXmlSerializeScalar(subctx, value, name);
  9596. break;
  9597. }
  9598. }
  9599. break;
  9600. case no_ifblock:
  9601. {
  9602. OwnedHqlExpr cond = replaceSelector(expr->queryChild(0), querySelfReference(), selector);
  9603. BuildCtx condctx(subctx);
  9604. buildFilter(condctx, cond);
  9605. buildXmlSerialize(condctx, expr->queryChild(1), selector, assigns, pass, expectedIndex);
  9606. }
  9607. break;
  9608. case no_record:
  9609. {
  9610. ForEachChild(idx, expr)
  9611. buildXmlSerialize(subctx, expr->queryChild(idx), selector, assigns, pass, expectedIndex);
  9612. }
  9613. break;
  9614. case no_attr:
  9615. case no_attr_expr:
  9616. case no_attr_link:
  9617. break;
  9618. default:
  9619. UNIMPLEMENTED;
  9620. }
  9621. }
  9622. }
  9623. void HqlCppTranslator::buildXmlSerialize(BuildCtx & subctx, IHqlExpression * expr, IHqlExpression * selector, HqlExprArray * assigns)
  9624. {
  9625. unsigned expectedIndex = 0;
  9626. buildXmlSerialize(subctx, expr, selector, assigns, 0, expectedIndex);
  9627. expectedIndex = 0;
  9628. buildXmlSerialize(subctx, expr, selector, assigns, 1, expectedIndex);
  9629. }
  9630. void HqlCppTranslator::buildXmlSerialize(BuildCtx & ctx, IHqlExpression * dataset, const char * funcName, bool isMeta)
  9631. {
  9632. StringBuffer proto;
  9633. proto.append("virtual void ").append(funcName).append("(const byte * self, IXmlWriter & out)");
  9634. MemberFunction xmlFunc(*this, ctx, proto, MFdynamicproto);
  9635. if (!isMeta)
  9636. {
  9637. buildXmlSerializeUsingMeta(xmlFunc.ctx, dataset, "self");
  9638. }
  9639. else
  9640. {
  9641. BoundRow * selfCursor = bindTableCursor(xmlFunc.ctx, dataset, "self");
  9642. buildXmlSerialize(xmlFunc.ctx, dataset->queryRecord(), selfCursor->querySelector(), NULL);
  9643. }
  9644. }
  9645. void HqlCppTranslator::buildXmlSerializeUsingMeta(BuildCtx & ctx, IHqlExpression * dataset, const char * self)
  9646. {
  9647. MetaInstance meta(*this, dataset->queryRecord(), false);
  9648. buildMetaInfo(meta);
  9649. StringBuffer s;
  9650. ctx.addQuoted(s.append(meta.queryInstanceObject()).append(".toXML(").append(self).append(", out);"));
  9651. }
  9652. //-------------------------------------------------------------------------------------------------------------------
  9653. ABoundActivity * HqlCppTranslator::doBuildActivityOutputWorkunit(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  9654. {
  9655. IHqlExpression * dataset = expr->queryChild(0);
  9656. IHqlExpression * seq = querySequence(expr);
  9657. IHqlExpression * name = queryResultName(expr);
  9658. IHqlExpression * maxsize = expr->queryAttribute(maxSizeAtom);
  9659. int sequence = (int)getIntValue(seq, ResultSequenceInternal);
  9660. if (expr->hasAttribute(diskAtom))
  9661. {
  9662. StringBuffer suffix;
  9663. suffix.append("_").append(sequence);
  9664. IHqlExpression * newName = createConstant("~result::");
  9665. newName = createValue(no_concat, LINK(unknownStringType), newName, createValue(no_wuid, LINK(unknownStringType)));
  9666. newName = createValue(no_concat, LINK(unknownStringType), newName, createConstant(suffix));
  9667. HqlExprArray args;
  9668. unwindChildren(args, expr);
  9669. args.add(*newName, 1);
  9670. args.append(*createAttribute(overwriteAtom));
  9671. args.append(*createAttribute(resultAtom));
  9672. OwnedHqlExpr outputToTemp = expr->clone(args);
  9673. return buildActivity(ctx, outputToTemp, isRoot);
  9674. }
  9675. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9676. StringBuffer graphLabel;
  9677. bool useImplementationClass = options.minimizeActivityClasses && (sequence == ResultSequenceInternal) && !maxsize;
  9678. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKworkunitwrite, expr, "WorkUnitWrite");
  9679. if (useImplementationClass)
  9680. instance->setImplementationClass(newWorkUnitWriteArgId);
  9681. graphLabel.append(getActivityText(instance->kind)).append("\n");
  9682. getStoredDescription(graphLabel, seq, name, true);
  9683. instance->graphLabel.set(graphLabel.str());
  9684. buildActivityFramework(instance, isRoot && !isInternalSeq(seq));
  9685. buildInstancePrefix(instance);
  9686. noteResultDefined(ctx, instance, seq, name, isRoot);
  9687. //virtual unsigned getFlags()
  9688. StringBuffer flags;
  9689. if (expr->hasAttribute(extendAtom))
  9690. flags.append("|POFextend");
  9691. if (expr->hasAttribute(groupedAtom))
  9692. flags.append("|POFgrouped");
  9693. if (maxsize)
  9694. flags.append("|POFmaxsize");
  9695. if (!useImplementationClass)
  9696. {
  9697. doBuildSequenceFunc(instance->classctx, seq, true);
  9698. if (name)
  9699. {
  9700. MemberFunction func(*this, instance->startctx, "virtual const char * queryName()");
  9701. buildReturn(func.ctx, name, constUnknownVarStringType);
  9702. }
  9703. if (maxsize)
  9704. doBuildUnsignedFunction(instance->createctx, "getMaxSize", maxsize->queryChild(0));
  9705. HqlExprArray xmlnsAttrs;
  9706. gatherAttributes(xmlnsAttrs, xmlnsAtom, expr);
  9707. IHqlExpression * outputRecord = instance->meta.queryRecord();
  9708. Owned<IWUResult> result = createDatasetResultSchema(seq, name, outputRecord, xmlnsAttrs, true, false, 0);
  9709. if (result)
  9710. {
  9711. result->setResultRowLimit(-1);
  9712. if (sequence >= 0)
  9713. {
  9714. OwnedHqlExpr outputDs = createDataset(no_null, LINK(outputRecord));
  9715. buildXmlSerialize(instance->startctx, outputDs, "serializeXml", false);
  9716. }
  9717. }
  9718. if (flags.length())
  9719. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  9720. }
  9721. else
  9722. {
  9723. if (flags.length() == 0)
  9724. flags.append("|0");
  9725. OwnedHqlExpr flagsExpr = createQuoted(flags.str()+1, LINK(unsignedType));
  9726. instance->addConstructorParameter(name);
  9727. instance->addConstructorParameter(flagsExpr);
  9728. }
  9729. buildInstanceSuffix(instance);
  9730. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9731. associateRemoteResult(*instance, seq, name);
  9732. return instance->getBoundActivity();
  9733. }
  9734. void HqlCppTranslator::doBuildStmtOutput(BuildCtx & ctx, IHqlExpression * expr)
  9735. {
  9736. if (queryCurrentActivity(ctx))
  9737. {
  9738. ApplyStmtBuilder builder(*this);
  9739. builder.buildStmt(ctx, expr);
  9740. builder.flush(ctx);
  9741. return;
  9742. }
  9743. IHqlExpression * dataset = expr->queryChild(0);
  9744. if (expr->hasAttribute(groupedAtom) && (dataset->getOperator() != no_null))
  9745. throwError1(HQLERR_NotSupportedInsideNoThor, "Grouped OUTPUT");
  9746. LinkedHqlExpr seq = querySequence(expr);
  9747. LinkedHqlExpr name = queryResultName(expr);
  9748. assertex(seq != NULL);
  9749. int sequence = (int)getIntValue(seq, (int)ResultSequenceInternal);
  9750. if (!seq)
  9751. seq.setown(getSizetConstant(sequence));
  9752. if (!name)
  9753. name.setown(createQuoted("NULL", LINK(constUnknownVarStringType)));
  9754. HqlExprArray xmlnsAttrs;
  9755. gatherAttributes(xmlnsAttrs, xmlnsAtom, expr);
  9756. Owned<IWUResult> result = createDatasetResultSchema(seq, name, dataset->queryRecord(), xmlnsAttrs, true, false, 0);
  9757. CHqlBoundExpr bound;
  9758. buildDataset(ctx, dataset, bound, FormatNatural);
  9759. OwnedHqlExpr count = getBoundCount(bound);
  9760. HqlExprArray args;
  9761. args.append(*LINK(name));
  9762. args.append(*LINK(seq));
  9763. args.append(*bound.getTranslatedExpr());
  9764. args.append(*createTranslated(count));
  9765. args.append(*LINK(queryBoolExpr(expr->hasAttribute(extendAtom))));
  9766. buildFunctionCall(ctx, setResultDatasetId, args);
  9767. }
  9768. //-------------------------------------------------------------------------------------------------------------------
  9769. ABoundActivity * HqlCppTranslator::doBuildActivityDictionaryWorkunitWrite(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  9770. {
  9771. IHqlExpression * dictionary = expr->queryChild(0);
  9772. IHqlExpression * seq = querySequence(expr);
  9773. IHqlExpression * name = queryResultName(expr);
  9774. int sequence = (int)getIntValue(seq, ResultSequenceInternal);
  9775. OwnedHqlExpr dataset;
  9776. switch (dictionary->getOperator())
  9777. {
  9778. case no_null:
  9779. dataset.setown(createNullDataset(dictionary));
  9780. break;
  9781. case no_createdictionary:
  9782. dataset.set(dictionary->queryChild(0));
  9783. break;
  9784. default:
  9785. throwUnexpectedOp(dictionary->getOperator());
  9786. }
  9787. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9788. StringBuffer graphLabel;
  9789. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdictionaryworkunitwrite, expr, "DictionaryWorkUnitWrite");
  9790. graphLabel.append(getActivityText(instance->kind)).append("\n");
  9791. getStoredDescription(graphLabel, seq, name, true);
  9792. instance->graphLabel.set(graphLabel.str());
  9793. buildActivityFramework(instance, isRoot && !isInternalSeq(seq));
  9794. buildInstancePrefix(instance);
  9795. noteResultDefined(ctx, instance, seq, name, isRoot);
  9796. //virtual unsigned getFlags()
  9797. StringBuffer flags;
  9798. doBuildSequenceFunc(instance->classctx, seq, true);
  9799. if (name)
  9800. {
  9801. MemberFunction func(*this, instance->startctx, "virtual const char * queryName()");
  9802. buildReturn(func.ctx, name, constUnknownVarStringType);
  9803. }
  9804. //Owned<IWUResult> result = createDatasetResultSchema(seq, name, record, true, false);
  9805. buildDictionaryHashMember(instance->createctx, dictionary, "queryHashLookupInfo");
  9806. if (flags.length())
  9807. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  9808. buildInstanceSuffix(instance);
  9809. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9810. associateRemoteResult(*instance, seq, name);
  9811. return instance->getBoundActivity();
  9812. }
  9813. //---------------------------------------------------------------------------
  9814. ABoundActivity * HqlCppTranslator::doBuildActivityPipeThrough(BuildCtx & ctx, IHqlExpression * expr)
  9815. {
  9816. if (expr->hasAttribute(_disallowed_Atom))
  9817. throwError(HQLERR_PipeNotAllowed);
  9818. IHqlExpression * dataset = expr->queryChild(0);
  9819. IHqlExpression * pipe = expr->queryChild(1);
  9820. IHqlExpression * output = expr->queryAttribute(outputAtom);
  9821. IHqlExpression * csvToPipe = output ? output->queryAttribute(csvAtom) : NULL;
  9822. IHqlExpression * xmlToPipe = output ? output->queryAttribute(xmlAtom) : NULL;
  9823. IHqlExpression * csvFromPipe = expr->queryAttribute(csvAtom);
  9824. IHqlExpression * xmlFromPipe = expr->queryAttribute(xmlAtom);
  9825. //MORE: Could optimize dataset to not use LCR rows - if it is coming from a disk file
  9826. //Some other activities could similarly benefit (e.g., SORT), but they might need two
  9827. //metas and more intelligence in the activities...
  9828. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9829. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKpipethrough, expr, "PipeThrough");
  9830. if (csvToPipe)
  9831. instance->addBaseClass("IHThorCsvWriteExtra", true);
  9832. else if (xmlToPipe)
  9833. instance->addBaseClass("IHThorXmlWriteExtra", true);
  9834. buildActivityFramework(instance);
  9835. buildInstancePrefix(instance);
  9836. if (expr->hasAttribute(repeatAtom))
  9837. {
  9838. //virtual const char * getPipeProgram() { return "grep"; }
  9839. instance->startctx.addQuotedLiteral("virtual const char * getPipeProgram() { return NULL; }");
  9840. MemberFunction func(*this, instance->startctx, "virtual char * getNameFromRow(const void * _self)");
  9841. func.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *) _self;");
  9842. bindTableCursor(func.ctx, dataset, "self");
  9843. buildReturn(func.ctx, pipe, unknownVarStringType);
  9844. }
  9845. else
  9846. {
  9847. //virtual const char * getPipeProgram() { return "grep"; }
  9848. MemberFunction func(*this, instance->startctx, "virtual const char * getPipeProgram()");
  9849. buildReturn(func.ctx, pipe, unknownVarStringType);
  9850. }
  9851. if (csvToPipe)
  9852. {
  9853. buildCsvWriteMembers(instance, dataset, csvToPipe);
  9854. instance->classctx.addQuotedLiteral("virtual IHThorCsvWriteExtra * queryCsvOutput() { return this; }");
  9855. }
  9856. if (xmlToPipe)
  9857. {
  9858. buildXmlWriteMembers(instance, dataset, xmlToPipe);
  9859. instance->classctx.addQuotedLiteral("virtual IHThorXmlWriteExtra * queryXmlOutput() { return this; }");
  9860. }
  9861. bool usesContents = false;
  9862. if (csvFromPipe)
  9863. {
  9864. if (isValidCsvRecord(expr->queryRecord()))
  9865. {
  9866. StringBuffer csvInstanceName;
  9867. buildCsvReadTransformer(expr, csvInstanceName, csvFromPipe);
  9868. StringBuffer s;
  9869. s.append("virtual ICsvToRowTransformer * queryCsvTransformer() { return &").append(csvInstanceName).append("; }");
  9870. instance->classctx.addQuoted(s);
  9871. }
  9872. else
  9873. {
  9874. throwUnexpected(); // should be caught earlier
  9875. }
  9876. }
  9877. else if (xmlFromPipe)
  9878. {
  9879. doBuildXmlReadMember(*instance, expr, "queryXmlTransformer", usesContents);
  9880. doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryAttributeChild(xmlFromPipe, rowAtom, 0));
  9881. }
  9882. StringBuffer flags;
  9883. if (expr->hasAttribute(repeatAtom))
  9884. flags.append("|TPFrecreateeachrow");
  9885. if (expr->hasAttribute(groupAtom))
  9886. flags.append("|TPFgroupeachrow");
  9887. if (expr->hasAttribute(optAtom))
  9888. flags.append("|TPFnofail");
  9889. if (csvToPipe)
  9890. flags.append("|TPFwritecsvtopipe");
  9891. if (xmlToPipe)
  9892. flags.append("|TPFwritexmltopipe");
  9893. if (csvFromPipe)
  9894. flags.append("|TPFreadcsvfrompipe");
  9895. if (xmlFromPipe)
  9896. flags.append("|TPFreadxmlfrompipe");
  9897. if (usesContents)
  9898. flags.append("|TPFreadusexmlcontents");
  9899. if (xmlToPipe && xmlToPipe->hasAttribute(noRootAtom))
  9900. flags.append("|TPFwritenoroot");
  9901. if (xmlFromPipe && xmlFromPipe->hasAttribute(noRootAtom))
  9902. flags.append("|TPFreadnoroot");
  9903. if (flags.length())
  9904. doBuildUnsignedFunction(instance->classctx, "getPipeFlags", flags.str()+1);
  9905. buildInstanceSuffix(instance);
  9906. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9907. return instance->getBoundActivity();
  9908. }
  9909. //---------------------------------------------------------------------------
  9910. //-- no_join [JOIN] --
  9911. /* in parms: NOT linked */
  9912. void HqlCppTranslator::doCompareLeftRight(BuildCtx & ctx, const char * funcname, const DatasetReference & datasetLeft, const DatasetReference & datasetRight, const HqlExprArray & left, const HqlExprArray & right)
  9913. {
  9914. OwnedHqlExpr selSeq = createDummySelectorSequence();
  9915. OwnedHqlExpr leftList = createValueSafe(no_sortlist, makeSortListType(NULL), left);
  9916. OwnedHqlExpr leftSelect = datasetLeft.getSelector(no_left, selSeq);
  9917. OwnedHqlExpr leftResolved = datasetLeft.mapCompound(leftList, leftSelect);
  9918. OwnedHqlExpr rightList = createValueSafe(no_sortlist, makeSortListType(NULL), right);
  9919. OwnedHqlExpr rightSelect = datasetRight.getSelector(no_right, selSeq);
  9920. OwnedHqlExpr rightResolved = datasetRight.mapCompound(rightList, rightSelect);
  9921. OwnedHqlExpr order = createValue(no_order, LINK(signedType), LINK(leftResolved), LINK(rightResolved));
  9922. buildCompareMemberLR(ctx, funcname, order, datasetLeft.queryDataset(), datasetRight.queryDataset(), selSeq);
  9923. }
  9924. void HqlCppTranslator::buildSlidingMatchFunction(BuildCtx & ctx, const HqlExprArray & leftEq, const HqlExprArray & rightEq, const HqlExprArray & slidingMatches, const char * funcname, unsigned childIndex, const DatasetReference & datasetL, const DatasetReference & datasetR)
  9925. {
  9926. HqlExprArray left, right;
  9927. unsigned numSimple = leftEq.ordinality() - slidingMatches.ordinality();
  9928. for (unsigned j=0; j<numSimple; j++)
  9929. {
  9930. left.append(OLINK(leftEq.item(j)));
  9931. right.append(OLINK(rightEq.item(j)));
  9932. }
  9933. ForEachItemIn(i, slidingMatches)
  9934. {
  9935. IHqlExpression & cur = slidingMatches.item(i);
  9936. left.append(*LINK(cur.queryChild(0)));
  9937. right.append(*LINK(cur.queryChild(childIndex)));
  9938. }
  9939. doCompareLeftRight(ctx, funcname, datasetL, datasetR, left, right);
  9940. }
  9941. void HqlCppTranslator::generateSortCompare(BuildCtx & nestedctx, BuildCtx & ctx, node_operator side, const DatasetReference & dataset, const HqlExprArray & sorts, IHqlExpression * noSortAttr, bool canReuseLeft, bool isLightweight, bool isLocal)
  9942. {
  9943. StringBuffer s, compareName;
  9944. const char * sideText = (side == no_left) ? "Left" : "Right";
  9945. compareName.append("compare").append(sideText);
  9946. assertex(dataset.querySide() == no_activetable);
  9947. bool noNeedToSort = isAlreadySorted(dataset.queryDataset(), sorts, isLocal, true, true);
  9948. if (userPreventsSort(noSortAttr, side))
  9949. noNeedToSort = true;
  9950. if (noNeedToSort || isLightweight)
  9951. {
  9952. if (!noNeedToSort)
  9953. {
  9954. DBGLOG("Lightweight true, but code generator didn't think sort was required");
  9955. ctx.addQuotedLiteral("//Forced by lightweight");
  9956. }
  9957. s.clear().append("virtual bool is").append(sideText).append("AlreadySorted() { return true; }");
  9958. ctx.addQuoted(s);
  9959. }
  9960. if (canReuseLeft)
  9961. {
  9962. s.clear().append("virtual ICompare * queryCompare").append(sideText).append("() { return &compareLeft; }");
  9963. ctx.addQuoted(s);
  9964. }
  9965. else
  9966. {
  9967. s.clear().append("virtual ICompare * queryCompare").append(sideText).append("() { return &").append(compareName).append("; }");
  9968. ctx.addQuoted(s);
  9969. BuildCtx classctx(nestedctx);
  9970. IHqlStmt * classStmt = beginNestedClass(classctx, compareName.str(), "ICompare");
  9971. {
  9972. MemberFunction func(*this, classctx, "virtual int docompare(const void * _left, const void * _right) const" OPTIMIZE_FUNCTION_ATTRIBUTE);
  9973. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  9974. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  9975. func.ctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  9976. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  9977. buildReturnOrder(func.ctx, groupOrder, dataset);
  9978. }
  9979. endNestedClass(classStmt);
  9980. }
  9981. }
  9982. void HqlCppTranslator::generateSerializeAssigns(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * selector, IHqlExpression * selfSelect, IHqlExpression * leftSelect, const DatasetReference & srcDataset, const DatasetReference & tgtDataset, HqlExprArray & srcSelects, HqlExprArray & tgtSelects, bool needToClear, node_operator serializeOp, IAtom * serialForm)
  9983. {
  9984. ForEachChild(i, record)
  9985. {
  9986. IHqlExpression * cur = record->queryChild(i);
  9987. switch (cur->getOperator())
  9988. {
  9989. case no_field:
  9990. {
  9991. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  9992. unsigned matchIndex = tgtSelects.find(*selected);
  9993. if (matchIndex != NotFound)
  9994. {
  9995. Owned<IHqlExpression> self = tgtDataset.mapScalar(&tgtSelects.item(matchIndex), selfSelect);
  9996. Owned<IHqlExpression> left = srcDataset.mapScalar(&srcSelects.item(matchIndex), leftSelect);
  9997. if (self->queryType() != left->queryType())
  9998. {
  9999. HqlExprArray args;
  10000. args.append(*LINK(left));
  10001. if (serializeOp == no_deserialize)
  10002. args.append(*LINK(self->queryRecord()));
  10003. args.append(*createAttribute(serialForm));
  10004. left.setown(createWrapper(serializeOp, self->queryType(), args));
  10005. }
  10006. buildAssign(ctx, self, left);
  10007. //Note, we could stop here if needToClear and all fields have been assigned, and all the following fields are fixed width.
  10008. // but not really sure it is worth it.
  10009. }
  10010. else if (cur->isDatarow())
  10011. {
  10012. generateSerializeAssigns(ctx, cur->queryRecord(), selected, selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, needToClear, serializeOp, serialForm);
  10013. }
  10014. else if (needToClear || mustInitializeField(cur))
  10015. {
  10016. //MORE: Might want to recurse if a record
  10017. Owned<IHqlExpression> self = tgtDataset.mapScalar(selected, selfSelect);
  10018. buildClear(ctx, self);
  10019. }
  10020. break;
  10021. }
  10022. case no_record:
  10023. generateSerializeAssigns(ctx, cur, selector, selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, needToClear, serializeOp, serialForm);
  10024. break;
  10025. case no_ifblock:
  10026. //Filter on target...
  10027. UNIMPLEMENTED;
  10028. //generateSerializeAssigns(ctx, cur->queryChild(1), selector, selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, needToClear, serializeOp, serialForm);
  10029. break;
  10030. }
  10031. }
  10032. }
  10033. void HqlCppTranslator::generateSerializeFunction(BuildCtx & ctx, const char * funcName, const DatasetReference & srcDataset, const DatasetReference & tgtDataset, HqlExprArray & srcSelects, HqlExprArray & tgtSelects, node_operator serializeOp, IAtom * serialForm)
  10034. {
  10035. StringBuffer s;
  10036. s.append("virtual unsigned ").append(funcName).append("(ARowBuilder & crSelf, const void * _src, unsigned & thisRecordSize)");
  10037. MemberFunction func(*this, ctx, s, MFdynamicproto);
  10038. ensureRowAllocated(func.ctx, "crSelf");
  10039. func.ctx.addQuotedLiteral("const unsigned char * src = (const unsigned char *) _src;");
  10040. OwnedHqlExpr selSeq = createDummySelectorSequence();
  10041. BoundRow * tgtCursor = bindSelf(func.ctx, tgtDataset.queryDataset(), "crSelf");
  10042. BoundRow * srcCursor = bindTableCursor(func.ctx, srcDataset.queryDataset(), "src", no_left, selSeq);
  10043. IHqlExpression * leftSelect = srcCursor->querySelector();
  10044. IHqlExpression * selfSelect = tgtCursor->querySelector();
  10045. IHqlExpression * record = tgtDataset.queryDataset()->queryRecord();
  10046. generateSerializeAssigns(func.ctx, record, tgtDataset.querySelector(), selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, !isFixedRecordSize(record), serializeOp, serialForm);
  10047. const bool serialize = (serializeOp == no_serialize);
  10048. BoundRow * recordCursor = serialize ? srcCursor : tgtCursor;
  10049. OwnedHqlExpr recordSize = getRecordSize(recordCursor->querySelector());
  10050. OwnedHqlExpr recordSizeVar = createVariable("thisRecordSize", LINK(unsignedType));
  10051. buildAssignToTemp(func.ctx, recordSizeVar, recordSize);
  10052. buildReturnRecordSize(func.ctx, serialize ? tgtCursor : srcCursor);
  10053. }
  10054. class SerializeKeyInfo
  10055. {
  10056. public:
  10057. HqlExprArray keyFields;
  10058. HqlExprArray keySelects;
  10059. HqlExprArray keyCompares;
  10060. HqlExprArray allKeyCompares;
  10061. HqlExprArray datasetSelects;
  10062. HqlExprArray filteredSorts;
  10063. OwnedHqlExpr keyRecord;
  10064. OwnedHqlExpr keyDataset;
  10065. };
  10066. bool HqlCppTranslator::extractSerializeKey(SerializeKeyInfo & info, const DatasetReference & dataset, const HqlExprArray & sorts, bool isGlobal)
  10067. {
  10068. if (!targetThor() || !isGlobal)
  10069. return false;
  10070. //check if there are any ifblocks, and if so don't allow it. Even more accurate would be no join fields used in ifblocks
  10071. //This test could be removed if keyToRecord() wasn't generated anymore
  10072. IHqlExpression * record = dataset.queryDataset()->queryRecord();
  10073. if (recordContainsIfBlock(record))
  10074. return false;
  10075. ForEachItemIn(idx, sorts)
  10076. {
  10077. //MORE: Nested - this won't serialize the key if sorting by a field in a nested record
  10078. // If this is a problem we will need to create new fields for each value.
  10079. IHqlExpression & cur = sorts.item(idx);
  10080. IHqlExpression * value = &cur;
  10081. if (value->getOperator() == no_negate)
  10082. value=value->queryChild(0);
  10083. //It isn't possible to sensibly compare serialized dictionaries at the moment.
  10084. if (value->isDictionary())
  10085. return false;
  10086. if ((value->getOperator() == no_select) && (value->queryChild(0)->queryNormalizedSelector() == dataset.querySelector()))
  10087. {
  10088. if (value->queryType()->getTypeCode() == type_alien)
  10089. {
  10090. //MORE: Really should check if a self contained alien data type.
  10091. return false;
  10092. }
  10093. OwnedHqlExpr serializedField = getSerializedForm(value->queryChild(1), diskAtom); // Could be internal, but may require serialized compare
  10094. OwnedHqlExpr mappedSelect = dataset.mapScalar(value,queryActiveTableSelector());
  10095. OwnedHqlExpr keyedCompare = dataset.mapScalar(&cur,queryActiveTableSelector());
  10096. info.keyFields.append(*LINK(serializedField));
  10097. info.keySelects.append(*createSelectExpr(LINK(mappedSelect->queryChild(0)), LINK(serializedField)));
  10098. info.datasetSelects.append(*LINK(value));
  10099. info.keyCompares.append(*LINK(keyedCompare));
  10100. info.filteredSorts.append(OLINK(cur));
  10101. info.allKeyCompares.append(*LINK(keyedCompare));
  10102. }
  10103. else if (value->isConstant())
  10104. info.allKeyCompares.append(OLINK(cur));
  10105. else
  10106. return false;
  10107. }
  10108. const bool aggressive = false;
  10109. // When projecting is done by the serialize() function this will be worth changing to true
  10110. // otherwise the extra cost of the project probably isn't likely to outweigh the extra copy
  10111. unsigned numToSerialize = aggressive ? info.filteredSorts.ordinality() : sorts.ordinality();
  10112. //The following test will need to change if we serialize when nested fields are used (see above)
  10113. if (numToSerialize >= getFlatFieldCount(record))
  10114. return false;
  10115. info.keyRecord.setown(createRecord(info.keyFields));
  10116. info.keyDataset.setown(createDataset(no_anon, LINK(info.keyRecord)));
  10117. return true;
  10118. }
  10119. void HqlCppTranslator::generateSerializeKey(BuildCtx & nestedctx, node_operator side, SerializeKeyInfo & keyInfo, const DatasetReference & dataset, bool generateCompares)
  10120. {
  10121. //check if there are any ifblocks, and if so don't allow it. Even more accurate would be no join fields used in ifblocks
  10122. //IHqlExpression * record = dataset.queryDataset()->queryRecord();
  10123. const char * sideText = (side == no_none) ? "" : (side == no_left) ? "Left" : "Right";
  10124. StringBuffer s;
  10125. StringBuffer memberName;
  10126. memberName.append("serializer").append(sideText);
  10127. BuildCtx classctx(nestedctx);
  10128. IHqlStmt * classStmt = beginNestedClass(classctx, memberName, "ISortKeySerializer");
  10129. DatasetReference keyActiveRef(keyInfo.keyDataset, no_activetable, NULL);
  10130. OwnedHqlExpr keyOrder = createValueSafe(no_sortlist, makeSortListType(NULL), keyInfo.keyCompares);
  10131. generateSerializeFunction(classctx, "recordToKey", dataset, keyActiveRef, keyInfo.datasetSelects, keyInfo.keySelects, no_serialize, diskAtom);
  10132. generateSerializeFunction(classctx, "keyToRecord", keyActiveRef, dataset, keyInfo.keySelects, keyInfo.datasetSelects, no_deserialize, diskAtom);
  10133. buildMetaMember(classctx, keyInfo.keyRecord, false, "queryRecordSize");
  10134. buildCompareMember(classctx, "CompareKey", keyOrder, keyActiveRef);
  10135. doCompareLeftRight(classctx, "CompareKeyRow", keyActiveRef, dataset, keyInfo.keyCompares, keyInfo.filteredSorts);
  10136. endNestedClass(classStmt);
  10137. s.clear().append("virtual ISortKeySerializer * querySerialize").append(sideText).append("() { return &").append(memberName).append("; }");
  10138. nestedctx.addQuoted(s);
  10139. if (generateCompares)
  10140. {
  10141. buildCompareMember(nestedctx, "CompareKey", keyOrder, keyActiveRef);
  10142. doCompareLeftRight(nestedctx, "CompareRowKey", dataset, keyActiveRef, keyInfo.filteredSorts, keyInfo.keyCompares);
  10143. }
  10144. }
  10145. void HqlCppTranslator::generateSerializeKey(BuildCtx & nestedctx, node_operator side, const DatasetReference & dataset, const HqlExprArray & sorts, bool isGlobal, bool generateCompares)
  10146. {
  10147. SerializeKeyInfo keyInfo;
  10148. if (!extractSerializeKey(keyInfo, dataset, sorts, isGlobal))
  10149. return;
  10150. generateSerializeKey(nestedctx, side, keyInfo, dataset, generateCompares);
  10151. }
  10152. IHqlExpression * HqlCppTranslator::createFailMessage(const char * prefix, IHqlExpression * limit, IHqlExpression * filename, unique_id_t id)
  10153. {
  10154. StringBuffer s;
  10155. HqlExprArray values;
  10156. values.append(*createConstant(s.clear().append(prefix)));
  10157. if (limit)
  10158. {
  10159. values.append(*createConstant("("));
  10160. values.append(*ensureExprType(limit, unknownStringType));
  10161. values.append(*createConstant(")"));
  10162. }
  10163. if (filename)
  10164. {
  10165. values.append(*createConstant(" file '"));
  10166. values.append(*ensureExprType(filename, unknownStringType));
  10167. values.append(*createConstant("'"));
  10168. }
  10169. if (id)
  10170. values.append(*createConstant(s.clear().append(" [id=").append(id).append("]")));
  10171. OwnedHqlExpr errorText = createBalanced(no_concat, unknownStringType, values);
  10172. return foldHqlExpression(errorText);
  10173. }
  10174. IHqlExpression * HqlCppTranslator::createFailAction(const char * prefix, IHqlExpression * limit, IHqlExpression * filename, unique_id_t id)
  10175. {
  10176. IHqlExpression * msg = createFailMessage(prefix, limit, filename, id);
  10177. return createValue(no_fail, makeVoidType(), msg, getDefaultAttr());
  10178. }
  10179. void HqlCppTranslator::doBuildJoinRowLimitHelper(ActivityInstance & instance, IHqlExpression * rowlimit, IHqlExpression * filename, bool generateImplicitLimit)
  10180. {
  10181. if (rowlimit)
  10182. {
  10183. doBuildUnsignedFunction(instance.startctx, "getMatchAbortLimit", rowlimit->queryChild(0));
  10184. if (!rowlimit->hasAttribute(skipAtom))
  10185. {
  10186. LinkedHqlExpr fail = queryChildOperator(no_fail, rowlimit);
  10187. if (!fail)
  10188. fail.setown(createFailAction("JOIN limit exceeded", rowlimit->queryChild(0), filename, instance.activityId));
  10189. MemberFunction func(*this, instance.startctx, "virtual void onMatchAbortLimitExceeded()");
  10190. buildStmt(func.ctx, fail);
  10191. }
  10192. }
  10193. else if (generateImplicitLimit)
  10194. {
  10195. OwnedHqlExpr implicitLimit = getSizetConstant(options.defaultImplicitKeyedJoinLimit);
  10196. doBuildUnsignedFunction(instance.startctx, "getMatchAbortLimit", implicitLimit);
  10197. if (options.warnOnImplicitJoinLimit)
  10198. {
  10199. StringBuffer fname;
  10200. if (filename)
  10201. getExprECL(filename, fname.append(" "));
  10202. WARNING2(CategoryLimit, HQLWRN_ImplicitJoinLimit, options.defaultImplicitKeyedJoinLimit, fname.str());
  10203. }
  10204. }
  10205. }
  10206. static size32_t getMaxSubstringLength(IHqlExpression * expr)
  10207. {
  10208. IHqlExpression * rawSelect = expr->queryChild(0);
  10209. IHqlExpression * range = expr->queryChild(1);
  10210. IHqlExpression * rangeLow = range->queryChild(0);
  10211. unsigned rawLength = rawSelect->queryType()->getStringLen();
  10212. if (matchesConstantValue(rangeLow, 1))
  10213. return rawLength;
  10214. __int64 lowValue = getIntValue(rangeLow, UNKNOWN_LENGTH);
  10215. size32_t resultLength = UNKNOWN_LENGTH;
  10216. if ((rawLength != UNKNOWN_LENGTH) && (lowValue >= 1) && (lowValue <= rawLength))
  10217. resultLength = rawLength - (size32_t)(lowValue - 1);
  10218. return resultLength;
  10219. }
  10220. static IHqlExpression * getSimplifiedCommonSubstringRange(IHqlExpression * expr)
  10221. {
  10222. IHqlExpression * rawSelect = expr->queryChild(0);
  10223. IHqlExpression * range = expr->queryChild(1);
  10224. IHqlExpression * rangeLow = range->queryChild(0);
  10225. if (matchesConstantValue(rangeLow, 1))
  10226. return LINK(rawSelect);
  10227. HqlExprArray args;
  10228. args.append(*LINK(rawSelect));
  10229. args.append(*createValue(no_rangefrom, makeNullType(), LINK(rangeLow)));
  10230. return expr->clone(args);
  10231. }
  10232. ABoundActivity * HqlCppTranslator::doBuildActivityJoinOrDenormalize(BuildCtx & ctx, IHqlExpression * expr)
  10233. {
  10234. node_operator op = expr->getOperator();
  10235. assertex(op==no_join || op==no_selfjoin || op==no_denormalize || op==no_denormalizegroup);
  10236. LinkedHqlExpr dataset1 = expr->queryChild(0);
  10237. LinkedHqlExpr dataset2 = queryJoinRhs(expr);
  10238. IHqlExpression * transform = expr->queryChild(3);
  10239. IHqlExpression * noSortAttr = expr->queryAttribute(noSortAtom);
  10240. IHqlExpression * rowlimit = expr->queryAttribute(rowLimitAtom);
  10241. IHqlExpression * selSeq = querySelSeq(expr);
  10242. bool isLeftOuter = false;
  10243. bool isRightOuter = false;
  10244. bool excludeMatches = false;
  10245. bool isAllJoin = false;
  10246. bool isLightweight = expr->hasAttribute(_lightweight_Atom);
  10247. bool isManyLookup = expr->hasAttribute(manyAtom);
  10248. if (expr->hasAttribute(leftouterAtom))
  10249. isLeftOuter = true;
  10250. if (expr->hasAttribute(rightouterAtom))
  10251. isRightOuter = true;
  10252. if (expr->hasAttribute(fullouterAtom))
  10253. {
  10254. isLeftOuter = true;
  10255. isRightOuter = true;
  10256. }
  10257. if (expr->hasAttribute(leftonlyAtom))
  10258. {
  10259. isLeftOuter = true;
  10260. excludeMatches = true;
  10261. }
  10262. if (expr->hasAttribute(rightonlyAtom))
  10263. {
  10264. isRightOuter = true;
  10265. excludeMatches = true;
  10266. }
  10267. if (expr->hasAttribute(fullonlyAtom))
  10268. {
  10269. isLeftOuter = true;
  10270. isRightOuter = true;
  10271. excludeMatches = true;
  10272. }
  10273. if (expr->hasAttribute(allAtom))
  10274. isAllJoin = true;
  10275. bool isSmartJoin = expr->hasAttribute(smartAtom);
  10276. bool isLookupJoin = expr->hasAttribute(lookupAtom) && !isSmartJoin;
  10277. bool isHashJoin = targetThor() && expr->hasAttribute(hashAtom) && !isSmartJoin;
  10278. bool isLocalJoin = !isHashJoin && expr->hasAttribute(localAtom);
  10279. bool joinToSelf = (op == no_selfjoin);
  10280. bool allowAllToLookupConvert = !options.noAllToLookupConversion;
  10281. IHqlExpression * atmostAttr = expr->queryAttribute(atmostAtom);
  10282. LinkedHqlExpr keepLimit = queryAttributeChild(expr, keepAtom, 0);
  10283. //Delay removing ungroups until this point because they can be useful for reducing the size of spill files.
  10284. if (isUngroup(dataset1) && !isLookupJoin)
  10285. dataset1.set(dataset1->queryChild(0));
  10286. if (isUngroup(dataset2))
  10287. dataset2.set(dataset2->queryChild(0));
  10288. if (expr->hasAttribute(groupedAtom) && targetThor())
  10289. WARNING(CategoryEfficiency, HQLWRN_GroupedJoinIsLookupJoin);
  10290. //Hash and smart joins are not valid inside child queries - convert to a normal join.
  10291. //The flags should already have been stripped if targetting hthor/roxie
  10292. if (insideChildQuery(ctx) && (isHashJoin || isSmartJoin))
  10293. {
  10294. assertex(targetThor());
  10295. isHashJoin = false;
  10296. isSmartJoin = false;
  10297. }
  10298. if ((op == no_denormalize || op == no_denormalizegroup) && targetThor() && options.checkThorRestrictions)
  10299. {
  10300. if (isHashJoin)
  10301. throwError1(HQLERR_ThorDenormNoFeatureX, "HASH");
  10302. if (expr->hasAttribute(firstAtom))
  10303. throwError1(HQLERR_ThorDenormNoFeatureX, "FIRST");
  10304. if (expr->hasAttribute(firstLeftAtom))
  10305. throwError1(HQLERR_ThorDenormNoFeatureX, "FIRST LEFT");
  10306. if (expr->hasAttribute(firstRightAtom))
  10307. throwError1(HQLERR_ThorDenormNoFeatureX, "FIRST RIGHT");
  10308. if (expr->hasAttribute(partitionRightAtom))
  10309. throwError1(HQLERR_ThorDenormNoFeatureX, "PARTITION RIGHT");
  10310. }
  10311. bool slidingAllowed = options.slidingJoins && canBeSlidingJoin(expr);
  10312. JoinSortInfo joinInfo(expr);
  10313. joinInfo.findJoinSortOrders(slidingAllowed);
  10314. if (atmostAttr && joinInfo.hasHardRightNonEquality())
  10315. {
  10316. if (isAllJoin)
  10317. allowAllToLookupConvert = false;
  10318. else
  10319. {
  10320. StringBuffer s;
  10321. throwError1(HQLERR_BadJoinConditionAtMost,getExprECL(joinInfo.extraMatch, s.append(" (")).append(")").str());
  10322. }
  10323. }
  10324. LinkedHqlExpr rhs = dataset2;
  10325. if (isAllJoin)
  10326. {
  10327. if (joinInfo.hasRequiredEqualities() && allowAllToLookupConvert)
  10328. {
  10329. //Convert an all join to a many lookup if it can be done that way - more efficient, and same resourcing/semantics ...
  10330. isManyLookup = true;
  10331. isAllJoin = false;
  10332. isLookupJoin = true;
  10333. }
  10334. }
  10335. else if (!joinInfo.hasRequiredEqualities() && !joinInfo.hasOptionalEqualities())
  10336. {
  10337. if (expr->hasAttribute(_conditionFolded_Atom))
  10338. {
  10339. //LIMIT on an ALL join is equivalent to applying a limit to the rhs of the join (since all will hard match).
  10340. //This could be transformed early, but uncommon enough to not be too concerned.
  10341. if (rowlimit)
  10342. {
  10343. HqlExprArray args;
  10344. args.append(*LINK(rhs));
  10345. //A LIMIT on a join means no limit, whilst a LIMIT(ds, 0) limits to no records.
  10346. //So avoid adding a zero limit (if constant), or ensure 0 is mapped to a maximal value.
  10347. LinkedHqlExpr count = rowlimit->queryChild(0);
  10348. if (count->queryValue())
  10349. {
  10350. if (isZero(count))
  10351. count.clear();
  10352. }
  10353. else
  10354. {
  10355. OwnedHqlExpr zero = createConstant(count->queryType()->castFrom(false, I64C(0)));
  10356. OwnedHqlExpr all = createConstant(count->queryType()->castFrom(false, I64C(-1)));
  10357. OwnedHqlExpr ne = createBoolExpr(no_ne, LINK(count), zero.getClear());
  10358. count.setown(createValue(no_if, count->getType(), LINK(ne), LINK(count), LINK(all)));
  10359. }
  10360. if (count)
  10361. {
  10362. args.append(*LINK(count));
  10363. unwindChildren(args, rowlimit, 1);
  10364. rhs.setown(createDataset(no_limit, args));
  10365. }
  10366. }
  10367. isAllJoin = true;
  10368. //A non-many LOOKUP join can't really be converted to an ALL join.
  10369. //Possibly if KEEP(1) was added, no limits, no skipping in transform etc.
  10370. if ((isLookupJoin && !isManyLookup) || (op == no_selfjoin))
  10371. isAllJoin = false;
  10372. WARNING(CategoryUnusual, HQLWRN_JoinConditionFoldedNowAll);
  10373. }
  10374. else
  10375. {
  10376. StringBuffer name;
  10377. if (expr->queryName())
  10378. name.append(" ").append(expr->queryName());
  10379. throwError1(HQLERR_JoinXTooComplex, name.str());
  10380. }
  10381. }
  10382. if (isAllJoin)
  10383. isLightweight = false;
  10384. Owned<ABoundActivity> boundDataset1 = buildCachedActivity(ctx, dataset1);
  10385. Owned<ABoundActivity> boundDataset2;
  10386. if (!joinToSelf)
  10387. boundDataset2.setown(buildCachedActivity(ctx, rhs));
  10388. const char * argName;
  10389. ThorActivityKind kind;
  10390. if (op == no_selfjoin)
  10391. {
  10392. if (isLightweight)
  10393. kind = TAKselfjoinlight;
  10394. else
  10395. kind = TAKselfjoin;
  10396. argName = "Join";
  10397. }
  10398. else if (op == no_join)
  10399. {
  10400. if (isAllJoin)
  10401. {
  10402. kind = TAKalljoin;
  10403. argName = "AllJoin";
  10404. }
  10405. else if (isLookupJoin)
  10406. {
  10407. kind = TAKlookupjoin;
  10408. argName = "HashJoin";
  10409. }
  10410. else if (isSmartJoin)
  10411. {
  10412. kind = TAKsmartjoin;
  10413. argName = "HashJoin";
  10414. }
  10415. else if (isHashJoin)
  10416. {
  10417. kind = TAKhashjoin;
  10418. argName = "HashJoin";
  10419. }
  10420. else
  10421. {
  10422. kind = TAKjoin;
  10423. argName = "Join";
  10424. }
  10425. }
  10426. else if (op == no_denormalize)
  10427. {
  10428. if (isAllJoin)
  10429. {
  10430. kind = TAKalldenormalize;
  10431. argName = "AllDenormalize";
  10432. }
  10433. else if (isLookupJoin)
  10434. {
  10435. kind = TAKlookupdenormalize;
  10436. argName = "HashDenormalize";
  10437. }
  10438. else if (isSmartJoin)
  10439. {
  10440. kind = TAKsmartdenormalize;
  10441. argName = "HashDenormalize";
  10442. }
  10443. else if (isHashJoin)
  10444. {
  10445. kind = TAKhashdenormalize;
  10446. argName = "HashDenormalize";
  10447. }
  10448. else
  10449. {
  10450. kind = TAKdenormalize;
  10451. argName = "Denormalize";
  10452. }
  10453. }
  10454. else
  10455. {
  10456. if (isAllJoin)
  10457. {
  10458. kind = TAKalldenormalizegroup;
  10459. argName = "AllDenormalizeGroup";
  10460. }
  10461. else if (isLookupJoin)
  10462. {
  10463. kind = TAKlookupdenormalizegroup;
  10464. argName = "HashDenormalizeGroup";
  10465. }
  10466. else if (isSmartJoin)
  10467. {
  10468. kind = TAKsmartdenormalizegroup;
  10469. argName = "HashDenormalizeGroup";
  10470. }
  10471. else if (isHashJoin)
  10472. {
  10473. kind = TAKhashdenormalizegroup;
  10474. argName = "HashDenormalizeGroup";
  10475. }
  10476. else
  10477. {
  10478. kind = TAKdenormalizegroup;
  10479. argName = "DenormalizeGroup";
  10480. }
  10481. }
  10482. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, argName);
  10483. if (isLightweight)
  10484. {
  10485. StringBuffer graphLabel;
  10486. if (kind != TAKselfjoinlight)
  10487. graphLabel.append("Lightweight ");
  10488. graphLabel.append(getActivityText(kind));
  10489. instance->graphLabel.set(graphLabel.str());
  10490. }
  10491. instance->setLocal(isLocalJoin && !insideChildQuery(ctx));
  10492. buildActivityFramework(instance);
  10493. buildInstancePrefix(instance);
  10494. bool partitionRight = expr->hasAttribute(partitionRightAtom) && (kind != TAKselfjoin) && !joinInfo.isSlidingJoin();
  10495. DatasetReference lhsDsRef(dataset1, no_activetable, NULL);
  10496. DatasetReference rhsDsRef(dataset2, no_activetable, NULL);
  10497. bool couldBeKeepOne = keepLimit && (!keepLimit->queryValue() || (keepLimit->queryValue()->getIntValue() <= 1));
  10498. if (dataset1->queryRecord() == dataset2->queryRecord())
  10499. {
  10500. //more could use the compareLeftRight function instead of generating the same code
  10501. //several time....
  10502. }
  10503. bool canReuseLeftCompare = recordTypesMatch(dataset1, dataset2) && arraysMatch(joinInfo.queryLeftSort(), joinInfo.queryRightSort());
  10504. if (!isAllJoin)
  10505. {
  10506. bool isLocalSort = isLocalJoin || !targetThor();
  10507. //Lookup join doesn't need the left sort (unless it is reused elsewhere), or the right sort unless it is deduping.
  10508. if (canReuseLeftCompare || !isLookupJoin)
  10509. generateSortCompare(instance->nestedctx, instance->classctx, no_left, lhsDsRef, joinInfo.queryLeftSort(), noSortAttr, false, isLightweight, isLocalSort);
  10510. generateSortCompare(instance->nestedctx, instance->classctx, no_right, rhsDsRef, joinInfo.queryRightSort(), noSortAttr, canReuseLeftCompare, isLightweight, isLocalSort);
  10511. //Only joins that partition need the serialization functions
  10512. if (!isHashJoin && !isLookupJoin && !joinInfo.isSlidingJoin())
  10513. {
  10514. bool isGlobal = !isLocalJoin && !instance->isChildActivity();
  10515. BuildCtx nestedctx(instance->nestedctx);
  10516. SerializeKeyInfo keyInfo;
  10517. if (!partitionRight)
  10518. {
  10519. if (extractSerializeKey(keyInfo, lhsDsRef, joinInfo.queryLeftSort(), isGlobal))
  10520. {
  10521. generateSerializeKey(nestedctx, no_left, keyInfo, lhsDsRef, false);
  10522. DatasetReference keyActiveRef(keyInfo.keyDataset, no_activetable, NULL);
  10523. HqlExprArray keyRequired;
  10524. appendArray(keyRequired, keyInfo.allKeyCompares);
  10525. keyRequired.trunc(joinInfo.numRequiredEqualities());
  10526. doCompareLeftRight(nestedctx, "CompareLeftKeyRightRow", keyActiveRef, rhsDsRef, keyRequired, joinInfo.queryRightReq());
  10527. }
  10528. }
  10529. else
  10530. {
  10531. if (extractSerializeKey(keyInfo, rhsDsRef, joinInfo.queryRightSort(), isGlobal))
  10532. {
  10533. generateSerializeKey(nestedctx, no_right, keyInfo, rhsDsRef, false);
  10534. DatasetReference keyActiveRef(keyInfo.keyDataset, no_activetable, NULL);
  10535. HqlExprArray keyRequired;
  10536. appendArray(keyRequired, keyInfo.allKeyCompares);
  10537. keyRequired.trunc(joinInfo.numRequiredEqualities());
  10538. doCompareLeftRight(nestedctx, "CompareRightKeyLeftRow", keyActiveRef, lhsDsRef, keyRequired, joinInfo.queryLeftReq());
  10539. }
  10540. }
  10541. }
  10542. }
  10543. StringBuffer flags;
  10544. if (excludeMatches) flags.append("|JFexclude");
  10545. if (isLeftOuter) flags.append("|JFleftouter");
  10546. if (isRightOuter) flags.append("|JFrightouter");
  10547. if (expr->hasAttribute(firstAtom)) flags.append("|JFfirst");
  10548. if (expr->hasAttribute(firstLeftAtom)) flags.append("|JFfirstleft");
  10549. if (expr->hasAttribute(firstRightAtom)) flags.append("|JFfirstright");
  10550. if (partitionRight) flags.append("|JFpartitionright");
  10551. if (expr->hasAttribute(parallelAtom)) flags.append("|JFparallel");
  10552. if (expr->hasAttribute(sequentialAtom)) flags.append("|JFsequential");
  10553. if (transformContainsSkip(transform))
  10554. flags.append("|JFtransformMaySkip");
  10555. if (rowlimit && rowlimit->hasAttribute(skipAtom))
  10556. flags.append("|JFmatchAbortLimitSkips");
  10557. if (rowlimit && rowlimit->hasAttribute(countAtom))
  10558. flags.append("|JFcountmatchabortlimit");
  10559. if (joinInfo.isSlidingJoin()) flags.append("|JFslidingmatch");
  10560. if (joinInfo.extraMatch) flags.append("|JFmatchrequired");
  10561. if (isLookupJoin && isManyLookup) flags.append("|JFmanylookup");
  10562. if (expr->hasAttribute(onFailAtom))
  10563. flags.append("|JFonfail");
  10564. if (!isOrdered(expr))
  10565. flags.append("|JFreorderable");
  10566. if (transformReturnsSide(expr, no_left, 0))
  10567. flags.append("|JFtransformmatchesleft");
  10568. if (joinInfo.hasOptionalEqualities())
  10569. flags.append("|JFlimitedprefixjoin");
  10570. if (isAlreadySorted(dataset1, joinInfo.queryLeftSort(), true, true, false) || userPreventsSort(noSortAttr, no_left))
  10571. flags.append("|JFleftSortedLocally");
  10572. if (isAlreadySorted(dataset2, joinInfo.queryRightSort(), true, true, false) || userPreventsSort(noSortAttr, no_right))
  10573. flags.append("|JFrightSortedLocally");
  10574. if (isSmartJoin) flags.append("|JFsmart|JFmanylookup");
  10575. if (isSmartJoin || expr->hasAttribute(unstableAtom))
  10576. flags.append("|JFunstable");
  10577. if (joinInfo.neverMatchSelf())
  10578. flags.append("|JFnevermatchself");
  10579. if (flags.length())
  10580. doBuildUnsignedFunction(instance->classctx, "getJoinFlags", flags.str()+1);
  10581. if (!isAllJoin)
  10582. {
  10583. buildSkewThresholdMembers(instance->classctx, expr);
  10584. if (!isZero(joinInfo.atmost.limit))
  10585. doBuildUnsignedFunction(instance->startctx, "getJoinLimit", joinInfo.atmost.limit);
  10586. }
  10587. if (keepLimit)
  10588. doBuildUnsignedFunction(instance->startctx, "getKeepLimit", keepLimit);
  10589. // The transform function is pretty standard - no need for copies here
  10590. switch (op)
  10591. {
  10592. case no_join:
  10593. case no_selfjoin:
  10594. case no_denormalize:
  10595. {
  10596. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned counter, unsigned flags)");
  10597. ensureRowAllocated(func.ctx, "crSelf");
  10598. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  10599. associateCounter(func.ctx, counter, "counter");
  10600. associateLocalJoinTransformFlags(func.ctx, "flags", dataset1, no_left, selSeq);
  10601. associateLocalJoinTransformFlags(func.ctx, "flags", dataset2, no_right, selSeq);
  10602. buildTransformBody(func.ctx, transform, dataset1, dataset2, instance->dataset, selSeq);
  10603. break;
  10604. }
  10605. case no_denormalizegroup:
  10606. {
  10607. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned numRows, const void * * _rows, unsigned flags)");
  10608. ensureRowAllocated(func.ctx, "crSelf");
  10609. associateLocalJoinTransformFlags(func.ctx, "flags", dataset1, no_left, selSeq);
  10610. associateLocalJoinTransformFlags(func.ctx, "flags", dataset2, no_right, selSeq);
  10611. func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
  10612. BoundRow * selfCursor = buildTransformCursors(func.ctx, transform, dataset1, dataset2, instance->dataset, selSeq);
  10613. bindRows(func.ctx, no_right, selSeq, expr->queryAttribute(_rowsid_Atom), dataset2, "numRows", "rows", options.mainRowsAreLinkCounted);
  10614. doBuildTransformBody(func.ctx, transform, selfCursor);
  10615. break;
  10616. }
  10617. }
  10618. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  10619. if (onFail)
  10620. {
  10621. MemberFunction func(*this, instance->startctx, "virtual size32_t onFailTransform(ARowBuilder & crSelf, const void * _left, const void * _right, IException * except, unsigned flags)");
  10622. ensureRowAllocated(func.ctx, "crSelf");
  10623. associateLocalFailure(func.ctx, "except");
  10624. associateLocalJoinTransformFlags(func.ctx, "flags", dataset1, no_left, selSeq);
  10625. associateLocalJoinTransformFlags(func.ctx, "flags", dataset2, no_right, selSeq);
  10626. buildTransformBody(func.ctx, onFail->queryChild(0), dataset1, dataset2, instance->dataset, selSeq);
  10627. }
  10628. // The collate function is used to work out which side to read from or if we have a potentially matching record
  10629. if (!isAllJoin)
  10630. {
  10631. //if left and right match, then leftright compare function is also the same
  10632. if (canReuseLeftCompare && !joinInfo.hasOptionalEqualities())
  10633. instance->nestedctx.addQuotedLiteral("virtual ICompare * queryCompareLeftRight() { return &compareLeft; }");
  10634. else
  10635. doCompareLeftRight(instance->nestedctx, "CompareLeftRight", lhsDsRef, rhsDsRef, joinInfo.queryLeftReq(), joinInfo.queryRightReq());
  10636. }
  10637. doBuildJoinRowLimitHelper(*instance, rowlimit, NULL, false);
  10638. //--function to clear left, used for right outer join and vice-versa
  10639. bool createDefaultRight = onFail || isLeftOuter;
  10640. if (isRightOuter)
  10641. buildClearRecordMember(instance->createctx, "Left", dataset1);
  10642. if (createDefaultRight)
  10643. buildClearRecordMember(instance->createctx, "Right", dataset2);
  10644. buildJoinMatchFunction(instance->startctx, "match", dataset1, dataset2, joinInfo.extraMatch, selSeq);
  10645. if (joinInfo.isSlidingJoin())
  10646. {
  10647. buildSlidingMatchFunction(instance->nestedctx, joinInfo.queryLeftSort(), joinInfo.queryRightSort(), joinInfo.slidingMatches, "CompareLeftRightLower", 1, lhsDsRef, rhsDsRef);
  10648. buildSlidingMatchFunction(instance->nestedctx, joinInfo.queryLeftSort(), joinInfo.queryRightSort(), joinInfo.slidingMatches, "CompareLeftRightUpper", 2, lhsDsRef, rhsDsRef);
  10649. }
  10650. if (isHashJoin||isLookupJoin|isSmartJoin)
  10651. {
  10652. OwnedHqlExpr leftList = createValueSafe(no_sortlist, makeSortListType(NULL), joinInfo.queryLeftReq());
  10653. buildHashOfExprsClass(instance->nestedctx, "HashLeft", leftList, lhsDsRef, false);
  10654. bool canReuseLeftHash = recordTypesMatch(dataset1, dataset2) && arraysMatch(joinInfo.queryLeftReq(), joinInfo.queryRightReq());
  10655. if (!canReuseLeftHash)
  10656. {
  10657. OwnedHqlExpr rightList = createValueSafe(no_sortlist, makeSortListType(NULL), joinInfo.queryRightReq());
  10658. buildHashOfExprsClass(instance->nestedctx, "HashRight", rightList, rhsDsRef, false);
  10659. }
  10660. else
  10661. instance->nestedctx.addQuotedLiteral("virtual IHash * queryHashRight() { return &HashLeft; }");
  10662. }
  10663. if (joinInfo.hasOptionalEqualities())
  10664. {
  10665. OwnedHqlExpr leftSelect = createSelector(no_left, dataset1, selSeq);
  10666. OwnedHqlExpr rightSelect = createSelector(no_right, dataset2, selSeq);
  10667. UnsignedArray origins;
  10668. unsigned origin = 0;
  10669. ForEachItemIn(i, joinInfo.queryLeftOpt())
  10670. {
  10671. IHqlExpression & left = joinInfo.queryLeftOpt().item(i);
  10672. IHqlExpression & right = joinInfo.queryRightOpt().item(i);
  10673. unsigned delta;
  10674. if (origin == UNKNOWN_LENGTH)
  10675. throwError(HQLERR_AtmostFollowUnknownSubstr);
  10676. if (isCommonSubstringRange(&left))
  10677. {
  10678. size32_t leftLen = getMaxSubstringLength(&left);
  10679. size32_t rightLen = getMaxSubstringLength(&right);
  10680. if (leftLen == rightLen)
  10681. delta = leftLen;
  10682. else
  10683. delta = UNKNOWN_LENGTH;
  10684. }
  10685. else
  10686. delta = 1;
  10687. origins.append(origin);
  10688. if (delta != UNKNOWN_LENGTH)
  10689. origin += delta;
  10690. else
  10691. origin = UNKNOWN_LENGTH;
  10692. }
  10693. OwnedHqlExpr compare;
  10694. OwnedITypeInfo retType = makeIntType(4, true);
  10695. OwnedHqlExpr zero = createConstant(retType->castFrom(true, 0));
  10696. ForEachItemInRev(i1, joinInfo.queryLeftOpt())
  10697. {
  10698. IHqlExpression & left = joinInfo.queryLeftOpt().item(i1);
  10699. IHqlExpression & right = joinInfo.queryRightOpt().item(i1);
  10700. unsigned origin = origins.item(i1);
  10701. if (isCommonSubstringRange(&left))
  10702. {
  10703. OwnedHqlExpr simpleLeft = getSimplifiedCommonSubstringRange(&left);
  10704. OwnedHqlExpr simpleRight = getSimplifiedCommonSubstringRange(&right);
  10705. HqlExprArray args;
  10706. args.append(*lhsDsRef.mapCompound(simpleLeft, leftSelect));
  10707. args.append(*rhsDsRef.mapCompound(simpleRight, rightSelect));
  10708. IIdAtom * func = prefixDiffStrId;
  10709. ITypeInfo * lhsType = args.item(0).queryType();
  10710. if (isUnicodeType(lhsType))
  10711. {
  10712. func = prefixDiffUnicodeId;
  10713. args.append(*createConstant(str(lhsType->queryLocale())));
  10714. }
  10715. args.append(*getSizetConstant(origin));
  10716. OwnedHqlExpr diff = bindFunctionCall(func, args);
  10717. if (compare)
  10718. {
  10719. OwnedHqlExpr alias = createAlias(diff, NULL);
  10720. OwnedHqlExpr compareNe = createValue(no_ne, makeBoolType(), LINK(alias), LINK(zero));
  10721. compare.setown(createValue(no_if, LINK(retType), compareNe.getClear(), LINK(alias), compare.getClear()));
  10722. }
  10723. else
  10724. compare.set(diff);
  10725. }
  10726. else
  10727. {
  10728. OwnedHqlExpr leftExpr = lhsDsRef.mapCompound(&left, leftSelect);
  10729. OwnedHqlExpr rightExpr = lhsDsRef.mapCompound(&right, rightSelect);
  10730. OwnedHqlExpr compareGt = createValue(no_gt, makeBoolType(), LINK(leftExpr), LINK(rightExpr));
  10731. OwnedHqlExpr gtValue = createConstant(retType->castFrom(true, origin+1));
  10732. OwnedHqlExpr ltValue = createConstant(retType->castFrom(true, -(int)(origin+1)));
  10733. OwnedHqlExpr mismatch = createValue(no_if, LINK(retType), compareGt.getClear(), gtValue.getClear(), ltValue.getClear());
  10734. OwnedHqlExpr compareNe = createValue(no_ne, makeBoolType(), LINK(leftExpr), LINK(rightExpr));
  10735. OwnedHqlExpr eqValue = compare ? LINK(compare) : LINK(zero);
  10736. compare.setown(createValue(no_if, LINK(retType), compareNe.getClear(), mismatch.getClear(), eqValue.getClear()));
  10737. origin += 1;
  10738. }
  10739. }
  10740. buildCompareMemberLR(instance->nestedctx, "PrefixCompare", compare, dataset1, dataset2, selSeq);
  10741. }
  10742. // buildCompareMemberLR(instance->nestedctx, "CompareLeftKeyRightRow", compare, dataset1, dataset2, selSeq);
  10743. buildInstanceSuffix(instance);
  10744. buildConnectInputOutput(ctx, instance, boundDataset1, 0, 0, boundDataset2 ? "LEFT" : NULL);
  10745. if (boundDataset2)
  10746. buildConnectInputOutput(ctx, instance, boundDataset2, 0, 1, "RIGHT");
  10747. return instance->getBoundActivity();
  10748. }
  10749. ABoundActivity * HqlCppTranslator::doBuildActivityJoin(BuildCtx & ctx, IHqlExpression * expr)
  10750. {
  10751. if (isKeyedJoin(expr))
  10752. return doBuildActivityKeyedJoinOrDenormalize(ctx, expr);
  10753. else
  10754. return doBuildActivityJoinOrDenormalize(ctx, expr);
  10755. }
  10756. //---------------------------------------------------------------------------
  10757. void HqlCppTranslator::doUserTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self)
  10758. {
  10759. node_operator transformOp = transform->getOperator();
  10760. assertex(transformOp == no_call || transformOp == no_externalcall);
  10761. //Ugly, but target selector is passed in as the target.expr. Should possibly have an extra parameter.
  10762. CHqlBoundTarget target;
  10763. target.expr.set(self->querySelector());
  10764. doBuildCall(ctx, &target, transform, NULL);
  10765. }
  10766. void HqlCppTranslator::doTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self)
  10767. {
  10768. HqlExprArray assigns;
  10769. IHqlExpression * record = self->queryRecord();
  10770. TransformBuilder builder(*this, ctx, record, self, assigns);
  10771. builder.doTransform(ctx, transform, self);
  10772. }
  10773. void HqlCppTranslator::doUpdateTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self, BoundRow * previous, bool alwaysNextRow)
  10774. {
  10775. HqlExprArray assigns;
  10776. IHqlExpression * record = self->queryRecord();
  10777. UpdateTransformBuilder builder(*this, ctx, record, self, previous->querySelector(), assigns, alwaysNextRow);
  10778. builder.doTransform(ctx, transform, self);
  10779. }
  10780. void HqlCppTranslator::doInlineTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * targetRow)
  10781. {
  10782. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, targetRow);
  10783. doTransform(ctx, transform, rowBuilder);
  10784. finalizeTempRow(ctx, targetRow, rowBuilder);
  10785. }
  10786. void HqlCppTranslator::precalculateFieldOffsets(BuildCtx & ctx, IHqlExpression * expr, BoundRow * cursor)
  10787. {
  10788. if (!cursor)
  10789. return;
  10790. if (isFixedRecordSize(cursor->queryRecord()))
  10791. return;
  10792. IHqlExpression * lastField;
  10793. IHqlExpression * selector = cursor->querySelector();
  10794. {
  10795. FieldAccessAnalyser analyser(selector);
  10796. analyser.analyse(expr, 0);
  10797. lastField = analyser.queryLastFieldAccessed();
  10798. }
  10799. if (!lastField)
  10800. return;
  10801. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(lastField));
  10802. Owned<IReferenceSelector> ref = buildReference(ctx, selected);
  10803. CHqlBoundExpr boundOffset;
  10804. ref->buildAddress(ctx, boundOffset);
  10805. }
  10806. BoundRow * HqlCppTranslator::buildTransformCursors(BuildCtx & ctx, IHqlExpression * transform, IHqlExpression * left, IHqlExpression * right, IHqlExpression * self, IHqlExpression * selSeq)
  10807. {
  10808. if (transform->getOperator() == no_skip)
  10809. return NULL;
  10810. assertRecordTypesMatch(self->queryRecord(), transform->queryRecord());
  10811. if (left)
  10812. ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  10813. if (right)
  10814. ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  10815. // Bind left to "left" and right to RIGHT
  10816. BoundRow * leftRow = NULL;
  10817. BoundRow * rightRow = NULL;
  10818. if (left)
  10819. leftRow = bindTableCursor(ctx, left, "left", no_left, selSeq);
  10820. if (right)
  10821. rightRow = bindTableCursor(ctx, right, "right", no_right, selSeq);
  10822. if (options.precalculateFieldOffsets)
  10823. {
  10824. precalculateFieldOffsets(ctx, transform, leftRow);
  10825. precalculateFieldOffsets(ctx, transform, rightRow);
  10826. }
  10827. return bindSelf(ctx, self, "crSelf");
  10828. }
  10829. void HqlCppTranslator::doBuildTransformBody(BuildCtx & ctx, IHqlExpression * transform, BoundRow * selfCursor)
  10830. {
  10831. if (transform->getOperator() == no_skip)
  10832. {
  10833. ctx.addReturn(queryZero());
  10834. return;
  10835. }
  10836. associateSkipReturnMarker(ctx, queryZero(), selfCursor);
  10837. doTransform(ctx, transform, selfCursor);
  10838. buildReturnRecordSize(ctx, selfCursor);
  10839. }
  10840. void HqlCppTranslator::buildTransformBody(BuildCtx & ctx, IHqlExpression * transform, IHqlExpression * left, IHqlExpression * right, IHqlExpression * self, IHqlExpression * selSeq)
  10841. {
  10842. BoundRow * selfCursor = buildTransformCursors(ctx, transform, left, right, self, selSeq);
  10843. doBuildTransformBody(ctx, transform, selfCursor);
  10844. }
  10845. void HqlCppTranslator::buildIterateTransformFunction(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * transform, IHqlExpression * counter, IHqlExpression * selSeq)
  10846. {
  10847. MemberFunction func(*this, ctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned __int64 counter)");
  10848. ensureRowAllocated(func.ctx, "crSelf");
  10849. associateCounter(func.ctx, counter, "counter");
  10850. buildTransformBody(func.ctx, transform, dataset, dataset, dataset, selSeq);
  10851. }
  10852. void HqlCppTranslator::buildRollupTransformFunction(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * transform, IHqlExpression * selSeq)
  10853. {
  10854. MemberFunction func(*this, ctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right)");
  10855. ensureRowAllocated(func.ctx, "crSelf");
  10856. buildTransformBody(func.ctx, transform, dataset, dataset, dataset, selSeq);
  10857. }
  10858. ABoundActivity * HqlCppTranslator::doBuildActivityIterate(BuildCtx & ctx, IHqlExpression * expr)
  10859. {
  10860. IHqlExpression * dataset = expr->queryChild(0);
  10861. IHqlExpression * transform = expr->queryChild(1);
  10862. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  10863. IHqlExpression * selSeq = querySelSeq(expr);
  10864. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  10865. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKiterate, expr, "Iterate");
  10866. buildActivityFramework(instance);
  10867. buildInstancePrefix(instance);
  10868. buildIterateTransformFunction(instance->startctx, dataset, transform, counter, selSeq);
  10869. buildClearRecordMember(instance->createctx, "", dataset);
  10870. if (transformContainsSkip(transform))
  10871. doBuildBoolFunction(instance->classctx, "canFilter", true);
  10872. buildInstanceSuffix(instance);
  10873. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  10874. return instance->getBoundActivity();
  10875. }
  10876. //---------------------------------------------------------------------------
  10877. IHqlExpression * HqlCppTranslator::queryExpandAliasScope(BuildCtx & ctx, IHqlExpression * expr)
  10878. {
  10879. for (;;)
  10880. {
  10881. switch (expr->getOperator())
  10882. {
  10883. case no_alias_scope:
  10884. expandAliasScope(ctx, expr);
  10885. expr = expr->queryChild(0);
  10886. break;
  10887. case no_compound:
  10888. buildStmt(ctx, expr->queryChild(0));
  10889. expr = expr->queryChild(1);
  10890. break;
  10891. default:
  10892. return expr;
  10893. }
  10894. }
  10895. }
  10896. void HqlCppTranslator::buildProcessTransformFunction(BuildCtx & ctx, IHqlExpression * expr)
  10897. {
  10898. IHqlExpression * dataset = expr->queryChild(0);
  10899. IHqlExpression * right = expr->queryChild(1);
  10900. IHqlExpression * transformRow = expr->queryChild(2);
  10901. IHqlExpression * transformRight = expr->queryChild(3);
  10902. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  10903. IHqlExpression * selSeq = querySelSeq(expr);
  10904. MemberFunction func(*this, ctx, "virtual size32_t transform(ARowBuilder & crSelf, ARowBuilder & crSelfRight, const void * _left, const void * _right, unsigned __int64 counter)");
  10905. associateCounter(func.ctx, counter, "counter");
  10906. if ((transformRow->getOperator() == no_skip) || (transformRight->getOperator() == no_skip))
  10907. {
  10908. func.ctx.addReturn(queryZero());
  10909. return;
  10910. }
  10911. ensureRowAllocated(func.ctx, "crSelf");
  10912. ensureRowAllocated(func.ctx, "crSelfRight");
  10913. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  10914. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  10915. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  10916. bindTableCursor(func.ctx, right, "right", no_right, selSeq);
  10917. LinkedHqlExpr skipReturnValue = queryZero();
  10918. associateSkipReturnMarker(func.ctx, skipReturnValue, NULL);
  10919. //Perform cse on both transforms
  10920. OwnedHqlExpr comma = createComma(LINK(transformRow), LINK(transformRight));
  10921. comma.setown(spotScalarCSE(comma, NULL, queryOptions().spotCseInIfDatasetConditions));
  10922. if (comma->getOperator() == no_alias_scope)
  10923. comma.set(comma->queryChild(0));
  10924. HqlExprArray unwound;
  10925. comma->unwindList(unwound, no_comma);
  10926. unsigned max = unwound.ordinality();
  10927. BoundRow * selfCursor = bindSelf(func.ctx, dataset, "crSelf");
  10928. BoundRow * selfRowCursor = bindSelf(func.ctx, right, "crSelfRight");
  10929. for (unsigned i=0; i<max-2; i++)
  10930. buildStmt(func.ctx, &unwound.item(i));
  10931. IHqlExpression * newTransformRow = queryExpandAliasScope(func.ctx, &unwound.item(max-2));
  10932. IHqlExpression * newTransformRight = queryExpandAliasScope(func.ctx, &unwound.item(max-1));
  10933. assertex(newTransformRow->getOperator() == no_transform && newTransformRight->getOperator() == no_transform);
  10934. doTransform(func.ctx, newTransformRow, selfCursor);
  10935. doTransform(func.ctx, newTransformRight, selfRowCursor);
  10936. buildReturnRecordSize(func.ctx, selfCursor);
  10937. }
  10938. ABoundActivity * HqlCppTranslator::doBuildActivityProcess(BuildCtx & ctx, IHqlExpression * expr)
  10939. {
  10940. IHqlExpression * dataset = expr->queryChild(0);
  10941. IHqlExpression * right = expr->queryChild(1);
  10942. IHqlExpression * transformRow = expr->queryChild(2);
  10943. IHqlExpression * transformRight = expr->queryChild(3);
  10944. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  10945. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKprocess, expr, "Process");
  10946. buildActivityFramework(instance);
  10947. buildInstancePrefix(instance);
  10948. buildMetaMember(instance->classctx, right->queryRecord(), false, "queryRightRecordSize");
  10949. {
  10950. MemberFunction func(*this, instance->startctx, "virtual size32_t createInitialRight(ARowBuilder & crSelf)");
  10951. ensureRowAllocated(func.ctx, "crSelf");
  10952. BoundRow * cursor = bindSelf(func.ctx, right, "crSelf");
  10953. Owned<IReferenceSelector> createdRef = createReferenceSelector(cursor);
  10954. buildRowAssign(func.ctx, createdRef, right);
  10955. buildReturnRecordSize(func.ctx, cursor);
  10956. }
  10957. buildProcessTransformFunction(instance->startctx, expr);
  10958. if (transformContainsSkip(transformRow) || transformContainsSkip(transformRight))
  10959. doBuildBoolFunction(instance->classctx, "canFilter", true);
  10960. buildInstanceSuffix(instance);
  10961. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  10962. return instance->getBoundActivity();
  10963. }
  10964. //---------------------------------------------------------------------------
  10965. ABoundActivity * HqlCppTranslator::doBuildActivitySelectNth(BuildCtx & ctx, IHqlExpression * expr)
  10966. {
  10967. IHqlExpression * dataset = expr->queryChild(0);
  10968. IHqlExpression * index = expr->queryChild(1);
  10969. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  10970. //If selecting 1st element of a non-grouped aggregate (which can only produce one row) then don't need to
  10971. //add the selectNth operator.
  10972. IHqlExpression * search = dataset;
  10973. if (hasSingleRow(dataset))
  10974. {
  10975. IValue * indexValue = index->queryValue();
  10976. if (indexValue && (indexValue->getIntValue() == 1))
  10977. {
  10978. //index first element - don't need to do anything...
  10979. //if x[n] is ever used as a dataset this assumption is invalid....
  10980. return LINK(boundDataset);
  10981. }
  10982. }
  10983. #if 0
  10984. //MORE: Should optimize left.child[1] and probably others - e.g., localresult[n]
  10985. switch (dataset->getOperator())
  10986. {
  10987. case no_select:
  10988. if (!isNewSelector(dataset))
  10989. return doBuildActivityChildDataset(ctx, expr);
  10990. break;
  10991. //MORE: What other selects are worth special casing?
  10992. }
  10993. #endif
  10994. bool useImplementationClass = options.minimizeActivityClasses && (index->getOperator() == no_constant);
  10995. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKselectn, expr, "SelectN");
  10996. if (useImplementationClass)
  10997. instance->setImplementationClass(newSelectNArgId);
  10998. buildActivityFramework(instance);
  10999. if (matchesConstantValue(index, 1))
  11000. instance->graphLabel.set("Select 1st");
  11001. buildInstancePrefix(instance);
  11002. if (!useImplementationClass)
  11003. {
  11004. MemberFunction func(*this, instance->startctx, "virtual unsigned __int64 getRowToSelect()");
  11005. buildReturn(func.ctx, index);
  11006. buildClearRecordMember(instance->createctx, "", dataset);
  11007. }
  11008. else
  11009. {
  11010. instance->addConstructorParameter(index);
  11011. OwnedHqlExpr func = getClearRecordFunction(dataset->queryRecord());
  11012. //This is a mess - pretend that the pointer to function parameter is a boolean
  11013. //The code generator really should have better support for classes etc.. One day...
  11014. OwnedHqlExpr fakeFunc = createValue(no_typetransfer, makeBoolType(), LINK(func));
  11015. OwnedHqlExpr translatedFakeFunc = createValue(no_translated, makeBoolType(), LINK(fakeFunc));
  11016. instance->addConstructorParameter(translatedFakeFunc);
  11017. }
  11018. buildInstanceSuffix(instance);
  11019. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  11020. return instance->getBoundActivity();
  11021. }
  11022. //---------------------------------------------------------------------------
  11023. void HqlCppTranslator::doBuildClearAggregateRecord(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * self, IHqlExpression * transform)
  11024. {
  11025. ForEachChild(i, record)
  11026. {
  11027. IHqlExpression * cur = record->queryChild(i);
  11028. switch (cur->getOperator())
  11029. {
  11030. case no_record:
  11031. doBuildClearAggregateRecord(ctx, cur, self, transform);
  11032. break;
  11033. case no_field:
  11034. {
  11035. OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(cur));
  11036. IHqlExpression * value = queryTransformAssignValue(transform, cur);
  11037. assertex(value);
  11038. if (value->isConstant())
  11039. buildAssign(ctx, target, value);
  11040. else
  11041. buildClear(ctx, target);
  11042. break;
  11043. }
  11044. case no_ifblock:
  11045. throwUnexpected();
  11046. }
  11047. }
  11048. }
  11049. void HqlCppTranslator::doBuildAggregateClearFunc(BuildCtx & ctx, IHqlExpression * expr)
  11050. {
  11051. IHqlExpression * tgtRecord = expr->queryChild(1);
  11052. IHqlExpression * transform = expr->queryChild(2);
  11053. MemberFunction func(*this, ctx, "virtual size32_t clearAggregate(ARowBuilder & crSelf)");
  11054. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  11055. BoundRow * selfRow = bindSelf(func.ctx, resultDataset, "crSelf");
  11056. if (!isKnownTransform(transform))
  11057. {
  11058. OwnedHqlExpr clearCall = createClearRowCall(func.ctx, selfRow);
  11059. func.ctx.addReturn(clearCall);
  11060. return;
  11061. }
  11062. ensureRowAllocated(func.ctx, "crSelf");
  11063. doBuildClearAggregateRecord(func.ctx, transform->queryRecord(), selfRow->querySelector(), transform);
  11064. buildReturnRecordSize(func.ctx, selfRow);
  11065. }
  11066. void HqlCppTranslator::doBuildAggregateFirstFunc(BuildCtx & ctx, IHqlExpression * expr)
  11067. {
  11068. IHqlExpression * dataset = expr->queryChild(0);
  11069. IHqlExpression * tgtRecord = expr->queryChild(1);
  11070. MemberFunction func(*this, ctx, "virtual size32_t processFirst(ARowBuilder & crSelf, const void * _src)");
  11071. ensureRowAllocated(func.ctx, "crSelf");
  11072. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  11073. //NOTE: no_throughaggregate recordof(expr) != tgtRecord => we need to create a temporary dataset
  11074. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  11075. BoundRow * selfRow = bindSelf(func.ctx, resultDataset, "crSelf");
  11076. bindTableCursor(func.ctx, dataset, "src");
  11077. doBuildAggregateProcessTransform(func.ctx, selfRow, expr, queryBoolExpr(false));
  11078. buildReturnRecordSize(func.ctx, selfRow);
  11079. }
  11080. void HqlCppTranslator::doBuildAggregateNextFunc(BuildCtx & ctx, IHqlExpression * expr)
  11081. {
  11082. IHqlExpression * dataset = expr->queryChild(0);
  11083. IHqlExpression * tgtRecord = expr->queryChild(1);
  11084. MemberFunction func(*this, ctx, "virtual size32_t processNext(ARowBuilder & crSelf, const void * _src)");
  11085. //no need ensureRowAllocated(func.ctx, "crSelf");
  11086. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  11087. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  11088. BoundRow * selfRow = bindSelf(func.ctx, resultDataset, "crSelf");
  11089. bindTableCursor(func.ctx, dataset, "src");
  11090. doBuildAggregateProcessTransform(func.ctx, selfRow, expr, queryBoolExpr(true));
  11091. buildReturnRecordSize(func.ctx, selfRow);
  11092. }
  11093. void HqlCppTranslator::doBuildAggregateProcessTransform(BuildCtx & ctx, BoundRow * selfRow, IHqlExpression * expr, IHqlExpression * alreadyDoneExpr)
  11094. {
  11095. bool alwaysFirstRow = matchesBoolean(alreadyDoneExpr, false);
  11096. bool alwaysNextRow = matchesBoolean(alreadyDoneExpr, true);
  11097. OwnedHqlExpr notAlreadyDone = getInverse(alreadyDoneExpr);
  11098. IHqlExpression * transform = expr->queryChild(2);
  11099. unsigned numAggregates = transform->numChildren();
  11100. unsigned idx;
  11101. bool isVariableOffset = false;
  11102. bool isDynamicOffset = false;
  11103. OwnedHqlExpr self = getSelf(expr->queryChild(1));
  11104. for (idx = 0; idx < numAggregates; idx++)
  11105. {
  11106. IHqlExpression * cur = transform->queryChild(idx);
  11107. if (cur->isAttribute())
  11108. continue;
  11109. OwnedHqlExpr target = selfRow->bindToRow(cur->queryChild(0), self);
  11110. IHqlExpression * src = cur->queryChild(1);
  11111. IHqlExpression * arg = src->queryChild(0);
  11112. IHqlExpression * cond = queryRealChild(src, 1);
  11113. BuildCtx condctx(ctx);
  11114. node_operator srcOp = src->getOperator();
  11115. switch (srcOp)
  11116. {
  11117. case no_countgroup:
  11118. {
  11119. //This could be supported in more situations - e.g. if always/neverFirstRow.
  11120. if (arg && isVariableOffset)
  11121. throwError1(HQLERR_ConditionalAggregateVarOffset, str(target->queryChild(1)->queryId()));
  11122. if (arg)
  11123. buildFilter(condctx, arg);
  11124. OwnedHqlExpr one = createConstant(createIntValue(1,8,true));
  11125. if (alwaysFirstRow)
  11126. {
  11127. buildAssign(condctx, target, one);
  11128. }
  11129. else
  11130. {
  11131. if (!alwaysNextRow && isVariableOffset)
  11132. {
  11133. IHqlStmt * ifStmt = condctx.addFilter(notAlreadyDone);
  11134. buildAssign(condctx, target, one);
  11135. condctx.selectElse(ifStmt);
  11136. }
  11137. buildIncrementAssign(condctx, target, one);
  11138. }
  11139. }
  11140. break;
  11141. case no_sumgroup:
  11142. {
  11143. if (cond && isVariableOffset)
  11144. throwError1(HQLERR_ConditionalAggregateVarOffset, str(target->queryChild(1)->queryId()));
  11145. if (cond)
  11146. buildFilter(condctx, cond);
  11147. if (alwaysFirstRow)
  11148. {
  11149. buildAssign(condctx, target, arg);
  11150. }
  11151. else
  11152. {
  11153. if (!alwaysNextRow && isVariableOffset)
  11154. {
  11155. IHqlStmt * ifStmt = condctx.addFilter(notAlreadyDone);
  11156. buildAssign(condctx, target, arg);
  11157. condctx.selectElse(ifStmt);
  11158. }
  11159. OwnedITypeInfo type = getPromotedECLType(target->queryType(), arg->queryType());
  11160. buildIncrementAssign(condctx, target, arg);
  11161. }
  11162. }
  11163. break;
  11164. case no_maxgroup:
  11165. case no_mingroup:
  11166. {
  11167. node_operator compareOp = (srcOp == no_maxgroup) ? no_gt : no_lt;
  11168. assertex(!cond);
  11169. OwnedHqlExpr castArg = ensureExprType(arg, target->queryType()); // cast to correct type, assume it can fit in the target type.
  11170. if (!alwaysFirstRow)
  11171. {
  11172. castArg.setown(buildSimplifyExpr(condctx, castArg));
  11173. OwnedHqlExpr compare = createBoolExpr (compareOp, LINK(castArg), LINK(target));
  11174. if (!alwaysNextRow)
  11175. compare.setown(createBoolExpr(no_or, LINK(notAlreadyDone), LINK(compare)));
  11176. buildFilter(condctx, compare);
  11177. }
  11178. buildAssign(condctx, target, castArg);
  11179. }
  11180. break;
  11181. case no_existsgroup:
  11182. if (arg && isVariableOffset)
  11183. throwError1(HQLERR_ConditionalAggregateVarOffset, str(target->queryChild(1)->queryId()));
  11184. cond = arg;
  11185. if (cond || !alwaysNextRow)
  11186. {
  11187. //The assign is conditional because unconditionally it is done in the AggregateFirst
  11188. if (cond)
  11189. buildFilter(condctx, cond);
  11190. buildAssign(condctx, target, queryBoolExpr(true));
  11191. }
  11192. break;
  11193. default:
  11194. if (!src->isConstant() || isVariableOffset)
  11195. {
  11196. if (!alwaysNextRow)
  11197. {
  11198. if (!alwaysFirstRow)
  11199. buildFilter(condctx, notAlreadyDone);
  11200. buildAssign(condctx, target, src);
  11201. }
  11202. }
  11203. break;
  11204. }
  11205. if (isDynamicOffset)
  11206. throwError1(HQLERR_AggregateDynamicOffset, str(target->queryChild(1)->queryId()));
  11207. if (target->queryType()->getSize() == UNKNOWN_LENGTH)
  11208. {
  11209. isVariableOffset = true;
  11210. if (src->isGroupAggregateFunction())
  11211. isDynamicOffset = true;
  11212. }
  11213. }
  11214. }
  11215. void HqlCppTranslator::doBuildAggregateMergeFunc(BuildCtx & ctx, IHqlExpression * expr, bool & requiresOrderedMerge)
  11216. {
  11217. if (expr->getOperator() == no_aggregate)
  11218. {
  11219. OwnedHqlExpr mergeTransform = getUserAggregateMergeTransform(expr, requiresOrderedMerge);
  11220. doBuildUserMergeAggregateFunc(ctx, expr, mergeTransform);
  11221. return;
  11222. }
  11223. IHqlExpression * tgtRecord = expr->queryChild(1);
  11224. IHqlExpression * transform = expr->queryChild(2);
  11225. requiresOrderedMerge = false;
  11226. OwnedHqlExpr selSeq = createDummySelectorSequence();
  11227. MemberFunction func(*this, ctx, "virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * _right)");
  11228. //ensureRowAllocated(func.ctx, "crSelf"); must be non null
  11229. func.ctx.addQuotedLiteral("unsigned char * right = (unsigned char *) _right;");
  11230. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  11231. BoundRow * selfRow = bindSelf(func.ctx, resultDataset, "crSelf");
  11232. BoundRow * rightCursor = bindTableCursor(func.ctx, resultDataset, "right", no_right, selSeq);
  11233. unsigned numAggregates = transform->numChildren();
  11234. unsigned idx;
  11235. IHqlExpression * right = rightCursor->querySelector();
  11236. OwnedHqlExpr self = getSelf(tgtRecord);
  11237. for (idx = 0; idx < numAggregates; idx++)
  11238. {
  11239. IHqlExpression * cur = transform->queryChild(idx);
  11240. if (cur->isAttribute())
  11241. continue;
  11242. OwnedHqlExpr target = selfRow->bindToRow(cur->queryChild(0), self);
  11243. OwnedHqlExpr src = replaceSelector(cur->queryChild(0), self, right);
  11244. IHqlExpression * op = cur->queryChild(1);
  11245. //MORE: How bind cursors...
  11246. switch (op->getOperator())
  11247. {
  11248. case no_countgroup:
  11249. case no_sumgroup:
  11250. {
  11251. buildIncrementAssign(func.ctx, target, src);
  11252. }
  11253. break;
  11254. case no_maxgroup:
  11255. {
  11256. OwnedHqlExpr compare = createBoolExpr (no_gt, LINK(src), LINK(target));
  11257. BuildCtx filteredctx(func.ctx);
  11258. buildFilter(filteredctx, compare);
  11259. buildAssign(filteredctx, target, src);
  11260. }
  11261. break;
  11262. case no_mingroup:
  11263. {
  11264. OwnedHqlExpr compare = createBoolExpr (no_lt, LINK(src), LINK(target));
  11265. BuildCtx filteredctx(func.ctx);
  11266. buildFilter(filteredctx, compare);
  11267. buildAssign(filteredctx, target, src);
  11268. }
  11269. break;
  11270. case no_existsgroup:
  11271. {
  11272. BuildCtx condctx(func.ctx);
  11273. buildFilter(condctx, src);
  11274. buildAssign(condctx, target, queryBoolExpr(true));
  11275. break;
  11276. }
  11277. default:
  11278. //already filled in and wouldn't be legal to have an expression in this case anyway...
  11279. break;
  11280. }
  11281. }
  11282. buildReturnRecordSize(func.ctx, selfRow);
  11283. }
  11284. //--------------------------------------------------------------------------------------
  11285. // User aggregate helpers
  11286. //--------------------------------------------------------------------------------------
  11287. void HqlCppTranslator::doBuildUserAggregateProcessTransform(BuildCtx & ctx, BoundRow * selfRow, IHqlExpression * expr, IHqlExpression * transform, IHqlExpression * alreadyDoneExpr)
  11288. {
  11289. bool alwaysFirstRow = matchesBoolean(alreadyDoneExpr, false);
  11290. bool alwaysNextRow = matchesBoolean(alreadyDoneExpr, true);
  11291. OwnedHqlExpr right = createSelector(no_right, expr, querySelSeq(expr));
  11292. bool usesRight = exprReferencesDataset(transform, right);
  11293. BuildCtx condctx(ctx);
  11294. if (!isKnownTransform(transform))
  11295. {
  11296. if (!alwaysNextRow)
  11297. {
  11298. IHqlStmt * ifStmt = NULL;
  11299. if (!alwaysFirstRow)
  11300. ifStmt = condctx.addFilter(alreadyDoneExpr);
  11301. if (usesRight)
  11302. {
  11303. CHqlBoundExpr boundNullRow;
  11304. buildDefaultRow(condctx, transform, boundNullRow);
  11305. bindTableCursor(condctx, transform->queryRecord(), boundNullRow.expr, no_right, querySelSeq(expr));
  11306. }
  11307. doUserTransform(condctx, transform, selfRow);
  11308. if (ifStmt)
  11309. condctx.selectElse(ifStmt);
  11310. }
  11311. if (!alwaysFirstRow)
  11312. {
  11313. if (usesRight)
  11314. bindTableCursor(condctx, transform->queryRecord(), selfRow->queryBound(), no_right, querySelSeq(expr));
  11315. doUserTransform(condctx, transform, selfRow);
  11316. }
  11317. }
  11318. else
  11319. {
  11320. if (usesRight)
  11321. {
  11322. BoundRow * rightCursor;
  11323. if (alwaysNextRow)
  11324. rightCursor = bindTableCursor(condctx, transform->queryRecord(), selfRow->queryBound(), no_right, querySelSeq(expr));
  11325. else
  11326. {
  11327. CHqlBoundExpr boundNullRow;
  11328. buildDefaultRow(condctx, transform, boundNullRow);
  11329. if (alwaysFirstRow)
  11330. {
  11331. //MORE: Only do this (and create default row) if transform refers to RIGHT...
  11332. rightCursor = bindTableCursor(condctx, transform->queryRecord(), boundNullRow.expr, no_right, querySelSeq(expr));
  11333. }
  11334. else
  11335. {
  11336. //create a temporary
  11337. Owned<ITypeInfo> rowType = makeReferenceModifier(expr->getType());
  11338. OwnedHqlExpr rowExpr = ctx.getTempDeclare(rowType, NULL);
  11339. OwnedHqlExpr defaultRowPtr = getPointer(boundNullRow.expr);
  11340. OwnedHqlExpr condRow = createValue(no_if, LINK(rowType), LINK(alreadyDoneExpr), LINK(selfRow->queryBound()), LINK(defaultRowPtr));
  11341. condctx.addAssign(rowExpr, condRow);
  11342. rightCursor = bindTableCursor(condctx, transform->queryRecord(), rowExpr, no_right, querySelSeq(expr));
  11343. }
  11344. }
  11345. if (alwaysFirstRow)
  11346. doTransform(condctx, transform, selfRow);
  11347. else
  11348. doUpdateTransform(condctx, transform, selfRow, rightCursor, alwaysNextRow);
  11349. }
  11350. else
  11351. doTransform(condctx, transform, selfRow);
  11352. }
  11353. }
  11354. //------------------------------------------------------------------------------------------------
  11355. static bool matchesSelect(IHqlExpression * expr, IHqlExpression * selector, IHqlExpression * field)
  11356. {
  11357. if (isCast(expr))
  11358. {
  11359. ITypeInfo * afterType = expr->queryType();
  11360. ITypeInfo * beforeType = expr->queryChild(0)->queryType();
  11361. if (preservesValue(afterType, beforeType))
  11362. expr = expr->queryChild(0);
  11363. else if (beforeType->isInteger() && afterType->isInteger() && beforeType->getSize() == afterType->getSize())
  11364. expr = expr->queryChild(0);
  11365. }
  11366. if (expr->getOperator() != no_select)
  11367. return false;
  11368. if (expr->queryChild(0) != selector)
  11369. return false;
  11370. if (expr->queryChild(1) != field)
  11371. return false;
  11372. return true;
  11373. }
  11374. //MORE: Derive a merge transform by walking and spotting self.x := self.x := right.x op a or a op right.x
  11375. class MergeTransformCreator
  11376. {
  11377. public:
  11378. MergeTransformCreator(IHqlExpression * expr)
  11379. {
  11380. IHqlExpression * dataset = expr->queryChild(0);
  11381. IHqlExpression * selSeq = querySelSeq(expr);
  11382. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  11383. self.setown(getSelf(expr));
  11384. left.setown(createSelector(no_left, dataset, selSeq));
  11385. right.setown(createSelector(no_right, expr, selSeq));
  11386. mergeLeft.set(right);
  11387. OwnedHqlExpr rows = createDataset(no_rows, LINK(right), LINK(rowsid));
  11388. mergeRight.setown(createRow(no_selectnth, LINK(rows), createConstant(2)));
  11389. requiresOrderedMerge = false;
  11390. }
  11391. IHqlExpression * transform(IHqlExpression * expr);
  11392. inline bool isOrdered() { return requiresOrderedMerge; }
  11393. protected:
  11394. IHqlExpression * transformAssign(IHqlExpression * expr);
  11395. protected:
  11396. OwnedHqlExpr self;
  11397. OwnedHqlExpr left;
  11398. OwnedHqlExpr right;
  11399. OwnedHqlExpr mergeLeft;
  11400. OwnedHqlExpr mergeRight;
  11401. bool requiresOrderedMerge;
  11402. };
  11403. //self.x := right.x append|concat f() -> self.x := right.x <op> rows(right)[2].x
  11404. //self.x := f() append|concat right.x -> self.x := rows(right)[2].x <op> right.x
  11405. //self.x := right.x [+|band|bor|max|min|xor] f() -> self.x := right.x <op> rows(right)[2].x
  11406. //self.x := f() [+|band|bor|max|min|xor] right.x -> self.x := right.x <op> rows(right)[2].x
  11407. IHqlExpression * MergeTransformCreator::transformAssign(IHqlExpression * expr)
  11408. {
  11409. IHqlExpression * lhs = expr->queryChild(0);
  11410. IHqlExpression * rhs = expr->queryChild(1);
  11411. IHqlExpression * field = lhs->queryChild(1);
  11412. bool commutative = true;
  11413. node_operator op = rhs->getOperator();
  11414. HqlExprArray args;
  11415. switch (op)
  11416. {
  11417. case no_concat:
  11418. case no_addfiles:
  11419. commutative = false;
  11420. rhs->unwindList(args, op);
  11421. break;
  11422. case no_add:
  11423. case no_band:
  11424. case no_bor:
  11425. case no_bxor:
  11426. case no_mul:
  11427. rhs->unwindList(args, op);
  11428. break;
  11429. case no_sumlist:
  11430. case no_maxlist:
  11431. case no_minlist:
  11432. {
  11433. IHqlExpression * list = rhs->queryChild(0);
  11434. if (list->getOperator() != no_list)
  11435. return NULL;
  11436. unwindChildren(args, list);
  11437. break;
  11438. }
  11439. default:
  11440. //ok, if it is only assigned once.
  11441. if (exprReferencesDataset(rhs, right))
  11442. return NULL;
  11443. //need to preserve the value if at a variable offset... Should be stripped if unnecessary
  11444. OwnedHqlExpr newRhs = createSelectExpr(LINK(mergeLeft), LINK(field));
  11445. return createAssign(LINK(lhs), newRhs.getClear());
  11446. }
  11447. unsigned matchPos = NotFound;
  11448. ForEachItemIn(i, args)
  11449. {
  11450. IHqlExpression & cur = args.item(i);
  11451. if (exprReferencesDataset(&cur, right))
  11452. {
  11453. if ((matchPos == NotFound) && matchesSelect(&cur, right, field))
  11454. matchPos = i;
  11455. else
  11456. return NULL;
  11457. }
  11458. }
  11459. if (matchPos == NotFound)
  11460. return NULL;
  11461. if (!commutative)
  11462. requiresOrderedMerge = true;
  11463. HqlExprArray newArgs;
  11464. if (commutative || (matchPos == 0))
  11465. {
  11466. newArgs.append(*createSelectExpr(LINK(mergeLeft), LINK(field)));
  11467. newArgs.append(*createSelectExpr(LINK(mergeRight), LINK(field)));
  11468. }
  11469. else if (matchPos == args.ordinality() - 1)
  11470. {
  11471. newArgs.append(*createSelectExpr(LINK(mergeRight), LINK(field)));
  11472. newArgs.append(*createSelectExpr(LINK(mergeLeft), LINK(field)));
  11473. }
  11474. if (newArgs.ordinality())
  11475. {
  11476. switch (op)
  11477. {
  11478. case no_sumlist:
  11479. case no_minlist:
  11480. case no_maxlist:
  11481. {
  11482. OwnedHqlExpr list = rhs->queryChild(0)->clone(newArgs);
  11483. newArgs.kill();
  11484. newArgs.append(*list.getClear());
  11485. break;
  11486. }
  11487. }
  11488. return createAssign(LINK(lhs), rhs->clone(newArgs));
  11489. }
  11490. return NULL;
  11491. }
  11492. IHqlExpression * MergeTransformCreator::transform(IHqlExpression * expr)
  11493. {
  11494. HqlExprArray children;
  11495. ForEachChild(i, expr)
  11496. {
  11497. IHqlExpression * cur = expr->queryChild(i);
  11498. OwnedHqlExpr mapped;
  11499. switch (cur->getOperator())
  11500. {
  11501. case no_assign:
  11502. mapped.setown(transformAssign(cur));
  11503. if (!mapped)
  11504. return NULL;
  11505. break;
  11506. case no_assignall:
  11507. mapped.setown(transform(cur));
  11508. if (!mapped)
  11509. return NULL;
  11510. break;
  11511. case no_alias_scope:
  11512. //Not so sure - there shouldn't be any at this point... Maybe we should allow...
  11513. return NULL;
  11514. case no_assert:
  11515. case no_skip:
  11516. return NULL;
  11517. case no_attr:
  11518. case no_attr_link:
  11519. case no_attr_expr:
  11520. break;
  11521. default:
  11522. UNIMPLEMENTED;
  11523. }
  11524. if (mapped)
  11525. children.append(*mapped.getClear());
  11526. }
  11527. return expr->clone(children);
  11528. }
  11529. //------------------------------------------------------------------------------------------------
  11530. // Replace SELF.x := F(LEFT) with SELF.x := RIGHT.x.
  11531. //i) To ensure the first value is always used and
  11532. //ii) to allow subsequent optimizations to remove the assignment
  11533. class NextTransformCreator
  11534. {
  11535. public:
  11536. NextTransformCreator(IHqlExpression * expr)
  11537. {
  11538. IHqlExpression * dataset = expr->queryChild(0);
  11539. IHqlExpression * selSeq = querySelSeq(expr);
  11540. self.setown(getSelf(expr));
  11541. left.setown(createSelector(no_left, dataset, selSeq));
  11542. right.setown(createSelector(no_right, expr, selSeq));
  11543. }
  11544. IHqlExpression * transform(IHqlExpression * expr);
  11545. protected:
  11546. IHqlExpression * transformAssign(IHqlExpression * expr);
  11547. protected:
  11548. OwnedHqlExpr self;
  11549. OwnedHqlExpr left;
  11550. OwnedHqlExpr right;
  11551. };
  11552. IHqlExpression * NextTransformCreator::transformAssign(IHqlExpression * expr)
  11553. {
  11554. IHqlExpression * lhs = expr->queryChild(0);
  11555. IHqlExpression * rhs = expr->queryChild(1);
  11556. IHqlExpression * field = lhs->queryChild(1);
  11557. if (!rhs->isConstant() && !exprReferencesDataset(rhs, right))
  11558. {
  11559. OwnedHqlExpr newRhs = createSelectExpr(LINK(right), LINK(field));
  11560. return createAssign(LINK(lhs), newRhs.getClear());
  11561. }
  11562. return LINK(expr);
  11563. }
  11564. IHqlExpression * NextTransformCreator::transform(IHqlExpression * expr)
  11565. {
  11566. HqlExprArray children;
  11567. ForEachChild(i, expr)
  11568. {
  11569. IHqlExpression * cur = expr->queryChild(i);
  11570. OwnedHqlExpr mapped = LINK(cur);
  11571. switch (cur->getOperator())
  11572. {
  11573. case no_assign:
  11574. mapped.setown(transformAssign(cur));
  11575. break;
  11576. case no_assignall:
  11577. mapped.setown(transform(cur));
  11578. break;
  11579. }
  11580. children.append(*mapped.getClear());
  11581. }
  11582. return expr->clone(children);
  11583. }
  11584. //------------------------------------------------------------------------------------------------
  11585. void HqlCppTranslator::processUserAggregateTransform(IHqlExpression * expr, IHqlExpression * transform, SharedHqlExpr & firstTransform, SharedHqlExpr & nextTransform)
  11586. {
  11587. if (isKnownTransform(transform))
  11588. {
  11589. OwnedHqlExpr right = createSelector(no_right, expr, querySelSeq(expr));
  11590. OwnedHqlExpr nullRow = createRow(no_newrow, createRow(no_null, LINK(expr->queryRecord())));
  11591. firstTransform.setown(replaceSelector(transform, right, nullRow));
  11592. firstTransform.setown(foldHqlExpression(firstTransform));
  11593. }
  11594. else
  11595. firstTransform.set(transform);
  11596. if (isKnownTransform(transform))
  11597. {
  11598. {
  11599. NextTransformCreator builder(expr);
  11600. nextTransform.setown(builder.transform(transform));
  11601. }
  11602. }
  11603. else
  11604. nextTransform.set(transform);
  11605. }
  11606. IHqlExpression * HqlCppTranslator::getUserAggregateMergeTransform(IHqlExpression * expr, bool & requiresOrderedMerge)
  11607. {
  11608. IHqlExpression * mergeTransform = queryAttributeChild(expr, mergeTransformAtom, 0);
  11609. if (mergeTransform)
  11610. {
  11611. requiresOrderedMerge = true;
  11612. return LINK(mergeTransform);
  11613. }
  11614. IHqlExpression * transform = expr->queryChild(2);
  11615. if (!isKnownTransform(transform))
  11616. return NULL;
  11617. MergeTransformCreator builder(expr);
  11618. OwnedHqlExpr ret = builder.transform(transform);
  11619. requiresOrderedMerge = builder.isOrdered();
  11620. return ret.getClear();
  11621. }
  11622. void HqlCppTranslator::doBuildUserMergeAggregateFunc(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * mergeTransform)
  11623. {
  11624. IHqlExpression * selSeq = querySelSeq(expr);
  11625. if (!mergeTransform)
  11626. throwError(HQLERR_AggregateNeedMergeTransform);
  11627. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  11628. MemberFunction func(*this, ctx, "virtual size32_t mergeAggregate(ARowBuilder & upRight1, const void * _right2)");
  11629. func.ctx.addQuotedLiteral("unsigned char * right2 = (unsigned char *) _right2;");
  11630. BoundRow * rightCursor = bindTableCursor(func.ctx, expr, "upRight1.row()", no_right, selSeq);
  11631. BoundRow * leftCursor = bindTableCursor(func.ctx, expr, "right2", no_left, selSeq);
  11632. BoundRow * selfCursor = bindSelf(func.ctx, expr, "upRight1");
  11633. //Ugly!! RIGHT:2 is represented as ROWS(RIGHT)[2]. Change it to no_left since it will make like cleaner
  11634. //If we fail to replace all references then fall back to the worse case generation
  11635. OwnedHqlExpr rows = createDataset(no_rows, LINK(rightCursor->querySelector()), LINK(rowsid));
  11636. OwnedHqlExpr complexRight1 = createRow(no_selectnth, LINK(rows), createConstant(1));
  11637. OwnedHqlExpr complexRight2 = createRow(no_selectnth, LINK(rows), createConstant(2));
  11638. OwnedHqlExpr mappedTransform1 = removeAnnotations(mergeTransform, rows);
  11639. OwnedHqlExpr mappedTransform2 = replaceExpression(mappedTransform1, complexRight1, rightCursor->querySelector());
  11640. OwnedHqlExpr mappedTransform3 = replaceExpression(mappedTransform2, complexRight2, leftCursor->querySelector());
  11641. if (containsExpression(mappedTransform3, rows))
  11642. {
  11643. //Worse case fallback behaviour. Shouldn't occur in practice.
  11644. //If ROWS() really is needed due to some weird expression then we need to clone the target/RIGHT1 row because
  11645. //any modification may cause it to relocate and so invalidate the pointer passed in.
  11646. IHqlExpression * leftBound = leftCursor->queryBound();
  11647. ITypeInfo * rowType = leftBound->queryType();
  11648. CHqlBoundExpr boundRow1;
  11649. buildTempExpr(func.ctx, rightCursor->querySelector(), boundRow1);
  11650. OwnedHqlExpr rows = createVariable("rows", makeArrayType(LINK(rowType), 2));
  11651. OwnedHqlExpr initializer = createValue(no_list, makeSetType(LINK(rowType)), LINK(boundRow1.expr), LINK(leftBound));
  11652. func.ctx.addDeclare(rows, initializer);
  11653. bindRows(func.ctx, no_right, selSeq, rowsid, expr, "2", "rows", options.mainRowsAreLinkCounted);
  11654. }
  11655. doUpdateTransform(func.ctx, mappedTransform3, selfCursor, rightCursor, true);
  11656. buildReturnRecordSize(func.ctx, selfCursor);
  11657. }
  11658. void HqlCppTranslator::doBuildUserAggregateFuncs(BuildCtx & ctx, IHqlExpression * expr, bool & requiresOrderedMerge)
  11659. {
  11660. IHqlExpression * dataset = expr->queryChild(0);
  11661. IHqlExpression * transform = expr->queryChild(2);
  11662. IHqlExpression * selSeq = querySelSeq(expr);
  11663. LinkedHqlExpr firstTransform;
  11664. LinkedHqlExpr nextTransform;
  11665. processUserAggregateTransform(expr, transform, firstTransform, nextTransform);
  11666. {
  11667. MemberFunction func(*this, ctx, "virtual size32_t processFirst(ARowBuilder & crSelf, const void * _src)");
  11668. ensureRowAllocated(func.ctx, "crSelf");
  11669. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  11670. BoundRow * selfRow = bindSelf(func.ctx, expr, "crSelf");
  11671. bindTableCursor(func.ctx, dataset, "src", options.mainRowsAreLinkCounted, no_left, selSeq);
  11672. doBuildUserAggregateProcessTransform(func.ctx, selfRow, expr, firstTransform, queryBoolExpr(false));
  11673. buildReturnRecordSize(func.ctx, selfRow);
  11674. }
  11675. {
  11676. MemberFunction func(*this, ctx, "virtual size32_t processNext(ARowBuilder & crSelf, const void * _src)");
  11677. ensureRowAllocated(func.ctx, "crSelf");
  11678. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  11679. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  11680. bindTableCursor(func.ctx, dataset, "src", options.mainRowsAreLinkCounted, no_left, selSeq);
  11681. bindTableCursor(func.ctx, expr, "crSelf.row()", no_right, selSeq);
  11682. doBuildUserAggregateProcessTransform(func.ctx, selfCursor, expr, nextTransform, queryBoolExpr(true));
  11683. buildReturnRecordSize(func.ctx, selfCursor);
  11684. }
  11685. if (targetThor() && !isGrouped(dataset) && !expr->hasAttribute(localAtom))
  11686. {
  11687. OwnedHqlExpr mergeTransform = getUserAggregateMergeTransform(expr, requiresOrderedMerge);
  11688. doBuildUserMergeAggregateFunc(ctx, expr, mergeTransform);
  11689. }
  11690. }
  11691. //--------------------------------------------------------------------------------------
  11692. void getMappedFields(HqlExprArray & aggregateFields, IHqlExpression * transform, HqlExprArray & recordFields, IHqlExpression * newSelector)
  11693. {
  11694. unsigned numFields = transform->numChildren();
  11695. OwnedHqlExpr self = getSelf(transform);
  11696. ForEachItemIn(idx, recordFields)
  11697. {
  11698. IHqlExpression & cur = recordFields.item(idx);
  11699. unsigned fieldIdx;
  11700. for (fieldIdx = 0; fieldIdx < numFields; fieldIdx++)
  11701. {
  11702. IHqlExpression * curAssign = transform->queryChild(fieldIdx);
  11703. IHqlExpression * rhs = curAssign->queryChild(1);
  11704. if (rhs->getOperator() == no_activerow)
  11705. rhs = rhs->queryChild(0);
  11706. if (rhs == &cur)
  11707. {
  11708. aggregateFields.append(*replaceSelector(curAssign->queryChild(0), self, newSelector));
  11709. break;
  11710. }
  11711. }
  11712. if (fieldIdx == numFields)
  11713. {
  11714. StringBuffer s;
  11715. getExprECL(&cur, s);
  11716. throwError1(HQLERR_AggregateMissingGroupingFields, s.str());
  11717. }
  11718. }
  11719. }
  11720. ABoundActivity * HqlCppTranslator::doBuildActivityAggregate(BuildCtx & ctx, IHqlExpression * expr)
  11721. {
  11722. IHqlExpression * dataset = expr->queryChild(0);
  11723. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  11724. node_operator op = expr->getOperator();
  11725. IHqlExpression * transform = expr->queryChild(2);
  11726. LinkedHqlExpr grouping = queryRealChild(expr, 3);
  11727. bool passThrough = (op == no_throughaggregate);
  11728. if (passThrough)
  11729. grouping.clear();
  11730. unsigned tableType = dataset->queryType()->getTypeCode();
  11731. const char *activity;
  11732. ThorActivityKind kind = TAKaggregate;
  11733. node_operator specialOp = no_none;
  11734. IIdAtom * implementationClassId = NULL;
  11735. if (passThrough)
  11736. {
  11737. activity = "ThroughAggregate";
  11738. kind = TAKthroughaggregate;
  11739. }
  11740. else if (grouping)
  11741. {
  11742. activity = "HashAggregate";
  11743. kind = TAKhashaggregate;
  11744. }
  11745. else if (targetThor() && (tableType == type_groupedtable))
  11746. activity = "GroupAggregate";
  11747. else
  11748. {
  11749. activity = "Aggregate";
  11750. specialOp = querySimpleAggregate(expr, false, false);
  11751. if (specialOp == no_existsgroup)
  11752. {
  11753. kind = TAKexistsaggregate;
  11754. activity = "ExistsAggregate";
  11755. if (options.minimizeActivityClasses)
  11756. implementationClassId = newExistsAggregateArgId;
  11757. }
  11758. else if (specialOp == no_countgroup)
  11759. {
  11760. kind = TAKcountaggregate;
  11761. activity = "CountAggregate";
  11762. if (options.minimizeActivityClasses)
  11763. implementationClassId = newCountAggregateArgId;
  11764. }
  11765. else
  11766. specialOp = no_none;
  11767. }
  11768. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, activity);
  11769. if (implementationClassId)
  11770. instance->setImplementationClass(implementationClassId);
  11771. if (passThrough)
  11772. {
  11773. StringBuffer graphLabel;
  11774. graphLabel.append("Through Aggregate");
  11775. ForEachChild(idx, expr)
  11776. {
  11777. IHqlExpression * cur = expr->queryChild(idx);
  11778. if (cur->getOperator() == no_setresult || cur->getOperator() == no_extractresult)
  11779. {
  11780. IHqlExpression * sequence = queryAttributeChild(cur, sequenceAtom, 0);
  11781. IHqlExpression * name = queryAttributeChild(cur, namedAtom, 0);
  11782. getStoredDescription(graphLabel.append("\n"), sequence, name, false);
  11783. }
  11784. }
  11785. instance->graphLabel.set(graphLabel.str());
  11786. }
  11787. if (isKeyedCountAggregate(expr))
  11788. throwError(HQLERR_KeyedCountNonKeyable);
  11789. buildActivityFramework(instance);
  11790. buildInstancePrefix(instance);
  11791. StringBuffer flags;
  11792. bool requiresOrderedMerge = false;
  11793. if (specialOp == no_none)
  11794. {
  11795. doBuildAggregateClearFunc(instance->startctx, expr);
  11796. if (op == no_aggregate)
  11797. {
  11798. doBuildUserAggregateFuncs(instance->startctx, expr, requiresOrderedMerge);
  11799. }
  11800. else
  11801. {
  11802. doBuildAggregateFirstFunc(instance->startctx, expr);
  11803. doBuildAggregateNextFunc(instance->startctx, expr);
  11804. doBuildAggregateMergeFunc(instance->startctx, expr, requiresOrderedMerge);
  11805. }
  11806. }
  11807. if (requiresOrderedMerge)
  11808. flags.append("|TAForderedmerge");
  11809. if (flags.length())
  11810. doBuildUnsignedFunction(instance->classctx, "getAggregateFlags", flags.str()+1);
  11811. if (grouping)
  11812. {
  11813. HqlExprArray recordFields, aggregateFields;
  11814. grouping->unwindList(recordFields, no_sortlist);
  11815. getMappedFields(aggregateFields, transform, recordFields, queryActiveTableSelector());
  11816. DatasetReference inputRef(dataset, (op == no_aggregate) ? no_left : no_none, querySelSeq(expr));
  11817. DatasetReference outRef(expr, no_activetable, NULL);
  11818. OwnedHqlExpr allRecordFields = createValueSafe(no_sortlist, makeSortListType(NULL), recordFields);
  11819. OwnedHqlExpr allAggregateFields = createValueSafe(no_sortlist, makeSortListType(NULL), aggregateFields);
  11820. buildCompareMember(instance->nestedctx, "CompareElements", allAggregateFields, outRef); // compare transformed elements
  11821. doCompareLeftRight(instance->nestedctx, "CompareRowElement", inputRef, outRef, recordFields, aggregateFields);
  11822. buildHashOfExprsClass(instance->nestedctx, "Hash", allRecordFields, inputRef, true);
  11823. buildHashOfExprsClass(instance->nestedctx, "HashElement", allAggregateFields, outRef, true);
  11824. }
  11825. if (passThrough)
  11826. {
  11827. MemberFunction func(*this, instance->startctx, "virtual void sendResult(const void * _self)");
  11828. func.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *)_self;");
  11829. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(expr->queryChild(1)), NULL);
  11830. bindTableCursor(func.ctx, resultDataset, "self");
  11831. bindTableCursor(func.ctx, dataset, "self");
  11832. ForEachChild(idx, expr)
  11833. {
  11834. IHqlExpression * cur = expr->queryChild(idx);
  11835. if (cur->getOperator() == no_setresult)
  11836. {
  11837. IHqlExpression * value = cur->queryChild(0);
  11838. IHqlExpression * sequence = queryAttributeChild(cur, sequenceAtom, 0);
  11839. IHqlExpression * name = queryAttributeChild(cur, namedAtom, 0);
  11840. buildSetResultInfo(func.ctx, cur, value, NULL, false, false);
  11841. associateRemoteResult(*instance, sequence, name);
  11842. }
  11843. else if (cur->getOperator() == no_extractresult)
  11844. {
  11845. IHqlExpression * value = cur->queryChild(1);
  11846. IHqlExpression * sequence = queryAttributeChild(cur, sequenceAtom, 0);
  11847. IHqlExpression * name = queryAttributeChild(cur, namedAtom, 0);
  11848. buildSetResultInfo(func.ctx, cur, value, NULL, false, false);
  11849. associateRemoteResult(*instance, sequence, name);
  11850. }
  11851. }
  11852. buildMetaMember(instance->classctx, resultDataset, isGrouped(resultDataset), "queryAggregateRecordSize");
  11853. }
  11854. buildInstanceSuffix(instance);
  11855. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  11856. return instance->getBoundActivity();
  11857. }
  11858. //---------------------------------------------------------------------------
  11859. static bool isDistributedFunctionCall(IHqlExpression * expr)
  11860. {
  11861. IHqlExpression * funcdef = NULL;
  11862. switch (expr->getOperator())
  11863. {
  11864. case no_externalcall:
  11865. funcdef = expr->queryBody()->queryExternalDefinition();
  11866. break;
  11867. case no_call:
  11868. funcdef = expr->queryBody()->queryFunctionDefinition();
  11869. break;
  11870. }
  11871. return (funcdef && queryFunctionAttribute(funcdef, distributedAtom));
  11872. }
  11873. ABoundActivity * HqlCppTranslator::doBuildActivityChildDataset(BuildCtx & ctx, IHqlExpression * expr)
  11874. {
  11875. if (options.mainRowsAreLinkCounted || isGrouped(expr))
  11876. return doBuildActivityLinkedRawChildDataset(ctx, expr);
  11877. StringBuffer s;
  11878. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKchilditerator, expr, "ChildIterator");
  11879. if (isDistributedFunctionCall(expr))
  11880. instance->setLocal(true);
  11881. buildActivityFramework(instance);
  11882. buildInstancePrefix(instance);
  11883. //Dummy implementation that just clears the record
  11884. OwnedHqlExpr value = LINK(expr);
  11885. switch (value->getOperator())
  11886. {
  11887. case no_alias:
  11888. case no_left:
  11889. case no_right:
  11890. case no_top:
  11891. case no_id2blob:
  11892. case no_rows:
  11893. case no_getgraphresult:
  11894. case no_activetable:
  11895. break;
  11896. case no_select:
  11897. if (!isNewSelector(expr))
  11898. break;
  11899. //fall through
  11900. default:
  11901. {
  11902. CHqlBoundExpr bound;
  11903. doBuildAliasValue(instance->onstartctx, value, bound, NULL);
  11904. value.setown(bound.getTranslatedExpr());
  11905. break;
  11906. }
  11907. }
  11908. Owned<IHqlCppDatasetCursor> iter = createDatasetSelector(instance->onstartctx, value);
  11909. iter->buildIterateMembers(instance->startctx, instance->onstartctx);
  11910. //virtual size32_t transform(ARowBuilder & crSelf) = 0;
  11911. {
  11912. MemberFunction func(*this, instance->startctx, "size32_t transform(ARowBuilder & crSelf)");
  11913. ensureRowAllocated(func.ctx, "crSelf");
  11914. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  11915. OwnedHqlExpr active = ensureActiveRow(value);
  11916. buildAssign(func.ctx, selfCursor->querySelector(), active);
  11917. buildReturnRecordSize(func.ctx, selfCursor);
  11918. }
  11919. buildInstanceSuffix(instance);
  11920. return instance->getBoundActivity();
  11921. }
  11922. //---------------------------------------------------------------------------
  11923. ABoundActivity * HqlCppTranslator::doBuildActivityStreamedCall(BuildCtx & ctx, IHqlExpression * expr)
  11924. {
  11925. StringBuffer s;
  11926. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKstreamediterator, expr, "StreamedIterator");
  11927. if (isDistributedFunctionCall(expr))
  11928. instance->setLocal(true);
  11929. buildActivityFramework(instance);
  11930. buildInstancePrefix(instance);
  11931. {
  11932. MemberFunction func(*this, instance->startctx, "virtual IRowStream * createInput()");
  11933. buildReturn(func.ctx, expr);
  11934. }
  11935. buildInstanceSuffix(instance);
  11936. return instance->getBoundActivity();
  11937. }
  11938. //---------------------------------------------------------------------------
  11939. ABoundActivity * HqlCppTranslator::doBuildActivityLinkedRawChildDataset(BuildCtx & ctx, IHqlExpression * expr)
  11940. {
  11941. StringBuffer s;
  11942. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKlinkedrawiterator, expr, "LinkedRawIterator");
  11943. if (isDistributedFunctionCall(expr))
  11944. instance->setLocal(true);
  11945. buildActivityFramework(instance);
  11946. buildInstancePrefix(instance);
  11947. OwnedHqlExpr nonparallel = removeAttribute(expr, parallelAtom);
  11948. OwnedHqlExpr value = expr->isDatarow() ? createDatasetFromRow(nonparallel.getClear()) : nonparallel.getClear();
  11949. BuildCtx * declarectx;
  11950. BuildCtx * callctx;
  11951. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, &callctx, false, true); // possibly should sometimes generate in onCreate(), if can evaluate in parent
  11952. CHqlBoundTarget invariantDs;
  11953. buildTempExpr(*callctx, *declarectx, invariantDs, value, FormatLinkedDataset, false);
  11954. CHqlBoundExpr boundDs;
  11955. boundDs.setFromTarget(invariantDs);
  11956. CHqlBoundTarget boundActiveIndex;
  11957. OwnedHqlExpr zero = getSizetConstant(0);
  11958. buildTempExpr(*callctx, *declarectx, boundActiveIndex, zero, FormatNatural, false);
  11959. //virtual byte * next() = 0;
  11960. {
  11961. MemberFunction func(*this, instance->startctx, "virtual byte * next()");
  11962. OwnedHqlExpr count = getBoundCount(boundDs);
  11963. OwnedHqlExpr test = createValue(no_lt, makeBoolType(), LINK(boundActiveIndex.expr), LINK(count));
  11964. BuildCtx subctx(func.ctx);
  11965. subctx.addFilter(test);
  11966. OwnedHqlExpr ret = createValue(no_index, expr->getType(), LINK(boundDs.expr), createValue(no_postinc, LINK(sizetType), LINK(boundActiveIndex.expr)));
  11967. subctx.addReturn(ret);
  11968. func.ctx.addReturn(queryQuotedNullExpr());
  11969. }
  11970. buildInstanceSuffix(instance);
  11971. return instance->getBoundActivity();
  11972. }
  11973. //---------------------------------------------------------------------------
  11974. static void gatherDedupCompareExpr(HqlExprArray & equalities, HqlExprArray & comparisons, HqlExprArray & conds, IHqlExpression * left, IHqlExpression * right, IHqlExpression * dataset)
  11975. {
  11976. ForEachItemIn(idx, conds)
  11977. {
  11978. IHqlExpression * cond = &conds.item(idx);
  11979. if (cond->getOperator() == no_and)
  11980. {
  11981. HqlExprArray expanded;
  11982. cond->unwindList(expanded, no_and);
  11983. gatherDedupCompareExpr(equalities, comparisons, expanded, left, right, dataset);
  11984. }
  11985. else if (containsSelector(cond, left) || containsSelector(cond, right))
  11986. comparisons.append(*LINK(cond));
  11987. else if (!cond->isConstant())
  11988. equalities.append(*LINK(cond));
  11989. }
  11990. }
  11991. void optimizeGroupOrder(HqlExprArray & optimized, IHqlExpression * dataset, HqlExprArray & exprs)
  11992. {
  11993. RecordSelectIterator iter(dataset->queryRecord(), dataset->queryNormalizedSelector());
  11994. ForEach(iter)
  11995. {
  11996. IHqlExpression * select = iter.query();
  11997. unsigned match = exprs.find(*select);
  11998. if (match != NotFound)
  11999. {
  12000. optimized.append(*LINK(select));
  12001. //Remove this item, and all other matches (unusual, but if it does occur it is wasteful.)
  12002. do
  12003. {
  12004. exprs.remove(match);
  12005. match = exprs.find(*select);
  12006. } while (match != NotFound);
  12007. if (exprs.empty())
  12008. break;
  12009. }
  12010. }
  12011. }
  12012. IHqlExpression * createOrderFromCompareArray(HqlExprArray & exprs, IHqlExpression * dataset, IHqlExpression * left, IHqlExpression * right)
  12013. {
  12014. OwnedHqlExpr equalExpr = createSortList(exprs);
  12015. OwnedHqlExpr lhs = replaceSelector(equalExpr, dataset, left);
  12016. OwnedHqlExpr rhs = replaceSelector(equalExpr, dataset, right);
  12017. return createValue(no_order, LINK(signedType), lhs.getClear(), rhs.getClear());
  12018. }
  12019. void HqlCppTranslator::buildDedupFilterFunction(BuildCtx & ctx, HqlExprArray & equalities, HqlExprArray & conds, IHqlExpression * dataset, IHqlExpression * selSeq)
  12020. {
  12021. HqlExprArray comparisons;
  12022. HqlExprArray allEqualities;
  12023. //MORE: The equalities really shouldn't be here - the activities should do them via the primaryCompare
  12024. appendArray(allEqualities, equalities);
  12025. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  12026. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  12027. gatherDedupCompareExpr(allEqualities, comparisons, conds, left, right, dataset);
  12028. MemberFunction func(*this, ctx, "virtual bool matches(const void * _left, const void * _right)");
  12029. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  12030. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  12031. BuildCtx filterctx(func.ctx);
  12032. BoundRow * lRow = bindTableCursor(filterctx, dataset, "left", no_left, selSeq);
  12033. BoundRow * rRow = bindTableCursor(filterctx, dataset, "right", no_right, selSeq);
  12034. //convert any LEFT.x = RIGHT.y to an equality
  12035. unsigned numComparisons = comparisons.ordinality();
  12036. for (unsigned i1=0; i1 < numComparisons; )
  12037. {
  12038. IHqlExpression * cur = &comparisons.item(i1);
  12039. if (cur->getOperator() == no_eq)
  12040. {
  12041. IHqlExpression * lhs = cur->queryChild(0);
  12042. OwnedHqlExpr newLhs = replaceSelector(lhs, lRow->querySelector(), rRow->querySelector());
  12043. if (newLhs == cur->queryChild(1))
  12044. {
  12045. allEqualities.append(*replaceSelector(lhs, lRow->querySelector(), dataset));
  12046. comparisons.remove(i1);
  12047. numComparisons--;
  12048. }
  12049. //could check for right.x = left.x, but pretty unlikely.
  12050. else
  12051. i1++;
  12052. }
  12053. else
  12054. i1++;
  12055. }
  12056. if (comparisons.ordinality() || allEqualities.ordinality())
  12057. {
  12058. ForEachItemIn(i, comparisons)
  12059. {
  12060. IHqlExpression * cur = &comparisons.item(i);
  12061. //if no equalities to follow, generate a return for the last non-equality
  12062. if (allEqualities.empty() && (i+1 == numComparisons))
  12063. {
  12064. buildReturn(filterctx, cur);
  12065. }
  12066. else
  12067. {
  12068. OwnedHqlExpr inverse = getInverse(cur);
  12069. buildFilteredReturn(filterctx, inverse, queryBoolExpr(false));
  12070. }
  12071. }
  12072. if (allEqualities.ordinality())
  12073. {
  12074. HqlExprArray optimized;
  12075. //Even better... sort the equality list by the field order...
  12076. if (options.optimizeGrouping && (allEqualities.ordinality() > 1))
  12077. optimizeGroupOrder(optimized, dataset, allEqualities);
  12078. appendArray(optimized, allEqualities);
  12079. OwnedHqlExpr order = createOrderFromCompareArray(optimized, dataset, lRow->querySelector(), rRow->querySelector());
  12080. doBuildReturnCompare(filterctx, order, no_eq, true, false);
  12081. }
  12082. }
  12083. else
  12084. func.setIncluded(false); // Use the implementation in the base class
  12085. }
  12086. void HqlCppTranslator::buildDedupSerializeFunction(BuildCtx & ctx, const char * funcName, IHqlExpression * srcDataset, IHqlExpression * tgtDataset, HqlExprArray & srcValues, HqlExprArray & tgtValues, IHqlExpression * selSeq)
  12087. {
  12088. StringBuffer s;
  12089. s.append("virtual unsigned ").append(funcName).append("(ARowBuilder & crSelf, const void * _src)");
  12090. MemberFunction func(*this, ctx, s, MFdynamicproto);
  12091. ensureRowAllocated(func.ctx, "crSelf");
  12092. func.ctx.addQuotedLiteral("const unsigned char * src = (const unsigned char *) _src;");
  12093. BoundRow * tgtCursor = bindSelf(func.ctx, tgtDataset, "crSelf");
  12094. BoundRow * srcCursor = bindTableCursor(func.ctx, srcDataset, "src", no_left, selSeq);
  12095. ForEachItemIn(idx2, srcValues)
  12096. {
  12097. Owned<IHqlExpression> self = tgtCursor->bindToRow(&tgtValues.item(idx2), queryActiveTableSelector());
  12098. Owned<IHqlExpression> left = srcCursor->bindToRow(&srcValues.item(idx2), srcDataset);
  12099. buildAssign(func.ctx, self, left);
  12100. }
  12101. buildReturnRecordSize(func.ctx, tgtCursor);
  12102. }
  12103. ABoundActivity * HqlCppTranslator::doBuildActivityDedup(BuildCtx & ctx, IHqlExpression * expr)
  12104. {
  12105. StringBuffer s;
  12106. DedupInfoExtractor info(expr);
  12107. IHqlExpression * dataset = expr->queryChild(0);
  12108. IHqlExpression * selSeq = querySelSeq(expr);
  12109. bool isGrouped = ::isGrouped(dataset);
  12110. bool isLocal = isLocalActivity(expr);
  12111. bool useHash = expr->hasAttribute(hashAtom);
  12112. if (targetThor() && !isGrouped && !isLocal)
  12113. {
  12114. //Should really be done via an attribute on the dedup.
  12115. if (info.compareAllRows && !info.conds.ordinality())
  12116. useHash = true;
  12117. }
  12118. if (useHash && info.conds.ordinality())
  12119. throwError(HQLERR_GlobalDedupFuzzy);
  12120. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12121. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, useHash ? TAKhashdedup : TAKdedup, expr, useHash ? "HashDedup" : "Dedup");
  12122. buildActivityFramework(instance);
  12123. buildInstancePrefix(instance);
  12124. bool wholeRecord = false;
  12125. if (!useHash)
  12126. {
  12127. if (!matchesConstantValue(info.numToKeep, 1))
  12128. {
  12129. doBuildUnsignedFunction(instance->startctx, "numToKeep", info.numToKeep);
  12130. if (info.keepBest)
  12131. throwError(HQLERR_DedupBestWithKeepn);
  12132. }
  12133. //MORE: If input is grouped (pretty likely), then no need to include fields in the filter function that are already included.
  12134. if (instance->isGrouped)
  12135. {
  12136. HqlExprArray normalizedEqualities;
  12137. ForEachItemIn(i1, info.equalities)
  12138. normalizedEqualities.append(*replaceSelector(info.equalities.item(i1).queryBody(), dataset, queryActiveTableSelector()));
  12139. IHqlExpression * grouping = queryGrouping(dataset);
  12140. ForEachChild(i, grouping)
  12141. {
  12142. IHqlExpression * curGroup = grouping->queryChild(i);
  12143. unsigned match = normalizedEqualities.find(*curGroup);
  12144. if (match != NotFound)
  12145. {
  12146. normalizedEqualities.remove(match);
  12147. info.equalities.remove(match);
  12148. }
  12149. }
  12150. }
  12151. HqlExprArray noEqualities;
  12152. HqlExprArray * equalities = &info.equalities;
  12153. if (info.compareAllRows)
  12154. {
  12155. if (info.equalities.ordinality() && !instance->isGrouped)
  12156. {
  12157. OwnedHqlExpr order = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  12158. buildCompareMember(instance->nestedctx, "ComparePrimary", order, DatasetReference(dataset));
  12159. if (!targetThor())
  12160. equalities = &noEqualities;
  12161. }
  12162. }
  12163. buildDedupFilterFunction(instance->startctx, *equalities, info.conds, dataset, selSeq);
  12164. }
  12165. else
  12166. {
  12167. if (info.equalities.ordinality() == 0)
  12168. throwError(HQLERR_GlobalDedupNoEquality);
  12169. if (!matchesConstantValue(info.numToKeep, 1))
  12170. throwError1(HQLERR_HashDedupNotSupportX, "KEEP");
  12171. if (!info.keepLeft)
  12172. throwError1(HQLERR_HashDedupNotSupportX, "RIGHT");
  12173. OwnedHqlExpr order = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  12174. buildCompareMember(instance->nestedctx, "Compare", order, DatasetReference(dataset));
  12175. buildHashOfExprsClass(instance->nestedctx, "Hash", order, DatasetReference(dataset), true);
  12176. bool reuseCompare = false;
  12177. HqlExprArray fields, selects;
  12178. ForEachItemIn(idx, info.equalities)
  12179. {
  12180. IHqlExpression & cur = info.equalities.item(idx);
  12181. IHqlExpression * field;
  12182. if ((cur.getOperator() == no_select) && (cur.queryChild(0) == dataset->queryNormalizedSelector()))
  12183. field = LINK(cur.queryChild(1));
  12184. else
  12185. {
  12186. StringBuffer name;
  12187. name.append("_expression_").append(idx);
  12188. field = createFieldFromValue(createIdAtom(name.str()), &cur);
  12189. }
  12190. fields.append(*field);
  12191. selects.append(*createSelectExpr(getActiveTableSelector(), LINK(field)));
  12192. }
  12193. OwnedHqlExpr keyDataset = createDataset(no_anon, createRecord(fields));
  12194. //virtual IOutputMetaData * queryKeySize()
  12195. buildMetaMember(instance->classctx, keyDataset, false, "queryKeySize");
  12196. //virtual unsigned recordToKey(void * _key, const void * _record)
  12197. buildDedupSerializeFunction(instance->startctx, "recordToKey", dataset, keyDataset, info.equalities, selects, selSeq);
  12198. // Helper function relating to selecting a record from a set of "duplicate" records
  12199. if (info.keepBest)
  12200. {
  12201. // KeepBest stores entire record (not just the key field) so the KeyCompare and queryRowKeyCompare is the same as Compare.
  12202. reuseCompare = true;
  12203. }
  12204. else
  12205. {
  12206. //virtual ICompare * queryKeyCompare()
  12207. OwnedHqlExpr keyOrder = createValueSafe(no_sortlist, makeSortListType(NULL), selects);
  12208. if (recordTypesMatch(dataset, keyDataset))
  12209. {
  12210. OwnedHqlExpr globalOrder = replaceSelector(order, dataset, queryActiveTableSelector());
  12211. if (keyOrder == globalOrder)
  12212. reuseCompare = true;
  12213. }
  12214. if (!reuseCompare)
  12215. {
  12216. buildCompareMember(instance->nestedctx, "KeyCompare", keyOrder, DatasetReference(keyDataset, no_activetable, NULL));
  12217. buildHashOfExprsClass(instance->nestedctx, "KeyHash", keyOrder, DatasetReference(keyDataset, no_activetable, NULL), true);
  12218. //virtual ICompare * queryRowKeyCompare()=0; // lhs is a row, rhs is a key
  12219. doCompareLeftRight(instance->nestedctx, "RowKeyCompare", DatasetReference(dataset), DatasetReference(keyDataset, no_activetable, NULL), info.equalities, selects);
  12220. }
  12221. wholeRecord = recordTypesMatch(dataset, keyDataset);
  12222. }
  12223. if (reuseCompare)
  12224. {
  12225. instance->nestedctx.addQuotedLiteral("virtual ICompare * queryKeyCompare() { return &Compare; }");
  12226. instance->nestedctx.addQuotedLiteral("virtual IHash * queryKeyHash() { return &Hash; }");
  12227. instance->nestedctx.addQuotedLiteral("virtual ICompare * queryRowKeyCompare() { return &Compare; }");
  12228. }
  12229. }
  12230. StringBuffer flags;
  12231. if (info.compareAllRows) flags.append("|HDFcompareall");
  12232. if (info.keepLeft) flags.append("|HDFkeepleft");
  12233. if (info.keepBest) flags.append("|HDFkeepbest");
  12234. if (wholeRecord) flags.append("|HDFwholerecord");
  12235. if (!streq(flags.str(), "|HDFkeepleft"))
  12236. {
  12237. if (flags.length()==0) flags.append("|0");
  12238. doBuildUnsignedFunction(instance->startctx, "getFlags", flags.str()+1);
  12239. }
  12240. if (info.keepBest)
  12241. {
  12242. IHqlExpression * sortOrder = expr->queryAttribute(bestAtom)->queryChild(0);
  12243. buildCompareClass(instance->startctx, "bestCompare", sortOrder, DatasetReference(dataset));
  12244. instance->startctx.addQuotedLiteral("virtual ICompare * queryCompareBest() { return &bestCompare; }");
  12245. }
  12246. buildInstanceSuffix(instance);
  12247. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12248. return instance->getBoundActivity();
  12249. }
  12250. //---------------------------------------------------------------------------
  12251. // no_distribute
  12252. ABoundActivity * HqlCppTranslator::doBuildActivityDistribute(BuildCtx & ctx, IHqlExpression * expr)
  12253. {
  12254. IHqlExpression * dataset = expr->queryChild(0);
  12255. if (!targetThor() || insideChildQuery(ctx))
  12256. {
  12257. if (isGrouped(dataset))
  12258. {
  12259. Owned<ABoundActivity> boundInput = buildCachedActivity(ctx, dataset);
  12260. return doBuildActivityUngroup(ctx, expr, boundInput);
  12261. }
  12262. return buildCachedActivity(ctx, dataset);
  12263. }
  12264. StringBuffer s;
  12265. if (isUngroup(dataset))
  12266. dataset = dataset->queryChild(0);
  12267. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12268. IHqlExpression * cond = expr->queryChild(1);
  12269. IHqlExpression * mergeOrder = queryAttributeChild(expr, mergeAtom, 0);
  12270. if (cond->getOperator() == no_sortpartition)
  12271. {
  12272. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKpartition, expr, "Merge");
  12273. buildActivityFramework(instance);
  12274. buildInstancePrefix(instance);
  12275. HqlExprArray sorts;
  12276. unwindChildren(sorts, cond);
  12277. OwnedHqlExpr sortOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  12278. instance->startctx.addQuotedLiteral("virtual ICompare * queryCompare() { return &compare; }");
  12279. DatasetReference dsRef(dataset);
  12280. buildCompareClass(instance->nestedctx, "compare", sortOrder, dsRef);
  12281. if (!instance->isLocal)
  12282. generateSerializeKey(instance->nestedctx, no_none, dsRef, sorts, true, true);
  12283. buildInstanceSuffix(instance);
  12284. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12285. return instance->getBoundActivity();
  12286. }
  12287. else
  12288. {
  12289. //Now generate the instance definition...
  12290. ThorActivityKind tak = (expr->getOperator() == no_distribute) ?
  12291. (mergeOrder ? TAKhashdistributemerge : TAKhashdistribute) : TAKdistributed;
  12292. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "HashDistribute");
  12293. if (expr->hasAttribute(skewAtom))
  12294. instance->graphLabel.set("Skew Distribute");
  12295. buildActivityFramework(instance);
  12296. buildInstancePrefix(instance);
  12297. if (!expr->hasAttribute(skewAtom))
  12298. buildHashClass(instance->nestedctx, "Hash", cond, DatasetReference(dataset));
  12299. doBuildBoolFunction(instance->classctx, "isPulled", expr->hasAttribute(pulledAtom));
  12300. buildSkewThresholdMembers(instance->classctx, expr);
  12301. if (mergeOrder)
  12302. buildCompareMember(instance->nestedctx, "MergeCompare", mergeOrder, DatasetReference(dataset));
  12303. buildInstanceSuffix(instance);
  12304. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12305. return instance->getBoundActivity();
  12306. }
  12307. }
  12308. //---------------------------------------------------------------------------
  12309. // no_rollup
  12310. void HqlCppTranslator::checkAmbiguousRollupCondition(IHqlExpression * expr)
  12311. {
  12312. IHqlExpression * select = queryAmbiguousRollupCondition(expr, false);
  12313. if (select)
  12314. {
  12315. IHqlExpression * dataset = expr->queryChild(0);
  12316. OwnedHqlExpr newSelect = replaceSelector(select, dataset->queryNormalizedSelector(), queryActiveTableSelector());
  12317. StringBuffer selectText;
  12318. getExprECL(newSelect, selectText);
  12319. reportWarning(CategoryUnexpected, SeverityUnknown, queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupCondition), selectText.str());
  12320. }
  12321. }
  12322. ABoundActivity * HqlCppTranslator::doBuildActivityRollup(BuildCtx & ctx, IHqlExpression * expr)
  12323. {
  12324. StringBuffer s;
  12325. IHqlExpression * dataset = expr->queryChild(0);
  12326. IHqlExpression * cond = expr->queryChild(1);
  12327. IHqlExpression * transform = expr->queryChild(2);
  12328. IHqlExpression * selSeq = querySelSeq(expr);
  12329. HqlExprArray equalities;
  12330. HqlExprArray conds;
  12331. if (cond->getOperator() == no_sortlist)
  12332. unwindChildren(conds, cond);
  12333. else
  12334. conds.append(*LINK(cond));
  12335. //build child table....
  12336. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12337. //Now generate the instance definition...
  12338. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKrollup, expr, "Rollup");
  12339. buildActivityFramework(instance);
  12340. buildInstancePrefix(instance);
  12341. if (options.checkAmbiguousRollupCondition)
  12342. checkAmbiguousRollupCondition(expr);
  12343. buildDedupFilterFunction(instance->startctx, equalities, conds, dataset, selSeq);
  12344. buildRollupTransformFunction(instance->startctx, dataset, transform, selSeq);
  12345. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  12346. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  12347. StringBuffer flags;
  12348. if (cond->usesSelector(left) || cond->usesSelector(right))
  12349. flags.append("|RFrolledismatchleft");
  12350. if (flags.length())
  12351. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  12352. buildInstanceSuffix(instance);
  12353. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12354. return instance->getBoundActivity();
  12355. }
  12356. //---------------------------------------------------------------------------
  12357. // no_denormalize
  12358. ABoundActivity * HqlCppTranslator::doBuildActivityDenormalize(BuildCtx & ctx, IHqlExpression * expr)
  12359. {
  12360. if (isKeyedJoin(expr))
  12361. return doBuildActivityKeyedJoinOrDenormalize(ctx, expr);
  12362. return doBuildActivityJoinOrDenormalize(ctx, expr);
  12363. }
  12364. //---------------------------------------------------------------------------
  12365. ABoundActivity * HqlCppTranslator::doBuildActivityFirstN(BuildCtx & ctx, IHqlExpression * expr)
  12366. {
  12367. IHqlExpression * dataset = expr->queryChild(0);
  12368. IHqlExpression * limit = expr->queryChild(1);
  12369. //choosen(x,ALL) does nothing, but is a way of getting round the implicit limitation.
  12370. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12371. if (isChooseNAllLimit(limit) && !expr->queryChild(2))
  12372. return boundDataset.getClear();
  12373. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfirstn, expr, "FirstN");
  12374. buildActivityFramework(instance);
  12375. buildInstancePrefix(instance);
  12376. {
  12377. MemberFunction func(*this, instance->startctx, "virtual __int64 getLimit()");
  12378. OwnedHqlExpr newLimit = ensurePositiveOrZeroInt64(limit);
  12379. if (options.spotCSE)
  12380. newLimit.setown(spotScalarCSE(newLimit, NULL, queryOptions().spotCseInIfDatasetConditions));
  12381. buildReturn(func.ctx, newLimit);
  12382. }
  12383. if (queryRealChild(expr, 2))
  12384. {
  12385. MemberFunction func(*this, instance->startctx, "virtual __int64 numToSkip()");
  12386. OwnedHqlExpr adjusted = adjustValue(expr->queryChild(2), -1);
  12387. OwnedHqlExpr newAdjusted = ensurePositiveOrZeroInt64(adjusted);
  12388. buildReturn(func.ctx, newAdjusted);
  12389. }
  12390. if (expr->hasAttribute(groupedAtom))
  12391. doBuildBoolFunction(instance->classctx, "preserveGrouping", true);
  12392. buildInstanceSuffix(instance);
  12393. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12394. return instance->getBoundActivity();
  12395. }
  12396. //---------------------------------------------------------------------------
  12397. ABoundActivity * HqlCppTranslator::doBuildActivityChooseSetsEx(BuildCtx & ctx, IHqlExpression * expr)
  12398. {
  12399. IHqlExpression * dataset = expr->queryChild(0);
  12400. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12401. bool isEnth = expr->hasAttribute(enthAtom);
  12402. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, isEnth ? TAKchoosesetsenth : TAKchoosesetslast, expr, "ChooseSetsEx");
  12403. buildActivityFramework(instance);
  12404. buildInstancePrefix(instance);
  12405. unsigned numArgs = expr->numChildren();
  12406. bool keepExtras = false;
  12407. unsigned numConditions = 0;
  12408. for (unsigned idx1 = 1; idx1 < numArgs; idx1++)
  12409. {
  12410. switch (expr->queryChild(idx1)->getOperator())
  12411. {
  12412. case no_mapto:
  12413. numConditions++;
  12414. break;
  12415. case no_attr:
  12416. break;
  12417. default:
  12418. keepExtras = true;
  12419. }
  12420. }
  12421. unsigned numCategories = numConditions + (keepExtras ? 1 : 0);
  12422. //virtual unsigned getNumSets()
  12423. {
  12424. MemberFunction func(*this, instance->classctx, "virtual unsigned getNumSets()");
  12425. OwnedHqlExpr numExpr = createConstant((int)numCategories);
  12426. buildReturn(func.ctx, numExpr, unsignedType);
  12427. }
  12428. //virtual unsigned getRecordCategory(const void * _self) = 0;
  12429. {
  12430. MemberFunction func(*this, instance->startctx, "virtual unsigned getCategory(const void * _self)");
  12431. func.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *)_self;");
  12432. bindTableCursor(func.ctx, dataset, "self");
  12433. HqlExprArray args;
  12434. for (unsigned idx3 = 1; idx3 <= numConditions; idx3++)
  12435. {
  12436. IHqlExpression * cur = expr->queryChild(idx3);
  12437. args.append(*createValue(no_mapto, makeVoidType(), LINK(cur->queryChild(0)), createConstant(unsignedType->castFrom(false, (__int64)idx3))));
  12438. }
  12439. if (keepExtras)
  12440. args.append(*createConstant((__int64)numConditions+1));
  12441. else
  12442. args.append(*createConstant((__int64)0));
  12443. OwnedHqlExpr map = createValue(no_map, LINK(unsignedType), args);
  12444. buildReturn(func.ctx, map);
  12445. }
  12446. //virtual void getLimits(unsigned * counts) = 0;
  12447. {
  12448. StringBuffer s;
  12449. MemberFunction func(*this, instance->startctx, "virtual void getLimits(__int64 * counts)");
  12450. for (unsigned idx2 = 1; idx2 <= numCategories; idx2++)
  12451. {
  12452. IHqlExpression * cur = expr->queryChild(idx2);
  12453. s.clear().append("counts[").append(idx2-1).append("]");
  12454. OwnedHqlExpr target = createVariable(s.str(), LINK(defaultIntegralType));
  12455. switch (cur->getOperator())
  12456. {
  12457. case no_mapto:
  12458. buildAssignToTemp(func.ctx, target, cur->queryChild(1));
  12459. break;
  12460. default:
  12461. buildAssignToTemp(func.ctx, target, cur);
  12462. break;
  12463. }
  12464. }
  12465. }
  12466. buildInstanceSuffix(instance);
  12467. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12468. return instance->getBoundActivity();
  12469. }
  12470. ABoundActivity * HqlCppTranslator::doBuildActivityChooseSets(BuildCtx & ctx, IHqlExpression * expr)
  12471. {
  12472. if (expr->hasAttribute(enthAtom) || expr->hasAttribute(lastAtom))
  12473. return doBuildActivityChooseSetsEx(ctx, expr);
  12474. IHqlExpression * dataset = expr->queryChild(0);
  12475. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12476. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKchoosesets, expr, "ChooseSets");
  12477. buildActivityFramework(instance);
  12478. buildInstancePrefix(instance);
  12479. unsigned numArgs = expr->numChildren();
  12480. bool allowSpill = !expr->hasAttribute(exclusiveAtom);
  12481. bool keepExtras = false;
  12482. unsigned numConditions = 0;
  12483. for (unsigned idx1 = 1; idx1 < numArgs; idx1++)
  12484. {
  12485. switch (expr->queryChild(idx1)->getOperator())
  12486. {
  12487. case no_mapto:
  12488. numConditions++;
  12489. break;
  12490. case no_attr:
  12491. case no_attr_expr:
  12492. case no_attr_link:
  12493. break;
  12494. default:
  12495. keepExtras = true;
  12496. }
  12497. }
  12498. unsigned numCategories = numConditions + (keepExtras ? 1 : 0);
  12499. {
  12500. MemberFunction func(*this, instance->classctx, "virtual unsigned getNumSets()");
  12501. OwnedHqlExpr numExpr = createConstant((int)numCategories);
  12502. buildReturn(func.ctx, numExpr, unsignedType);
  12503. }
  12504. instance->startctx.addQuotedLiteral("unsigned * counts;");
  12505. instance->startctx.addQuotedLiteral("unsigned numFull;");
  12506. StringBuffer s;
  12507. MemberFunction limitFunc(*this, instance->classctx, "virtual bool setCounts(unsigned * data)");
  12508. limitFunc.ctx.addQuotedLiteral("counts = data;");
  12509. limitFunc.ctx.addQuotedLiteral("numFull = 0;");
  12510. OwnedHqlExpr tally = createVariable("counts", makeIntType(4, false));
  12511. MemberFunction validFunc(*this, instance->startctx, "virtual unsigned getRecordAction(const void * _self)");
  12512. validFunc.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *)_self;");
  12513. bindTableCursor(validFunc.ctx, dataset, "self");
  12514. OwnedHqlExpr one = createConstant((int)1);
  12515. for (unsigned idx = 0; idx < numCategories; idx++)
  12516. {
  12517. OwnedHqlExpr indexExpr = getSizetConstant(idx);
  12518. OwnedHqlExpr bucketExpr = createValue(no_index, LINK(unsignedType), tally.getLink(), indexExpr.getLink());
  12519. OwnedHqlExpr transBucketExpr = createTranslated(bucketExpr);
  12520. IHqlExpression * arg = expr->queryChild(idx+1);
  12521. IHqlExpression * count = (arg->getOperator() == no_mapto ? arg->queryChild(1) : arg);
  12522. OwnedHqlExpr cond2 = createBoolExpr(no_lt, transBucketExpr.getLink(), ensureExprType(count, unsignedType));
  12523. OwnedHqlExpr condDone = createBoolExpr(no_eq, transBucketExpr.getLink(), ensureExprType(count, unsignedType));
  12524. BuildCtx condctx(validFunc.ctx);
  12525. if (arg->getOperator() == no_mapto)
  12526. {
  12527. IHqlExpression * filter = arg->queryChild(0);
  12528. if (allowSpill)
  12529. {
  12530. OwnedHqlExpr cond = createBoolExpr(no_and, LINK(filter), cond2.getLink());
  12531. CHqlBoundExpr bound;
  12532. buildExpr(condctx, cond, bound);
  12533. condctx.addFilter(bound.expr);
  12534. }
  12535. else
  12536. {
  12537. buildFilter(condctx, filter);
  12538. BuildCtx failctx(condctx);
  12539. buildFilter(condctx, cond2);
  12540. buildReturn(failctx, queryZero());
  12541. }
  12542. }
  12543. else
  12544. {
  12545. buildFilter(condctx, cond2);
  12546. }
  12547. OwnedHqlExpr inc = createValue(no_postinc, bucketExpr.getLink());
  12548. condctx.addExpr(inc);
  12549. BuildCtx doneCtx(condctx);
  12550. buildFilter(doneCtx, condDone);
  12551. doneCtx.addQuoted(s.clear().append("if (++numFull == ").append(numCategories).append(") return 2;"));
  12552. buildReturn(condctx, one, unsignedType);
  12553. BuildCtx limitCondCtx(limitFunc.ctx);
  12554. buildFilter(limitCondCtx, condDone);
  12555. limitCondCtx.addQuotedLiteral("numFull++;");
  12556. }
  12557. buildReturn(validFunc.ctx, queryZero());
  12558. limitFunc.ctx.addQuoted(s.clear().append("return numFull == ").append(numCategories).append(";"));
  12559. buildInstanceSuffix(instance);
  12560. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12561. return instance->getBoundActivity();
  12562. }
  12563. //---------------------------------------------------------------------------
  12564. ABoundActivity * HqlCppTranslator::doBuildActivityNormalizeGroup(BuildCtx & ctx, IHqlExpression * expr)
  12565. {
  12566. throwUnexpected();
  12567. IHqlExpression * dataset = expr->queryChild(0);
  12568. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12569. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalize, expr,"Normalize");
  12570. buildActivityFramework(instance);
  12571. buildInstancePrefix(instance);
  12572. buildInstanceSuffix(instance);
  12573. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12574. return instance->getBoundActivity();
  12575. }
  12576. //---------------------------------------------------------------------------
  12577. ABoundActivity * HqlCppTranslator::doBuildActivityNormalize(BuildCtx & ctx, IHqlExpression * expr)
  12578. {
  12579. IHqlExpression * numRows = expr->queryChild(1);
  12580. if (!numRows->queryType()->isScalar())
  12581. return doBuildActivityNormalizeChild(ctx, expr);
  12582. IHqlExpression * dataset = expr->queryChild(0);
  12583. IHqlExpression * transform = expr->queryChild(2);
  12584. IHqlExpression * selSeq = querySelSeq(expr);
  12585. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12586. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalize, expr,"Normalize");
  12587. buildActivityFramework(instance);
  12588. buildInstancePrefix(instance);
  12589. {
  12590. MemberFunction func(*this, instance->startctx, "virtual unsigned numExpandedRows(const void * _left)");
  12591. func.ctx.addQuotedLiteral("unsigned char * left = (unsigned char *) _left;");
  12592. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  12593. bindTableCursor(func.ctx, dataset, "left");
  12594. buildReturn(func.ctx, numRows);
  12595. }
  12596. {
  12597. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned counter)");
  12598. ensureRowAllocated(func.ctx, "crSelf");
  12599. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12600. associateCounter(func.ctx, counter, "counter");
  12601. buildTransformBody(func.ctx, transform, dataset, NULL, instance->dataset, selSeq);
  12602. }
  12603. buildInstanceSuffix(instance);
  12604. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12605. return instance->getBoundActivity();
  12606. }
  12607. //---------------------------------------------------------------------------
  12608. ABoundActivity * HqlCppTranslator::doBuildActivityNormalizeChild(BuildCtx & ctx, IHqlExpression * expr)
  12609. {
  12610. IHqlExpression * dataset = expr->queryChild(0);
  12611. LinkedHqlExpr childDataset = expr->queryChild(1);
  12612. IHqlExpression * transform = expr->queryChild(2);
  12613. IHqlExpression * selSeq = querySelSeq(expr);
  12614. if (transformReturnsSide(expr, no_right, 1))
  12615. return doBuildActivityNormalizeLinkedChild(ctx, expr);
  12616. StringBuffer s;
  12617. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12618. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalizechild, expr,"NormalizeChild");
  12619. buildActivityFramework(instance);
  12620. buildInstancePrefix(instance);
  12621. //Generate queryChildRecordSize();
  12622. buildMetaMember(instance->classctx, childDataset, isGrouped(childDataset), "queryChildRecordSize");
  12623. // INormalizeChildIterator * queryIterator();
  12624. {
  12625. bool outOfLine = true;
  12626. bool streamed = false;
  12627. if (childDataset->isDatarow())
  12628. childDataset.setown(createDatasetFromRow(childDataset.getClear()));
  12629. if (childDataset->getOperator() == no_select)
  12630. outOfLine = isArrayRowset(childDataset->queryType());
  12631. if (hasLinkCountedModifier(childDataset))
  12632. outOfLine = true;
  12633. if (isStreamed(childDataset))
  12634. {
  12635. outOfLine = true;
  12636. streamed = true;
  12637. }
  12638. BuildCtx iterclassctx(instance->nestedctx);
  12639. StringBuffer memberName, className;
  12640. getUniqueId(memberName.append("m"));
  12641. getMemberClassName(className, memberName.str());
  12642. ExpressionFormat format;
  12643. IHqlStmt * classStmt = nullptr;
  12644. if (streamed)
  12645. {
  12646. classStmt = beginNestedClass(iterclassctx, memberName, "CNormalizeStreamedChildIterator");
  12647. format = FormatStreamedDataset;
  12648. }
  12649. else if (outOfLine)
  12650. {
  12651. classStmt = beginNestedClass(iterclassctx, memberName, "CNormalizeLinkedChildIterator");
  12652. format = FormatLinkedDataset;
  12653. }
  12654. else
  12655. {
  12656. classStmt = beginNestedClass(iterclassctx, memberName, "CNormalizeChildIterator");
  12657. format = FormatBlockedDataset;
  12658. MetaInstance childmeta(*this, childDataset->queryRecord(), isGrouped(childDataset));
  12659. buildMetaInfo(childmeta);
  12660. s.clear().append(className).append("() : CNormalizeChildIterator(").append(childmeta.queryInstanceObject()).append(") {}");
  12661. iterclassctx.addQuoted(s);
  12662. }
  12663. bool callFromActivity = false;
  12664. {
  12665. MemberFunction activityInitFunc(*this, instance->startctx);
  12666. MemberFunction func(*this, iterclassctx, "virtual void init(const void * _left)");
  12667. func.ctx.addQuotedLiteral("const byte * left = (const byte *)_left;");
  12668. CHqlBoundExpr bound;
  12669. if (childDataset->getOperator() != no_select)
  12670. {
  12671. //Ugly......
  12672. //If this is a complex expression, then ensure the temporary variable is a member of the activity class, and
  12673. //evaluate it in the function defined inside the activity (so the member variables don't need mangling)
  12674. func.ctx.addQuotedLiteral("activity->init(left);");
  12675. BuildCtx * declarectx = NULL;
  12676. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, NULL, false, true);
  12677. queryEvalContext(iterclassctx)->ensureHelpersExist();
  12678. assertex(declarectx);
  12679. activityInitFunc.start("void init(const byte * left)");
  12680. bindTableCursor(activityInitFunc.ctx, dataset, "left", no_left, selSeq);
  12681. CHqlBoundTarget tempTarget;
  12682. buildTempExpr(activityInitFunc.ctx, *declarectx, tempTarget, childDataset, format, false);
  12683. bound.setFromTarget(tempTarget);
  12684. callFromActivity = true;
  12685. }
  12686. else
  12687. {
  12688. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  12689. buildDataset(func.ctx, childDataset, bound, format);
  12690. }
  12691. s.clear();
  12692. if (callFromActivity)
  12693. s.append(memberName).append(".");
  12694. s.append("setDataset(");
  12695. if (streamed)
  12696. {
  12697. generateExprCpp(s, bound.expr).append(");");
  12698. }
  12699. else
  12700. {
  12701. if (outOfLine)
  12702. {
  12703. generateExprCpp(s, bound.count).append(",");
  12704. generateExprCpp(s, bound.expr).append(");");
  12705. }
  12706. else
  12707. {
  12708. OwnedHqlExpr length = getBoundLength(bound);
  12709. generateExprCpp(s, length).append(",");
  12710. generateExprCpp(s, bound.expr).append(");");
  12711. }
  12712. }
  12713. if (callFromActivity)
  12714. activityInitFunc.ctx.addQuoted(s);
  12715. else
  12716. func.ctx.addQuoted(s);
  12717. }
  12718. endNestedClass(classStmt);
  12719. s.clear().append("INormalizeChildIterator * queryIterator() { return &").append(memberName).append("; }");
  12720. instance->startctx.addQuoted(s);
  12721. }
  12722. {
  12723. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned counter)");
  12724. ensureRowAllocated(func.ctx, "crSelf");
  12725. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12726. associateCounter(func.ctx, counter, "counter");
  12727. buildTransformBody(func.ctx, transform, dataset, childDataset, instance->dataset, selSeq);
  12728. }
  12729. buildInstanceSuffix(instance);
  12730. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12731. return instance->getBoundActivity();
  12732. }
  12733. //---------------------------------------------------------------------------
  12734. ABoundActivity * HqlCppTranslator::doBuildActivityNormalizeLinkedChild(BuildCtx & ctx, IHqlExpression * expr)
  12735. {
  12736. OwnedHqlExpr dataset;
  12737. OwnedHqlExpr childDataset;
  12738. node_operator selectorOp = no_none;
  12739. IHqlExpression * selSeq = NULL;
  12740. switch (expr->getOperator())
  12741. {
  12742. case no_select:
  12743. {
  12744. bool isNew;
  12745. dataset.set(querySelectorDataset(expr, isNew));
  12746. //Ensure input is a dataset so cleanly bound as a cursor later
  12747. if (dataset->isDatarow())
  12748. dataset.setown(createDatasetFromRow(dataset.getClear()));
  12749. assertex(isNew);
  12750. OwnedHqlExpr active = ensureActiveRow(dataset);
  12751. childDataset.setown(replaceSelectorDataset(expr, active));
  12752. break;
  12753. }
  12754. case no_normalize:
  12755. {
  12756. dataset.set(expr->queryChild(0));
  12757. childDataset.set(expr->queryChild(1));
  12758. selectorOp = no_left;
  12759. selSeq = querySelSeq(expr);
  12760. break;
  12761. }
  12762. default:
  12763. throwUnexpectedOp(expr->getOperator());
  12764. }
  12765. StringBuffer s;
  12766. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12767. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalizelinkedchild, expr,"NormalizeLinkedChild");
  12768. buildActivityFramework(instance);
  12769. buildInstancePrefix(instance);
  12770. OwnedHqlExpr value = childDataset->isDatarow() ? createDatasetFromRow(LINK(childDataset)) : LINK(childDataset);
  12771. BuildCtx * declarectx = NULL;
  12772. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, NULL, false, true);
  12773. assertex(declarectx);
  12774. StringBuffer iterName;
  12775. //virtual byte * first(const void * parentRecord) = 0;
  12776. {
  12777. MemberFunction func(*this, instance->startctx, "virtual byte * first(const void * parentRecord)");
  12778. func.ctx.addQuotedLiteral("const byte * left = (const byte *)parentRecord;");
  12779. bindTableCursor(func.ctx, dataset, "left", selectorOp, selSeq);
  12780. ExpressionFormat format = !hasLinkCountedModifier(value) ? FormatLinkedDataset : FormatNatural;
  12781. Owned<IHqlCppDatasetCursor> dsCursor = createDatasetSelector(func.ctx, value, format);
  12782. dsCursor->buildIterateClass(instance->startctx, iterName, &func.ctx);
  12783. StringBuffer s;
  12784. OwnedHqlExpr callFirst = createQuoted(s.clear().append("(byte *)").append(iterName).append(".first()"), makeBoolType());
  12785. func.ctx.addReturn(callFirst);
  12786. }
  12787. {
  12788. //virtual byte * next() = 0;
  12789. BuildCtx nextctx(instance->startctx);
  12790. nextctx.addQuotedFunction("virtual byte * next()");
  12791. StringBuffer s;
  12792. OwnedHqlExpr callNext = createQuoted(s.clear().append("(byte *)").append(iterName).append(".next()"), makeBoolType());
  12793. nextctx.addReturn(callNext);
  12794. }
  12795. buildInstanceSuffix(instance);
  12796. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12797. return instance->getBoundActivity();
  12798. }
  12799. //---------------------------------------------------------------------------
  12800. ABoundActivity * HqlCppTranslator::doBuildActivitySelectNew(BuildCtx & ctx, IHqlExpression * expr)
  12801. {
  12802. if (!expr->isDatarow())
  12803. return doBuildActivityNormalizeLinkedChild(ctx, expr);
  12804. bool isNew = false;
  12805. IHqlExpression * dataset = querySelectorDataset(expr, isNew);
  12806. assertex(isNew);
  12807. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12808. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKproject, expr, "Project");
  12809. buildActivityFramework(instance);
  12810. buildInstancePrefix(instance);
  12811. {
  12812. //Need to create a dataset to replace the parent selector - since it might be a row
  12813. OwnedHqlExpr anon = createDataset(no_anon, LINK(dataset->queryRecord()));
  12814. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  12815. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  12816. ensureRowAllocated(func.ctx, "crSelf");
  12817. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  12818. bindTableCursor(func.ctx, anon->queryNormalizedSelector(), "left");
  12819. OwnedHqlExpr activeAnon = ensureActiveRow(anon);
  12820. OwnedHqlExpr value = replaceSelectorDataset(expr, activeAnon);
  12821. buildAssign(func.ctx, selfCursor->querySelector(), value);
  12822. buildReturnRecordSize(func.ctx, selfCursor);
  12823. }
  12824. buildInstanceSuffix(instance);
  12825. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12826. return instance->getBoundActivity();
  12827. }
  12828. //---------------------------------------------------------------------------
  12829. ABoundActivity * HqlCppTranslator::doBuildActivityPrefetchProject(BuildCtx & ctx, IHqlExpression * expr)
  12830. {
  12831. IHqlExpression * dataset = expr->queryChild(0);
  12832. IHqlExpression * transform = queryNewColumnProvider(expr);
  12833. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12834. IHqlExpression * selSeq = querySelSeq(expr);
  12835. IHqlExpression * prefetch = expr->queryAttribute(prefetchAtom);
  12836. IHqlExpression * lookahead = queryAttributeChild(expr, prefetchAtom, 0);
  12837. IHqlExpression * record = expr->queryRecord();
  12838. #ifdef _DEBUG
  12839. assertex((counter != NULL) == transformContainsCounter(transform, counter));
  12840. #endif
  12841. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12842. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, counter ? TAKprefetchcountproject : TAKprefetchproject, expr, "PrefetchProject");
  12843. buildActivityFramework(instance);
  12844. buildInstancePrefix(instance);
  12845. StringBuffer flags;
  12846. if (prefetch && prefetch->hasAttribute(parallelAtom)) flags.append("|PPFparallel");
  12847. if (flags.length())
  12848. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  12849. if (transformContainsSkip(transform))
  12850. doBuildBoolFunction(instance->classctx, "canFilter", true);
  12851. if (lookahead)
  12852. doBuildUnsignedFunction(instance->startctx, "getLookahead", lookahead);
  12853. //Similar code to project below. First generate the post processing function (which all aliases etc. will get generated into)
  12854. MemberFunction transformFunc(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IEclGraphResults * results, unsigned __int64 _counter)");
  12855. ensureRowAllocated(transformFunc.ctx, "crSelf");
  12856. transformFunc.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  12857. if (expr->getOperator() == no_hqlproject)
  12858. bindTableCursor(transformFunc.ctx, dataset, "left", no_left, selSeq);
  12859. else
  12860. bindTableCursor(transformFunc.ctx, dataset, "left");
  12861. BoundRow * selfCursor = bindSelf(transformFunc.ctx, expr, "crSelf");
  12862. associateSkipReturnMarker(transformFunc.ctx, queryZero(), selfCursor);
  12863. if (counter)
  12864. associateCounter(transformFunc.ctx, counter, "counter");
  12865. //Now process the transform
  12866. HqlExprArray assigns;
  12867. //Introduce a scope to ensure that mapper and builder have the minimum lifetime.
  12868. {
  12869. //Possibly cleaner if this was implemented inside a class derived from TransformBuilder
  12870. TransformBuilder builder(*this, transformFunc.ctx, record, selfCursor, assigns);
  12871. filterExpandAssignments(transformFunc.ctx, &builder, assigns, transform);
  12872. builder.buildTransformChildren(transformFunc.ctx, record, selfCursor->querySelector());
  12873. OwnedHqlExpr subgraph = builder.getPrefetchGraph();
  12874. if (subgraph)
  12875. {
  12876. //Generate the extract preparation function
  12877. MemberFunction preTransformFunc(*this, instance->startctx, "virtual bool preTransform(rtlRowBuilder & builder, const void * _left, unsigned __int64 _counter)");
  12878. associateSkipReturnMarker(preTransformFunc.ctx, queryBoolExpr(false), NULL);
  12879. preTransformFunc.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  12880. if (expr->getOperator() == no_hqlproject)
  12881. bindTableCursor(preTransformFunc.ctx, dataset, "left", no_left, selSeq);
  12882. else
  12883. bindTableCursor(preTransformFunc.ctx, dataset, "left");
  12884. if (counter)
  12885. associateCounter(preTransformFunc.ctx, counter, "counter");
  12886. OwnedHqlExpr graphInstance;
  12887. ChildGraphBuilder graphBuilder(*this, subgraph);
  12888. graphBuilder.generatePrefetchGraph(preTransformFunc.ctx, &graphInstance);
  12889. preTransformFunc.ctx.addReturn(queryBoolExpr(true));
  12890. BuildCtx childctx(instance->startctx);
  12891. childctx.addQuotedFunction("virtual IThorChildGraph *queryChild()");
  12892. childctx.addReturn(graphInstance);
  12893. //Add an association for the results into the transform function.
  12894. IHqlExpression * graph = subgraph->queryChild(0);
  12895. OwnedHqlExpr results = createAttribute(resultsAtom, LINK(graph));
  12896. OwnedHqlExpr resultsInstanceExpr = createQuoted("results", makeBoolType());
  12897. transformFunc.ctx.associateExpr(results, resultsInstanceExpr);
  12898. }
  12899. builder.flush(transformFunc.ctx);
  12900. }
  12901. buildReturnRecordSize(transformFunc.ctx, selfCursor);
  12902. buildInstanceSuffix(instance);
  12903. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12904. return instance->getBoundActivity();
  12905. }
  12906. ABoundActivity * HqlCppTranslator::doBuildActivityProject(BuildCtx & ctx, IHqlExpression * expr)
  12907. {
  12908. if (expr->hasAttribute(prefetchAtom) || options.usePrefetchForAllProjects)
  12909. return doBuildActivityPrefetchProject(ctx, expr);
  12910. const node_operator op = expr->getOperator();
  12911. IHqlExpression * dataset = expr->queryChild(0);
  12912. IHqlExpression * normalized = dataset->queryNormalizedSelector();
  12913. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12914. IHqlExpression * selSeq = querySelSeq(expr);
  12915. LinkedHqlExpr transform = queryNewColumnProvider(expr);
  12916. LinkedHqlExpr invariantCondition;
  12917. HqlExprArray filterConditions;
  12918. OwnedHqlExpr leftSelector = (op != no_newusertable) ? createSelector(no_left, normalized, selSeq) : NULL;
  12919. //Spot any filters preceding this project/user table, and fold them into the project
  12920. //It doesn't work with count projects though - because it would alter the counter passed to the transform.
  12921. //MORE: It would be possible to spot a skip condition for a count project which was input invariant, but thor
  12922. //would need a new implementation if the input wasn't grouped because the count would need to be global.
  12923. if (!counter)
  12924. {
  12925. bool done = false;
  12926. do
  12927. {
  12928. switch (dataset->getOperator())
  12929. {
  12930. case no_filter:
  12931. {
  12932. LinkedHqlExpr invariant;
  12933. OwnedHqlExpr cond = extractFilterConditions(invariant, dataset, normalized, false, false);
  12934. //A dataset invariant filter is only worth combining if the engine supports a filtered project operation.
  12935. if (!options.supportFilterProject && invariant)
  12936. {
  12937. done = true;
  12938. break;
  12939. }
  12940. //Don't merge the condition if it would create an ambiguity on LEFT - highly unlikely to occur in practice
  12941. if (leftSelector && cond)
  12942. {
  12943. if (containsSelectorAnywhere(cond, leftSelector))
  12944. {
  12945. done = true;
  12946. break;
  12947. }
  12948. cond.setown(replaceSelector(cond, normalized, leftSelector));
  12949. }
  12950. extendConditionOwn(invariantCondition, no_and, invariant.getClear());
  12951. if (cond)
  12952. cond->unwindList(filterConditions, no_and);
  12953. dataset = dataset->queryChild(0);
  12954. break;
  12955. }
  12956. case no_sorted:
  12957. dataset = dataset->queryChild(0);
  12958. break;
  12959. default:
  12960. done = true;
  12961. break;
  12962. }
  12963. } while (!done);
  12964. }
  12965. bool isFilterProject = invariantCondition != NULL;
  12966. bool containsCounter = expr->hasAttribute(_countProject_Atom);
  12967. #ifdef _DEBUG
  12968. assertex(containsCounter == transformContainsCounter(transform, counter));
  12969. #endif
  12970. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12971. Owned<ActivityInstance> instance = isFilterProject ? new ActivityInstance(*this, ctx, TAKfilterproject, expr, "FilterProject") :
  12972. containsCounter ? new ActivityInstance(*this, ctx, TAKcountproject, expr, "CountProject")
  12973. : new ActivityInstance(*this, ctx, TAKproject, expr, "Project");
  12974. if (filterConditions.ordinality())
  12975. {
  12976. if (isGroupedActivity(expr))
  12977. instance->graphLabel.set("Grouped Filtered Project");
  12978. else
  12979. instance->graphLabel.set("Filtered Project");
  12980. }
  12981. buildActivityFramework(instance);
  12982. buildInstancePrefix(instance);
  12983. {
  12984. MemberFunction func(*this, instance->startctx);
  12985. if (isFilterProject || containsCounter)
  12986. {
  12987. func.start("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned __int64 counter)");
  12988. if (containsCounter)
  12989. associateCounter(func.ctx, counter, "counter");
  12990. }
  12991. else
  12992. func.start("virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  12993. ensureRowAllocated(func.ctx, "crSelf");
  12994. if (filterConditions.ordinality())
  12995. {
  12996. HqlExprArray args;
  12997. ForEachItemIn(i, filterConditions)
  12998. {
  12999. OwnedHqlExpr test = createValue(no_skip, makeVoidType(), getInverse(&filterConditions.item(i)));
  13000. args.append(*LINK(test));
  13001. }
  13002. unwindChildren(args, transform);
  13003. transform.setown(transform->clone(args));
  13004. }
  13005. if (op == no_newusertable)
  13006. {
  13007. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  13008. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  13009. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  13010. bindTableCursor(func.ctx, dataset, "left");
  13011. doTransform(func.ctx, transform, selfCursor);
  13012. buildReturnRecordSize(func.ctx, selfCursor);
  13013. }
  13014. else
  13015. buildTransformBody(func.ctx, transform, dataset, NULL, instance->dataset, selSeq);
  13016. }
  13017. if (filterConditions.ordinality() || transformContainsSkip(transform))
  13018. doBuildBoolFunction(instance->classctx, "canFilter", true);
  13019. if (invariantCondition)
  13020. doBuildBoolFunction(instance->startctx, "canMatchAny", invariantCondition);
  13021. buildInstanceSuffix(instance);
  13022. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13023. return instance->getBoundActivity();
  13024. }
  13025. //---------------------------------------------------------------------------
  13026. ABoundActivity * HqlCppTranslator::doBuildActivitySerialize(BuildCtx & ctx, IHqlExpression * expr)
  13027. {
  13028. IHqlExpression * dataset = expr->queryChild(0);
  13029. bool serialize = (expr->getOperator() == no_serialize);
  13030. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13031. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKproject, expr, "Project");
  13032. buildActivityFramework(instance);
  13033. buildInstancePrefix(instance);
  13034. {
  13035. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  13036. // Bind left to "left" and right to RIGHT
  13037. bindTableCursor(func.ctx, dataset, "_left");
  13038. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  13039. //MORE: I don't have any examples that trigger this code as far as I know...
  13040. IIdAtom * funcId = serialize ? rtlSerializeToBuilderId : rtlDeserializeToBuilderId;
  13041. IAtom * kind = serialize ? serializerAtom : deserializerAtom;
  13042. IAtom * serializeForm = serialize ? expr->queryChild(1)->queryName() : expr->queryChild(2)->queryName();
  13043. IHqlExpression * record = expr->queryRecord();
  13044. HqlExprArray args;
  13045. args.append(*createSerializer(func.ctx, record, serializeForm, kind));
  13046. args.append(*ensureActiveRow(dataset));
  13047. Owned<ITypeInfo> type = makeTransformType(record->getType());
  13048. OwnedHqlExpr call = bindFunctionCall(funcId, args, type);
  13049. doTransform(func.ctx, call, selfCursor);
  13050. buildReturnRecordSize(func.ctx, selfCursor);
  13051. }
  13052. buildInstanceSuffix(instance);
  13053. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13054. return instance->getBoundActivity();
  13055. }
  13056. //---------------------------------------------------------------------------
  13057. ABoundActivity * HqlCppTranslator::doBuildActivityDefineSideEffect(BuildCtx & ctx, IHqlExpression * expr)
  13058. {
  13059. Owned<ABoundActivity> parentActivity = buildCachedActivity(ctx, expr->queryChild(0));
  13060. OwnedHqlExpr attr = createAttribute(_sideEffect_Atom, LINK(expr->queryAttribute(_uid_Atom)));
  13061. OwnedHqlExpr unknown = createUnknown(no_attr, NULL, NULL, LINK(parentActivity));
  13062. activeGraphCtx->associateExpr(attr, unknown);
  13063. return parentActivity.getClear();
  13064. }
  13065. //---------------------------------------------------------------------------
  13066. ABoundActivity * HqlCppTranslator::doBuildActivityCallSideEffect(BuildCtx & ctx, IHqlExpression * expr)
  13067. {
  13068. OwnedHqlExpr attr = createAttribute(_sideEffect_Atom, LINK(expr->queryAttribute(_uid_Atom)));
  13069. HqlExprAssociation * match = activeGraphCtx->queryMatchExpr(attr);
  13070. if (!match)
  13071. throwUnexpected();
  13072. ABoundActivity * activity = static_cast<ABoundActivity *>(match->queryExpr()->queryUnknownExtra());
  13073. return LINK(activity);
  13074. }
  13075. //---------------------------------------------------------------------------
  13076. ABoundActivity * HqlCppTranslator::doBuildActivityExecuteWhen(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13077. {
  13078. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13079. Owned<ABoundActivity> associatedActivity = buildCachedActivity(ctx, expr->queryChild(1));
  13080. if (!associatedActivity)
  13081. return boundDataset.getClear();
  13082. const char * label;
  13083. int when;
  13084. if (expr->hasAttribute(successAtom))
  13085. {
  13086. label = "Success";
  13087. when = WhenSuccessId;
  13088. }
  13089. else if (expr->hasAttribute(failureAtom))
  13090. {
  13091. label = "Failure";
  13092. when = WhenFailureId;
  13093. }
  13094. else if (expr->hasAttribute(parallelAtom))
  13095. {
  13096. label = "Parallel";
  13097. when = WhenParallelId;
  13098. }
  13099. else if (expr->hasAttribute(beforeAtom))
  13100. {
  13101. label = "Before";
  13102. when = WhenBeforeId;
  13103. }
  13104. else
  13105. {
  13106. //Should WHEN default to BEFORE or PARALLEL??
  13107. label = "Parallel";
  13108. when = WhenParallelId;
  13109. }
  13110. bool useImplementationClass = options.minimizeActivityClasses;
  13111. ThorActivityKind kind = (expr->isAction() ? TAKwhen_action : TAKwhen_dataset);
  13112. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "WhenAction");
  13113. if (useImplementationClass)
  13114. instance->setImplementationClass(newWhenActionArgId);
  13115. buildActivityFramework(instance, isRoot);
  13116. buildInstancePrefix(instance);
  13117. buildInstanceSuffix(instance);
  13118. if (expr->isAction())
  13119. addActionConnection(ctx, boundDataset, instance, dependencyAtom, NULL, 0, 1);
  13120. else
  13121. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13122. addActionConnection(ctx, associatedActivity, instance, dependencyAtom, label, 0, when);
  13123. return instance->getBoundActivity();
  13124. }
  13125. //---------------------------------------------------------------------------
  13126. IHqlExpression * extractFilterConditions(HqlExprAttr & invariant, IHqlExpression * expr, IHqlExpression * dataset, bool spotCSE, bool spotCseInIfDatasetConditions)
  13127. {
  13128. unsigned num = expr->numChildren();
  13129. assertex(num > 1);
  13130. HqlExprAttr cond = queryRealChild(expr, 1);
  13131. bool changed = false;
  13132. unsigned idx;
  13133. for (idx = 2; idx < num; idx++)
  13134. {
  13135. IHqlExpression * cur = expr->queryChild(idx);
  13136. if (!cur->isAttribute())
  13137. extendConditionOwn(cond, no_and, LINK(cur));
  13138. }
  13139. if (!cond)
  13140. return NULL;
  13141. if (spotCSE)
  13142. cond.setown(spotScalarCSE(cond, NULL, spotCseInIfDatasetConditions));
  13143. HqlExprArray tests;
  13144. cond->unwindList(tests, no_and);
  13145. ForEachItemInRev(i, tests)
  13146. {
  13147. IHqlExpression & cur = tests.item(i);
  13148. if (!exprReferencesDataset(&cur, dataset))
  13149. {
  13150. changed = true;
  13151. if (!matchesBoolean(&cur, true))
  13152. invariant.setown(extendConditionOwn(no_and, LINK(&cur), invariant.getClear()));
  13153. tests.remove(i);
  13154. }
  13155. }
  13156. if (changed)
  13157. cond.setown(createBalanced(no_and, queryBoolType(), tests));
  13158. return cond.getClear();
  13159. }
  13160. ABoundActivity * HqlCppTranslator::doBuildActivityFilter(BuildCtx & ctx, IHqlExpression * expr)
  13161. {
  13162. IHqlExpression * dataset = expr->queryChild(0);
  13163. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13164. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfilter, expr,"Filter");
  13165. buildActivityFramework(instance);
  13166. buildInstancePrefix(instance);
  13167. HqlExprAttr invariant;
  13168. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, dataset, options.spotCSE, queryOptions().spotCseInIfDatasetConditions);
  13169. //Base class returns true, so only generate if no non-invariant conditions
  13170. if (cond)
  13171. {
  13172. MemberFunction func(*this, instance->startctx, "virtual bool isValid(const void * _self)");
  13173. func.ctx.addQuotedLiteral("unsigned char * self = (unsigned char *) _self;");
  13174. bindTableCursor(func.ctx, dataset, "self");
  13175. buildReturn(func.ctx, cond);
  13176. if (options.addLikelihoodToGraph)
  13177. {
  13178. double likelihood = queryLikelihood(cond);
  13179. if (isKnownLikelihood(likelihood))
  13180. {
  13181. StringBuffer text;
  13182. likelihood *= 100;
  13183. text.setf("%3.2f%%", likelihood);
  13184. instance->addAttribute("matchLikelihood", text);
  13185. }
  13186. }
  13187. }
  13188. if (invariant)
  13189. doBuildBoolFunction(instance->startctx, "canMatchAny", invariant);
  13190. buildInstanceSuffix(instance);
  13191. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13192. return instance->getBoundActivity();
  13193. }
  13194. ABoundActivity * HqlCppTranslator::doBuildActivityFilterGroup(BuildCtx & ctx, IHqlExpression * expr)
  13195. {
  13196. IHqlExpression * dataset = expr->queryChild(0);
  13197. IHqlExpression * selSeq = querySelSeq(expr);
  13198. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  13199. if (targetThor() && !isGrouped(dataset))
  13200. throwError(HQLERR_ThorHavingMustBeGrouped);
  13201. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13202. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfiltergroup, expr,"FilterGroup");
  13203. buildActivityFramework(instance);
  13204. buildInstancePrefix(instance);
  13205. HqlExprAttr invariant;
  13206. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  13207. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, left, options.spotCSE, options.spotCseInIfDatasetConditions);
  13208. //Base class returns true, so only generate if no non-invariant conditions
  13209. if (cond)
  13210. {
  13211. MemberFunction func(*this, instance->startctx, "virtual bool isValid(unsigned numRows, const void * * _rows)");
  13212. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _rows[0];");
  13213. func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
  13214. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  13215. bindRows(func.ctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  13216. buildReturn(func.ctx, cond);
  13217. }
  13218. if (invariant)
  13219. doBuildBoolFunction(instance->startctx, "canMatchAny", invariant);
  13220. buildInstanceSuffix(instance);
  13221. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13222. return instance->getBoundActivity();
  13223. }
  13224. //---------------------------------------------------------------------------
  13225. ABoundActivity * HqlCppTranslator::doBuildActivityCombine(BuildCtx & ctx, IHqlExpression * expr)
  13226. {
  13227. //MORE: Need to expand nested combines so they have multiple inputs.
  13228. //But will need to assign aliases to the inputs + do a reasonable amount of processing.
  13229. IHqlExpression * left = expr->queryChild(0);
  13230. IHqlExpression * right = expr->queryChild(1);
  13231. IHqlExpression * transform = expr->queryChild(2);
  13232. IHqlExpression * selSeq = querySelSeq(expr);
  13233. if (targetThor() && !expr->hasAttribute(localAtom) && !insideChildQuery(ctx))
  13234. ERRORAT(queryLocation(expr), HQLERR_ThorCombineOnlyLocal);
  13235. CIArray bound;
  13236. bound.append(*buildCachedActivity(ctx, left));
  13237. bound.append(*buildCachedActivity(ctx, right));
  13238. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKcombine, expr, "Combine");
  13239. buildActivityFramework(instance);
  13240. buildInstancePrefix(instance);
  13241. {
  13242. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, unsigned _num, const void * * _rows)");
  13243. if (transform->getOperator() != no_skip)
  13244. {
  13245. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _rows[0];");
  13246. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _rows[1];");
  13247. ensureRowAllocated(func.ctx, "crSelf");
  13248. bindTableCursor(func.ctx, left, "left", no_left, selSeq);
  13249. bindTableCursor(func.ctx, right, "right", no_right, selSeq);
  13250. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  13251. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  13252. doTransform(func.ctx, transform, selfCursor);
  13253. buildReturnRecordSize(func.ctx, selfCursor);
  13254. }
  13255. else
  13256. func.ctx.addReturn(queryZero());
  13257. }
  13258. if (transformContainsSkip(transform))
  13259. doBuildBoolFunction(instance->classctx, "canFilter", true);
  13260. buildInstanceSuffix(instance);
  13261. ForEachItemIn(idx2, bound)
  13262. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  13263. return instance->getBoundActivity();
  13264. }
  13265. //---------------------------------------------------------------------------
  13266. void HqlCppTranslator::bindRows(BuildCtx & ctx, node_operator side, IHqlExpression * selSeq, IHqlExpression * rowsid, IHqlExpression * dataset, const char * numText, const char * rowsText, bool rowsAreLinkCounted)
  13267. {
  13268. OwnedHqlExpr selector = createSelector(side, dataset, selSeq);
  13269. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(selector), LINK(rowsid));
  13270. Owned<ITypeInfo> rowType = makeReferenceModifier(LINK(rowsExpr->queryType()->queryChildType()));
  13271. if (rowsAreLinkCounted)
  13272. rowType.setown(setLinkCountedAttr(rowType, true));
  13273. //Rows may be link counted, but rows() is not a linkable rowset
  13274. OwnedITypeInfo rowsType = makeReferenceModifier(makeTableType(rowType.getClear()));
  13275. rowsType.setown(makeOutOfLineModifier(LINK(rowsType)));
  13276. CHqlBoundExpr boundRows;
  13277. boundRows.count.setown(createQuoted(numText, LINK(unsignedType)));
  13278. boundRows.expr.setown(createQuoted(rowsText, LINK(rowsType)));
  13279. ctx.associateExpr(rowsExpr, boundRows);
  13280. }
  13281. //---------------------------------------------------------------------------
  13282. ABoundActivity * HqlCppTranslator::doBuildActivityCombineGroup(BuildCtx & ctx, IHqlExpression * expr)
  13283. {
  13284. //MORE: Need to expand nested combines so they have multiple inputs.
  13285. //But will need to assign aliases to the inputs + do a reasonable amount of processing.
  13286. IHqlExpression * left = expr->queryChild(0);
  13287. IHqlExpression * right = expr->queryChild(1);
  13288. IHqlExpression * selSeq = querySelSeq(expr);
  13289. IHqlExpression * transform = expr->queryChild(2);
  13290. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  13291. CIArray bound;
  13292. bound.append(*buildCachedActivity(ctx, left));
  13293. bound.append(*buildCachedActivity(ctx, right));
  13294. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKcombinegroup, expr, "CombineGroup");
  13295. buildActivityFramework(instance);
  13296. buildInstancePrefix(instance);
  13297. {
  13298. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned numRows, const void * * _rows)");
  13299. if (transform->getOperator() != no_skip)
  13300. {
  13301. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *)_left;");
  13302. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _rows[0];");
  13303. func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
  13304. ensureRowAllocated(func.ctx, "crSelf");
  13305. bindTableCursor(func.ctx, left, "left", no_left, selSeq);
  13306. bindTableCursor(func.ctx, right, "right", no_right, selSeq);
  13307. bindRows(func.ctx, no_right, selSeq, rowsid, right, "numRows", "rows", options.mainRowsAreLinkCounted);
  13308. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  13309. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  13310. doTransform(func.ctx, transform, selfCursor);
  13311. buildReturnRecordSize(func.ctx, selfCursor);
  13312. }
  13313. else
  13314. func.ctx.addReturn(queryZero());
  13315. }
  13316. if (transformContainsSkip(transform))
  13317. doBuildBoolFunction(instance->classctx, "canFilter", true);
  13318. buildInstanceSuffix(instance);
  13319. ForEachItemIn(idx2, bound)
  13320. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  13321. return instance->getBoundActivity();
  13322. }
  13323. //---------------------------------------------------------------------------
  13324. ABoundActivity * HqlCppTranslator::doBuildActivityRollupGroup(BuildCtx & ctx, IHqlExpression * expr)
  13325. {
  13326. //MORE: Need to expand nested combines so they have multiple inputs.
  13327. IHqlExpression * dataset = expr->queryChild(0);
  13328. IHqlExpression * transform = expr->queryChild(1);
  13329. IHqlExpression * selSeq = querySelSeq(expr);
  13330. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  13331. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13332. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKrollupgroup, expr, "RollupGroup");
  13333. instance->graphLabel.set("Rollup Group"); // Grouped Rollup Group looks silly
  13334. buildActivityFramework(instance);
  13335. buildInstancePrefix(instance);
  13336. {
  13337. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, unsigned numRows, const void * * _rows)");
  13338. if (transform->getOperator() != no_skip)
  13339. {
  13340. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _rows[0];");
  13341. func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
  13342. ensureRowAllocated(func.ctx, "crSelf");
  13343. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  13344. bindRows(func.ctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  13345. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  13346. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  13347. doTransform(func.ctx, transform, selfCursor);
  13348. buildReturnRecordSize(func.ctx, selfCursor);
  13349. }
  13350. else
  13351. func.ctx.addReturn(queryZero());
  13352. }
  13353. if (transformContainsSkip(transform))
  13354. doBuildBoolFunction(instance->classctx, "canFilter", true);
  13355. buildInstanceSuffix(instance);
  13356. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13357. return instance->getBoundActivity();
  13358. }
  13359. //---------------------------------------------------------------------------
  13360. ABoundActivity * HqlCppTranslator::doBuildActivityAssert(BuildCtx & ctx, IHqlExpression * expr)
  13361. {
  13362. HqlExprArray args;
  13363. expr->unwindList(args, expr->getOperator());
  13364. IHqlExpression * dataset = &args.item(0);
  13365. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13366. //MORE: Change this when ThroughApply activities are supported in engines.
  13367. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfilter, expr,"Filter");
  13368. instance->graphLabel.set("Assert");
  13369. buildActivityFramework(instance);
  13370. buildInstancePrefix(instance);
  13371. unsigned num = args.ordinality();
  13372. {
  13373. MemberFunction func(*this, instance->startctx, "virtual bool isValid(const void * _self)");
  13374. func.ctx.addQuotedLiteral("unsigned char * self = (unsigned char *) _self;");
  13375. bindTableCursor(func.ctx, dataset, "self");
  13376. for (unsigned i=1; i < num; i++)
  13377. {
  13378. IHqlExpression & cur = args.item(i);
  13379. if (!cur.isAttribute())
  13380. buildStmt(func.ctx, &cur);
  13381. }
  13382. func.ctx.addReturn(queryBoolExpr(true));
  13383. }
  13384. buildInstanceSuffix(instance);
  13385. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13386. return instance->getBoundActivity();
  13387. }
  13388. //---------------------------------------------------------------------------
  13389. void HqlCppTranslator::buildLimitHelpers(BuildCtx & ctx, IHqlExpression * rowLimit, IHqlExpression * failAction, bool isSkip, IHqlExpression * filename, unique_id_t id)
  13390. {
  13391. doBuildUnsigned64Function(ctx, "getRowLimit", rowLimit);
  13392. if (isZero(rowLimit))
  13393. WARNING(CategoryUnusual, HQLWRN_LimitIsZero);
  13394. if (!isSkip)
  13395. {
  13396. LinkedHqlExpr fail = failAction;
  13397. if (!fail || fail->isAttribute())
  13398. {
  13399. if (!id)
  13400. id = queryCurrentActivityId(ctx);
  13401. fail.setown(createFailAction("Limit exceeded", rowLimit, filename, id));
  13402. }
  13403. MemberFunction func(*this, ctx, "virtual void onLimitExceeded()");
  13404. buildStmt(func.ctx, fail);
  13405. }
  13406. }
  13407. void HqlCppTranslator::buildLimitHelpers(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * filename, unique_id_t id)
  13408. {
  13409. buildLimitHelpers(ctx, expr->queryChild(1), queryRealChild(expr, 2), expr->hasAttribute(skipAtom), filename, id);
  13410. IHqlExpression * transform = queryAttributeChild(expr, onFailAtom, 0);
  13411. if (transform)
  13412. {
  13413. MemberFunction func(*this, ctx, "virtual size32_t transformOnLimitExceeded(ARowBuilder & crSelf)");
  13414. ensureRowAllocated(func.ctx, "crSelf");
  13415. buildTransformBody(func.ctx, transform, NULL, NULL, expr, NULL);
  13416. }
  13417. }
  13418. ABoundActivity * HqlCppTranslator::doBuildActivityLimit(BuildCtx & ctx, IHqlExpression * expr)
  13419. {
  13420. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13421. IHqlExpression * transform = queryAttributeChild(expr, onFailAtom, 0);
  13422. ThorActivityKind kind = TAKlimit;
  13423. const char * helper = "Limit";
  13424. if (transform)
  13425. {
  13426. kind = TAKcreaterowlimit;
  13427. helper = "CreateRowLimit";
  13428. }
  13429. else if (expr->hasAttribute(skipAtom))
  13430. kind = TAKskiplimit;
  13431. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  13432. buildActivityFramework(instance);
  13433. buildInstancePrefix(instance);
  13434. buildLimitHelpers(instance->startctx, expr, NULL, instance->activityId);
  13435. buildInstanceSuffix(instance);
  13436. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13437. return instance->getBoundActivity();
  13438. }
  13439. ABoundActivity * HqlCppTranslator::doBuildActivityCatch(BuildCtx & ctx, IHqlExpression * expr)
  13440. {
  13441. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13442. IHqlExpression * arg1 = queryRealChild(expr, 1);
  13443. IHqlExpression * filter = NULL;
  13444. IHqlExpression * action = NULL;
  13445. if (arg1 && arg1->isBoolean())
  13446. {
  13447. filter = arg1;
  13448. action = queryRealChild(expr, 2);
  13449. }
  13450. else
  13451. action = arg1;
  13452. IHqlExpression * transform = queryAttributeChild(expr, onFailAtom, 0);
  13453. bool isSkip = expr->hasAttribute(skipAtom);
  13454. ThorActivityKind kind = TAKcatch;
  13455. const char * helper = "Catch";
  13456. if (transform)
  13457. kind = TAKcreaterowcatch;
  13458. else if (isSkip)
  13459. kind = TAKskipcatch;
  13460. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  13461. buildActivityFramework(instance);
  13462. buildInstancePrefix(instance);
  13463. if (filter)
  13464. {
  13465. MemberFunction func(*this, instance->startctx, "virtual bool isMatch(IException * except)");
  13466. associateLocalFailure(func.ctx, "except");
  13467. OwnedHqlExpr cseFilter = spotScalarCSE(filter, NULL, queryOptions().spotCseInIfDatasetConditions);
  13468. buildReturn(func.ctx, cseFilter, queryBoolType());
  13469. }
  13470. if (transform)
  13471. {
  13472. MemberFunction func(*this, instance->startctx, "virtual unsigned transformOnExceptionCaught(ARowBuilder & crSelf, IException * except)");
  13473. ensureRowAllocated(func.ctx, "crSelf");
  13474. associateLocalFailure(func.ctx, "except");
  13475. buildTransformBody(func.ctx, transform, NULL, NULL, expr, NULL);
  13476. }
  13477. else if (!isSkip)
  13478. {
  13479. LinkedHqlExpr fail = action;
  13480. if (!fail)
  13481. fail.setown(createFailAction("Missing failure", NULL, NULL, instance->activityId));
  13482. MemberFunction func(*this, instance->startctx, "virtual void onExceptionCaught()");
  13483. buildStmt(func.ctx, fail);
  13484. }
  13485. buildInstanceSuffix(instance);
  13486. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13487. return instance->getBoundActivity();
  13488. }
  13489. ABoundActivity * HqlCppTranslator::doBuildActivitySection(BuildCtx & ctx, IHqlExpression * expr)
  13490. {
  13491. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13492. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsection, expr, "Section");
  13493. StringBuffer label;
  13494. getStringValue(label, expr->queryChild(1));
  13495. instance->graphLabel.set(label.str());
  13496. buildActivityFramework(instance);
  13497. buildInstancePrefix(instance);
  13498. StringBuffer flags;
  13499. IHqlExpression * description = NULL;
  13500. ForEachChildFrom(i, expr, 2)
  13501. {
  13502. IHqlExpression * cur = expr->queryChild(i);
  13503. if (cur->isAttribute())
  13504. {
  13505. IAtom * name= cur->queryName();
  13506. if (name == privateAtom)
  13507. flags.append("|TSFprivate");
  13508. }
  13509. else if (isStringType(cur->queryType()))
  13510. {
  13511. description = cur;
  13512. flags.append("|TSFdynamicDescription");
  13513. }
  13514. }
  13515. if (description)
  13516. doBuildStringFunction(instance->startctx, "getDescription", description);
  13517. if (flags.length())
  13518. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  13519. buildInstanceSuffix(instance);
  13520. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13521. return instance->getBoundActivity();
  13522. }
  13523. ABoundActivity * HqlCppTranslator::doBuildActivitySectionInput(BuildCtx & ctx, IHqlExpression * expr)
  13524. {
  13525. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13526. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsectioninput, expr, "SectionInput");
  13527. StringBuffer label;
  13528. expr->queryChild(1)->queryValue()->getStringValue(label);
  13529. instance->graphLabel.set(label.str());
  13530. instance->graphEclText.append("<>");
  13531. buildActivityFramework(instance);
  13532. buildInstancePrefix(instance);
  13533. StringBuffer flags;
  13534. if (expr->hasAttribute(privateAtom))
  13535. flags.append("|TSFprivate");
  13536. if (flags.length())
  13537. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  13538. buildInstanceSuffix(instance);
  13539. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13540. return instance->getBoundActivity();
  13541. }
  13542. //---------------------------------------------------------------------------
  13543. ABoundActivity * HqlCppTranslator::doBuildActivityPullActivity(BuildCtx & ctx, IHqlExpression * expr)
  13544. {
  13545. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13546. if (targetHThor())
  13547. return boundDataset.getClear();
  13548. assertex(expr->hasAttribute(pullAtom));
  13549. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKpull, expr, "Pull");
  13550. buildActivityFramework(instance);
  13551. buildInstancePrefix(instance);
  13552. buildInstanceSuffix(instance);
  13553. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13554. return instance->getBoundActivity();
  13555. }
  13556. ABoundActivity * HqlCppTranslator::doBuildActivityTraceActivity(BuildCtx & ctx, IHqlExpression * expr)
  13557. {
  13558. IHqlExpression * dataset = expr->queryChild(0);
  13559. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13560. assertex(expr->hasAttribute(traceAtom));
  13561. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKtrace, expr, "Trace");
  13562. buildActivityFramework(instance);
  13563. buildInstancePrefix(instance);
  13564. IHqlExpression *keepLimit = queryAttributeChild(expr, keepAtom, 0);
  13565. if (keepLimit)
  13566. doBuildUnsignedFunction(instance->startctx, "getKeepLimit", keepLimit);
  13567. IHqlExpression *skip = queryAttributeChild(expr, skipAtom, 0);
  13568. if (skip)
  13569. doBuildUnsignedFunction(instance->startctx, "getSkip", skip);
  13570. IHqlExpression *sample = queryAttributeChild(expr, sampleAtom, 0);
  13571. if (sample)
  13572. doBuildUnsignedFunction(instance->startctx, "getSample", sample);
  13573. IHqlExpression *named = queryAttributeChild(expr, namedAtom, 0);
  13574. if (named)
  13575. doBuildVarStringFunction(instance->startctx, "getName", named);
  13576. HqlExprAttr invariant;
  13577. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, dataset, options.spotCSE, queryOptions().spotCseInIfDatasetConditions);
  13578. //Base class returns true, so only generate if no non-invariant conditions
  13579. if (cond)
  13580. {
  13581. MemberFunction func(*this, instance->startctx, "virtual bool isValid(const void * _self)");
  13582. func.ctx.addQuotedLiteral("unsigned char * self = (unsigned char *) _self;");
  13583. bindTableCursor(func.ctx, dataset, "self");
  13584. buildReturn(func.ctx, cond);
  13585. }
  13586. if (invariant)
  13587. doBuildBoolFunction(instance->startctx, "canMatchAny", invariant);
  13588. buildInstanceSuffix(instance);
  13589. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13590. return instance->getBoundActivity();
  13591. }
  13592. //---------------------------------------------------------------------------
  13593. //-- no_sub --
  13594. ABoundActivity * HqlCppTranslator::doBuildActivitySub(BuildCtx & ctx, IHqlExpression * expr)
  13595. {
  13596. assertex(!"MORE!");
  13597. return NULL;
  13598. }
  13599. //---------------------------------------------------------------------------
  13600. //-- no_sample [GROUP] --
  13601. ABoundActivity * HqlCppTranslator::doBuildActivityEnth(BuildCtx & ctx, IHqlExpression * expr)
  13602. {
  13603. IHqlExpression * dataset = expr->queryChild(0);
  13604. IHqlExpression * numerator = expr->queryChild(1);
  13605. IHqlExpression * denominator = expr->queryChild(2);
  13606. IHqlExpression * sample = expr->queryChild(3);
  13607. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13608. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKenth, expr, "Enth");
  13609. buildActivityFramework(instance);
  13610. buildInstancePrefix(instance);
  13611. {
  13612. MemberFunction func(*this, instance->startctx, "virtual unsigned __int64 getProportionNumerator()");
  13613. buildReturn(func.ctx, numerator);
  13614. }
  13615. {
  13616. MemberFunction func(*this, instance->startctx, "virtual unsigned __int64 getProportionDenominator()");
  13617. if (denominator && !denominator->isAttribute())
  13618. buildReturn(func.ctx, denominator);
  13619. else
  13620. {
  13621. OwnedHqlExpr notProvided = createConstant(counterType->castFrom(true, I64C(-1)));
  13622. buildReturn(func.ctx, notProvided);
  13623. }
  13624. }
  13625. {
  13626. MemberFunction func(*this, instance->startctx, "virtual unsigned getSampleNumber()");
  13627. if (sample && !sample->isAttribute())
  13628. buildReturn(func.ctx, sample);
  13629. else
  13630. func.ctx.addQuotedLiteral("return 1;");
  13631. }
  13632. buildInstanceSuffix(instance);
  13633. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13634. return instance->getBoundActivity();
  13635. }
  13636. //---------------------------------------------------------------------------
  13637. //-- no_sample [GROUP] --
  13638. ABoundActivity * HqlCppTranslator::doBuildActivitySample(BuildCtx & ctx, IHqlExpression * expr)
  13639. {
  13640. StringBuffer s;
  13641. IHqlExpression * dataset = expr->queryChild(0);
  13642. LinkedHqlExpr sampleExpr = queryRealChild(expr, 2);
  13643. if (!sampleExpr)
  13644. sampleExpr.setown(getSizetConstant(1));
  13645. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13646. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsample, expr,"Sample");
  13647. buildActivityFramework(instance);
  13648. buildInstancePrefix(instance);
  13649. doBuildUnsignedFunction(instance->startctx, "getProportion", expr->queryChild(1));
  13650. doBuildUnsignedFunction(instance->startctx, "getSampleNumber", sampleExpr);
  13651. buildInstanceSuffix(instance);
  13652. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13653. return instance->getBoundActivity();
  13654. }
  13655. //---------------------------------------------------------------------------
  13656. //-- no_group [GROUP] --
  13657. /* In parms: NOT linked. Return: linked */
  13658. IHqlExpression * HqlCppTranslator::createOrderFromSortList(const DatasetReference & dataset, IHqlExpression * sortList, IHqlExpression * leftSelect, IHqlExpression * rightSelect)
  13659. {
  13660. HqlExprArray leftList, rightList;
  13661. unsigned max = sortList->numChildren();
  13662. unsigned idx;
  13663. for (idx = 0; idx < max; idx++)
  13664. {
  13665. IHqlExpression * next = sortList->queryChild(idx);
  13666. //optimize order on (string)qstring to order on qstring for example. Can make quite a difference.
  13667. if (isCast(next))
  13668. {
  13669. IHqlExpression * uncast = next->queryChild(0);
  13670. ITypeInfo * castType = next->queryType();
  13671. ITypeInfo * uncastType = uncast->queryType();
  13672. if (preservesValue(castType, uncastType) && preservesOrder(castType, uncastType))
  13673. next = uncast;
  13674. }
  13675. bool invert = false;
  13676. if (next->getOperator() == no_negate)
  13677. {
  13678. invert = true;
  13679. next = next->queryChild(0);
  13680. }
  13681. IHqlExpression * leftResolved = dataset.mapScalar(next, leftSelect);
  13682. IHqlExpression * rightResolved = dataset.mapScalar(next, rightSelect);
  13683. if (invert)
  13684. {
  13685. leftList.append(*rightResolved);
  13686. rightList.append(*leftResolved);
  13687. }
  13688. else
  13689. {
  13690. leftList.append(*leftResolved);
  13691. rightList.append(*rightResolved);
  13692. }
  13693. }
  13694. return createValue(no_order, LINK(signedType), createSortList(leftList), createSortList(rightList));
  13695. }
  13696. void HqlCppTranslator::buildReturnOrder(BuildCtx & ctx, IHqlExpression *sortList, const DatasetReference & dataset)
  13697. {
  13698. OwnedHqlExpr selSeq = createDummySelectorSequence();
  13699. OwnedHqlExpr leftSelect = dataset.getSelector(no_left, selSeq);
  13700. OwnedHqlExpr rightSelect = dataset.getSelector(no_right, selSeq);
  13701. OwnedHqlExpr order = createOrderFromSortList(dataset, sortList, leftSelect, rightSelect);
  13702. bindTableCursor(ctx, dataset.queryDataset(), "left", no_left, selSeq);
  13703. bindTableCursor(ctx, dataset.queryDataset(), "right", no_right, selSeq);
  13704. doBuildReturnCompare(ctx, order, no_order, false, false);
  13705. }
  13706. void HqlCppTranslator::doBuildFuncIsSameGroup(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * sortlist)
  13707. {
  13708. MemberFunction func(*this, ctx, "virtual bool isSameGroup(const void * _left, const void * _right)");
  13709. if (sortlist->getOperator() == no_activetable)
  13710. buildReturn(func.ctx, queryBoolExpr(false));
  13711. else
  13712. {
  13713. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  13714. func.ctx.addQuotedLiteral("const unsigned char * right = (const unsigned char *) _right;");
  13715. OwnedHqlExpr selSeq = createSelectorSequence();
  13716. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, selSeq);
  13717. OwnedHqlExpr rightSelect = createSelector(no_right, dataset, selSeq);
  13718. HqlExprArray args;
  13719. HqlExprArray leftValues, rightValues;
  13720. HqlExprArray compares;
  13721. unwindChildren(compares, sortlist);
  13722. //Optimize the grouping conditions by ordering them by the fields in the record (so the
  13723. //doBuildReturnCompare() can combine as many as possible), and remove duplicates
  13724. if (options.optimizeGrouping && (compares.ordinality() > 1))
  13725. {
  13726. HqlExprArray equalities;
  13727. optimizeGroupOrder(equalities, dataset, compares);
  13728. ForEachItemIn(i, equalities)
  13729. {
  13730. IHqlExpression * test = &equalities.item(i);
  13731. leftValues.append(*replaceSelector(test, dataset, leftSelect));
  13732. rightValues.append(*replaceSelector(test, dataset, rightSelect));
  13733. }
  13734. }
  13735. ForEachItemIn(idx, compares)
  13736. {
  13737. IHqlExpression * test = &compares.item(idx);
  13738. if (containsSelector(test, leftSelect) || containsSelector(test, rightSelect))
  13739. args.append(*LINK(test));
  13740. else
  13741. {
  13742. OwnedHqlExpr lhs = replaceSelector(test, dataset, leftSelect);
  13743. OwnedHqlExpr rhs = replaceSelector(test, dataset, rightSelect);
  13744. if (lhs != rhs)
  13745. {
  13746. leftValues.append(*lhs.getClear());
  13747. rightValues.append(*rhs.getClear());
  13748. }
  13749. }
  13750. }
  13751. OwnedHqlExpr result;
  13752. OwnedHqlExpr orderResult;
  13753. //Use the optimized equality code for more than one element - which often combines the comparisons.
  13754. if (leftValues.ordinality() != 0)
  13755. {
  13756. if (leftValues.ordinality() == 1)
  13757. args.append(*createValue(no_eq, makeBoolType(), LINK(&leftValues.item(0)), LINK(&rightValues.item(0))));
  13758. else
  13759. orderResult.setown(createValue(no_order, LINK(signedType), createSortList(leftValues), createSortList(rightValues)));
  13760. }
  13761. if (args.ordinality() == 1)
  13762. result.set(&args.item(0));
  13763. else if (args.ordinality() != 0)
  13764. result.setown(createValue(no_and, makeBoolType(), args));
  13765. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  13766. bindTableCursor(func.ctx, dataset, "right", no_right, selSeq);
  13767. IHqlExpression * trueExpr = queryBoolExpr(true);
  13768. if (result)
  13769. {
  13770. if (orderResult)
  13771. {
  13772. buildFilteredReturn(func.ctx, result, trueExpr);
  13773. doBuildReturnCompare(func.ctx, orderResult, no_eq, true, false);
  13774. }
  13775. else
  13776. {
  13777. buildReturn(func.ctx, result);
  13778. }
  13779. }
  13780. else
  13781. {
  13782. if (orderResult)
  13783. doBuildReturnCompare(func.ctx, orderResult, no_eq, true, false);
  13784. else
  13785. buildReturn(func.ctx, trueExpr);
  13786. }
  13787. }
  13788. }
  13789. ABoundActivity * HqlCppTranslator::doBuildActivityUngroup(BuildCtx & ctx, IHqlExpression * expr, ABoundActivity * boundDataset)
  13790. {
  13791. bool useImplementationClass = options.minimizeActivityClasses;
  13792. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdegroup, expr,"Degroup");
  13793. if (useImplementationClass)
  13794. instance->setImplementationClass(newDegroupArgId);
  13795. buildActivityFramework(instance);
  13796. buildInstancePrefix(instance);
  13797. buildInstanceSuffix(instance);
  13798. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13799. return instance->getBoundActivity();
  13800. }
  13801. ABoundActivity * HqlCppTranslator::doBuildActivityGroup(BuildCtx & ctx, IHqlExpression * expr)
  13802. {
  13803. IHqlExpression * dataset = expr->queryChild(0);
  13804. IHqlExpression * child = dataset;
  13805. while (child->getOperator() == no_group)
  13806. child = child->queryChild(0);
  13807. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, child);
  13808. if (queryGrouping(expr) == queryGrouping(child))
  13809. return boundDataset.getClear();
  13810. IHqlExpression * sortlist = queryRealChild(expr, 1);
  13811. if (!sortlist || ((sortlist->numChildren() == 0) && (sortlist->getOperator() != no_activetable)))
  13812. {
  13813. return doBuildActivityUngroup(ctx, expr, boundDataset);
  13814. }
  13815. else
  13816. {
  13817. ThorActivityKind tak = (expr->getOperator() == no_group) ? TAKgroup: TAKgrouped;
  13818. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "Group");
  13819. buildActivityFramework(instance);
  13820. buildInstancePrefix(instance);
  13821. //virtual bool isSameGroup(const void *left, const void *right);
  13822. doBuildFuncIsSameGroup(instance->startctx, dataset, sortlist);
  13823. buildInstanceSuffix(instance);
  13824. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13825. return instance->getBoundActivity();
  13826. }
  13827. }
  13828. //---------------------------------------------------------------------------
  13829. //-- no_if (dataset) --
  13830. ABoundActivity * queryAssociatedActivity(BuildCtx & ctx, IHqlExpression * expr)
  13831. {
  13832. ActivityAssociation * match = static_cast<ActivityAssociation *>(ctx.queryAssociation(expr, AssocActivity, NULL));
  13833. if (match)
  13834. return match->activity;
  13835. return NULL;
  13836. }
  13837. ABoundActivity * HqlCppTranslator::getConditionalActivity(BuildCtx & ctx, IHqlExpression * expr, bool isChild)
  13838. {
  13839. if (!expr)
  13840. return NULL;
  13841. return buildCachedActivity(ctx, expr);
  13842. }
  13843. ABoundActivity * HqlCppTranslator::doBuildActivityIf(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13844. {
  13845. LinkedHqlExpr cond = expr->queryChild(0);
  13846. IHqlExpression * trueBranch = expr->queryChild(1);
  13847. IHqlExpression * falseBranch = queryRealChild(expr, 2);
  13848. const char * firstLabel = "True";
  13849. if (!expr->isDatarow())
  13850. {
  13851. if (falseBranch && (falseBranch->getOperator() == no_null))
  13852. falseBranch = NULL;
  13853. else if (trueBranch->getOperator() == no_null)
  13854. {
  13855. trueBranch = falseBranch;
  13856. falseBranch = NULL;
  13857. cond.setown(getInverse(cond));
  13858. firstLabel = "False";
  13859. }
  13860. }
  13861. OwnedHqlExpr cseCond = options.spotCSE ? spotScalarCSE(cond, NULL, queryOptions().spotCseInIfDatasetConditions) : LINK(cond);
  13862. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx) || insideLibrary());
  13863. IHqlExpression * activeGraph = queryActiveSubGraph(ctx)->graphTag;
  13864. if (isChild)
  13865. {
  13866. Owned<ABoundActivity> boundTrue = buildCachedActivity(ctx, trueBranch);
  13867. Owned<ABoundActivity> boundFalse = falseBranch ? buildCachedActivity(ctx, falseBranch) : NULL;
  13868. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKchildif, expr, "If");
  13869. buildActivityFramework(instance, isRoot);
  13870. buildInstancePrefix(instance);
  13871. {
  13872. MemberFunction getcond(*this, instance->startctx, "virtual bool getCondition()", MFsingle);
  13873. buildReturn(getcond.ctx, cseCond);
  13874. }
  13875. if (isGraphIndependent(cseCond, activeGraph) && !instance->hasChildActivity)
  13876. instance->addAttributeBool("_graphIndependent", true);
  13877. buildConnectInputOutput(ctx, instance, boundTrue, 0, 0, firstLabel);
  13878. if (boundFalse)
  13879. buildConnectInputOutput(ctx, instance, boundFalse, 0, 1, "False");
  13880. buildInstanceSuffix(instance);
  13881. return instance->getBoundActivity();
  13882. }
  13883. else
  13884. {
  13885. Owned<ABoundActivity> boundTrue = getConditionalActivity(ctx, trueBranch, isChild);
  13886. Owned<ABoundActivity> boundFalse = getConditionalActivity(ctx, falseBranch, isChild);
  13887. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, expr->isAction() ? TAKifaction : TAKif, expr,"If");
  13888. buildActivityFramework(instance, isRoot);
  13889. buildInstancePrefix(instance);
  13890. {
  13891. MemberFunction getcond(*this, instance->startctx, "virtual bool getCondition()", MFsingle);
  13892. buildReturn(getcond.ctx, cseCond);
  13893. }
  13894. if (isGraphIndependent(cseCond, activeGraph) && !instance->hasChildActivity)
  13895. instance->addAttributeBool("_graphIndependent", true);
  13896. if (expr->isAction())
  13897. {
  13898. if (boundTrue)
  13899. addActionConnection(ctx, boundTrue, instance, dependencyAtom, firstLabel, 0, 1);
  13900. if (boundFalse)
  13901. addActionConnection(ctx, boundFalse, instance, dependencyAtom, "False", 1, 2);
  13902. }
  13903. else
  13904. {
  13905. if (boundTrue)
  13906. buildConnectInputOutput(ctx, instance, boundTrue, 0, 0, firstLabel);
  13907. if (boundFalse)
  13908. buildConnectInputOutput(ctx, instance, boundFalse, 0, 1, "False");
  13909. }
  13910. buildInstanceSuffix(instance);
  13911. return instance->getBoundActivity();
  13912. }
  13913. }
  13914. //---------------------------------------------------------------------------
  13915. ABoundActivity * HqlCppTranslator::doBuildActivitySequentialParallel(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13916. {
  13917. IArray boundActivities;
  13918. ForEachChild(i, expr)
  13919. {
  13920. IHqlExpression * cur = expr->queryChild(i);
  13921. if (!cur->isAttribute() && (cur->getOperator() != no_null))
  13922. {
  13923. ABoundActivity * activity = buildCachedActivity(ctx, cur);
  13924. if (activity)
  13925. boundActivities.append(*activity);
  13926. }
  13927. }
  13928. ThorActivityKind kind = (expr->getOperator() != no_parallel) ? TAKsequential : TAKparallel;
  13929. const char * helper = (expr->getOperator() != no_parallel) ? "Sequential" : "Parallel";
  13930. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  13931. buildActivityFramework(instance, isRoot);
  13932. buildInstancePrefix(instance);
  13933. doBuildUnsignedFunction(instance->createctx, "numBranches", boundActivities.ordinality());
  13934. ForEachItemIn(j, boundActivities)
  13935. {
  13936. ABoundActivity & cur = (ABoundActivity&)boundActivities.item(j);
  13937. StringBuffer temp;
  13938. temp.append("Action #").append(j+1);
  13939. addActionConnection(ctx, &cur, instance, dependencyAtom, temp.str(), j, j+1);
  13940. }
  13941. buildInstanceSuffix(instance);
  13942. return instance->getBoundActivity();
  13943. }
  13944. ABoundActivity * HqlCppTranslator::doBuildActivityChoose(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * cond, CIArrayOf<ABoundActivity> & inputs, bool isRoot)
  13945. {
  13946. Owned<ABoundActivity> boundDefault = &inputs.popGet();
  13947. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx));
  13948. assertex(!expr->isAction());
  13949. ThorActivityKind tak = isChild ? TAKchildcase : TAKcase;
  13950. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "Case");
  13951. buildActivityFramework(instance, isRoot);
  13952. buildInstancePrefix(instance);
  13953. OwnedHqlExpr fullCond(foldHqlExpression(cond));
  13954. if (options.spotCSE)
  13955. fullCond.setown(spotScalarCSE(fullCond, NULL, queryOptions().spotCseInIfDatasetConditions));
  13956. {
  13957. MemberFunction func(*this, instance->startctx, "virtual unsigned getBranch()");
  13958. buildReturn(func.ctx, fullCond);
  13959. }
  13960. StringBuffer label;
  13961. ForEachItemIn(branchIdx, inputs)
  13962. {
  13963. ABoundActivity * boundBranch = &inputs.item(branchIdx);
  13964. label.clear().append("Branch ").append(branchIdx+1);
  13965. if (expr->isAction())
  13966. addActionConnection(ctx, boundBranch, instance, dependencyAtom, label.str(), branchIdx, branchIdx+1);
  13967. else
  13968. buildConnectInputOutput(ctx, instance, boundBranch, 0, branchIdx, label.str());
  13969. }
  13970. IHqlExpression * activeGraph = queryActiveSubGraph(ctx)->graphTag;
  13971. bool graphIndependent = isGraphIndependent(fullCond, activeGraph);
  13972. if (graphIndependent && !instance->hasChildActivity)
  13973. instance->addAttributeBool("_graphIndependent", true);
  13974. buildConnectInputOutput(ctx, instance, boundDefault, 0, inputs.ordinality(), "default");
  13975. buildInstanceSuffix(instance);
  13976. return instance->getBoundActivity();
  13977. }
  13978. ABoundActivity * HqlCppTranslator::doBuildActivityChoose(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13979. {
  13980. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx));
  13981. CIArrayOf<ABoundActivity> inputs;
  13982. ForEachChildFrom(i, expr, 1)
  13983. {
  13984. IHqlExpression * cur = queryRealChild(expr, i);
  13985. if (cur)
  13986. inputs.append(*getConditionalActivity(ctx, cur, isChild));
  13987. }
  13988. OwnedHqlExpr branch = adjustValue(expr->queryChild(0), -1);
  13989. return doBuildActivityChoose(ctx, expr, branch, inputs, isRoot);
  13990. }
  13991. ABoundActivity * HqlCppTranslator::doBuildActivityCase(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13992. {
  13993. node_operator op = expr->getOperator();
  13994. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx));
  13995. unsigned first = 0;
  13996. unsigned max = expr->numChildren();
  13997. if (op == no_case)
  13998. first++;
  13999. CIArrayOf<ABoundActivity> inputs;
  14000. for (unsigned iinput = first; iinput < max-1; iinput++)
  14001. inputs.append(*getConditionalActivity(ctx, expr->queryChild(iinput)->queryChild(1), isChild));
  14002. Owned<ABoundActivity> boundDefault = getConditionalActivity(ctx, expr->queryChild(max-1), isChild);
  14003. ThorActivityKind tak = isChild ? TAKchildcase : TAKcase;
  14004. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "Case");
  14005. buildActivityFramework(instance, isRoot);
  14006. buildInstancePrefix(instance);
  14007. //MORE: If we created a map/case expression and then called buildReturn it would potentially generate better code.
  14008. // code is below, but not enabled because it doesn't necessarily improve things at the moment (see jholt39.xhql)
  14009. IHqlExpression * activeGraph = queryActiveSubGraph(ctx)->graphTag;
  14010. HqlExprArray args;
  14011. if (op == no_case)
  14012. args.append(*LINK(expr->queryChild(0)));
  14013. StringBuffer label;
  14014. for (unsigned idx = first; idx < max-1; idx++)
  14015. {
  14016. unsigned branchIdx = idx-first;
  14017. IHqlExpression * branch = expr->queryChild(idx);
  14018. IHqlExpression * branchCond = branch->queryChild(0);
  14019. OwnedHqlExpr ret = getSizetConstant(branchIdx);
  14020. args.append(*createValue(no_mapto, ret->getType(), LINK(branchCond), LINK(ret)));
  14021. ABoundActivity * boundBranch = &inputs.item(branchIdx);
  14022. getExprECL(branchCond, label.clear(), false, true);
  14023. if (label.length() > 20)
  14024. label.clear().append("Branch ").append(branchIdx+1);
  14025. if (expr->isAction())
  14026. addActionConnection(ctx, boundBranch, instance, dependencyAtom, label.str(), branchIdx, branchIdx+1);
  14027. else
  14028. buildConnectInputOutput(ctx, instance, boundBranch, 0, branchIdx, label.str());
  14029. }
  14030. args.append(*createConstant(unsignedType->castFrom(false, (__int64)max-1)));
  14031. OwnedHqlExpr fullCond = createValue(op, LINK(unsignedType), args);
  14032. {
  14033. MemberFunction func(*this, instance->startctx, "virtual unsigned getBranch()");
  14034. fullCond.setown(foldHqlExpression(fullCond));
  14035. if (options.spotCSE)
  14036. fullCond.setown(spotScalarCSE(fullCond, NULL, queryOptions().spotCseInIfDatasetConditions));
  14037. buildReturn(func.ctx, fullCond);
  14038. }
  14039. bool graphIndependent = isGraphIndependent(fullCond, activeGraph);
  14040. if (graphIndependent && !instance->hasChildActivity)
  14041. instance->addAttributeBool("_graphIndependent", true);
  14042. buildConnectInputOutput(ctx, instance, boundDefault, 0, max-1-first, "default");
  14043. buildInstanceSuffix(instance);
  14044. return instance->getBoundActivity();
  14045. }
  14046. //---------------------------------------------------------------------------
  14047. //-- no_sort [SORT] --
  14048. void HqlCppTranslator::buildSkewThresholdMembers(BuildCtx & ctx, IHqlExpression * expr)
  14049. {
  14050. StringBuffer s, temp;
  14051. if (getAttribute(expr, thresholdAtom, temp.clear()))
  14052. {
  14053. s.clear().append("virtual unsigned __int64 getThreshold() { return ").append(temp).append("; }");
  14054. ctx.addQuoted(s);
  14055. }
  14056. IHqlExpression * skew = expr->queryAttribute(skewAtom);
  14057. if (skew)
  14058. {
  14059. Owned<ITypeInfo> doubleType = makeRealType(8);
  14060. IHqlExpression * skewMax = skew->queryChild(0);
  14061. if (skewMax->getOperator() != no_null)
  14062. doBuildFunction(ctx, doubleType, "getSkew", skewMax);
  14063. IHqlExpression * skewTarget = queryRealChild(skew, 1);
  14064. doBuildFunction(ctx, doubleType, "getTargetSkew", skewTarget);
  14065. }
  14066. }
  14067. ABoundActivity * HqlCppTranslator::doBuildActivitySort(BuildCtx & ctx, IHqlExpression * expr)
  14068. {
  14069. IHqlExpression * dataset = expr->queryChild(0);
  14070. LinkedHqlExpr sortlist = expr->queryChild(1);
  14071. IHqlExpression * limit = NULL;
  14072. IHqlExpression * cosort = NULL;
  14073. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  14074. const char *helper;
  14075. ThorActivityKind actKind = TAKsort;
  14076. switch (expr->getOperator())
  14077. {
  14078. case no_topn:
  14079. {
  14080. actKind = TAKtopn;
  14081. limit = expr->queryChild(2);
  14082. helper = "TopN";
  14083. break;
  14084. }
  14085. case no_assertsorted:
  14086. {
  14087. actKind = TAKsorted;
  14088. helper = "Sort";
  14089. break;
  14090. }
  14091. case no_subsort:
  14092. actKind = TAKsubsort;
  14093. helper = "SubSort";
  14094. break;
  14095. default:
  14096. {
  14097. cosort = expr->queryChild(2);
  14098. if (cosort && cosort->isAttribute())
  14099. cosort = NULL;
  14100. helper = "Sort";
  14101. break;
  14102. }
  14103. }
  14104. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, actKind, expr, helper);
  14105. buildActivityFramework(instance);
  14106. StringBuffer s;
  14107. buildInstancePrefix(instance);
  14108. instance->classctx.addQuotedLiteral("virtual ICompare * queryCompare() { return &compare; }");
  14109. // sortlist.setown(spotScalarCSE(sortlist));
  14110. buildCompareClass(instance->nestedctx, "compare", sortlist, DatasetReference(dataset));
  14111. IHqlExpression * record = dataset->queryRecord();
  14112. IAtom * serializeType = diskAtom; //MORE: Does this place a dependency on the implementation?
  14113. OwnedHqlExpr serializedRecord = getSerializedForm(record, serializeType);
  14114. if (!targetRoxie())
  14115. {
  14116. if (record != serializedRecord)
  14117. {
  14118. instance->classctx.addQuotedLiteral("virtual ICompare * queryCompareSerializedRow() { return &compareSR; }");
  14119. OwnedHqlExpr selSeq = createSelectorSequence();
  14120. OwnedHqlExpr leftSelector = createSelector(no_left, dataset, selSeq);
  14121. OwnedHqlExpr mappedSortlist = replaceSelector(sortlist, dataset, leftSelector);
  14122. OwnedHqlExpr serializedSortlist = replaceMemorySelectorWithSerializedSelector(mappedSortlist, record, no_left, selSeq, serializeType);
  14123. OwnedHqlExpr serializedDataset = createDataset(no_null, LINK(serializedRecord));
  14124. DatasetReference serializedRef(serializedDataset, no_left, selSeq);
  14125. try
  14126. {
  14127. buildCompareClass(instance->nestedctx, "compareSR", serializedSortlist, serializedRef);
  14128. }
  14129. catch (IException * e)
  14130. {
  14131. e->Release();
  14132. ERRORAT(queryLocation(expr), HQLERR_CannotGenerateSerializedCompare);
  14133. }
  14134. }
  14135. }
  14136. HqlExprArray sorts;
  14137. sortlist->unwindList(sorts, no_sortlist);
  14138. bool tryToSerializeKey = (actKind == TAKsort) && !isGroupedActivity(expr) && !isLocalActivity(expr) && !instance->isChildActivity();
  14139. generateSerializeKey(instance->nestedctx, no_none, DatasetReference(dataset), sorts, tryToSerializeKey, false);
  14140. buildSkewThresholdMembers(instance->classctx, expr);
  14141. if (expr->getOperator() == no_subsort)
  14142. doBuildFuncIsSameGroup(instance->startctx, dataset, expr->queryChild(2));
  14143. if (limit)
  14144. {
  14145. OwnedHqlExpr newLimit = ensurePositiveOrZeroInt64(limit);
  14146. MemberFunction func(*this, instance->startctx, "virtual __int64 getLimit()");
  14147. buildReturn(func.ctx, newLimit, defaultIntegralType);
  14148. }
  14149. IHqlExpression * best = expr->queryAttribute(bestAtom);
  14150. if (best)
  14151. {
  14152. doBuildBoolFunction(instance->classctx, "hasBest", true);
  14153. HqlExprArray sortValues, maxValues;
  14154. sortlist->unwindList(sortValues, no_sortlist);
  14155. unwindChildren(maxValues, best);
  14156. ForEachItemIn(i, sortValues)
  14157. {
  14158. IHqlExpression & cur = sortValues.item(i);
  14159. if (cur.getOperator() == no_negate)
  14160. {
  14161. sortValues.replace(OLINK(maxValues.item(i)), i);
  14162. maxValues.replace(*LINK(cur.queryChild(0)), i);
  14163. }
  14164. }
  14165. OwnedHqlExpr order = createValue(no_order, LINK(signedType), createSortList(sortValues), createSortList(maxValues));
  14166. MemberFunction func(*this, instance->startctx, "virtual int compareBest(const void * _self)");
  14167. func.ctx.addQuotedLiteral("unsigned char * self = (unsigned char *) _self;");
  14168. bindTableCursor(func.ctx, dataset, "self");
  14169. buildReturn(func.ctx, order);
  14170. }
  14171. if (cosort)
  14172. {
  14173. //cosort has form joined(dataset),
  14174. IHqlExpression * cosortDataset = cosort->queryChild(0);
  14175. if (cosortDataset->getOperator() == no_compound_diskread)
  14176. cosortDataset = cosortDataset->queryChild(0);
  14177. if (cosortDataset->getOperator() == no_sorted)
  14178. {
  14179. IHqlExpression * source = cosortDataset->queryChild(0);
  14180. if (source->getOperator() != no_table)
  14181. throwError(HQLERR_JoinSortedMustBeDataset);
  14182. IHqlExpression * sourceType = source->queryChild(2);
  14183. if (!sourceType || sourceType->getOperator() != no_thor)
  14184. throwError(HQLERR_JoinSortedMustBeThor);
  14185. s.clear().append("virtual const char * getSortedFilename() { return ");
  14186. generateExprCpp(s, source->queryChild(0)).append("; }");
  14187. instance->startctx.addQuoted(s);
  14188. buildMetaMember(instance->classctx, cosortDataset, false, "querySortedRecordSize");
  14189. }
  14190. else
  14191. {
  14192. instance->startctx.addQuotedLiteral("virtual const char * getSortedFilename() { return NULL; }");
  14193. instance->classctx.addQuotedLiteral("virtual IOutputMetaData * querySortedRecordSize() { return NULL; }");
  14194. ABoundActivity * masterSort = queryAssociatedActivity(ctx, cosortDataset);
  14195. if (!masterSort)
  14196. throwError(HQLERR_SortAndCoSortConcurrent);
  14197. Owned<ABoundActivity> slave = instance->getBoundActivity();
  14198. buildConnectOrders(ctx, slave, masterSort);
  14199. }
  14200. HqlExprArray left, right;
  14201. cosortDataset->queryChild(1)->unwindList(left, no_sortlist);
  14202. sortlist->unwindList(right, no_sortlist);
  14203. doCompareLeftRight(instance->nestedctx, "CompareLeftRight", DatasetReference(cosortDataset), DatasetReference(dataset), left, right);
  14204. }
  14205. if (expr->hasAttribute(manyAtom))
  14206. instance->classctx.addQuotedLiteral("virtual bool hasManyRecords() { return true; }");
  14207. IHqlExpression * stable = expr->queryAttribute(stableAtom);
  14208. IHqlExpression * unstable = expr->queryAttribute(unstableAtom);
  14209. IHqlExpression * spill = expr->queryAttribute(spillAtom);
  14210. IHqlExpression * method = NULL;
  14211. StringBuffer flags;
  14212. if (stable)
  14213. {
  14214. flags.append("|TAFstable");
  14215. method = stable->queryChild(0);
  14216. }
  14217. else if (unstable)
  14218. {
  14219. flags.append("|TAFunstable");
  14220. method = unstable->queryChild(0);
  14221. }
  14222. else
  14223. {
  14224. //If a dataset is sorted by all fields then it is impossible to determine if the original order
  14225. //was preserved - so mark the sort as potentially unstable (to reduce memory usage at runtime)
  14226. if (options.optimizeSortAllFields &&
  14227. allFieldsAreSorted(expr->queryRecord(), sortlist, dataset->queryNormalizedSelector(), options.optimizeSortAllFieldsStrict))
  14228. {
  14229. flags.append("|TAFunstable");
  14230. }
  14231. }
  14232. if (!method)
  14233. method = queryAttributeChild(expr, algorithmAtom, 0);
  14234. if (spill)
  14235. flags.append("|TAFspill");
  14236. if (!method || method->isConstant())
  14237. flags.append("|TAFconstant");
  14238. if (expr->hasAttribute(parallelAtom))
  14239. flags.append("|TAFparallel");
  14240. if (method)
  14241. doBuildVarStringFunction(instance->startctx, "getAlgorithm", method);
  14242. if (!streq(flags.str(), "|TAFconstant"))
  14243. instance->classctx.addQuotedF("virtual unsigned getAlgorithmFlags() { return %s; }", flags.str()+1);
  14244. buildInstanceSuffix(instance);
  14245. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  14246. return instance->getBoundActivity();
  14247. }
  14248. ABoundActivity * HqlCppTranslator::doBuildActivityQuantile(BuildCtx & ctx, IHqlExpression * expr)
  14249. {
  14250. IHqlExpression * dataset = expr->queryChild(0);
  14251. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  14252. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKquantile, expr, "Quantile");
  14253. buildActivityFramework(instance);
  14254. buildInstancePrefix(instance);
  14255. IHqlExpression * number = expr->queryChild(1);
  14256. IHqlExpression * sortlist = expr->queryChild(2);
  14257. IHqlExpression * transform = expr->queryChild(3);
  14258. IHqlExpression * score = queryAttributeChild(expr, scoreAtom, 0);
  14259. IHqlExpression * skew = queryAttributeChild(expr, skewAtom, 0);
  14260. IHqlExpression * dedupAttr = expr->queryAttribute(dedupAtom);
  14261. IHqlExpression * range = queryAttributeChild(expr, rangeAtom, 0);
  14262. instance->classctx.addQuotedLiteral("virtual ICompare * queryCompare() { return &compare; }");
  14263. buildCompareClass(instance->nestedctx, "compare", sortlist, DatasetReference(dataset));
  14264. doBuildUnsigned64Function(instance->startctx, "getNumDivisions", number);
  14265. if (skew)
  14266. doBuildFunction(instance->startctx, doubleType, "getSkew", skew);
  14267. if (range)
  14268. {
  14269. Owned<ITypeInfo> setType = makeSetType(makeIntType(8, false));
  14270. doBuildFunction(instance->startctx, setType, "getRange", range);
  14271. }
  14272. if (score)
  14273. {
  14274. MemberFunction func(*this, instance->startctx, "virtual unsigned __int64 getScore(const void * _self)");
  14275. func.ctx.addQuotedLiteral("unsigned char * self = (unsigned char *) _self;");
  14276. bindTableCursor(func.ctx, dataset, "self");
  14277. buildReturn(func.ctx, score);
  14278. }
  14279. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  14280. IHqlExpression * selSeq = querySelSeq(expr);
  14281. {
  14282. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned __int64 counter)");
  14283. if (counter)
  14284. associateCounter(func.ctx, counter, "counter");
  14285. buildTransformBody(func.ctx, transform, dataset, NULL, instance->dataset, selSeq);
  14286. }
  14287. buildClearRecordMember(instance->createctx, "", dataset);
  14288. //If a dataset is sorted by all fields then it is impossible to determine if the original order
  14289. //was preserved - so mark the sort as potentially unstable (to reduce memory usage at runtime)
  14290. bool unstable = expr->hasAttribute(unstableAtom);
  14291. if (options.optimizeSortAllFields &&
  14292. allFieldsAreSorted(expr->queryRecord(), sortlist, dataset->queryNormalizedSelector(), options.optimizeSortAllFieldsStrict))
  14293. unstable = true;
  14294. StringBuffer flags;
  14295. if (expr->hasAttribute(firstAtom))
  14296. flags.append("|TQFfirst");
  14297. if (expr->hasAttribute(lastAtom))
  14298. flags.append("|TQFlast");
  14299. if (isAlreadySorted(dataset, sortlist, false, false, false))
  14300. flags.append("|TQFsorted|TQFlocalsorted");
  14301. else if (isAlreadySorted(dataset, sortlist, true, false, false))
  14302. flags.append("|TQFlocalsorted");
  14303. if (score)
  14304. flags.append("|TQFhasscore");
  14305. if (range)
  14306. flags.append("|TQFhasrange");
  14307. if (skew)
  14308. flags.append("|TQFhasskew");
  14309. if (dedupAttr)
  14310. flags.append("|TQFdedup");
  14311. if (unstable)
  14312. flags.append("|TQFunstable");
  14313. if (!number->queryValue())
  14314. flags.append("|TQFvariabledivisions");
  14315. if (!transformReturnsSide(expr, no_left, 0))
  14316. flags.append("|TQFneedtransform");
  14317. if (flags.length())
  14318. instance->classctx.addQuotedF("virtual unsigned getFlags() { return %s; }", flags.str()+1);
  14319. buildInstanceSuffix(instance);
  14320. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  14321. return instance->getBoundActivity();
  14322. }
  14323. //---------------------------------------------------------------------------
  14324. void HqlCppTranslator::doBuildXmlReadMember(ActivityInstance & instance, IHqlExpression * expr, const char * functionName, bool & usesContents)
  14325. {
  14326. IHqlExpression * mode = expr->queryChild(2);
  14327. node_operator modeType = mode->getOperator();
  14328. StringBuffer s, xmlInstanceName;
  14329. usesContents = false;
  14330. if (isValidXmlRecord(expr->queryRecord()))
  14331. {
  14332. StringBuffer xmlFactoryName;
  14333. getUniqueId(xmlInstanceName.append((modeType==no_json) ? "json" : "xml"));
  14334. buildXmlReadTransform(expr, xmlFactoryName, usesContents);
  14335. instance.classctx.addQuoted(s.clear().append("Owned<IXmlToRowTransformer> ").append(xmlInstanceName).append(";"));
  14336. BuildCtx * callctx = NULL;
  14337. instance.evalContext->getInvariantMemberContext(NULL, NULL, &callctx, true, false);
  14338. callctx->addQuoted(s.clear().append(xmlInstanceName).append(".setown(").append(xmlFactoryName).append("(ctx,").append(instance.activityId).append("));"));
  14339. }
  14340. else
  14341. xmlInstanceName.append("NULL");
  14342. s.clear().append("virtual IXmlToRowTransformer * ").append(functionName).append("() { return ").append(xmlInstanceName).append("; }");
  14343. instance.classctx.addQuoted(s);
  14344. }
  14345. ABoundActivity * HqlCppTranslator::doBuildActivityWorkunitRead(BuildCtx & ctx, IHqlExpression * expr)
  14346. {
  14347. IHqlExpression * wuid = expr->queryAttribute(wuidAtom);
  14348. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  14349. IHqlExpression * name = queryAttributeChild(expr, nameAtom, 0);
  14350. __int64 sequenceValue = sequence->queryValue()->getIntValue();
  14351. bool isStored = (sequenceValue == ResultSequenceStored);
  14352. bool useImplementationClass = options.minimizeActivityClasses && !wuid && (sequenceValue == ResultSequenceInternal);
  14353. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKworkunitread, expr,"WorkunitRead");
  14354. if (useImplementationClass)
  14355. instance->setImplementationClass(newWorkUnitReadArgId);
  14356. noteResultAccessed(ctx, sequence, name);
  14357. StringBuffer graphLabel;
  14358. graphLabel.append(getActivityText(instance->kind)).append("\n");
  14359. getStoredDescription(graphLabel, sequence, name, true);
  14360. instance->graphLabel.set(graphLabel.str());
  14361. buildActivityFramework(instance);
  14362. buildInstancePrefix(instance);
  14363. if (!useImplementationClass)
  14364. {
  14365. doBuildVarStringFunction(instance->classctx, "queryName", name);
  14366. if (sequenceValue != ResultSequenceInternal)
  14367. {
  14368. MemberFunction func(*this, instance->classctx, "virtual int querySequence()");
  14369. buildReturn(func.ctx, sequence, signedType);
  14370. }
  14371. if (wuid)
  14372. doBuildVarStringFunction(instance->startctx, "getWUID", wuid->queryChild(0));
  14373. bool usesContents = false;
  14374. if (isStored || (targetRoxie() && (sequenceValue >= 0)))
  14375. doBuildXmlReadMember(*instance, expr, "queryXmlTransformer", usesContents);
  14376. StringBuffer csvInstanceName;
  14377. if (isValidCsvRecord(expr->queryRecord()) && isStored && options.allowCsvWorkunitRead)
  14378. {
  14379. buildCsvReadTransformer(expr, csvInstanceName, NULL);
  14380. StringBuffer s;
  14381. s.append("virtual ICsvToRowTransformer * queryCsvTransformer() { return &").append(csvInstanceName).append("; }");
  14382. instance->classctx.addQuoted(s);
  14383. }
  14384. }
  14385. else
  14386. {
  14387. instance->addConstructorParameter(name);
  14388. }
  14389. queryAddResultDependancy(*instance->queryBoundActivity(), sequence, name);
  14390. buildInstanceSuffix(instance);
  14391. return instance->getBoundActivity();
  14392. }
  14393. //---------------------------------------------------------------------------
  14394. //-- xmlparse
  14395. void HqlCppTranslator::noteXpathUsed(const char * xpath)
  14396. {
  14397. if (strstr(xpath, XPATH_CONTENTS_TEXT))
  14398. xmlUsesContents = true;
  14399. }
  14400. void HqlCppTranslator::noteXpathUsed(IHqlExpression * expr)
  14401. {
  14402. IValue * value = expr->queryValue();
  14403. if (value)
  14404. {
  14405. StringBuffer temp;
  14406. value->getStringValue(temp);
  14407. noteXpathUsed(temp);
  14408. }
  14409. else
  14410. xmlUsesContents = true;
  14411. }
  14412. ABoundActivity * HqlCppTranslator::doBuildActivityXmlParse(BuildCtx & ctx, IHqlExpression * expr)
  14413. {
  14414. IHqlExpression * dataset = expr->queryChild(0);
  14415. IHqlExpression * selSeq = querySelSeq(expr);
  14416. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  14417. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKxmlparse, expr, "XmlParse");
  14418. buildActivityFramework(instance);
  14419. buildInstancePrefix(instance);
  14420. IHqlExpression * xmlAttr = expr->queryAttribute(xmlAtom);
  14421. //MORE: What encoding is the search text in???
  14422. doBuildParseSearchText(instance->startctx, dataset, expr->queryChild(1), type_utf8, unknownStringType);
  14423. doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", xmlAttr ? queryRealChild(xmlAttr, 0) : NULL);
  14424. {
  14425. MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IColumnProvider * parsed)");
  14426. ensureRowAllocated(func.ctx, "crSelf");
  14427. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  14428. // Both left and the dataset are bound to left because it might be a new transform or a transform
  14429. IHqlExpression * transform = expr->queryChild(3);
  14430. BoundRow * selfCursor = bindSelf(func.ctx, expr, "crSelf");
  14431. if (transform->getOperator() == no_newtransform)
  14432. bindTableCursor(func.ctx, dataset, "left");
  14433. else
  14434. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  14435. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  14436. OwnedHqlExpr helperName = createQuoted("parsed", makeBoolType());
  14437. func.ctx.associateExpr(xmlColumnProviderMarkerExpr, helperName);
  14438. bindTableCursor(func.ctx, queryXmlParsePseudoTable(), queryXmlParsePseudoTable());
  14439. xmlUsesContents = false;
  14440. doTransform(func.ctx, transform, selfCursor);
  14441. buildReturnRecordSize(func.ctx, selfCursor);
  14442. }
  14443. if (xmlUsesContents)
  14444. instance->classctx.addQuotedLiteral("virtual bool requiresContents() { return true; }");
  14445. buildInstanceSuffix(instance);
  14446. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  14447. return instance->getBoundActivity();
  14448. }
  14449. void HqlCppTranslator::doBuildExprXmlText(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  14450. {
  14451. HqlExprAssociation * match = ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  14452. if (!match)
  14453. throwError(HQLERR_XmlTextNotValid);
  14454. IHqlExpression * xpath = expr->queryChild(0);
  14455. noteXpathUsed(xpath);
  14456. HqlExprArray args;
  14457. args.append(*LINK(match->queryExpr()));
  14458. args.append(*LINK(xpath));
  14459. OwnedHqlExpr call = bindFunctionCall(columnGetStringXId, args);
  14460. buildCachedExpr(ctx, call, tgt);
  14461. }
  14462. void HqlCppTranslator::doBuildExprXmlUnicode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  14463. {
  14464. HqlExprAssociation * match = ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  14465. if (!match)
  14466. throwError(HQLERR_XmlUnicodeNotValid);
  14467. IHqlExpression * xpath = expr->queryChild(0);
  14468. noteXpathUsed(xpath);
  14469. HqlExprArray args;
  14470. args.append(*LINK(match->queryExpr()));
  14471. args.append(*LINK(xpath));
  14472. OwnedHqlExpr call = bindFunctionCall(columnGetUnicodeXId, args);
  14473. buildCachedExpr(ctx, call, tgt);
  14474. }
  14475. void HqlCppTranslator::buildDatasetAssignXmlProject(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  14476. {
  14477. HqlExprAssociation * match = ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  14478. if (!match)
  14479. throwError(HQLERR_XmlTextNotValid);
  14480. StringBuffer iterTag;
  14481. IHqlExpression * xpath = expr->queryChild(0);
  14482. if (xpath->queryValue())
  14483. xpath->queryValue()->getStringValue(iterTag);
  14484. noteXpathUsed(xpath);
  14485. //Generate the code to process a child iterator
  14486. OwnedHqlExpr subRowExpr;
  14487. BuildCtx loopctx(ctx);
  14488. buildXmlReadChildrenIterator(loopctx, iterTag.str(), match->queryExpr(), subRowExpr);
  14489. loopctx.associateExpr(xmlColumnProviderMarkerExpr, subRowExpr);
  14490. BoundRow * targetRow = target->buildCreateRow(loopctx);
  14491. Owned<IReferenceSelector> targetRef = buildActiveRow(loopctx, targetRow->querySelector());
  14492. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(expr->queryChild(1)));
  14493. buildRowAssign(loopctx, targetRef, rowValue);
  14494. target->finishRow(loopctx, targetRow);
  14495. }
  14496. //---------------------------------------------------------------------------
  14497. //-- no_temptable [DATASET] --
  14498. void HqlCppTranslator::doBuildTempTableFlags(BuildCtx & ctx, IHqlExpression * expr, bool isConstant, bool canFilter)
  14499. {
  14500. StringBuffer flags;
  14501. if (expr->hasAttribute(distributedAtom))
  14502. flags.append("|TTFdistributed");
  14503. if (!isConstant)
  14504. flags.append("|TTFnoconstant");
  14505. if (canFilter)
  14506. flags.append("|TTFfiltered");
  14507. if (flags.length())
  14508. doBuildUnsignedFunction(ctx, "getFlags", flags.str()+1);
  14509. }
  14510. ABoundActivity * HqlCppTranslator::doBuildActivityTempTable(BuildCtx & ctx, IHqlExpression * expr)
  14511. {
  14512. StringBuffer s;
  14513. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineTable");
  14514. OwnedHqlExpr values = normalizeListCasts(expr->queryChild(0));
  14515. IHqlExpression * record = expr->queryChild(1);
  14516. assertex(values->getOperator() != no_recordlist); // should have been transformed by now.
  14517. //-----------------
  14518. buildActivityFramework(instance);
  14519. buildInstancePrefix(instance);
  14520. OwnedHqlExpr rowsExpr;
  14521. {
  14522. MemberFunction func(*this, instance->startctx, "virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14523. ensureRowAllocated(func.ctx, "crSelf");
  14524. BoundRow * selfCursor = bindSelf(func.ctx, instance->dataset, "crSelf");
  14525. IHqlExpression * self = selfCursor->querySelector();
  14526. OwnedHqlExpr clearAction;
  14527. OwnedHqlExpr rowVar = createVariable("row", makeIntType(8, false));
  14528. if (expr->getOperator() == no_datasetfromrow)
  14529. {
  14530. BuildCtx subctx(func.ctx);
  14531. subctx.addFilter(rowVar);
  14532. if (clearAction)
  14533. subctx.addExpr(clearAction);
  14534. subctx.addReturn(queryZero());
  14535. buildAssign(func.ctx, self, values);
  14536. buildReturnRecordSize(func.ctx, selfCursor);
  14537. rowsExpr.setown(getSizetConstant(1));
  14538. }
  14539. else if ((values->getOperator() == no_list) || (values->getOperator() == no_null))
  14540. {
  14541. unsigned maxRows = values->numChildren();
  14542. if (maxRows)
  14543. {
  14544. unsigned dummyIdx = 0;
  14545. OwnedHqlExpr tgt = createSelectExpr(LINK(self), LINK(queryNextRecordField(record, dummyIdx)));
  14546. BuildCtx switchctx(func.ctx);
  14547. switchctx.addQuotedCompoundLiteral("switch (row)");
  14548. unsigned row;
  14549. for (row = 0; row < maxRows; row++)
  14550. {
  14551. BuildCtx casectx(switchctx);
  14552. casectx.addQuotedCompound(s.clear().append("case ").append(row).append(":"), nullptr);
  14553. buildAssign(casectx, tgt, values->queryChild(row));
  14554. buildReturnRecordSize(casectx, selfCursor);
  14555. }
  14556. }
  14557. if (clearAction)
  14558. func.ctx.addExpr(clearAction);
  14559. func.ctx.addReturn(queryZero());
  14560. rowsExpr.setown(getSizetConstant(maxRows));
  14561. }
  14562. else
  14563. {
  14564. CHqlBoundExpr bound;
  14565. //MORE: This shouldn't be done this way...
  14566. OwnedHqlExpr normalized = normalizeListCasts(values);
  14567. if (options.spotCSE)
  14568. normalized.setown(spotScalarCSE(normalized, NULL, queryOptions().spotCseInIfDatasetConditions));
  14569. if (normalized->getOperator() == no_alias)
  14570. {
  14571. buildExpr(func.ctx, normalized, bound);
  14572. rowsExpr.setown(createValue(no_countlist, makeIntType(8, false), LINK(normalized)));
  14573. }
  14574. else
  14575. {
  14576. BuildCtx * declarectx;
  14577. BuildCtx * callctx;
  14578. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, &callctx, false, isContextDependent(normalized, false, false) || !isIndependentOfScope(normalized));
  14579. // if (isContextDependent(normalized, false, false))
  14580. // buildTempExpr(instance->onstartctx, *declarectx, normalized, bound, FormatNatural);
  14581. // else
  14582. CHqlBoundTarget tempTarget;
  14583. buildTempExpr(*callctx, *declarectx, tempTarget, normalized, FormatNatural, !canSetBeAll(normalized));
  14584. bound.setFromTarget(tempTarget);
  14585. rowsExpr.setown(getBoundCount(bound));
  14586. rowsExpr.setown(createTranslated(rowsExpr));
  14587. }
  14588. OwnedHqlExpr compare = createValue(no_ge, makeBoolType(), LINK(rowVar), ensureExprType(rowsExpr, rowVar->queryType()));
  14589. BuildCtx condctx(func.ctx);
  14590. buildFilter(condctx, compare);
  14591. if (clearAction)
  14592. condctx.addExpr(clearAction);
  14593. buildReturn(condctx, queryZero());
  14594. HqlExprArray args;
  14595. args.append(*bound.getTranslatedExpr());
  14596. args.append(*adjustValue(rowVar, 1));
  14597. args.append(*createAttribute(noBoundCheckAtom));
  14598. args.append(*createAttribute(forceAllCheckAtom));
  14599. OwnedHqlExpr src = createValue(no_index, LINK(values->queryType()->queryChildType()), args);
  14600. OwnedHqlExpr tgt = createSelectExpr(LINK(self), LINK(queryOnlyField(record)));
  14601. buildAssign(func.ctx, tgt, src);
  14602. buildReturnRecordSize(func.ctx, selfCursor);
  14603. }
  14604. }
  14605. doBuildUnsigned64Function(instance->startctx, "numRows", rowsExpr);
  14606. doBuildTempTableFlags(instance->startctx, expr, values->isConstant(), false);
  14607. buildInstanceSuffix(instance);
  14608. return instance->getBoundActivity();
  14609. }
  14610. //NB: Also used to create row no_null as an activity.
  14611. ABoundActivity * HqlCppTranslator::doBuildActivityCreateRow(BuildCtx & ctx, IHqlExpression * expr, bool isDataset)
  14612. {
  14613. bool valuesAreConstant = false;
  14614. StringBuffer valueText;
  14615. IValue * singleValue = NULL;
  14616. node_operator op = expr->getOperator();
  14617. if (op == no_createrow)
  14618. {
  14619. IHqlExpression * transform = expr->queryChild(0);
  14620. if (transform->isConstant())
  14621. {
  14622. IHqlExpression * assign = queryTransformSingleAssign(transform);
  14623. if (assign)
  14624. {
  14625. singleValue = assign->queryChild(1)->queryValue();
  14626. if (singleValue)
  14627. singleValue->generateECL(valueText);
  14628. }
  14629. valuesAreConstant = true;
  14630. }
  14631. if (!isDataset && containsSkip(transform))
  14632. reportError(queryLocation(transform), ECODETEXT(HQLERR_SkipInsideCreateRow));
  14633. }
  14634. else if (op == no_null)
  14635. {
  14636. valueText.append("Blank");
  14637. valuesAreConstant = true;
  14638. }
  14639. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineRow");
  14640. if (valueText.length())
  14641. {
  14642. StringBuffer graphLabel;
  14643. elideString(valueText, MAX_ROW_VALUE_TEXT_LEN);
  14644. graphLabel.append("Inline Row\n{").append(valueText).append("}");
  14645. instance->graphLabel.set(graphLabel.str());
  14646. }
  14647. else
  14648. instance->graphLabel.set("Inline Row");
  14649. //-----------------
  14650. buildActivityFramework(instance);
  14651. buildInstancePrefix(instance);
  14652. {
  14653. // Ignoring row argument, since engines will stop at numRows(), which is 1
  14654. MemberFunction func(*this, instance->startctx, "virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14655. ensureRowAllocated(func.ctx, "crSelf");
  14656. BoundRow * selfCursor = bindSelf(func.ctx, instance->dataset, "crSelf");
  14657. IHqlExpression * self = selfCursor->querySelector();
  14658. if (isDataset)
  14659. associateSkipReturnMarker(func.ctx, queryZero(), selfCursor);
  14660. LinkedHqlExpr cseExpr = expr;
  14661. if (options.spotCSE)
  14662. cseExpr.setown(spotScalarCSE(cseExpr, NULL, options.spotCseInIfDatasetConditions));
  14663. buildAssign(func.ctx, self, cseExpr);
  14664. buildReturnRecordSize(func.ctx, selfCursor);
  14665. }
  14666. doBuildTempTableFlags(instance->startctx, expr, valuesAreConstant, false);
  14667. buildInstanceSuffix(instance);
  14668. return instance->getBoundActivity();
  14669. }
  14670. ABoundActivity * HqlCppTranslator::doBuildActivityInlineTable(BuildCtx & ctx, IHqlExpression * expr)
  14671. {
  14672. IHqlExpression * values = expr->queryChild(0);
  14673. if (values->numChildren() == 1)
  14674. {
  14675. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(values->queryChild(0)));
  14676. OwnedHqlExpr row = expr->cloneAllAnnotations(rowValue);
  14677. return doBuildActivityCreateRow(ctx, row, true);
  14678. }
  14679. if (values->isConstant() && !expr->hasAttribute(distributedAtom))
  14680. {
  14681. CHqlBoundExpr bound;
  14682. if (doBuildConstantDatasetInlineTable(expr, bound, FormatNatural))
  14683. {
  14684. OwnedHqlExpr constDataset = bound.getTranslatedExpr();
  14685. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKlinkedrawiterator, expr, "LinkedRawIterator");
  14686. instance->graphLabel.set("Inline Dataset");
  14687. instance->setImplementationClass(newLibraryConstantRawIteratorArgId);
  14688. buildActivityFramework(instance);
  14689. buildInstancePrefix(instance);
  14690. instance->addConstructorParameter(constDataset);
  14691. buildInstanceSuffix(instance);
  14692. return instance->getBoundActivity();
  14693. }
  14694. }
  14695. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineTable");
  14696. //-----------------
  14697. buildActivityFramework(instance);
  14698. buildInstancePrefix(instance);
  14699. unsigned maxRows = values->numChildren();
  14700. bool canFilter = false;
  14701. {
  14702. MemberFunction func(*this, instance->startctx, "virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14703. associateSkipReturnMarker(func.ctx, queryZero(), NULL);
  14704. ensureRowAllocated(func.ctx, "crSelf");
  14705. BoundRow * selfCursor = bindSelf(func.ctx, instance->dataset, "crSelf");
  14706. IHqlExpression * self = selfCursor->querySelector();
  14707. if (maxRows)
  14708. {
  14709. StringBuffer s;
  14710. BuildCtx switchctx(func.ctx);
  14711. switchctx.addQuotedCompoundLiteral("switch (row)");
  14712. unsigned row;
  14713. for (row = 0; row < maxRows; row++)
  14714. {
  14715. BuildCtx casectx(switchctx);
  14716. casectx.addQuotedCompound(s.clear().append("case ").append(row).append(":"), nullptr);
  14717. IHqlExpression * cur = values->queryChild(row);
  14718. if (containsSkip(cur))
  14719. canFilter = true;
  14720. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(cur));
  14721. buildAssign(casectx, self, rowValue);
  14722. buildReturnRecordSize(casectx, selfCursor);
  14723. }
  14724. }
  14725. func.ctx.addReturn(queryZero());
  14726. }
  14727. OwnedHqlExpr rowsExpr = getSizetConstant(maxRows);
  14728. doBuildUnsigned64Function(instance->startctx, "numRows", rowsExpr);
  14729. doBuildTempTableFlags(instance->startctx, expr, values->isConstant(), canFilter);
  14730. buildInstanceSuffix(instance);
  14731. return instance->getBoundActivity();
  14732. }
  14733. //---------------------------------------------------------------------------
  14734. ABoundActivity * HqlCppTranslator::doBuildActivityCountTransform(BuildCtx & ctx, IHqlExpression * expr)
  14735. {
  14736. IHqlExpression * count = expr->queryChild(0);
  14737. IHqlExpression * transform = queryNewColumnProvider(expr);
  14738. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  14739. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineTable");
  14740. buildActivityFramework(instance);
  14741. buildInstancePrefix(instance);
  14742. {
  14743. // size32_t getRow()
  14744. MemberFunction func(*this, instance->startctx, "virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14745. ensureRowAllocated(func.ctx, "crSelf");
  14746. BoundRow * selfCursor = bindSelf(func.ctx, instance->dataset, "crSelf");
  14747. IHqlExpression * self = selfCursor->querySelector();
  14748. associateCounter(func.ctx, counter, "(row+1)");
  14749. buildTransformBody(func.ctx, transform, NULL, NULL, instance->dataset, self);
  14750. }
  14751. // unsigned numRows() - count is guaranteed by lexer
  14752. doBuildUnsigned64Function(instance->startctx, "numRows", count);
  14753. // unsigned getFlags()
  14754. doBuildTempTableFlags(instance->startctx, expr, isConstantTransform(transform), containsSkip(transform));
  14755. buildInstanceSuffix(instance);
  14756. return instance->getBoundActivity();
  14757. }
  14758. //---------------------------------------------------------------------------
  14759. void HqlCppTranslator::buildHTTPtoXml(BuildCtx & ctx)
  14760. {
  14761. MemberFunction func(*this, ctx, "virtual void toXML(const byte *, IXmlWriter & out)");
  14762. //Contains nothing
  14763. }
  14764. //---------------------------------------------------------------------------
  14765. void HqlCppTranslator::buildSOAPtoXml(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * transform, IHqlExpression * selSeq)
  14766. {
  14767. MemberFunction func(*this, ctx);
  14768. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  14769. if (dataset)
  14770. {
  14771. func.start("virtual void toXML(const byte * left, IXmlWriter & out)");
  14772. if (transform->getOperator() == no_newtransform)
  14773. bindTableCursor(func.ctx, dataset, "left");
  14774. else
  14775. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  14776. }
  14777. else
  14778. func.start("virtual void toXML(const byte *, IXmlWriter & out)");
  14779. // Bind left to "left" and right to RIGHT
  14780. HqlExprArray assigns;
  14781. filterExpandAssignments(func.ctx, NULL, assigns, transform);
  14782. OwnedHqlExpr self = getSelf(transform);
  14783. buildXmlSerialize(func.ctx, transform->queryRecord(), self, &assigns);
  14784. }
  14785. void HqlCppTranslator::associateLocalJoinTransformFlags(BuildCtx & ctx, const char * name, IHqlExpression *ds, node_operator side, IHqlExpression *selSeq)
  14786. {
  14787. __int64 mask = 0;
  14788. if (side==no_right)
  14789. mask = JTFmatchedright;
  14790. else if (side==no_left)
  14791. mask = JTFmatchedleft;
  14792. OwnedIValue maskValue = createIntValue(mask, 4, false);
  14793. OwnedHqlExpr flagsVariable = createVariable(name, makeIntType(4, false));
  14794. OwnedHqlExpr matchedRowExpr = createValue(no_band, makeIntType(4, false), flagsVariable.getClear(), createConstant(maskValue.getClear()));
  14795. OwnedHqlExpr markerExpr = createValue(no_matched_injoin, makeBoolType(), createSelector(side, ds, selSeq));
  14796. OwnedHqlExpr testExpr = createValue(no_ne, makeBoolType(), matchedRowExpr.getClear(), createConstant(createIntValue(0, 4, false)));
  14797. ctx.associateExpr(markerExpr, testExpr);
  14798. }
  14799. IHqlExpression * HqlCppTranslator::associateLocalFailure(BuildCtx & ctx, const char * exceptionName)
  14800. {
  14801. OwnedHqlExpr activeFailMarker = createAttribute(activeFailureAtom);
  14802. OwnedHqlExpr activeFailVariable = createVariable(exceptionName, makeBoolType());
  14803. ctx.associateExpr(activeFailMarker, activeFailVariable);
  14804. return activeFailVariable;
  14805. }
  14806. void HqlCppTranslator::validateExprScope(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * expr, const char * opName, const char * argName)
  14807. {
  14808. if (dataset && exprReferencesDataset(expr, dataset) && !resolveSelectorDataset(ctx, dataset))
  14809. throwError2(HQLERR_OpArgDependsDataset, opName, argName);
  14810. }
  14811. void HqlCppTranslator::doBuildHttpHeaderStringFunction(BuildCtx &ctx, IHqlExpression * expr)
  14812. {
  14813. HqlExprArray headerExprs;
  14814. gatherAttributes(headerExprs, httpHeaderAtom, expr);
  14815. if (headerExprs.length())
  14816. {
  14817. Owned<ITypeInfo> string2Type = makeStringType(2);
  14818. OwnedHqlExpr endName = createConstant(createStringValue(": ", LINK(string2Type)));
  14819. OwnedHqlExpr endLine = createConstant(createStringValue("\r\n", LINK(string2Type)));
  14820. HqlExprArray headerStringExprs;
  14821. ForEachItemIn(i, headerExprs)
  14822. {
  14823. IHqlExpression * httpHeader = &headerExprs.item(i);
  14824. headerStringExprs.append(*LINK(httpHeader->queryChild(0)));
  14825. headerStringExprs.append(*LINK(endName));
  14826. headerStringExprs.append(*LINK(httpHeader->queryChild(1)));
  14827. headerStringExprs.append(*LINK(endLine));
  14828. }
  14829. OwnedHqlExpr concatHeaders = createBalanced(no_concat, unknownVarStringType, headerStringExprs);
  14830. concatHeaders.setown(foldHqlExpression(concatHeaders));
  14831. doBuildVarStringFunction(ctx, "getHttpHeaders", concatHeaders);
  14832. }
  14833. }
  14834. ABoundActivity * HqlCppTranslator::doBuildActivitySOAP(BuildCtx & ctx, IHqlExpression * expr, bool isSink, bool isRoot)
  14835. {
  14836. ThorActivityKind tak;
  14837. const char * helper;
  14838. unsigned firstArg = 0;
  14839. IHqlExpression * dataset = NULL;
  14840. Owned<ABoundActivity> boundDataset;
  14841. IHqlExpression * selSeq = querySelSeq(expr);
  14842. if (expr->getOperator() == no_newsoapcall)
  14843. {
  14844. if (isSink)
  14845. {
  14846. tak = TAKsoap_rowaction;
  14847. helper = "SoapAction";
  14848. }
  14849. else
  14850. {
  14851. tak = TAKsoap_rowdataset;
  14852. helper = "SoapCall";
  14853. }
  14854. }
  14855. else
  14856. {
  14857. if (isSink)
  14858. {
  14859. tak = TAKsoap_datasetaction;
  14860. helper = "SoapAction";
  14861. }
  14862. else
  14863. {
  14864. tak = TAKsoap_datasetdataset;
  14865. helper = "SoapCall";
  14866. }
  14867. dataset = expr->queryChild(0);
  14868. boundDataset.setown(buildCachedActivity(ctx, dataset));
  14869. firstArg = 1;
  14870. }
  14871. StringBuffer s;
  14872. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, helper);
  14873. //-----------------
  14874. buildActivityFramework(instance, isRoot);
  14875. buildInstancePrefix(instance);
  14876. IHqlExpression * hosts = expr->queryChild(firstArg);
  14877. IHqlExpression * service = expr->queryChild(firstArg+1);
  14878. //Because of scope handling in parser it is possible for these expressions to be unexpectedly dependent on the dataset
  14879. const char * opText = getOpString(expr->getOperator());
  14880. validateExprScope(instance->startctx, dataset, hosts, opText, "host url");
  14881. validateExprScope(instance->startctx, dataset, service, opText, "service");
  14882. //virtual const char * getHosts() = 0;
  14883. doBuildVarStringFunction(instance->startctx, "getHosts", hosts);
  14884. //virtual const char * getService() = 0;
  14885. doBuildVarStringFunction(instance->startctx, "getService", service);
  14886. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  14887. buildSOAPtoXml(instance->startctx, dataset, expr->queryChild(firstArg+3), selSeq);
  14888. //virtual const char * queryOutputIteratorPath()
  14889. IHqlExpression * separator = expr->queryAttribute(separatorAtom);
  14890. if (separator)
  14891. doBuildVarStringFunction(instance->startctx, "queryOutputIteratorPath", separator->queryChild(0));
  14892. //virtual const char * getHeader()
  14893. //virtual const char * getFooter()
  14894. IHqlExpression * header = expr->queryAttribute(headingAtom);
  14895. if (header)
  14896. {
  14897. doBuildVarStringFunction(instance->startctx, "getHeader", header->queryChild(0));
  14898. doBuildVarStringFunction(instance->startctx, "getFooter", header->queryChild(1));
  14899. }
  14900. IHqlExpression * action = expr->queryAttribute(soapActionAtom);
  14901. if (action)
  14902. doBuildVarStringFunction(instance->startctx, "getSoapAction", action->queryChild(0));
  14903. doBuildHttpHeaderStringFunction(instance->startctx, expr);
  14904. IHqlExpression * proxyAddress = expr->queryAttribute(proxyAddressAtom);
  14905. if (proxyAddress)
  14906. doBuildVarStringFunction(instance->startctx, "getProxyAddress", proxyAddress->queryChild(0));
  14907. IHqlExpression * namespaceAttr = expr->queryAttribute(namespaceAtom);
  14908. IHqlExpression * responseAttr = expr->queryAttribute(responseAtom);
  14909. IHqlExpression * logText = NULL;
  14910. bool logMin = false;
  14911. bool logXml = false;
  14912. ForEachChildFrom(i, expr, 1)
  14913. {
  14914. IHqlExpression * cur = expr->queryChild(i);
  14915. if (cur->isAttribute() && cur->queryName()==logAtom)
  14916. {
  14917. IHqlExpression * opt = cur->queryChild(0);
  14918. if (!opt)
  14919. logXml = true;
  14920. else if (!opt->isAttribute())
  14921. logText = opt;
  14922. else if (opt->queryName() == minAtom)
  14923. logMin = true;
  14924. }
  14925. }
  14926. //virtual unsigned getFlags()
  14927. {
  14928. StringBuffer flags;
  14929. if (expr->hasAttribute(groupAtom))
  14930. flags.append("|SOAPFgroup");
  14931. if (expr->hasAttribute(onFailAtom))
  14932. flags.append("|SOAPFonfail");
  14933. if (logXml)
  14934. flags.append("|SOAPFlog");
  14935. if (expr->hasAttribute(trimAtom))
  14936. flags.append("|SOAPFtrim");
  14937. if (expr->hasAttribute(literalAtom))
  14938. flags.append("|SOAPFliteral");
  14939. if (namespaceAttr)
  14940. flags.append("|SOAPFnamespace");
  14941. if (expr->hasAttribute(encodingAtom))
  14942. flags.append("|SOAPFencoding");
  14943. if (responseAttr && responseAttr->hasAttribute(noTrimAtom))
  14944. flags.append("|SOAPFpreserveSpace");
  14945. if (logMin)
  14946. flags.append("|SOAPFlogmin");
  14947. if (logText)
  14948. flags.append("|SOAPFlogusermsg");
  14949. if (expr->hasAttribute(httpHeaderAtom))
  14950. flags.append("|SOAPFhttpheaders");
  14951. if (flags.length())
  14952. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  14953. }
  14954. //virtual unsigned numParallelThreads()
  14955. doBuildUnsignedFunction(instance->startctx, "numParallelThreads", queryAttributeChild(expr, parallelAtom, 0));
  14956. //virtual unsigned numRecordsPerBatch()
  14957. doBuildUnsignedFunction(instance->startctx, "numRecordsPerBatch", queryAttributeChild(expr, mergeAtom, 0));
  14958. //virtual int numRetries()
  14959. doBuildSignedFunction(instance->startctx, "numRetries", queryAttributeChild(expr, retryAtom, 0));
  14960. //virtual double getTimeout()
  14961. doBuildDoubleFunction(instance->startctx, "getTimeout", queryAttributeChild(expr, timeoutAtom, 0));
  14962. //virtual double getTimeLimit()
  14963. doBuildDoubleFunction(instance->startctx, "getTimeLimit", queryAttributeChild(expr, timeLimitAtom, 0));
  14964. if (namespaceAttr)
  14965. {
  14966. doBuildVarStringFunction(instance->startctx, "getNamespaceName", namespaceAttr->queryChild(0));
  14967. if (namespaceAttr->queryChild(1))
  14968. doBuildVarStringFunction(instance->startctx, "getNamespaceVar", namespaceAttr->queryChild(1));
  14969. }
  14970. if (logText)
  14971. {
  14972. MemberFunction func(*this, instance->startctx, "virtual void getLogText(size32_t & __lenResult, char * & __result, const void * _left)");
  14973. if (dataset)
  14974. {
  14975. func.ctx.addQuotedLiteral("const unsigned char * left = (const unsigned char *) _left;");
  14976. bindTableCursor(func.ctx, dataset, "left");
  14977. bindTableCursor(func.ctx, dataset, "left", no_left, selSeq);
  14978. }
  14979. doBuildFunctionReturn(func.ctx, unknownStringType, logText);
  14980. }
  14981. if (!isSink)
  14982. {
  14983. //virtual IXmlToRowTransformer * queryTransformer()
  14984. bool usesContents = false;
  14985. doBuildXmlReadMember(*instance, expr, "queryInputTransformer", usesContents);
  14986. if (usesContents)
  14987. throwError(HQLERR_ContentsInSoapCall);
  14988. //virtual const char * getInputIteratorPath()
  14989. IHqlExpression * xpath = expr->queryAttribute(xpathAtom);
  14990. if (xpath)
  14991. doBuildVarStringFunction(instance->classctx, "getInputIteratorPath", xpath->queryChild(0));
  14992. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  14993. if (onFail)
  14994. {
  14995. IHqlExpression * onFailTransform = onFail->queryChild(0);
  14996. if (onFailTransform->isTransform())
  14997. assertex(recordTypesMatch(expr, onFailTransform));
  14998. //virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * e)
  14999. MemberFunction func(*this, instance->startctx, "virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * except)");
  15000. ensureRowAllocated(func.ctx, "crSelf");
  15001. associateLocalFailure(func.ctx, "except");
  15002. buildTransformBody(func.ctx, onFailTransform, dataset, NULL, expr, selSeq);
  15003. }
  15004. }
  15005. buildInstanceSuffix(instance);
  15006. if (boundDataset)
  15007. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  15008. if (isSink)
  15009. return NULL;
  15010. return instance->getBoundActivity();
  15011. }
  15012. //---------------------------------------------------------------------------
  15013. ABoundActivity * HqlCppTranslator::doBuildActivityHTTP(BuildCtx & ctx, IHqlExpression * expr, bool isSink, bool isRoot)
  15014. {
  15015. ThorActivityKind tak;
  15016. const char * helper = "HttpCall";
  15017. unsigned firstArg = 0;
  15018. IHqlExpression * dataset = NULL;
  15019. Owned<ABoundActivity> boundDataset;
  15020. IHqlExpression * selSeq = querySelSeq(expr);
  15021. assertex(!isSink);
  15022. tak = TAKhttp_rowdataset;
  15023. StringBuffer s;
  15024. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, helper);
  15025. //-----------------
  15026. buildActivityFramework(instance, isRoot);
  15027. buildInstancePrefix(instance);
  15028. //virtual const char * getHosts() = 0;
  15029. doBuildVarStringFunction(instance->startctx, "getHosts", expr->queryChild(firstArg));
  15030. //virtual const char * getService() = 0;
  15031. doBuildVarStringFunction(instance->startctx, "getService", expr->queryChild(firstArg+1));
  15032. //virtual const char * getAcceptType() = 0;
  15033. doBuildVarStringFunction(instance->startctx, "getAcceptType", expr->queryChild(firstArg+2));
  15034. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  15035. buildHTTPtoXml(instance->startctx);
  15036. doBuildHttpHeaderStringFunction(instance->startctx, expr);
  15037. IHqlExpression * proxyAddress = expr->queryAttribute(proxyAddressAtom);
  15038. if (proxyAddress)
  15039. doBuildVarStringFunction(instance->startctx, "getProxyAddress", proxyAddress->queryChild(0));
  15040. //virtual const char * queryOutputIteratorPath()
  15041. IHqlExpression * separator = expr->queryAttribute(separatorAtom);
  15042. if (separator)
  15043. doBuildVarStringFunction(instance->startctx, "queryOutputIteratorPath", separator->queryChild(0));
  15044. IHqlExpression * namespaceAttr = expr->queryAttribute(namespaceAtom);
  15045. IHqlExpression * logText = NULL;
  15046. bool logMin = false;
  15047. bool logXml = false;
  15048. ForEachChildFrom(i, expr, 1)
  15049. {
  15050. IHqlExpression * cur = expr->queryChild(i);
  15051. if (cur->isAttribute() && cur->queryName()==logAtom)
  15052. {
  15053. IHqlExpression * opt = cur->queryChild(0);
  15054. if (!opt)
  15055. logXml = true;
  15056. else if (!opt->isAttribute())
  15057. logText = opt;
  15058. else if (opt->queryName() == minAtom)
  15059. logMin = true;
  15060. }
  15061. }
  15062. //virtual unsigned getFlags()
  15063. {
  15064. StringBuffer flags;
  15065. if (expr->hasAttribute(groupAtom))
  15066. flags.append("|SOAPFgroup");
  15067. if (expr->hasAttribute(onFailAtom))
  15068. flags.append("|SOAPFonfail");
  15069. if (logXml)
  15070. flags.append("|SOAPFlog");
  15071. if (expr->hasAttribute(trimAtom))
  15072. flags.append("|SOAPFtrim");
  15073. if (expr->hasAttribute(literalAtom))
  15074. flags.append("|SOAPFliteral");
  15075. if (namespaceAttr)
  15076. flags.append("|SOAPFnamespace");
  15077. if (logMin)
  15078. flags.append("|SOAPFlogmin");
  15079. if (logText)
  15080. flags.append("|SOAPFlogusermsg");
  15081. if (expr->hasAttribute(httpHeaderAtom))
  15082. flags.append("|SOAPFhttpheaders");
  15083. if (flags.length())
  15084. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  15085. }
  15086. //virtual unsigned numParallelThreads()
  15087. doBuildUnsignedFunction(instance->classctx, "numParallelThreads", queryAttributeChild(expr, parallelAtom, 0));
  15088. //virtual unsigned numRecordsPerBatch()
  15089. doBuildUnsignedFunction(instance->classctx, "numRecordsPerBatch", queryAttributeChild(expr, mergeAtom, 0));
  15090. //virtual int numRetries()
  15091. doBuildSignedFunction(instance->classctx, "numRetries", queryAttributeChild(expr, retryAtom, 0));
  15092. //virtual double getTimeout()
  15093. doBuildDoubleFunction(instance->classctx, "getTimeout", queryAttributeChild(expr, timeoutAtom, 0));
  15094. //virtual double getTimeLimit()
  15095. doBuildDoubleFunction(instance->classctx, "getTimeLimit", queryAttributeChild(expr, timeLimitAtom, 0));
  15096. if (namespaceAttr)
  15097. {
  15098. doBuildVarStringFunction(instance->startctx, "getNamespaceName", namespaceAttr->queryChild(0));
  15099. if (namespaceAttr->queryChild(1))
  15100. doBuildVarStringFunction(instance->startctx, "getNamespaceVar", namespaceAttr->queryChild(1));
  15101. }
  15102. if (logText)
  15103. {
  15104. MemberFunction func(*this, instance->startctx, "virtual void getLogText(size32_t & __lenResult, char * & __result, const void * _left)");
  15105. doBuildFunctionReturn(func.ctx, unknownStringType, logText);
  15106. }
  15107. if (!isSink)
  15108. {
  15109. //virtual IXmlToRowTransformer * queryTransformer()
  15110. bool usesContents = false;
  15111. doBuildXmlReadMember(*instance, expr, "queryInputTransformer", usesContents);
  15112. if (usesContents)
  15113. throwError(HQLERR_ContentsInSoapCall);
  15114. //virtual const char * getInputIteratorPath()
  15115. IHqlExpression * xpath = expr->queryAttribute(xpathAtom);
  15116. if (xpath)
  15117. doBuildVarStringFunction(instance->classctx, "getInputIteratorPath", xpath->queryChild(0));
  15118. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  15119. if (onFail)
  15120. {
  15121. MemberFunction func(*this, instance->startctx, "virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * except)");
  15122. ensureRowAllocated(func.ctx, "crSelf");
  15123. associateLocalFailure(func.ctx, "except");
  15124. buildTransformBody(func.ctx, onFail->queryChild(0), dataset, NULL, expr, selSeq);
  15125. }
  15126. }
  15127. buildInstanceSuffix(instance);
  15128. if (boundDataset)
  15129. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  15130. if (isSink)
  15131. return NULL;
  15132. return instance->getBoundActivity();
  15133. }
  15134. //---------------------------------------------------------------------------
  15135. IHqlExpression * HqlCppTranslator::doBuildRegexCompileInstance(BuildCtx & ctx, IHqlExpression * pattern, bool isUnicode, bool isCaseSensitive)
  15136. {
  15137. OwnedHqlExpr searchKey = createAttribute(_regexInstance_Atom, LINK(pattern), createConstant(isUnicode), createConstant(isCaseSensitive));
  15138. HqlExprAssociation * match = ctx.queryMatchExpr(searchKey);
  15139. if (match)
  15140. return match->queryExpr();
  15141. BuildCtx * initCtx = &ctx;
  15142. BuildCtx * declareCtx = &ctx;
  15143. if (pattern->isConstant())
  15144. getInvariantMemberContext(ctx, &declareCtx, &initCtx, true, false);
  15145. StringBuffer tempName;
  15146. getUniqueId(tempName.append("regex"));
  15147. ITypeInfo * type = makeClassType(isUnicode ? "rtlCompiledUStrRegex" : "rtlCompiledStrRegex");
  15148. OwnedHqlExpr regexInstance = createVariable(tempName.str(), type);
  15149. declareCtx->addDeclare(regexInstance);
  15150. HqlExprArray args;
  15151. args.append(*LINK(regexInstance));
  15152. args.append(*LINK(pattern));
  15153. args.append(*createConstant(isCaseSensitive));
  15154. IIdAtom * func = isUnicode ? regexNewSetUStrPatternId : regexNewSetStrPatternId;
  15155. buildFunctionCall(*initCtx, func, args);
  15156. declareCtx->associateExpr(searchKey, regexInstance);
  15157. return regexInstance;
  15158. }
  15159. IHqlExpression * HqlCppTranslator::doBuildRegexFindInstance(BuildCtx & ctx, IHqlExpression * compiled, IHqlExpression * search, bool cloneSearch)
  15160. {
  15161. OwnedHqlExpr searchKey = createAttribute(_regexFindInstance_Atom, LINK(compiled), LINK(search), createConstant(cloneSearch));
  15162. HqlExprAssociation * match = ctx.queryMatchExpr(searchKey);
  15163. if (match)
  15164. return match->queryExpr();
  15165. bool isUnicode = isUnicodeType(search->queryType());
  15166. StringBuffer tempName;
  15167. getUniqueId(tempName.append("fi"));
  15168. ITypeInfo * type = makeClassType(isUnicode ? "rtlUStrRegexFindInstance" : "rtlStrRegexFindInstance");
  15169. OwnedHqlExpr regexInstance = createVariable(tempName.str(), type);
  15170. ctx.addDeclare(regexInstance);
  15171. //Would be better if I allowed classes in my external functions instead of faking booleans
  15172. OwnedHqlExpr castCompiled = createValue(no_typetransfer, makeBoolType(), LINK(compiled));
  15173. HqlExprArray args;
  15174. args.append(*LINK(regexInstance));
  15175. args.append(*createTranslated(castCompiled));
  15176. args.append(*LINK(search));
  15177. if (!isUnicode)
  15178. args.append(*createConstant(cloneSearch));
  15179. IIdAtom * func = isUnicode ? regexNewUStrFindId : regexNewStrFindId;
  15180. buildFunctionCall(ctx, func, args);
  15181. ctx.associateExpr(searchKey, regexInstance);
  15182. return regexInstance;
  15183. }
  15184. void HqlCppTranslator::doBuildNewRegexFindReplace(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * bound)
  15185. {
  15186. CHqlBoundExpr boundMatch;
  15187. if (ctx.getMatchExpr(expr, boundMatch))
  15188. {
  15189. if (bound)
  15190. bound->set(boundMatch);
  15191. else
  15192. assign(ctx, *target, boundMatch);
  15193. return;
  15194. }
  15195. IHqlExpression * pattern = expr->queryChild(0);
  15196. IHqlExpression * search = expr->queryChild(1);
  15197. bool isUnicode = isUnicodeType(search->queryType());
  15198. IHqlExpression * compiled = doBuildRegexCompileInstance(ctx, pattern, isUnicode, !expr->hasAttribute(noCaseAtom));
  15199. if (expr->getOperator() == no_regex_replace)
  15200. {
  15201. HqlExprArray args;
  15202. args.append(*LINK(compiled));
  15203. args.append(*LINK(search));
  15204. args.append(*LINK(expr->queryChild(2)));
  15205. IIdAtom * func = isUnicode ? regexNewUStrReplaceXId : regexNewStrReplaceXId;
  15206. OwnedHqlExpr call = bindFunctionCall(func, args);
  15207. //Need to associate???
  15208. buildExprOrAssign(ctx, target, call, bound);
  15209. return;
  15210. }
  15211. // Because the search instance is created locally, the search parameter is always going to be valid
  15212. // as long as the find instance. Only exception could be if call created a temporary class instance.
  15213. bool cloneSearch = false;
  15214. IHqlExpression * findInstance = doBuildRegexFindInstance(ctx, compiled, search, cloneSearch);
  15215. if(expr->queryType() == queryBoolType())
  15216. {
  15217. HqlExprArray args;
  15218. args.append(*LINK(findInstance));
  15219. IIdAtom * func= isUnicode ? regexNewUStrFoundId : regexNewStrFoundId;
  15220. OwnedHqlExpr call = bindFunctionCall(func, args);
  15221. buildExprOrAssign(ctx, target, call, bound);
  15222. }
  15223. else
  15224. {
  15225. HqlExprArray args;
  15226. args.append(*LINK(findInstance));
  15227. args.append(*LINK(expr->queryChild(2)));
  15228. IIdAtom * func= isUnicode ? regexNewUStrFoundXId : regexNewStrFoundXId;
  15229. OwnedHqlExpr call = bindFunctionCall(func, args);
  15230. buildExprOrAssign(ctx, target, call, bound);
  15231. }
  15232. }
  15233. void HqlCppTranslator::doBuildExprRegexFindReplace(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & bound)
  15234. {
  15235. doBuildNewRegexFindReplace(ctx, NULL, expr, &bound);
  15236. }
  15237. void HqlCppTranslator::doBuildAssignRegexFindReplace(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  15238. {
  15239. doBuildNewRegexFindReplace(ctx, &target, expr, NULL);
  15240. }
  15241. void HqlCppTranslator::doBuildExprRegexFindSet(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & bound)
  15242. {
  15243. CHqlBoundExpr boundMatch;
  15244. if (ctx.getMatchExpr(expr, boundMatch))
  15245. {
  15246. bound.set(boundMatch);
  15247. return;
  15248. }
  15249. IHqlExpression * pattern = expr->queryChild(0);
  15250. IHqlExpression * search = expr->queryChild(1);
  15251. bool isUnicode = isUnicodeType(search->queryType());
  15252. IHqlExpression * compiled = doBuildRegexCompileInstance(ctx, pattern, isUnicode, !expr->hasAttribute(noCaseAtom));
  15253. HqlExprArray args;
  15254. args.append(*LINK(compiled));
  15255. args.append(*LINK(search));
  15256. IIdAtom * func = isUnicode ? regexUStrMatchSetId : regexMatchSetId;
  15257. OwnedHqlExpr call = bindFunctionCall(func, args);
  15258. buildExprOrAssign(ctx, NULL, call, &bound);
  15259. }
  15260. //---------------------------------------------------------------------------
  15261. void HqlCppTranslator::buildStartTimer(BuildCtx & ctx, CHqlBoundExpr & boundTimer, CHqlBoundExpr & boundStart, const char * name)
  15262. {
  15263. BuildCtx * initCtx = &ctx;
  15264. BuildCtx * declareCtx = &ctx;
  15265. getInvariantMemberContext(ctx, &declareCtx, &initCtx, true, false);
  15266. unsigned activityId = 0;
  15267. ActivityInstance * activity = queryCurrentActivity(ctx);
  15268. if (activity)
  15269. activityId = activity->activityId;
  15270. HqlExprArray registerArgs;
  15271. registerArgs.append(*getSizetConstant(activityId));
  15272. registerArgs.append(*createConstant(name));
  15273. OwnedHqlExpr call = bindFunctionCall(registerTimerId, registerArgs);
  15274. if (!declareCtx->getMatchExpr(call, boundTimer))
  15275. {
  15276. Owned<ITypeInfo> timerType = makePointerType(makeClassType("ISectionTimer"));
  15277. OwnedHqlExpr timer = declareCtx->getTempDeclare(timerType, NULL);
  15278. boundTimer.expr.set(timer);
  15279. declareCtx->associateExpr(call, boundTimer);
  15280. initCtx->addAssign(boundTimer.expr, call);
  15281. }
  15282. HqlExprArray nowArgs;
  15283. nowArgs.append(*boundTimer.getTranslatedExpr());
  15284. OwnedHqlExpr now = bindFunctionCall(getStartCyclesId, nowArgs);
  15285. buildTempExpr(ctx, now, boundStart);
  15286. }
  15287. void HqlCppTranslator::buildStopTimer(BuildCtx & ctx, const CHqlBoundExpr & boundTimer, const CHqlBoundExpr & boundStart)
  15288. {
  15289. HqlExprArray nowArgs;
  15290. nowArgs.append(*boundTimer.getTranslatedExpr());
  15291. nowArgs.append(*boundStart.getTranslatedExpr());
  15292. OwnedHqlExpr done = bindFunctionCall(noteSectionTimeId, nowArgs);
  15293. buildStmt(ctx, done);
  15294. }
  15295. //---------------------------------------------------------------------------
  15296. //-- no_null [DATASET] --
  15297. ABoundActivity * HqlCppTranslator::doBuildActivityNull(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  15298. {
  15299. StringBuffer s;
  15300. ThorActivityKind kind = expr->isAction() ? TAKemptyaction : TAKnull;
  15301. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr,"Null");
  15302. if (options.minimizeActivityClasses)
  15303. instance->setImplementationClass(newNullArgId);
  15304. //-----------------
  15305. buildActivityFramework(instance, isRoot);
  15306. buildInstancePrefix(instance);
  15307. buildInstanceSuffix(instance);
  15308. return instance->getBoundActivity();
  15309. }
  15310. //---------------------------------------------------------------------------
  15311. ABoundActivity * HqlCppTranslator::doBuildActivitySideEffect(BuildCtx & ctx, IHqlExpression * expr, bool isRoot, bool expandChildren)
  15312. {
  15313. //Something that is treated like an input, but causes something else to happen - e.g., a failure
  15314. StringBuffer s;
  15315. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsideeffect, expr,"Action");
  15316. //-----------------
  15317. instance->graphLabel.set(getOpString(expr->getOperator())); // label node as "fail"
  15318. buildActivityFramework(instance, isRoot);
  15319. buildInstancePrefix(instance);
  15320. {
  15321. MemberFunction func(*this, instance->startctx, "virtual void action()", MFopt);
  15322. if (expandChildren)
  15323. {
  15324. unsigned numChildren = expr->numChildren();
  15325. for (unsigned idx=1; idx < numChildren; idx++)
  15326. {
  15327. IHqlExpression * cur = expr->queryChild(idx);
  15328. if (!cur->isAttribute())
  15329. buildStmt(func.ctx, cur);
  15330. }
  15331. }
  15332. else
  15333. {
  15334. buildStmt(func.ctx, expr);
  15335. }
  15336. }
  15337. buildInstanceSuffix(instance);
  15338. return instance->getBoundActivity();
  15339. }
  15340. ABoundActivity * HqlCppTranslator::doBuildActivityAction(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  15341. {
  15342. StringBuffer s;
  15343. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsimpleaction, expr, "Action");
  15344. //-----------------
  15345. instance->graphLabel.set(getOpString(expr->getOperator())); // label node as "fail"
  15346. buildActivityFramework(instance, isRoot);
  15347. buildInstancePrefix(instance);
  15348. {
  15349. MemberFunction func(*this, instance->startctx, "virtual void action()", MFopt);
  15350. buildStmt(func.ctx, expr);
  15351. }
  15352. buildInstanceSuffix(instance);
  15353. return instance->getBoundActivity();
  15354. }
  15355. //---------------------------------------------------------------------------
  15356. // if (ctx->currentWorkflowId() == number)
  15357. // doCode();
  15358. void HqlCppTranslator::buildWorkflowItem(BuildCtx & ctx, IHqlStmt * switchStmt, unsigned wfid, IHqlExpression * expr)
  15359. {
  15360. OwnedHqlExpr value = getSizetConstant(wfid);
  15361. BuildCtx condctx(ctx);
  15362. IHqlStmt * caseStmt = condctx.addCase(switchStmt, value);
  15363. //Unwind the statement list to prevent very deep recursion.
  15364. HqlExprArray exprs;
  15365. unwindCommaCompound(exprs, expr);
  15366. ForEachItemIn(i, exprs)
  15367. buildStmt(condctx, &exprs.item(i));
  15368. if (caseStmt->numChildren() == 0)
  15369. condctx.addGroup(); // ensure a break statement is generated...
  15370. }
  15371. void HqlCppTranslator::buildWorkflowPersistCheck(BuildCtx & ctx, IHqlExpression * expr)
  15372. {
  15373. OwnedHqlExpr resultName = ::createResultName(queryAttributeChild(expr, namedAtom, 0));
  15374. resultName.setown(ensureExprType(resultName, unknownVarStringType));
  15375. IHqlExpression * filesRead = expr->queryAttribute(_files_Atom);
  15376. DependenciesUsed dependencies(true);
  15377. if (filesRead)
  15378. {
  15379. ForEachChild(i, filesRead)
  15380. dependencies.tablesRead.append(*getNormalizedFilename(filesRead->queryChild(i)));
  15381. }
  15382. IHqlExpression * resultsRead = expr->queryAttribute(_results_Atom);
  15383. if (resultsRead)
  15384. unwindChildren(dependencies.resultsRead, resultsRead);
  15385. IHqlExpression * crcVal = queryAttributeChild(expr, _codehash_Atom, 0);
  15386. OwnedHqlExpr crcExpr = calculatePersistInputCrc(ctx, dependencies);
  15387. HqlExprArray args;
  15388. args.append(*LINK(resultName));
  15389. args.append(*LINK(crcVal));
  15390. args.append(*LINK(crcExpr));
  15391. args.append(*createConstant(expr->hasAttribute(fileAtom)));
  15392. buildFunctionCall(ctx, returnPersistVersionId, args);
  15393. }
  15394. void HqlCppTranslator::buildWorkflow(WorkflowArray & workflow)
  15395. {
  15396. //Generate a #define that can be used to optimize a particular function.
  15397. BuildCtx optimizectx(*code, includeAtom);
  15398. if (options.optimizeCriticalFunctions)
  15399. {
  15400. switch (options.targetCompiler)
  15401. {
  15402. #ifndef __APPLE__
  15403. case GccCppCompiler:
  15404. optimizectx.addQuoted("#define OPTIMIZE __attribute__((optimize(3)))");
  15405. break;
  15406. #endif
  15407. default:
  15408. optimizectx.addQuoted("#define OPTIMIZE");
  15409. break;
  15410. }
  15411. }
  15412. else
  15413. {
  15414. optimizectx.addQuoted("#define OPTIMIZE");
  15415. }
  15416. BuildCtx classctx(*code, goAtom);
  15417. classctx.addQuotedCompoundLiteral("struct MyEclProcess : public EclProcess", ";");
  15418. classctx.addQuotedLiteral("virtual unsigned getActivityVersion() const { return ACTIVITY_INTERFACE_VERSION; }");
  15419. MemberFunction performFunc(*this, classctx, "virtual int perform(IGlobalCodeContext * gctx, unsigned wfid)");
  15420. performFunc.ctx.addQuotedLiteral("ICodeContext * ctx;");
  15421. performFunc.ctx.addQuotedLiteral("ctx = gctx->queryCodeContext();");
  15422. performFunc.ctx.associateExpr(globalContextMarkerExpr, globalContextMarkerExpr);
  15423. performFunc.ctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  15424. OwnedHqlExpr function = createQuoted("wfid", LINK(unsignedType));
  15425. BuildCtx switchctx(performFunc.ctx);
  15426. IHqlStmt * switchStmt = switchctx.addSwitch(function);
  15427. ForEachItemIn(idx, workflow)
  15428. {
  15429. WorkflowItem & action = workflow.item(idx);
  15430. HqlExprArray & exprs = action.queryExprs();
  15431. unsigned wfid = action.queryWfid();
  15432. optimizePersists(exprs);
  15433. bool isEmpty = exprs.ordinality() == 0;
  15434. if (exprs.ordinality() == 1 && (exprs.item(0).getOperator() == no_workflow_action))
  15435. isEmpty = true;
  15436. if (!isEmpty)
  15437. {
  15438. if (action.isFunction())
  15439. {
  15440. OwnedHqlExpr function = action.getFunction();
  15441. buildFunctionDefinition(function);
  15442. }
  15443. else
  15444. {
  15445. OwnedHqlExpr expr = createActionList(action.queryExprs());
  15446. IHqlExpression * persistAttr = expr->queryAttribute(_workflowPersist_Atom);
  15447. curWfid = wfid;
  15448. if (persistAttr)
  15449. {
  15450. if (!options.freezePersists)
  15451. {
  15452. HqlExprArray args2;
  15453. unwindChildren(args2, expr);
  15454. OwnedHqlExpr setResult = createSetResult(args2);
  15455. buildWorkflowItem(switchctx, switchStmt, wfid, setResult);
  15456. }
  15457. }
  15458. else
  15459. buildWorkflowItem(switchctx, switchStmt, wfid, expr);
  15460. curWfid = 0;
  15461. }
  15462. }
  15463. }
  15464. OwnedHqlExpr returnExpr = getSizetConstant(maxSequence);
  15465. performFunc.ctx.addReturn(returnExpr);
  15466. }
  15467. //---------------------------------------------------------------------------
  15468. void HqlCppTranslator::doBuildStmtWait(BuildCtx & ctx, IHqlExpression * expr)
  15469. {
  15470. throwError(HQLERR_WaitNotSupported);
  15471. }
  15472. void HqlCppTranslator::doBuildStmtNotify(BuildCtx & ctx, IHqlExpression * expr)
  15473. {
  15474. IHqlExpression * event = expr->queryChild(0);
  15475. IHqlExpression * target = queryRealChild(expr, 1);
  15476. HqlExprArray args;
  15477. args.append(*LINK(event->queryChild(0)));
  15478. args.append(*LINK(event->queryChild(1)));
  15479. if (target)
  15480. {
  15481. args.append(*LINK(target));
  15482. buildFunctionCall(ctx, doNotifyTargetId, args);
  15483. }
  15484. else
  15485. buildFunctionCall(ctx, doNotifyId, args);
  15486. }
  15487. //---------------------------------------------------------------------------
  15488. // no_thorresult
  15489. // no_thorremoteresult
  15490. ABoundActivity * HqlCppTranslator::doBuildActivitySetResult(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  15491. {
  15492. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  15493. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  15494. IHqlExpression * persist = expr->queryAttribute(_workflowPersist_Atom);
  15495. HqlExprAttr dataset, row, attribute;
  15496. if (expr->getOperator() == no_extractresult)
  15497. {
  15498. row.set(expr->queryChild(0));
  15499. dataset.set(row->queryNormalizedSelector(true));
  15500. attribute.set(expr->queryChild(1));
  15501. }
  15502. else
  15503. {
  15504. if (!options.canGenerateSimpleAction)
  15505. {
  15506. row.setown(createDataset(no_null, LINK(queryNullRecord()), NULL));
  15507. dataset.set(row);
  15508. }
  15509. attribute.set(expr->queryChild(0));
  15510. }
  15511. // splitSetResultValue(dataset, row, attribute, value);
  15512. if (attribute->isAction())
  15513. {
  15514. //This code is decidedly strange - as far as I can see there is no explicit link between this activity and
  15515. //the child root activity, it works because they happen to be generated in the same graph
  15516. switch (attribute->getOperator())
  15517. {
  15518. case no_output:
  15519. buildRootActivity(ctx, attribute);
  15520. break;
  15521. default:
  15522. buildStmt(ctx, attribute);
  15523. break;
  15524. }
  15525. attribute.set(queryBoolExpr(true));
  15526. }
  15527. Owned<ABoundActivity> boundDataset;
  15528. ThorActivityKind kind = row ? TAKremoteresult : TAKsimpleaction;
  15529. if (row)
  15530. boundDataset.setown(buildCachedActivity(ctx, row));
  15531. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, kind == TAKremoteresult ? "RemoteResult" : "Action");
  15532. if (sequence)
  15533. {
  15534. StringBuffer graphLabel;
  15535. graphLabel.append("Store\n");
  15536. getStoredDescription(graphLabel, sequence, name, true);
  15537. instance->graphLabel.set(graphLabel.str());
  15538. }
  15539. buildActivityFramework(instance, isRoot && !isInternalSeq(sequence));
  15540. buildInstancePrefix(instance);
  15541. if (insideChildQuery(ctx))
  15542. {
  15543. StringBuffer description;
  15544. getStoredDescription(description, sequence, name, true);
  15545. reportWarning(CategoryUnusual, SeverityError, queryLocation(expr), ECODETEXT(HQLWRN_OutputScalarInsideChildQuery), description.str());
  15546. }
  15547. noteResultDefined(ctx, instance, sequence, name, isRoot);
  15548. if (attribute->isDatarow())
  15549. attribute.setown(::ensureSerialized(attribute, diskAtom));
  15550. if (kind == TAKremoteresult)
  15551. {
  15552. doBuildSequenceFunc(instance->classctx, sequence, true);
  15553. MemberFunction func(*this, instance->startctx, "virtual void sendResult(const void * _self)");
  15554. func.ctx.addQuotedLiteral("const unsigned char * self = (const unsigned char *)_self;");
  15555. if (dataset->isDatarow())
  15556. {
  15557. OwnedHqlExpr bound = createVariable("self", makeRowReferenceType(dataset));
  15558. bindRow(func.ctx, dataset, bound);
  15559. }
  15560. else
  15561. bindTableCursor(func.ctx, dataset, "self");
  15562. buildSetResultInfo(func.ctx, expr, attribute, NULL, (persist != NULL), false);
  15563. }
  15564. else
  15565. {
  15566. MemberFunction func(*this, instance->startctx, "virtual void action()");
  15567. buildSetResultInfo(func.ctx, expr, attribute, NULL, (persist != NULL), false);
  15568. }
  15569. buildInstanceSuffix(instance);
  15570. if (boundDataset)
  15571. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  15572. associateRemoteResult(*instance, sequence, name);
  15573. return instance->getBoundActivity();
  15574. }
  15575. //---------------------------------------------------------------------------
  15576. //-- no_distribution
  15577. static void getInterfaceName(StringBuffer & name, ITypeInfo * type)
  15578. {
  15579. switch (type->getTypeCode())
  15580. {
  15581. case type_boolean:
  15582. name.append("IBoolDistributionTable");
  15583. break;
  15584. case type_real:
  15585. name.append("IRealDistributionTable");
  15586. break;
  15587. case type_string:
  15588. case type_data:
  15589. case type_qstring:
  15590. assertex(type->getSize() != UNKNOWN_LENGTH);
  15591. name.append("IStringDistributionTable");
  15592. break;
  15593. case type_int:
  15594. case type_swapint:
  15595. case type_packedint:
  15596. if (type->isSigned())
  15597. {
  15598. if (type->getSize() == 8)
  15599. name.append("IInt64DistributionTable");
  15600. else
  15601. name.append("IIntDistributionTable");
  15602. }
  15603. else
  15604. {
  15605. if (type->getSize() == 8)
  15606. name.append("IUInt64DistributionTable");
  15607. else
  15608. name.append("IUIntDistributionTable");
  15609. }
  15610. break;
  15611. default:
  15612. UNIMPLEMENTED;
  15613. }
  15614. }
  15615. static bool expandFieldName(StringBuffer & s, IHqlExpression * e)
  15616. {
  15617. if (e->getOperator() == no_select)
  15618. {
  15619. if (expandFieldName(s, e->queryChild(0)))
  15620. s.append('.');
  15621. const char * name = str(e->queryChild(1)->queryName());
  15622. s.appendLower(strlen(name), name);
  15623. return true;
  15624. }
  15625. return false;
  15626. }
  15627. void HqlCppTranslator::doBuildDistributionClearFunc(BuildCtx & ctx, IHqlExpression * dataset, HqlExprArray & selects)
  15628. {
  15629. StringBuffer s, funcName;
  15630. MemberFunction func(*this, ctx, "virtual void clearAggregate(IDistributionTable * * tables)");
  15631. ForEachItemIn(idx, selects)
  15632. {
  15633. IHqlExpression * original = &selects.item(idx);
  15634. ITypeInfo * type = original->queryType();
  15635. getInterfaceName(funcName.clear().append("create"), type);
  15636. s.clear().append("tables[").append(idx).append("] = ").append(funcName).append("(\"");
  15637. expandFieldName(s, original);
  15638. s.append("\", ").append(type->getSize()).append(");");
  15639. func.ctx.addQuoted(s);
  15640. }
  15641. }
  15642. void HqlCppTranslator::doBuildDistributionNextFunc(BuildCtx & ctx, IHqlExpression * dataset, HqlExprArray & selects)
  15643. {
  15644. StringBuffer s;
  15645. MemberFunction func(*this, ctx, "virtual void process(IDistributionTable * * tables, const void * _src)");
  15646. func.ctx.addQuotedLiteral("unsigned char * src = (unsigned char *) _src;");
  15647. bindTableCursor(func.ctx, dataset, "src");
  15648. ForEachItemIn(idx, selects)
  15649. {
  15650. IHqlExpression * original = &selects.item(idx);
  15651. ITypeInfo * type = original->queryType();
  15652. CHqlBoundExpr bound;
  15653. buildExpr(func.ctx, original, bound);
  15654. s.clear().append("((");
  15655. getInterfaceName(s, type);
  15656. s.append(" *)tables[").append(idx).append("])->noteValue(");
  15657. switch (type->getTypeCode())
  15658. {
  15659. case type_string:
  15660. case type_data:
  15661. case type_qstring:
  15662. {
  15663. if (bound.length)
  15664. generateExprCpp(s, bound.length);
  15665. else
  15666. s.append(type->getSize());
  15667. s.append(",");
  15668. OwnedHqlExpr addr = getElementPointer(bound.expr);
  15669. generateExprCpp(s, addr);
  15670. }
  15671. break;
  15672. default:
  15673. generateExprCpp(s, bound.expr);
  15674. break;
  15675. }
  15676. s.append(");");
  15677. func.ctx.addQuoted(s);
  15678. }
  15679. }
  15680. void HqlCppTranslator::doBuildDistributionFunc(BuildCtx & funcctx, unsigned numFields, const char * action)
  15681. {
  15682. StringBuffer s;
  15683. s.clear().append("for (unsigned i=0;i<").append(numFields).append(";i++)");
  15684. funcctx.addQuotedCompound(s, nullptr);
  15685. s.clear().append("tables[i]->").append(action).append(";");
  15686. funcctx.addQuoted(s);
  15687. }
  15688. void HqlCppTranslator::doBuildDistributionDestructFunc(BuildCtx & ctx, unsigned numFields)
  15689. {
  15690. BuildCtx funcctx(ctx);
  15691. funcctx.addQuotedFunction("virtual void destruct(IDistributionTable * * tables)");
  15692. doBuildDistributionFunc(funcctx, numFields, "Release()");
  15693. }
  15694. void HqlCppTranslator::doBuildDistributionSerializeFunc(BuildCtx & ctx, unsigned numFields)
  15695. {
  15696. BuildCtx funcctx(ctx);
  15697. funcctx.addQuotedFunction("virtual void serialize(IDistributionTable * * tables, MemoryBuffer & out)");
  15698. doBuildDistributionFunc(funcctx, numFields, "serialize(out)");
  15699. }
  15700. void HqlCppTranslator::doBuildDistributionMergeFunc(BuildCtx & ctx, unsigned numFields)
  15701. {
  15702. BuildCtx funcctx(ctx);
  15703. funcctx.addQuotedFunction("virtual void merge(IDistributionTable * * tables, MemoryBuffer & in)");
  15704. doBuildDistributionFunc(funcctx, numFields, "merge(in)");
  15705. }
  15706. void HqlCppTranslator::doBuildDistributionGatherFunc(BuildCtx & ctx, unsigned numFields)
  15707. {
  15708. BuildCtx funcctx(ctx);
  15709. funcctx.addQuotedFunction("virtual void gatherResult(IDistributionTable * * tables, StringBuffer & out)");
  15710. doBuildDistributionFunc(funcctx, numFields, "report(out)");
  15711. }
  15712. static void expandDistributionFields(IHqlExpression * record, HqlExprArray & selects, IHqlExpression * selector)
  15713. {
  15714. ForEachChild(idx, record)
  15715. {
  15716. IHqlExpression * cur = record->queryChild(idx);
  15717. switch (cur->getOperator())
  15718. {
  15719. case no_ifblock:
  15720. expandDistributionFields(cur->queryChild(1), selects, selector);
  15721. break;
  15722. case no_record:
  15723. expandDistributionFields(cur, selects, selector);
  15724. break;
  15725. case no_field:
  15726. {
  15727. OwnedHqlExpr selected = selector ? createSelectExpr(LINK(selector), LINK(cur)) : LINK(cur);
  15728. if (cur->queryType()->getTypeCode() == type_row)
  15729. {
  15730. expandDistributionFields(cur->queryRecord(), selects, selected);
  15731. return;
  15732. }
  15733. selects.append(*selected.getClear());
  15734. break;
  15735. }
  15736. case no_attr:
  15737. case no_attr_expr:
  15738. case no_attr_link:
  15739. break;
  15740. default:
  15741. UNIMPLEMENTED;
  15742. break;
  15743. }
  15744. }
  15745. }
  15746. ABoundActivity * HqlCppTranslator::doBuildActivityDistribution(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  15747. {
  15748. IHqlExpression * dataset = expr->queryChild(0);
  15749. IHqlExpression * fields = queryRealChild(expr, 1);
  15750. IHqlExpression * sequence = expr->queryAttribute(sequenceAtom);
  15751. if (!sequence)
  15752. throwError(HQLERR_DistributionNoSequence);
  15753. useInclude("rtldistr.hpp");
  15754. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  15755. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdistribution, expr, "Distribution");
  15756. buildActivityFramework(instance, isRoot);
  15757. buildInstancePrefix(instance);
  15758. HqlExprArray selects;
  15759. if (fields)
  15760. unwindChildren(selects, fields);
  15761. else
  15762. expandDistributionFields(dataset->queryRecord(), selects, dataset);
  15763. ForEachItemIn(i, selects)
  15764. {
  15765. IHqlExpression & cur = selects.item(i);
  15766. ITypeInfo * type = cur.queryType();
  15767. switch (type->getTypeCode())
  15768. {
  15769. case type_boolean:
  15770. case type_real:
  15771. case type_int:
  15772. case type_swapint:
  15773. case type_packedint:
  15774. break;
  15775. case type_string:
  15776. case type_data:
  15777. case type_qstring:
  15778. if (type->getSize() == UNKNOWN_LENGTH)
  15779. throwError1(HQLERR_DistributionVariableLengthX, str(cur.queryChild(1)->queryId()));
  15780. break;
  15781. default:
  15782. {
  15783. StringBuffer typeName;
  15784. getFriendlyTypeStr(type, typeName);
  15785. throwError2(HQLERR_DistributionUnsupportedTypeXX, str(cur.queryChild(1)->queryId()), typeName.str());
  15786. }
  15787. }
  15788. }
  15789. unsigned numFields = selects.ordinality();
  15790. doBuildDistributionClearFunc(instance->startctx, dataset, selects);
  15791. doBuildDistributionNextFunc(instance->startctx, dataset, selects);
  15792. doBuildDistributionDestructFunc(instance->startctx, numFields);
  15793. doBuildDistributionGatherFunc(instance->startctx, numFields);
  15794. doBuildDistributionMergeFunc(instance->startctx, numFields);
  15795. doBuildDistributionSerializeFunc(instance->startctx, numFields);
  15796. //Need an extra meta information for the internal aggregate record
  15797. {
  15798. HqlExprArray fields;
  15799. fields.append(*createField(unnamedId, makeDataType(numFields*sizeof(void*)), NULL, NULL));
  15800. OwnedHqlExpr tempRecord = createRecord(fields);
  15801. buildMetaMember(instance->classctx, tempRecord, false, "queryInternalRecordSize");
  15802. }
  15803. //Generate the send Result method().
  15804. {
  15805. MemberFunction func(*this, instance->startctx, "virtual void sendResult(size32_t length, const char * text)");
  15806. CHqlBoundExpr bound;
  15807. HqlExprAttr translated;
  15808. bound.length.setown(createVariable("length", makeIntType(sizeof(size32_t), false)));
  15809. bound.expr.setown(createVariable("text", makeStringType(UNKNOWN_LENGTH, NULL, NULL)));
  15810. translated.setown(bound.getTranslatedExpr());
  15811. buildSetResultInfo(func.ctx, expr, translated, NULL, false, false);
  15812. }
  15813. buildInstanceSuffix(instance);
  15814. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  15815. return instance->getBoundActivity();
  15816. }
  15817. //---------------------------------------------------------------------------
  15818. //-- pure hole table --
  15819. void HqlCppTranslator::addFileDependency(IHqlExpression * name, ABoundActivity * whoAmI)
  15820. {
  15821. if (name && activeGraphCtx)
  15822. {
  15823. OwnedHqlExpr search = createAttribute(fileAtom, getNormalizedFilename(name));
  15824. HqlExprAssociation * match = activeGraphCtx->queryMatchExpr(search);
  15825. if (match)
  15826. addDependency(*activeGraphCtx, ((ABoundActivity *)match->queryExpr()->queryUnknownExtra()), whoAmI, sourceAtom);
  15827. }
  15828. }
  15829. //---------------------------------------------------------------------------
  15830. StringBuffer &expandDotLiteral(StringBuffer &s, const char *f)
  15831. {
  15832. unsigned lines = 0;
  15833. unsigned chars = 0;
  15834. char c;
  15835. while ((c = *f++) != 0)
  15836. {
  15837. switch (c)
  15838. {
  15839. case '\t':
  15840. s.append(" ");
  15841. break;
  15842. case '\r':
  15843. break;
  15844. case '\n':
  15845. s.append("\\l"); // Means left justify.
  15846. if (lines++ > 10)
  15847. return s;
  15848. break;
  15849. case '}':
  15850. case '{':
  15851. case '<':
  15852. case '>': // Special chars in dot graphs
  15853. case '\\':
  15854. case '\"':
  15855. case '\'':
  15856. s.append('\\');
  15857. // fall into...
  15858. default:
  15859. if (chars++ > 1000)
  15860. return s;
  15861. s.append(c);
  15862. break;
  15863. }
  15864. }
  15865. return s;
  15866. }
  15867. void HqlCppTranslator::logGraphEdge(IPropertyTree * subGraph, unsigned __int64 source, unsigned __int64 target, unsigned outputIndex, unsigned inputIndex, const char * label, bool nWay)
  15868. {
  15869. addSimpleGraphEdge(subGraph, source, target, outputIndex, inputIndex, NULL, label, nWay);
  15870. }
  15871. void HqlCppTranslator::buildActivityFramework(ActivityInstance * instance)
  15872. {
  15873. assertex(!instance->isAction()); // All actions should be calling the 2 parameter version below instead
  15874. buildActivityFramework(instance, false);
  15875. }
  15876. void HqlCppTranslator::buildActivityFramework(ActivityInstance * instance, bool alwaysExecuted)
  15877. {
  15878. instance->createGraphNode(activeGraph->xgmml, alwaysExecuted);
  15879. if (options.trackDuplicateActivities)
  15880. {
  15881. IHqlExpression * search = instance->dataset;
  15882. node_operator op = search->getOperator();
  15883. if ((op != no_select) && (op != no_workunit_dataset))
  15884. {
  15885. IHqlExpression * searchNorm = queryLocationIndependent(search);
  15886. unsigned crc = getExpressionCRC(search);
  15887. ForEachItemIn(i, tracking.activityExprs)
  15888. {
  15889. if (search == &tracking.activityExprs.item(i))
  15890. instance->addAttributeInt("_duplicateActivity_", tracking.activityIds.item(i));
  15891. else if (crc == tracking.activityCrcs.item(i))
  15892. instance->addAttributeInt("_duplicateCrcActivity_", tracking.activityIds.item(i));
  15893. else if (searchNorm == &tracking.activityNorms.item(i))
  15894. instance->addAttributeInt("_duplicateNormActivity_", tracking.activityIds.item(i));
  15895. }
  15896. tracking.activityExprs.append(*LINK(search));
  15897. tracking.activityNorms.append(*LINK(searchNorm));
  15898. tracking.activityIds.append(instance->activityId);
  15899. tracking.activityCrcs.append(crc);
  15900. }
  15901. }
  15902. }
  15903. void HqlCppTranslator::buildConnectOrders(BuildCtx & ctx, ABoundActivity * slaveActivity, ABoundActivity * masterActivity)
  15904. {
  15905. //I'm not sure we even use this information, but at least it's there if needed.
  15906. if (targetThor())
  15907. {
  15908. IPropertyTree *edge = createPTree();
  15909. edge->setPropInt64("@target", slaveActivity->queryActivityId());
  15910. edge->setPropInt64("@source", masterActivity->queryActivityId());
  15911. addGraphAttributeBool(edge, "cosort", true);
  15912. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  15913. assertex(activeSubgraph);
  15914. activeSubgraph->tree->addPropTree("edge", edge);
  15915. }
  15916. }
  15917. bool HqlCppTranslator::useRowAccessorClass(IHqlExpression * record, bool isTargetRow)
  15918. {
  15919. if (isTargetRow)
  15920. return false;
  15921. if (isFixedRecordSize(record))
  15922. return false;
  15923. if (!canCreateRtlTypeInfo(record))
  15924. return false;
  15925. return getVarSizeFieldCount(record, true) >= options.varFieldAccessorThreshold;
  15926. }
  15927. ColumnToOffsetMap * HqlCppTranslator::queryRecordOffsetMap(IHqlExpression * record, bool useAccessorClass)
  15928. {
  15929. if (record)
  15930. return recordMap.queryMapping(record, options.maxRecordSize, useAccessorClass);
  15931. return NULL;
  15932. }
  15933. unsigned HqlCppTranslator::getFixedRecordSize(IHqlExpression * record)
  15934. {
  15935. assertex(isFixedSizeRecord(record));
  15936. return getMinRecordSize(record);
  15937. }
  15938. bool HqlCppTranslator::isFixedRecordSize(IHqlExpression * record)
  15939. {
  15940. return ::isFixedSizeRecord(record);
  15941. }
  15942. void HqlCppTranslator::buildReturnRecordSize(BuildCtx & ctx, BoundRow * cursor)
  15943. {
  15944. OwnedHqlExpr size = getRecordSize(cursor->querySelector());
  15945. buildReturn(ctx, size);
  15946. }
  15947. bool HqlCppTranslator::recordContainsIfBlock(IHqlExpression * record)
  15948. {
  15949. return ::containsIfBlock(record);
  15950. }
  15951. void HqlCppTranslator::buildRowAccessors()
  15952. {
  15953. HashIterator iter(recordMap);
  15954. ForEach(iter)
  15955. {
  15956. ColumnToOffsetMap * map = static_cast<ColumnToOffsetMap *>(&iter.query());
  15957. buildRowAccessor(map);
  15958. }
  15959. }
  15960. void HqlCppTranslator::buildRowAccessor(ColumnToOffsetMap * map)
  15961. {
  15962. if (!map->usesAccessor())
  15963. return;
  15964. const bool isRead = true;
  15965. IHqlExpression * record = map->queryRecord();
  15966. BuildCtx declarectx(*code, declareAtom);
  15967. BuildCtx ctx(declarectx);
  15968. OwnedHqlExpr search = createAttribute(accessorAtom, LINK(record), createConstant(isRead));
  15969. if (ctx.queryMatchExpr(search))
  15970. return;
  15971. StringBuffer accessorName;
  15972. map->buildAccessor(accessorName, *this, ctx, NULL);
  15973. declarectx.associateExpr(search, search);
  15974. }
  15975. //-- Code to transform the expressions ready for generating source code.
  15976. static void logECL(const LogMsgCategory & category, size32_t len, const char * ecl)
  15977. {
  15978. const size32_t chunkSize = 31000;
  15979. while (len > chunkSize)
  15980. {
  15981. const char * next = strchr(ecl+chunkSize, '\n');
  15982. if (!next || !next[1])
  15983. break;
  15984. unsigned size = next-ecl;
  15985. if (ecl[size-1] == '\r')
  15986. size--;
  15987. LOG(category, unknownJob, "%.*s", size, ecl);
  15988. len -= (next+1-ecl);
  15989. ecl = next+1;
  15990. }
  15991. LOG(category, unknownJob, "%s", ecl);
  15992. }
  15993. void HqlCppTranslator::traceExpression(const char * title, IHqlExpression * expr, unsigned level)
  15994. {
  15995. if (!expr)
  15996. return;
  15997. checkAbort();
  15998. LOG(MCdebugInfo(200), unknownJob, "Tracing expressions: %s", title);
  15999. LogMsgCategory debug500 = MCdebugInfo(level);
  16000. if(REJECTLOG(debug500))
  16001. return;
  16002. if (options.traceIR)
  16003. {
  16004. EclIR::dbglogIR(expr);
  16005. }
  16006. else
  16007. {
  16008. StringBuffer s;
  16009. processedTreeToECL(expr, s);
  16010. logECL(debug500, s.length(), s.str());
  16011. }
  16012. }
  16013. void HqlCppTranslator::traceExpressions(const char * title, HqlExprArray & exprs, unsigned level)
  16014. {
  16015. OwnedHqlExpr compound = createComma(exprs);
  16016. traceExpression(title, compound, level);
  16017. }
  16018. void HqlCppTranslator::traceExpressions(const char * title, WorkflowArray & workflow)
  16019. {
  16020. checkAbort();
  16021. // PrintLog(title);
  16022. LOG(MCdebugInfo(200), unknownJob, "Tracing expressions: %s", title);
  16023. static LogMsgCategory debug500 = MCdebugInfo(500);
  16024. static LogMsgCategory debug5000 = MCdebugInfo(5000);
  16025. if(REJECTLOG(debug500))
  16026. return;
  16027. ForEachItemIn(idx1, workflow)
  16028. {
  16029. WorkflowItem & cur = workflow.item(idx1);
  16030. OwnedHqlExpr compound = createComma(cur.queryExprs());
  16031. if (compound)
  16032. {
  16033. LOG(debug500, unknownJob, "%s: #%d: id[%d]", title, idx1, cur.queryWfid());
  16034. if (options.traceIR)
  16035. {
  16036. EclIR::dbglogIR(compound);
  16037. }
  16038. else
  16039. {
  16040. StringBuffer s;
  16041. processedTreeToECL(compound, s);
  16042. logECL(debug500, s.length(), s.str());
  16043. }
  16044. }
  16045. }
  16046. }
  16047. void HqlCppTranslator::checkNormalized(WorkflowArray & workflow)
  16048. {
  16049. ForEachItemIn(i, workflow)
  16050. {
  16051. checkNormalized(workflow.item(i).queryExprs());
  16052. }
  16053. }
  16054. void HqlCppTranslator::checkNormalized(IHqlExpression * expr)
  16055. {
  16056. if (options.paranoidCheckDependencies)
  16057. checkDependencyConsistency(expr);
  16058. if (options.paranoidCheckNormalized)
  16059. {
  16060. ::checkNormalized(expr);
  16061. }
  16062. if (options.paranoidCheckSelects)
  16063. checkSelectConsistency(expr);
  16064. }
  16065. void HqlCppTranslator::checkNormalized(HqlExprArray & exprs)
  16066. {
  16067. if (options.paranoidCheckDependencies)
  16068. checkDependencyConsistency(exprs);
  16069. ForEachItemIn(i, exprs)
  16070. {
  16071. if (options.paranoidCheckNormalized)
  16072. ::checkNormalized(&exprs.item(i));
  16073. if (options.paranoidCheckSelects)
  16074. checkSelectConsistency(&exprs.item(i));
  16075. }
  16076. }
  16077. void HqlCppTranslator::checkNormalized(BuildCtx & ctx, IHqlExpression * expr)
  16078. {
  16079. if (options.paranoidCheckDependencies)
  16080. checkDependencyConsistency(expr);
  16081. if (options.paranoidCheckNormalized)
  16082. {
  16083. HqlExprArray activeTables;
  16084. //Added in reverse order, but normalize checker doesn't care
  16085. RowAssociationIterator iter(ctx);
  16086. ForEach(iter)
  16087. {
  16088. BoundRow & cur = iter.get();
  16089. if ((cur.querySide() != no_self) && !cur.isBuilder())
  16090. activeTables.append(*LINK(cur.querySelector()));
  16091. }
  16092. ::checkNormalized(expr, activeTables);
  16093. }
  16094. if (options.paranoidCheckSelects)
  16095. checkSelectConsistency(expr);
  16096. }
  16097. void createCompoundEnsure(HqlExprArray & exprs, unsigned first, unsigned last)
  16098. {
  16099. if (first >= last || last == NotFound)
  16100. return;
  16101. IHqlExpression * action = &exprs.item(last);
  16102. OwnedHqlExpr actionExpr = createActionList(exprs, first, last);
  16103. OwnedHqlExpr compound = createCompound(actionExpr.getClear(), LINK(action->queryChild(0)));
  16104. OwnedHqlExpr newAction = replaceChild(action, 0, compound);
  16105. exprs.replace(*newAction.getClear(), first);
  16106. exprs.removen(first+1, (last-first));
  16107. }
  16108. //move any set results inside a no_ensureresult so they don't get evaluated unless necessary.
  16109. void HqlCppTranslator::optimizePersists(HqlExprArray & exprs)
  16110. {
  16111. //If there is a single ensure result, and no set results created from other workflow items
  16112. //then move all previous actions inside the ensure result
  16113. unsigned max = exprs.ordinality();
  16114. if (max == 0)
  16115. return;
  16116. if (exprs.item(max-1).getOperator() != no_ensureresult)
  16117. return;
  16118. for (unsigned i=0; i < max-1; i++)
  16119. {
  16120. IHqlExpression & cur = exprs.item(i);
  16121. if ((cur.getOperator() == no_ensureresult) || cur.hasAttribute(_workflow_Atom))
  16122. return;
  16123. }
  16124. createCompoundEnsure(exprs, 0, max-1);
  16125. }
  16126. IHqlExpression * HqlCppTranslator::convertSetResultToExtract(IHqlExpression * expr)
  16127. {
  16128. SetResultToExtractTransformer transformer;
  16129. return transformer.transformRoot(expr);
  16130. }
  16131. IHqlExpression * HqlCppTranslator::extractGlobalCSE(IHqlExpression * expr)
  16132. {
  16133. AutoScopeMigrateTransformer transformer(wu(), *this);
  16134. HqlExprArray exprs;
  16135. unwindCommaCompound(exprs, expr);
  16136. transformer.analyseArray(exprs, 0);
  16137. if (!transformer.worthTransforming())
  16138. return LINK(expr);
  16139. HqlExprArray results;
  16140. transformer.transformRoot(exprs, results);
  16141. return createActionList(results);
  16142. }
  16143. IHqlExpression * HqlCppTranslator::spotGlobalCSE(IHqlExpression * _expr)
  16144. {
  16145. if (!_expr->isAction())
  16146. return LINK(_expr);
  16147. LinkedHqlExpr expr = _expr;
  16148. switch (expr->getOperator())
  16149. {
  16150. case no_if:
  16151. {
  16152. IHqlExpression * left = expr->queryChild(1);
  16153. IHqlExpression * right = expr->queryChild(2);
  16154. HqlExprArray args;
  16155. args.append(*LINK(expr->queryChild(0)));
  16156. args.append(*extractGlobalCSE(left));
  16157. if (right)
  16158. args.append(*extractGlobalCSE(right));
  16159. if ((left != &args.item(1)) || (right && right != &args.item(2)))
  16160. {
  16161. unwindChildren(args, expr, 3);
  16162. expr.setown(_expr->clone(args));
  16163. }
  16164. break;
  16165. }
  16166. case no_sequential:
  16167. {
  16168. HqlExprArray args;
  16169. ForEachChild(i, expr)
  16170. args.append(*extractGlobalCSE(expr->queryChild(i)));
  16171. expr.setown(_expr->clone(args));
  16172. break;
  16173. }
  16174. case no_nothor:
  16175. return LINK(expr);
  16176. }
  16177. bool same = true;
  16178. HqlExprArray args;
  16179. ForEachChild(i, expr)
  16180. {
  16181. IHqlExpression * cur = expr->queryChild(i);
  16182. IHqlExpression * next = spotGlobalCSE(cur);
  16183. args.append(*next);
  16184. if (cur != next)
  16185. same = false;
  16186. }
  16187. if (same)
  16188. return expr.getClear();
  16189. return expr->clone(args);
  16190. }
  16191. void HqlCppTranslator::spotGlobalCSE(HqlExprArray & exprs)
  16192. {
  16193. HqlExprArray results;
  16194. AutoScopeMigrateTransformer transformer(wu(), *this);
  16195. transformer.analyseArray(exprs, 0);
  16196. if (transformer.worthTransforming())
  16197. {
  16198. transformer.transformRoot(exprs, results);
  16199. replaceArray(exprs, results);
  16200. }
  16201. if (!options.resourceConditionalActions)
  16202. {
  16203. //Now need to recursively walk actions, and if any conditional actions could do with things being hoisted within them
  16204. ForEachItemIn(i, exprs)
  16205. exprs.replace(*spotGlobalCSE(&exprs.item(i)), i);
  16206. }
  16207. }
  16208. void HqlCppTranslator::spotGlobalCSE(WorkflowItem & curWorkflow)
  16209. {
  16210. if (!insideLibrary() && options.globalAutoHoist)
  16211. {
  16212. spotGlobalCSE(curWorkflow.queryExprs());
  16213. }
  16214. }
  16215. void HqlCppTranslator::flattenDatasets(WorkflowArray & array)
  16216. {
  16217. //MORE: Should project fields needed outside <ds>.<ds> so that they are available.
  16218. }
  16219. // Code to check whether thor is required for a query. It should err towards true.
  16220. // The idea is to prevent some very simple queries going to thor, mainly when users are examining data. The main examples are:
  16221. // 1. Unfiltered table count
  16222. // 2. Filtered index count.
  16223. // 3. Restricted set of records from an index/table.
  16224. enum { NRTfiltered = 0x0001, NRTcount = 0x0002, NRTlimited = 0x0004 };
  16225. static bool needsRealThor(IHqlExpression *expr, unsigned flags)
  16226. {
  16227. unsigned numChildrenToCheck = (unsigned)-1;
  16228. switch (expr->getOperator())
  16229. {
  16230. case no_table:
  16231. //only allow non filtered limited outputs, and non filtered counts
  16232. return !((flags == NRTlimited) || (flags == NRTcount));
  16233. case no_newkeyindex:
  16234. case no_keyindex:
  16235. case no_compound_indexread:
  16236. //Don't allow count(choosen(...)) otherwise likely to be better in hthor
  16237. if (flags & NRTcount)
  16238. return (flags & NRTlimited) != 0;
  16239. //unfiltered index read should go via thor
  16240. if (flags == 0)
  16241. return true;
  16242. //filtered index reads likely to be much better in hthor.
  16243. return false;
  16244. case no_attr:
  16245. case no_attr_expr:
  16246. case no_attr_link:
  16247. case no_datasetfromrow:
  16248. case no_rows:
  16249. case no_libraryinput:
  16250. case no_fail:
  16251. case no_persist_check:
  16252. return false;
  16253. case no_distribution:
  16254. case no_buildindex:
  16255. case no_keydiff:
  16256. case no_keypatch:
  16257. case no_forcelocal:
  16258. case no_forcenolocal:
  16259. case no_allnodes:
  16260. case no_thisnode:
  16261. return true;
  16262. case no_hqlproject:
  16263. //If count project, a count will not be done as a compound operation
  16264. if (expr->hasAttribute(_countProject_Atom) && (flags & NRTcount))
  16265. return true;
  16266. break;
  16267. case no_compound_indexcount:
  16268. case no_transformascii:
  16269. case no_transformebcdic:
  16270. case no_selectfields:
  16271. case no_thor:
  16272. case no_apply:
  16273. case no_distributed:
  16274. case no_unordered:
  16275. case no_preservemeta:
  16276. case no_sorted:
  16277. case no_limit:
  16278. case no_catchds:
  16279. case no_keyedlimit:
  16280. case no_assertsorted:
  16281. case no_assertgrouped:
  16282. case no_assertdistributed:
  16283. case no_section:
  16284. case no_sectioninput:
  16285. case no_forcegraph:
  16286. case no_nofold:
  16287. case no_nohoist:
  16288. case no_nocombine:
  16289. case no_actionlist:
  16290. case no_orderedactionlist:
  16291. case no_compound_fetch:
  16292. case no_addfiles:
  16293. case no_nonempty:
  16294. case no_dataset_alias:
  16295. //i.e. go through children...
  16296. break;
  16297. case no_compound:
  16298. case no_comma:
  16299. case no_executewhen:
  16300. numChildrenToCheck = expr->numChildren();
  16301. break;
  16302. case no_choosen:
  16303. case no_selectnth:
  16304. flags |= NRTlimited;
  16305. break;
  16306. case no_filter:
  16307. flags |= NRTfiltered;
  16308. break;
  16309. case no_newaggregate:
  16310. case no_newusertable:
  16311. if (isAggregateDataset(expr))
  16312. {
  16313. //Only allow aggregates we can do on an index directly
  16314. if (datasetHasGroupBy(expr))
  16315. return true;
  16316. node_operator aggOp = querySingleAggregate(expr, false, false, true);
  16317. if ((aggOp != no_exists) && (aggOp != no_count))
  16318. return true;
  16319. flags |= NRTcount;
  16320. }
  16321. break;
  16322. case no_if:
  16323. case no_choose:
  16324. case no_chooseds:
  16325. {
  16326. if (needsRealThor(expr->queryChild(0), 0))
  16327. return true;
  16328. ForEachChildFrom(i, expr, 1)
  16329. {
  16330. if (needsRealThor(expr->queryChild(i), flags))
  16331. return true;
  16332. }
  16333. return false;
  16334. }
  16335. case no_colon:
  16336. case no_globalscope:
  16337. case no_extractresult:
  16338. return needsRealThor(expr->queryChild(0), flags);
  16339. case no_call:
  16340. case no_externalcall:
  16341. if (isDistributedFunctionCall(expr))
  16342. return true;
  16343. //MORE: check for streamed inputs.
  16344. break;
  16345. case no_fetch:
  16346. return needsRealThor(expr->queryChild(1), flags);
  16347. case no_output:
  16348. {
  16349. //Assume any output to files needs to stay where it is.
  16350. IHqlExpression *child0 = expr->queryChild(0);
  16351. IHqlExpression *filename = queryRealChild(expr, 1);
  16352. if (filename)
  16353. return true;
  16354. return needsRealThor(child0, flags);
  16355. }
  16356. case no_ensureresult:
  16357. case no_setresult:
  16358. case no_evaluate_stmt:
  16359. case no_return_stmt:
  16360. {
  16361. IHqlExpression * child0 = expr->queryChild(0);
  16362. if (!child0->queryType()->isScalar())
  16363. return needsRealThor(child0, flags);
  16364. if (child0->getOperator() == no_evalonce)
  16365. child0 = child0->queryChild(0);
  16366. switch (child0->getOperator())
  16367. {
  16368. case no_externalcall:
  16369. case no_constant:
  16370. case no_all:
  16371. return false;
  16372. case no_select:
  16373. return needsRealThor(child0->queryChild(0), flags);
  16374. }
  16375. if (!containsAnyDataset(child0))
  16376. return false;
  16377. // return needsRealThor(child0, isFiltered);
  16378. //fallthrough...
  16379. }
  16380. default:
  16381. if (expr->isDataset())
  16382. return true;
  16383. ITypeInfo * type = expr->queryType();
  16384. if (!type || (type->getTypeCode() != type_void))
  16385. return false; //MORE Doesn't cope with scalar expressions that require thor e.g., counts of sorts of ....
  16386. //MORE: This means that lots of scalar expressions go to thor instead of hthor.
  16387. return true;
  16388. }
  16389. if (numChildrenToCheck == (unsigned)-1)
  16390. numChildrenToCheck = expr->isDataset() ? getNumChildTables(expr) : expr->numChildren();
  16391. for (unsigned idx=0; idx < numChildrenToCheck; idx++)
  16392. {
  16393. if (needsRealThor(expr->queryChild(idx), flags))
  16394. return true;
  16395. }
  16396. return false;
  16397. }
  16398. bool needsRealThor(IHqlExpression *expr)
  16399. {
  16400. return needsRealThor(expr, 0);
  16401. }
  16402. IHqlExpression * HqlCppTranslator::getDefaultOutputAttr(IHqlExpression * expr)
  16403. {
  16404. return createAttribute(workunitAtom);
  16405. }
  16406. void HqlCppTranslator::modifyOutputLocations(HqlExprArray & exprs)
  16407. {
  16408. ForEachItemIn(idx, exprs)
  16409. {
  16410. IHqlExpression &expr = exprs.item(idx);
  16411. IHqlExpression * filename = queryRealChild(&expr, 1);
  16412. //Deduce whether OUTPUT(x) should goes to SDS or a disk
  16413. if (expr.getOperator()==no_output && !filename)
  16414. {
  16415. if (!expr.hasAttribute(workunitAtom) && !expr.hasAttribute(firstAtom) && !expr.hasAttribute(diskAtom))
  16416. {
  16417. IHqlExpression * attr = getDefaultOutputAttr(&expr);
  16418. HqlExprArray args;
  16419. expr.unwindList(args, no_output);
  16420. args.append(*attr);
  16421. IHqlExpression * transformed = expr.clone(args);
  16422. exprs.replace(*transformed, idx);
  16423. }
  16424. }
  16425. }
  16426. }
  16427. void HqlCppTranslator::pickBestEngine(HqlExprArray & exprs)
  16428. {
  16429. // At this point it is not too late to decide whether real thor is needed.
  16430. // Basically, we will use real thor if available, unless it matches a very minimal set of patterns:
  16431. // 1. output(holequery)
  16432. // 2. output(choosen(holequery))
  16433. // 3. output([filtered/projected/firstn] thordiskfile); (not sure about the filtered)
  16434. // These correspond closely to the things that can eventually get turned into lazy remote views
  16435. //It would be more sensible to do this much earlier.....or not at all.
  16436. if (targetThor())
  16437. {
  16438. ForEachItemIn(idx, exprs)
  16439. {
  16440. if (needsRealThor(&exprs.item(idx)))
  16441. return;
  16442. }
  16443. // if we got this far, thor not required
  16444. setTargetClusterType(HThorCluster);
  16445. DBGLOG("Thor query redirected to hthor instead");
  16446. }
  16447. }
  16448. void HqlCppTranslator::pickBestEngine(WorkflowArray & workflow)
  16449. {
  16450. if (targetThor())
  16451. {
  16452. ForEachItemIn(idx2, workflow)
  16453. {
  16454. HqlExprArray & exprs = workflow.item(idx2).queryExprs();
  16455. ForEachItemIn(idx, exprs)
  16456. {
  16457. if (needsRealThor(&exprs.item(idx)))
  16458. return;
  16459. }
  16460. // if we got this far, thor not required
  16461. }
  16462. setTargetClusterType(HThorCluster);
  16463. DBGLOG("Thor query redirected to hthor instead");
  16464. }
  16465. }
  16466. unsigned getVirtualFieldSize(IHqlExpression * record)
  16467. {
  16468. unsigned size = 0;
  16469. ForEachChild(idx, record)
  16470. {
  16471. IHqlExpression * cur = record->queryChild(idx);
  16472. switch (cur->getOperator())
  16473. {
  16474. case no_field:
  16475. {
  16476. ITypeInfo * type = cur->queryType();
  16477. if (type->isScalar())
  16478. {
  16479. if (cur->hasAttribute(virtualAtom))
  16480. size += type->getSize();
  16481. }
  16482. else
  16483. size += getVirtualFieldSize(cur->queryRecord());
  16484. break;
  16485. }
  16486. case no_ifblock:
  16487. size += getVirtualFieldSize(cur->queryChild(1));
  16488. break;
  16489. case no_record:
  16490. size += getVirtualFieldSize(cur);
  16491. break;
  16492. }
  16493. }
  16494. return size;
  16495. }
  16496. //---------------------------------------------------------------------------
  16497. /*
  16498. The following transforms are applied to the graphs before the code is generated:
  16499. o replaceStoredValues(exprs, foldStored);
  16500. - Replaces any #stored values in the graph. Done first so everything remains consistent.
  16501. o normalizeHqlTree(exprs);
  16502. - Converts expressions to their normal form. Main change is to remove default values from fields, so the graph can be
  16503. transformed without having to remap fields its value (e.g., dataset on a select) changes. Impossible to do anything without
  16504. this stage.
  16505. - Also converts x : global to global(x) and normalizes a few simple constructs e.g., trim,right->trim
  16506. o allocateSequenceNumbers(exprs);
  16507. - Adds sequence numbers to all outputs
  16508. o foldHqlExpression
  16509. - does a global constant fold to simplify the graph before it gets broken up at all.
  16510. o optimizeHqlExpression
  16511. - could globally optimize the graph, but not enabled at the moment. I'm not sure why, maybe because we still don't trust it enough...
  16512. o extractWorkflow(exprs)
  16513. - Converts a list of expressions into a list of workflow items. Once this is done each workflow item can be treated independently.
  16514. --- The following aim to work out where each part of the query will be executed, and gather all parts that will be executed in the same place
  16515. --- together so increase likely hood for cses and reduce connections to the query engines.
  16516. o migrateExprToNaturalLevel [NewScopeMigrateTransformer]
  16517. - Ensure expressions are evaluated at the best level - e.g., counts moved to most appropriate level.
  16518. * global(x) is extracted to a global set/get result pair.
  16519. - This includes datasets, and specifically ignores any conditional context
  16520. * SET(dataset, field) is converted to a workunit output, workunit read pair
  16521. !!Needs revisiting for child queries
  16522. * global count(), max() on global tables used inside an activity are always hoisted
  16523. !!regardless of whether they are conditional or not.
  16524. * local(x) and global() interactions are processed
  16525. !!Once aggregate sources are implemented, this may not be so useful, or even needed.
  16526. o markThorBoundaries
  16527. - work out which engine is going to perform which operation.
  16528. o normalizeResultFormat
  16529. * convert thor(scalar|row) into compound(setresult,getresult) or global setresult, local getresult
  16530. !!It should common up conditional expressions with non conditional
  16531. * IF(count(x)...) inside thor, hoist the count(x) so it is global
  16532. * IF(ds[n]...) inside thor, hoist it so it is global.
  16533. !!Conditionals should be handled differently I am sure...
  16534. o flattenDatasets(array);
  16535. - Currently does nothing. It should add projects to hole to ensure fields are available.
  16536. o mergeThorGraphs
  16537. - Make sure thor graphs are together as much as possible to save transfers to thor, and maximise the cse chances.
  16538. - Combine results of above. Should probably just be a single transformation.
  16539. o spotGlobalCSE
  16540. - Spot CSEs between different graphs. E.g., f(a), if(x, g(a), h(a)) Should ensure a is spilled.
  16541. !!Current problem is that global can create a implicit dependency which isn't spotted.
  16542. !!also doesn't handle commoning up scalars very well.
  16543. o removeTrivialGraphs
  16544. - don't implement setresult(getresult) in thor - a waste of time....
  16545. o convertLogicalToActivities
  16546. - change representation from logical to actual implementation. E.g., dedup(a, b) becomes group(dedup(group(a,b,all)))
  16547. */