hqlhtcpp.cpp 668 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jliball.hpp"
  14. #include "hql.hpp"
  15. #include "platform.h"
  16. #include "jlib.hpp"
  17. #include "jmisc.hpp"
  18. #include "jstream.ipp"
  19. #include "jdebug.hpp"
  20. #include "build-config.h"
  21. #include "hql.hpp"
  22. #include "hqlthql.hpp"
  23. #include "hqlmeta.hpp"
  24. #include "hqlutil.hpp"
  25. #include "hqlpmap.hpp"
  26. #include "hqlattr.hpp"
  27. #include "hqlerrors.hpp"
  28. #include "hqlvalid.hpp"
  29. #include "hqlerror.hpp"
  30. #include "hqlhtcpp.ipp"
  31. #include "hqlttcpp.ipp"
  32. #include "hqlwcpp.hpp"
  33. #include "hqlcpputil.hpp"
  34. #include "hqltcppc.ipp"
  35. #include "hqlopt.hpp"
  36. #include "hqlfold.hpp"
  37. #include "hqlcerrors.hpp"
  38. #include "hqlcatom.hpp"
  39. #include "hqllib.ipp"
  40. #include "hqlresource.hpp"
  41. #include "hqlregex.ipp"
  42. #include "hqlsource.ipp"
  43. #include "hqlcse.ipp"
  44. #include "hqlgraph.ipp"
  45. #include "hqlscope.hpp"
  46. #include "hqlccommon.hpp"
  47. #include "deffield.hpp"
  48. #include "hqlinline.hpp"
  49. #include "hqlusage.hpp"
  50. #include "hqlhoist.hpp"
  51. #include "hqlcppds.hpp"
  52. //The following are include to ensure they call compile...
  53. #include "eclhelper.hpp"
  54. #include "eclrtl_imp.hpp"
  55. #include "rtlfield_imp.hpp"
  56. #include "rtlds_imp.hpp"
  57. #include "eclhelper_base.hpp"
  58. #define MAX_ROWS_OUTPUT_TO_SDS 1000
  59. #define MAX_SAFE_RECORD_SIZE 10000000
  60. #define MAX_GRAPH_ECL_LENGTH 1000
  61. #define MAX_ROW_VALUE_TEXT_LEN 10
  62. //#define TRACE_META_TO_GRAPH
  63. //#define FLATTEN_DATASETS
  64. //#define TraceTableFields
  65. //#define TRACE_ASSIGN_MATCH
  66. //#define TRACE_DUMPTREE
  67. //#define _GATHER_USAGE_STATS
  68. //#define _SR6_
  69. #define MAX_CSV_RECORD_SIZE 4096
  70. #define ECLRTL_LIB "eclrtl"
  71. //===========================================================================
  72. #ifdef _GATHER_USAGE_STATS
  73. unsigned activityCounts[TAKlast][TAKlast];
  74. #endif
  75. MODULE_INIT(INIT_PRIORITY_STANDARD)
  76. {
  77. return true;
  78. }
  79. MODULE_EXIT()
  80. {
  81. dumpActivityCounts();
  82. }
  83. //===========================================================================
  84. static const char * TF[2] = {"false","true"};
  85. const char * boolToText(bool value) { return TF[value]; } // is this strictly legal?
  86. //---------------------------------------------------------------------------
  87. /*
  88. When should an activity be executed?
  89. 1. If it is used unconditionally.
  90. and
  91. 2. if
  92. a) It isn't a result of some kind.
  93. or
  94. b) It is an external result
  95. or
  96. b) It is an internal result that is used by something outside this graph.
  97. Any subgraph that contains unconditional activities should be marked with the <attr name="RootGraph" value="1"/>
  98. And activity that should not be executed unconditionally should have _internal set.
  99. */
  100. inline bool isInternalSeq(IHqlExpression * seq)
  101. {
  102. return !seq || matchesConstantValue(seq, ResultSequenceInternal);
  103. }
  104. static void markSubGraphAsRoot(IPropertyTree * tree)
  105. {
  106. if (!tree->hasProp("att[@name=\"rootGraph\"]"))
  107. addGraphAttributeBool(tree, "rootGraph", true);
  108. }
  109. SubGraphInfo * matchActiveGraph(BuildCtx & ctx, IHqlExpression * graphTag)
  110. {
  111. FilteredAssociationIterator iter(ctx, AssocSubGraph);
  112. ForEach(iter)
  113. {
  114. SubGraphInfo & cur = static_cast<SubGraphInfo &>(iter.get());
  115. if (graphTag == cur.graphTag)
  116. return &cur;
  117. }
  118. return NULL;
  119. }
  120. bool isActiveGraph(BuildCtx & ctx, IHqlExpression * graphTag)
  121. {
  122. return matchActiveGraph(ctx, graphTag) != NULL;
  123. }
  124. //---------------------------------------------------------------------------
  125. class InternalResultTracker : public CInterface
  126. {
  127. public:
  128. InternalResultTracker(IHqlExpression * _name, IPropertyTree * _subGraphTree, unsigned _graphSeq, ActivityInstance * _definingActivity)
  129. : name(_name), subGraphTree(_subGraphTree), graphSeq(_graphSeq), definingActivity(_definingActivity)
  130. {
  131. }
  132. bool noteUse(IHqlExpression * searchName, unsigned curGraphSeq);
  133. public:
  134. LinkedHqlExpr name;
  135. Linked<IPropertyTree> subGraphTree;
  136. unsigned graphSeq;
  137. Linked<ActivityInstance> definingActivity;
  138. };
  139. bool InternalResultTracker::noteUse(IHqlExpression * searchName, unsigned curGraphSeq)
  140. {
  141. if (searchName == name)
  142. {
  143. if ((graphSeq != curGraphSeq) && subGraphTree)
  144. {
  145. markSubGraphAsRoot(subGraphTree);
  146. definingActivity->setInternalSink(false);
  147. subGraphTree.clear();
  148. }
  149. return true;
  150. }
  151. return false;
  152. }
  153. //---------------------------------------------------------------------------
  154. IHqlExpression * getMetaUniqueKey(IHqlExpression * record, bool grouped)
  155. {
  156. if (record) record = record->queryBody();
  157. LinkedHqlExpr search = record;
  158. if (grouped)
  159. search.setown(createAttribute(groupedAtom, search.getClear()));
  160. if (!search)
  161. search.setown(createValue(no_null));
  162. return search.getClear();
  163. }
  164. IHqlExpression * getNullStringPointer(bool translated)
  165. {
  166. IHqlExpression * null = createValue(no_nullptr, LINK(constUnknownVarStringType));
  167. if (translated)
  168. return createTranslatedOwned(null);
  169. return null;
  170. }
  171. //---------------------------------------------------------------------------
  172. bool canIterateTableInline(IHqlExpression * expr)
  173. {
  174. switch (expr->getOperator())
  175. {
  176. case no_filter:
  177. return canIterateTableInline(expr->queryChild(0));
  178. case no_field:
  179. case no_select:
  180. return true;
  181. case no_newaggregate:
  182. {
  183. IHqlExpression * child = expr->queryChild(0);
  184. if (!isGrouped(child))
  185. return canIterateTableInline(child);
  186. return false;
  187. }
  188. default:
  189. return false;
  190. }
  191. }
  192. static IHqlExpression * createResultName(IHqlExpression * name)
  193. {
  194. if (!name)
  195. return createQuoted("0", makeReferenceModifier(makeVarStringType(UNKNOWN_LENGTH)));
  196. switch (name->getOperator())
  197. {
  198. case no_constant:
  199. return LINK(name);
  200. default:
  201. return LINK(name);
  202. UNIMPLEMENTED;
  203. break;
  204. }
  205. return NULL;
  206. }
  207. //---------------------------------------------------------------------------
  208. ColumnToOffsetMap * RecordOffsetMap::queryMapping(IHqlExpression * record, unsigned maxRecordSize)
  209. {
  210. ColumnToOffsetMap * match = find(record);
  211. if (!match)
  212. {
  213. match = new ColumnToOffsetMap(record, 1, maxRecordSize, false);
  214. match->init(*this);
  215. addOwn(*match);
  216. }
  217. return match;
  218. }
  219. //---------------------------------------------------------------------------
  220. MemberFunction::MemberFunction(HqlCppTranslator & _translator, BuildCtx & classctx, const char * text, unsigned _flags) : translator(_translator), ctx(classctx)
  221. {
  222. ctx.addQuotedCompound(text);
  223. translator.pushMemberFunction(*this);
  224. flags = _flags;
  225. }
  226. MemberFunction::MemberFunction(HqlCppTranslator & _translator, BuildCtx & classctx, StringBuffer & text, unsigned _flags) : translator(_translator), ctx(classctx)
  227. {
  228. ctx.addQuotedCompound(text);
  229. translator.pushMemberFunction(*this);
  230. flags = _flags;
  231. }
  232. MemberFunction::~MemberFunction()
  233. {
  234. translator.popMemberFunction();
  235. }
  236. //---------------------------------------------------------------------------
  237. static HqlTransformerInfo childDatasetSpotterInfo("ChildDatasetSpotter");
  238. class NewChildDatasetSpotter : public ConditionalContextTransformer
  239. {
  240. public:
  241. NewChildDatasetSpotter(HqlCppTranslator & _translator, BuildCtx & _ctx, bool _forceRoot)
  242. : ConditionalContextTransformer(childDatasetSpotterInfo, true), translator(_translator), ctx(_ctx), forceRoot(_forceRoot)
  243. {
  244. //The following line forces the conditionalContextTransformer code to generate a single root subgraph.
  245. //An alternative would be to generate one (or more) graphs at the first unconditional place they are
  246. //used. e.g., adding a no_compound(no_childquery, f(no_getgraphresult)) into the tree.
  247. //This was the initial approach, but it causes problems for subsequent optimizations -
  248. //if an optimzation causes an expression containing the no_getgraphresult to be hoisted so it is
  249. //evaluated before the no_childquery it creates an out-of-order dependency.
  250. createRootGraph = true;
  251. }
  252. virtual void analyseExpr(IHqlExpression * expr)
  253. {
  254. switch (pass)
  255. {
  256. case PassFindCandidates:
  257. if (!alreadyVisited(expr->queryBody()))
  258. markHoistPoints(expr);
  259. break;
  260. default:
  261. ConditionalContextTransformer::analyseExpr(expr);
  262. break;
  263. }
  264. }
  265. //MORE: This is a bit of a hack, and should be improved (share code with resource child hoist?)
  266. inline bool walkFurtherDownTree(IHqlExpression * expr)
  267. {
  268. //There are operators which can occur down the tree which may contain datasets
  269. //This should match the analyse code above
  270. switch (expr->getOperator())
  271. {
  272. case no_createrow:
  273. case no_inlinetable:
  274. //The expressions in the transform may contain datasets
  275. case no_addfiles:
  276. case no_datasetfromrow:
  277. case no_datasetfromdictionary:
  278. case no_alias_scope:
  279. //child datasets may have something worth creating a graph for
  280. case no_if:
  281. //The condition may be worth hoisting (and some of the inputs)
  282. return true;
  283. }
  284. return false;
  285. }
  286. void markHoistPoints(IHqlExpression * expr)
  287. {
  288. node_operator op = expr->getOperator();
  289. if (expr->isDataset() || (expr->isDatarow() && (op != no_select)))
  290. {
  291. if (!translator.canAssignInline(&ctx, expr))
  292. {
  293. noteCandidate(expr);
  294. return;
  295. }
  296. if (!walkFurtherDownTree(expr))
  297. return;
  298. }
  299. doAnalyseExpr(expr);
  300. }
  301. IHqlExpression * createTransformed(IHqlExpression * expr)
  302. {
  303. IHqlExpression * body = expr->queryBody(true);
  304. if (expr != body)
  305. return createTransformedAnnotation(expr);
  306. ConditionalContextInfo * extra = queryBodyExtra(expr);
  307. //The following must preceed transforming the children
  308. OwnedHqlExpr subgraph = createDefinitions(extra);
  309. OwnedHqlExpr transformed = ConditionalContextTransformer::createTransformed(expr);
  310. updateOrphanedSelectors(transformed, expr);
  311. assertex(!extra->moveTo);
  312. if (subgraph)
  313. return createCompound(subgraph.getClear(), transformed.getClear());
  314. return transformed.getClear();
  315. }
  316. virtual void transformCandidate(ConditionalContextInfo * candidate)
  317. {
  318. while (builders.ordinality() < insertLocations.ordinality())
  319. builders.append(* new ChildGraphExprBuilder(0));
  320. IHqlExpression * expr = candidate->original;
  321. ConditionalContextInfo * moveTo = candidate->moveTo;
  322. OwnedHqlExpr guard;
  323. if (moveTo)
  324. {
  325. guard.setown(getGuardCondition(moveTo, expr));
  326. //Expressions which are very simple functions of unconditional expressions are treated as if they
  327. //are unconditional
  328. if (moveTo->isUnconditional() && isUsedUnconditionallyEnough(expr))
  329. guard.set(queryBoolExpr(true));
  330. bool invalid = !guard->isPure();
  331. //version 1: don't guard any child queries.
  332. if (!matchesBoolean(guard, true))
  333. {
  334. assertex(moveTo->guards);
  335. //MORE: For the moment disable any expressions that are only used conditionally.
  336. //Often including conditions improves the code, but sometimes the duplicate evaluation of the
  337. //guard conditions in the parent and the child causes excessive code generation.
  338. //And forcing it into an alias doesn't help becuase that isn't currently executed in the parent.
  339. //Uncomment: if (moveTo->guards->guardContainsCandidate(expr))
  340. {
  341. invalid = true;
  342. }
  343. }
  344. if (invalid)
  345. {
  346. removeDefinition(moveTo, candidate);
  347. moveTo = NULL;
  348. }
  349. }
  350. //A candidate inside a condition that prevents it being moved just creates a definition where it is.
  351. if (!moveTo)
  352. return;
  353. ChildGraphExprBuilder & builder = queryBuilder(moveTo);
  354. IHqlExpression * annotated = candidate->firstAnnotatedExpr ? candidate->firstAnnotatedExpr : expr;
  355. OwnedHqlExpr guarded = createGuardedDefinition(moveTo, annotated, guard);
  356. OwnedHqlExpr transformed = builder.addDataset(guarded);
  357. if (moveTo == candidate)
  358. {
  359. OwnedHqlExpr subgraph = createDefinitions(moveTo);
  360. transformed.setown(createCompound(subgraph.getClear(), transformed.getClear()));
  361. }
  362. setTransformed(expr, transformed);
  363. }
  364. virtual IHqlExpression * createDefinitions(ConditionalContextInfo * extra)
  365. {
  366. if (!extra->hasDefinitions())
  367. return NULL;
  368. ChildGraphExprBuilder & builder = queryBuilder(extra);
  369. OwnedHqlExpr graph = builder.getGraph();
  370. OwnedHqlExpr cleanedGraph = mapExternalToInternalResults(graph, builder.queryRepresents());
  371. return cleanedGraph.getClear();
  372. }
  373. ChildGraphExprBuilder & queryBuilder(ConditionalContextInfo * extra)
  374. {
  375. unsigned match = insertLocations.find(*extra);
  376. assertex(match != NotFound);
  377. return builders.item(match);
  378. }
  379. inline bool isUsedUnconditionallyEnough(IHqlExpression * expr)
  380. {
  381. IHqlExpression * search = expr;
  382. loop
  383. {
  384. if (isUsedUnconditionally(search))
  385. return true;
  386. switch (search->getOperator())
  387. {
  388. case no_selectnth:
  389. case no_newaggregate:
  390. case no_filter:
  391. break;
  392. case no_select:
  393. if (isNewSelector(search))
  394. break;
  395. return false;
  396. default:
  397. return false;
  398. }
  399. search = search->queryChild(0);
  400. }
  401. }
  402. protected:
  403. CIArrayOf<ChildGraphExprBuilder> builders;
  404. HqlCppTranslator & translator;
  405. BuildCtx & ctx;
  406. bool forceRoot;
  407. };
  408. class StatementCollection : public HqlExprArray
  409. {
  410. public:
  411. //Combine multiple conditional assigns, where the guard condition is the same.
  412. //Combine either IF() or CHOOSE()
  413. void combineConditions()
  414. {
  415. unsigned max = ordinality();
  416. for (unsigned first=0; first+1 < max; first++)
  417. {
  418. IHqlExpression & cur = item(first);
  419. if (cur.getOperator() == no_assign)
  420. {
  421. IHqlExpression * rhs = cur.queryChild(1);
  422. if (isCast(rhs))
  423. rhs = rhs->queryChild(0);
  424. node_operator firstOp = rhs->getOperator();
  425. unsigned numFirstChildren = rhs->numChildren();
  426. //Don't combine choose() operators with large numbers of constant values since an array lookup is probably more efficient.
  427. if ((firstOp == no_if) ||
  428. ((firstOp == no_choose) && (numFirstChildren <= 3 || !allBranchesAreConstant(rhs))))
  429. {
  430. IHqlExpression * cond = rhs->queryChild(0);
  431. unsigned next = first+1;
  432. while (next != max)
  433. {
  434. IHqlExpression & nextAssign = item(next);
  435. if (nextAssign.getOperator() != no_assign)
  436. break;
  437. IHqlExpression * nextRhs = nextAssign.queryChild(1);
  438. if (isCast(nextRhs))
  439. nextRhs = nextRhs->queryChild(0);
  440. if (nextRhs->getOperator() != firstOp)
  441. break;
  442. if (nextRhs->queryChild(0) != cond)
  443. break;
  444. if (nextRhs->numChildren() != numFirstChildren)
  445. break;
  446. next++;
  447. }
  448. if (next != first+1)
  449. {
  450. OwnedHqlExpr combined = combineConditionRange(first, next);
  451. replace(*combined.getClear(), first);
  452. unsigned num = (next - first - 1);
  453. removen(first+1, num);
  454. max -= num;
  455. }
  456. }
  457. //MORE: Combine no_case and no_map - but need to be careful,
  458. //because they don't currently have an implementation for actions, so either need to implement, or convert
  459. //to ifs, but also need to be careful we don't make the implementation worse!
  460. }
  461. }
  462. }
  463. void replaceAssignment(IHqlExpression & search, IHqlExpression & newAssign)
  464. {
  465. unsigned match = find(search);
  466. replace(OLINK(newAssign), match);
  467. }
  468. bool onlyOccursOnce(IHqlExpression * expr)
  469. {
  470. return (getNumOccurences(*this, expr, 2) == 1);
  471. }
  472. protected:
  473. bool allBranchesAreConstant(IHqlExpression * expr)
  474. {
  475. ForEachChildFrom(i, expr, 1)
  476. {
  477. IHqlExpression * cur = expr->queryChild(i);
  478. if (!cur->queryValue())
  479. return false;
  480. }
  481. return true;
  482. }
  483. IHqlExpression * extractBranches(unsigned from, unsigned to, unsigned child)
  484. {
  485. StatementCollection assigns;
  486. for (unsigned i=from; i < to; i++)
  487. {
  488. IHqlExpression & cur = item(i);
  489. IHqlExpression * lhs = cur.queryChild(0);
  490. IHqlExpression * rhs = cur.queryChild(1);
  491. OwnedHqlExpr newRhs;
  492. if (isCast(rhs))
  493. {
  494. IHqlExpression * branch = rhs->queryChild(0)->queryChild(child);
  495. newRhs.setown(ensureExprType(branch, rhs->queryType()));
  496. }
  497. else
  498. newRhs.set(rhs->queryChild(child));
  499. assigns.append(*createAssign(LINK(lhs), LINK(newRhs)));
  500. }
  501. assigns.combineConditions();
  502. return createActionList(assigns);
  503. }
  504. IHqlExpression * combineConditionRange(unsigned from, unsigned to)
  505. {
  506. IHqlExpression * firstRhs = item(from).queryChild(1);
  507. IHqlExpression * conditionExpr = isCast(firstRhs) ? firstRhs->queryChild(0) : firstRhs;
  508. HqlExprArray args;
  509. args.append(*LINK(conditionExpr->queryChild(0)));
  510. ForEachChildFrom(i, conditionExpr, 1)
  511. args.append(*extractBranches(from, to, i));
  512. return createValue(conditionExpr->getOperator(), makeVoidType(), args);
  513. }
  514. };
  515. class DelayedStatementExecutor
  516. {
  517. public:
  518. DelayedStatementExecutor(HqlCppTranslator & _translator, BuildCtx & _ctx)
  519. : translator(_translator), buildctx(_ctx)
  520. {
  521. processed = false;
  522. }
  523. void processAssign(BuildCtx & ctx, IHqlExpression * stmt)
  524. {
  525. pending.append(*LINK(stmt));
  526. }
  527. void processAlias(BuildCtx & ctx, IHqlExpression * stmt)
  528. {
  529. pending.append(*LINK(stmt));
  530. }
  531. void processStmts(IHqlExpression * expr)
  532. {
  533. expr->unwindList(pending, no_actionlist);
  534. }
  535. void clear()
  536. {
  537. pending.kill();
  538. processed = false;
  539. }
  540. IHqlExpression * getPrefetchGraph()
  541. {
  542. spotChildDatasets(true);
  543. if (pending.ordinality() == 0)
  544. return NULL;
  545. IHqlExpression & subquery = pending.item(0);
  546. if (subquery.getOperator() == no_childquery)
  547. {
  548. pending.remove(0, true);
  549. return &subquery;
  550. }
  551. return NULL;
  552. }
  553. void flush(BuildCtx & ctx)
  554. {
  555. spotChildDatasets(false);
  556. combineConditions();
  557. optimizeAssigns();
  558. ForEachItemIn(i, pending)
  559. translator.buildStmt(ctx, &pending.item(i));
  560. pending.kill();
  561. }
  562. void optimize()
  563. {
  564. spotChildDatasets(false);
  565. combineConditions();
  566. optimizeAssigns();
  567. }
  568. IHqlExpression * getActionList()
  569. {
  570. OwnedHqlExpr ret = createActionList(pending);
  571. pending.kill();
  572. return ret.getClear();
  573. }
  574. protected:
  575. //Combine multiple conditional assigns, where the guard condition is the same.
  576. void combineConditions()
  577. {
  578. pending.combineConditions();
  579. }
  580. void spotChildDatasets(bool forceRoot)
  581. {
  582. if (!processed && translator.queryCommonUpChildGraphs())
  583. {
  584. HqlExprArray analyseExprs;
  585. ForEachItemIn(i, pending)
  586. {
  587. IHqlExpression & cur = pending.item(i);
  588. IHqlExpression * value = &cur;
  589. switch (value->getOperator())
  590. {
  591. case no_assign:
  592. value = value->queryChild(1);
  593. break;
  594. case no_alias:
  595. case no_skip:
  596. value = value->queryChild(0);
  597. break;
  598. }
  599. if (value)
  600. analyseExprs.append(*LINK(value));
  601. }
  602. NewChildDatasetSpotter spotter(translator, buildctx, forceRoot);
  603. if (spotter.analyseNeedsTransform(analyseExprs))
  604. {
  605. //This could be conditional on whether or not there is an unconditional candidate, but that would stop
  606. //the same expression being commoned up between two conditional branches.
  607. //So, only avoid if 1 conditional candidate used in a single location.
  608. bool worthHoisting = true;
  609. if (!forceRoot)
  610. {
  611. if (spotter.hasSingleConditionalCandidate())
  612. worthHoisting = false;
  613. }
  614. if (worthHoisting)
  615. {
  616. //MORE: Remove || true to evaluate the subquery at the latest time.
  617. bool createSubQueryBeforeAll = forceRoot || true;
  618. spotter.transformAll(pending, createSubQueryBeforeAll);
  619. translator.traceExpressions("spotted child", pending);
  620. }
  621. }
  622. processed = true;
  623. }
  624. }
  625. virtual void optimizeAssigns() {}
  626. protected:
  627. HqlCppTranslator & translator;
  628. BuildCtx buildctx;
  629. StatementCollection pending;
  630. bool processed;
  631. };
  632. void HqlCppTranslator::optimizeBuildActionList(BuildCtx & ctx, IHqlExpression * exprs)
  633. {
  634. if ((exprs->getOperator() != no_actionlist) || !activeGraph)
  635. {
  636. buildStmt(ctx, exprs);
  637. return;
  638. }
  639. DelayedStatementExecutor delayed(*this, ctx);
  640. delayed.processStmts(exprs);
  641. delayed.flush(ctx);
  642. }
  643. //---------------------------------------------------------------------------
  644. static IHqlExpression * getExtractMatchingAssign(HqlExprArray & assigns, IHqlExpression * search, unsigned & expectedIndex, IHqlExpression * selfSelector)
  645. {
  646. if (assigns.isItem(expectedIndex))
  647. {
  648. IHqlExpression & candidate = assigns.item(expectedIndex);
  649. IHqlExpression * lhs = candidate.queryChild(0);
  650. IHqlExpression * candidateField = lhs->queryChild(1);
  651. if (candidateField == search)
  652. {
  653. OwnedHqlExpr ret;
  654. if (lhs->queryChild(0) == selfSelector)
  655. ret.set(&candidate);
  656. else
  657. {
  658. IHqlExpression * rhs = candidate.queryChild(1);
  659. ret.setown(createAssign(createSelectExpr(LINK(selfSelector), LINK(candidateField)), LINK(rhs)));
  660. }
  661. expectedIndex++;
  662. return ret.getClear();
  663. }
  664. }
  665. ForEachItemIn(idx, assigns)
  666. {
  667. IHqlExpression & assign = assigns.item(idx);
  668. #ifdef TRACE_ASSIGN_MATCH
  669. PrintLog("Next comparison:");
  670. x.clear().append("target(").append((unsigned)assign.queryChild(0)->queryChild(0)).append(":");
  671. x.appendf("%p", assign.queryChild(0)->queryChild(1)).append(") ");
  672. assign.queryChild(0)->toString(x);
  673. PrintLog(x.str());
  674. x.clear().append("search(").appendf("%p", search).append(") ");
  675. search->toString(x);
  676. PrintLog(x.str());
  677. #endif
  678. IHqlExpression * lhs = assign.queryChild(0);
  679. IHqlExpression * candidateField = lhs->queryChild(1);
  680. if (candidateField == search)
  681. {
  682. OwnedHqlExpr ret;
  683. if (lhs->queryChild(0) == selfSelector)
  684. ret.set(&assign);
  685. else
  686. {
  687. IHqlExpression * rhs = assign.queryChild(1);
  688. ret.setown(createAssign(createSelectExpr(LINK(selfSelector), LINK(candidateField)), LINK(rhs)));
  689. }
  690. expectedIndex = idx+1;
  691. return ret.getClear();
  692. }
  693. }
  694. return NULL;
  695. }
  696. class TransformBuilder : public DelayedStatementExecutor
  697. {
  698. public:
  699. TransformBuilder(HqlCppTranslator & _translator, BuildCtx & _ctx, IHqlExpression * _record, BoundRow * _self, HqlExprArray & _assigns) :
  700. DelayedStatementExecutor(_translator, _ctx), assigns(_assigns), record(_record), self(_self)
  701. {
  702. expectedIndex = 0;
  703. if (translator.recordContainsIfBlock(record))
  704. mapper.setown(new NestedHqlMapTransformer);
  705. }
  706. TransformBuilder(const TransformBuilder & other, BuildCtx & _ctx) :
  707. DelayedStatementExecutor(other.translator, _ctx), mapper(other.mapper), assigns(other.assigns)
  708. {
  709. expectedIndex = 0;
  710. }
  711. void doTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self);
  712. void buildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector);
  713. protected:
  714. virtual void checkAssigned() { }
  715. virtual void onIfBlock(IHqlExpression * expr) { }
  716. virtual void onMissingAssignment(IHqlExpression * expr)
  717. {
  718. StringBuffer s;
  719. expr->toString(s);
  720. throwError2(HQLERR_MissingTransformAssignXX, s.str(), expr);
  721. }
  722. void pushCondition(IHqlExpression * cond)
  723. {
  724. mapper->beginNestedScope();
  725. }
  726. void popCondition()
  727. {
  728. mapper->endNestedScope();
  729. }
  730. void buildTransform(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * parentSelector);
  731. void doBuildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector);
  732. public:
  733. Linked<NestedHqlMapTransformer> mapper;
  734. HqlExprArray & assigns;
  735. LinkedHqlExpr record;
  736. BoundRow * self;
  737. unsigned expectedIndex;
  738. };
  739. void TransformBuilder::buildTransform(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * parentSelector)
  740. {
  741. switch (expr->getOperator())
  742. {
  743. case no_ifblock:
  744. {
  745. onIfBlock(expr);
  746. flush(ctx);
  747. assertex(mapper != NULL);
  748. OwnedHqlExpr test = replaceSelector(expr->queryChild(0), querySelfReference(), parentSelector);
  749. OwnedHqlExpr foldedTest = mapper->transformRoot(test);
  750. foldedTest.setown(foldHqlExpression(foldedTest)); // can only contain references to self, so don't need to worry about other datasets in scope being messed up.
  751. OwnedHqlExpr sizeOfIfBlock = createValue(no_sizeof, makeIntType(4,false), createSelectExpr(LINK(parentSelector), LINK(expr)));
  752. IValue * mappedValue = foldedTest->queryValue();
  753. BuildCtx subctx(ctx);
  754. bool include = true;
  755. if (mappedValue)
  756. {
  757. //Associate the ifblock condition to avoid it being evaluated later when calculating the field offsets
  758. ctx.associateExpr(test, foldedTest);
  759. if (!mappedValue->getBoolValue())
  760. include = false;
  761. }
  762. else
  763. pushCondition(foldedTest);
  764. if (include)
  765. {
  766. translator.buildFilter(subctx, foldedTest);
  767. TransformBuilder childBuilder(*this, subctx);
  768. childBuilder.buildTransformChildren(subctx, expr->queryChild(1), parentSelector);
  769. childBuilder.flush(subctx);
  770. //This calculates the size of the previous block. It means that subsequent uses of the
  771. //offsets are cached - even if they are inside another ifblock().
  772. CHqlBoundExpr bound;
  773. translator.buildCachedExpr(ctx, sizeOfIfBlock, bound);
  774. }
  775. else
  776. {
  777. //This calculates the size of the previous block. It means that subsequent uses of the
  778. //offsets are cached - even if they are inside another ifblock().
  779. OwnedHqlExpr zero = getSizetConstant(0);
  780. ctx.associateExpr(sizeOfIfBlock, zero);
  781. }
  782. if (!mappedValue)
  783. popCondition();
  784. }
  785. break;
  786. case no_record:
  787. doBuildTransformChildren(ctx, expr, parentSelector);
  788. break;
  789. case no_field:
  790. {
  791. OwnedHqlExpr match = getExtractMatchingAssign(assigns, expr, expectedIndex, parentSelector);
  792. if (match)
  793. {
  794. processAssign(ctx, match);
  795. if (mapper && (match->getOperator() == no_assign))
  796. {
  797. IHqlExpression * rhs = match->queryChild(1);
  798. if (rhs->queryValue())
  799. {
  800. IHqlExpression * lhs = match->queryChild(0);
  801. OwnedHqlExpr cast = ensureExprType(rhs, lhs->queryType());
  802. mapper->setMapping(lhs, cast);
  803. }
  804. }
  805. return;
  806. }
  807. onMissingAssignment(expr);
  808. }
  809. break;
  810. case no_attr:
  811. case no_attr_expr:
  812. case no_attr_link:
  813. break;
  814. default:
  815. UNIMPLEMENTED;
  816. }
  817. }
  818. void TransformBuilder::doBuildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector)
  819. {
  820. ForEachChild(idx, record)
  821. buildTransform(ctx, record->queryChild(idx), parentSelector);
  822. }
  823. void TransformBuilder::buildTransformChildren(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * parentSelector)
  824. {
  825. assertex(parentSelector);
  826. expectedIndex = 0;
  827. doBuildTransformChildren(ctx, record, parentSelector);
  828. }
  829. void TransformBuilder::doTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self)
  830. {
  831. IHqlExpression * body = transform->queryBody(true);
  832. if (transform != body)
  833. {
  834. switch (transform->getAnnotationKind())
  835. {
  836. case annotate_meta:
  837. translator.queryWarningProcessor().processMetaAnnotation(transform);
  838. break;
  839. case annotate_symbol:
  840. {
  841. WarningProcessor::OnWarningStateSymbolBlock saved(translator.queryWarningProcessor(), transform);
  842. doTransform(ctx, body, self);
  843. return;
  844. }
  845. }
  846. doTransform(ctx, body, self);
  847. return;
  848. }
  849. if (!isKnownTransform(transform))
  850. {
  851. translator.doUserTransform(ctx, transform, self);
  852. return;
  853. }
  854. translator.filterExpandAssignments(ctx, this, assigns, transform);
  855. IHqlExpression * selfRecord = self->queryRecord();
  856. buildTransformChildren(ctx, selfRecord, self->querySelector());
  857. flush(ctx);
  858. checkAssigned();
  859. //If this is a blank record with the size "fixed" to 1, clear the byte so consistent and disk writes compress well
  860. if (isEmptyRecord(selfRecord) && selfRecord->hasAttribute(_nonEmpty_Atom))
  861. translator.buildClearRecord(ctx, self->querySelector(), selfRecord, 0);
  862. }
  863. class UpdateTransformBuilder : public TransformBuilder
  864. {
  865. friend class UnsafeSelectorReplacer;
  866. public:
  867. UpdateTransformBuilder(HqlCppTranslator & _translator, BuildCtx & _ctx, IHqlExpression * record, BoundRow * _self, IHqlExpression * _prevSelector, HqlExprArray & _assigns, bool _canRemoveLeadingAssigns) :
  868. TransformBuilder(_translator, _ctx, record, _self, _assigns), prevSelector(_prevSelector)
  869. {
  870. aliasInsertPos = 0;
  871. needToReassignAll = false;
  872. canRemoveLeadingAssigns = _canRemoveLeadingAssigns;
  873. }
  874. void ensureAlias(IHqlExpression * expr);
  875. inline bool isUnsafeSelector(IHqlExpression * expr) const
  876. {
  877. return needToReassignAll || unsafeSelectors.contains(*expr);
  878. }
  879. protected:
  880. virtual void checkAssigned() { }
  881. virtual void onIfBlock(IHqlExpression * expr) { throwUnexpected(); }
  882. virtual void onMissingAssignment(IHqlExpression * expr) {}
  883. virtual void optimizeAssigns();
  884. bool isSpecialAssignment(IHqlExpression * assign, node_operator op, IHqlExpression * previous) const;
  885. void optimizeAssigns(IHqlExpression * expr, IHqlExpression * parentSelector);
  886. void optimizeRecordAssigns(IHqlExpression * record, IHqlExpression * parentSelector);
  887. IHqlExpression * replaceUnsafeSelectors(IHqlExpression * rhs);
  888. void optimizeSpecialAssignments(IHqlExpression * expr, IHqlExpression * parentSelector);
  889. void optimizeRecordSpecialAssignments(IHqlExpression * expr, IHqlExpression * parentSelector);
  890. void protectAgainstLeaks(IHqlExpression * expr);
  891. void protectRecordAgainstLeaks(IHqlExpression * expr);
  892. protected:
  893. LinkedHqlExpr prevSelector;
  894. HqlExprArray unsafeSelectors;
  895. HqlExprArray preservedSelectors;
  896. unsigned aliasInsertPos;
  897. bool needToReassignAll;
  898. bool canRemoveLeadingAssigns;
  899. };
  900. void UpdateTransformBuilder::ensureAlias(IHqlExpression * expr)
  901. {
  902. if (!pending.contains(*expr))
  903. pending.add(*LINK(expr), aliasInsertPos++);
  904. }
  905. bool UpdateTransformBuilder::isSpecialAssignment(IHqlExpression * assign, node_operator op, IHqlExpression * previous) const
  906. {
  907. IHqlExpression * rhs = assign->queryChild(1);
  908. if (rhs->getOperator() != op)
  909. return false;
  910. if (rhs->queryChild(0) != previous)
  911. return false;
  912. return true;
  913. }
  914. void UpdateTransformBuilder::optimizeSpecialAssignments(IHqlExpression * expr, IHqlExpression * parentSelector)
  915. {
  916. switch (expr->getOperator())
  917. {
  918. case no_record:
  919. optimizeRecordSpecialAssignments(expr, parentSelector);
  920. break;
  921. case no_field:
  922. {
  923. //check for SELF.x := RIGHT.x <add-file> f(LEFT)
  924. node_operator newOp = no_none;
  925. OwnedHqlExpr previous = createSelectExpr(LINK(prevSelector), LINK(expr));
  926. OwnedHqlExpr match;
  927. if (expr->isDataset())
  928. {
  929. match.setown(getExtractMatchingAssign(pending, expr, expectedIndex, parentSelector));
  930. if (match && isSpecialAssignment(match, no_addfiles, previous))
  931. newOp = no_assign_addfiles;
  932. }
  933. if (newOp && pending.onlyOccursOnce(previous))
  934. {
  935. IHqlExpression * rhs = match->queryChild(1);
  936. OwnedHqlExpr newAssign = createValue(newOp, makeVoidType(), LINK(match->queryChild(0)), LINK(rhs->queryChild(1)));
  937. pending.replaceAssignment(*match, *newAssign);
  938. preservedSelectors.append(*LINK(previous));
  939. }
  940. }
  941. break;
  942. }
  943. }
  944. void UpdateTransformBuilder::optimizeRecordSpecialAssignments(IHqlExpression * record, IHqlExpression * parentSelector)
  945. {
  946. ForEachChild(idx, record)
  947. optimizeSpecialAssignments(record->queryChild(idx), parentSelector);
  948. }
  949. //Ensure all fields from SELF are cloned before they are overwritten.
  950. //If only fixed width fields have been updated so far then any fields not yet assigned can be used
  951. //If a variable width field has been updated all fields updated so far are invalid, and all field that
  952. //follow may have been overwritten => it will need an alias. For simplicity all fields are assumed tainted.
  953. void UpdateTransformBuilder::optimizeAssigns(IHqlExpression * expr, IHqlExpression * parentSelector)
  954. {
  955. switch (expr->getOperator())
  956. {
  957. case no_ifblock:
  958. throwUnexpected();
  959. case no_record:
  960. optimizeRecordAssigns(expr, parentSelector);
  961. break;
  962. case no_field:
  963. {
  964. OwnedHqlExpr match = getExtractMatchingAssign(pending, expr, expectedIndex, parentSelector);
  965. if (match)
  966. {
  967. IHqlExpression * source = match->queryChild(1);
  968. OwnedHqlExpr previous = createSelectExpr(LINK(prevSelector), LINK(expr));
  969. bool usesPrevious = (source != previous) && exprReferencesDataset(source, prevSelector);
  970. bool retainAssign = !canRemoveLeadingAssigns || needToReassignAll || usesPrevious || (match->getOperator() != no_assign) || isGraphDependent(source);
  971. if (retainAssign)
  972. {
  973. IHqlExpression * target = match->queryChild(0);
  974. //Variable offset => all subsequent fields need to be reassigned.
  975. ITypeInfo * type = expr->queryType();
  976. bool hasVariableSize = (type->getSize() == UNKNOWN_LENGTH);
  977. //Potential problems with fixed length strings. Otherwise it should be safe, or go via a temporary
  978. bool safeToAccessSelf = hasVariableSize || !isTypePassedByAddress(type); // not true for some fixed length strings, what else?
  979. //Any access to this field now needs to go via a temporary
  980. if (!safeToAccessSelf)
  981. unsafeSelectors.append(*LINK(previous));
  982. OwnedHqlExpr safeRhs = replaceUnsafeSelectors(source);
  983. if (safeToAccessSelf)
  984. unsafeSelectors.append(*LINK(previous));
  985. if (hasVariableSize)
  986. needToReassignAll = true;
  987. if (safeRhs != source)
  988. {
  989. //MORE: Create no_plusequals, no_concat_equals
  990. OwnedHqlExpr newAssign = createAssign(LINK(target), LINK(safeRhs));
  991. unsigned pos = pending.find(*match);
  992. assertex(pos != NotFound);
  993. pending.replace(*newAssign.getClear(), pos);
  994. }
  995. }
  996. else
  997. {
  998. preservedSelectors.append(*LINK(previous));
  999. pending.zap(*match);
  1000. }
  1001. return;
  1002. }
  1003. }
  1004. break;
  1005. case no_attr:
  1006. case no_attr_expr:
  1007. case no_attr_link:
  1008. break;
  1009. default:
  1010. UNIMPLEMENTED;
  1011. }
  1012. }
  1013. void UpdateTransformBuilder::optimizeRecordAssigns(IHqlExpression * record, IHqlExpression * parentSelector)
  1014. {
  1015. ForEachChild(idx, record)
  1016. optimizeAssigns(record->queryChild(idx), parentSelector);
  1017. }
  1018. void UpdateTransformBuilder::protectAgainstLeaks(IHqlExpression * expr)
  1019. {
  1020. switch (expr->getOperator())
  1021. {
  1022. case no_record:
  1023. protectRecordAgainstLeaks(expr);
  1024. break;
  1025. case no_field:
  1026. {
  1027. if (hasLinkCountedModifier(expr))
  1028. {
  1029. OwnedHqlExpr previous = createSelectExpr(LINK(prevSelector), LINK(expr));
  1030. if (!preservedSelectors.contains(*previous))
  1031. {
  1032. OwnedHqlExpr owned = createAliasOwn(ensureOwned(previous), NULL);
  1033. ensureAlias(owned);
  1034. }
  1035. }
  1036. }
  1037. break;
  1038. }
  1039. }
  1040. void UpdateTransformBuilder::protectRecordAgainstLeaks(IHqlExpression * record)
  1041. {
  1042. ForEachChild(idx, record)
  1043. protectAgainstLeaks(record->queryChild(idx));
  1044. }
  1045. void UpdateTransformBuilder::optimizeAssigns()
  1046. {
  1047. expectedIndex = 0;
  1048. optimizeRecordSpecialAssignments(record, self->querySelector());
  1049. expectedIndex = 0;
  1050. optimizeRecordAssigns(record, self->querySelector());
  1051. protectRecordAgainstLeaks(record);
  1052. }
  1053. static HqlTransformerInfo unsafeSelectorReplacerInfo("UnsafeSelectorReplacer");
  1054. class UnsafeSelectorReplacer : public NewHqlTransformer
  1055. {
  1056. public:
  1057. UnsafeSelectorReplacer(UpdateTransformBuilder & _builder, IHqlExpression * _searchSelector)
  1058. : NewHqlTransformer(unsafeSelectorReplacerInfo), builder(_builder), searchSelector(_searchSelector)
  1059. {
  1060. }
  1061. inline IHqlExpression * getReplacement(IHqlExpression * expr)
  1062. {
  1063. //Yuk if the whole row is referenced the code is not going to be good!
  1064. if (expr == searchSelector)
  1065. return ensureAliased(expr);
  1066. if ((expr->getOperator() == no_select) && (expr->queryChild(0) == searchSelector))
  1067. {
  1068. if (builder.isUnsafeSelector(expr))
  1069. return ensureAliased(expr);
  1070. return LINK(expr);
  1071. }
  1072. return NULL;
  1073. }
  1074. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  1075. {
  1076. IHqlExpression * body = expr->queryBody(true);
  1077. if (expr == body)
  1078. {
  1079. IHqlExpression * replacement = getReplacement(expr);
  1080. if (replacement)
  1081. return replacement;
  1082. return NewHqlTransformer::createTransformed(expr);
  1083. }
  1084. OwnedHqlExpr transformed = transform(body);
  1085. return expr->cloneAnnotation(transformed);
  1086. }
  1087. virtual IHqlExpression * createTransformedSelector(IHqlExpression * expr)
  1088. {
  1089. IHqlExpression * replacement = getReplacement(expr);
  1090. if (replacement)
  1091. return replacement;
  1092. return NewHqlTransformer::createTransformedSelector(expr);
  1093. }
  1094. IHqlExpression * ensureAliased(IHqlExpression * expr)
  1095. {
  1096. OwnedHqlExpr alias = createAlias(expr, NULL);
  1097. builder.ensureAlias(alias);
  1098. return alias.getClear();
  1099. }
  1100. protected:
  1101. UpdateTransformBuilder & builder;
  1102. IHqlExpression * searchSelector;
  1103. };
  1104. IHqlExpression * UpdateTransformBuilder::replaceUnsafeSelectors(IHqlExpression * rhs)
  1105. {
  1106. UnsafeSelectorReplacer replacer(*this, prevSelector);
  1107. return replacer.transformRoot(rhs);
  1108. }
  1109. //---------------------------------------------------------------------------
  1110. void HqlCppTranslator::doFilterAssignment(BuildCtx & ctx, TransformBuilder * builder, HqlExprArray & assigns, IHqlExpression * cur)
  1111. {
  1112. node_operator op = cur->getOperator();
  1113. switch (op)
  1114. {
  1115. case no_assignall:
  1116. case no_newtransform:
  1117. case no_transform:
  1118. case no_alias_scope:
  1119. doFilterAssignments(ctx, builder, assigns, cur);
  1120. break;
  1121. case no_assign:
  1122. assigns.append(*LINK(cur));
  1123. break;
  1124. case no_assert:
  1125. case no_skip:
  1126. case no_alias:
  1127. if (builder)
  1128. builder->processAlias(ctx, cur);
  1129. else
  1130. buildStmt(ctx, cur);
  1131. break;
  1132. case no_attr:
  1133. case no_attr_link:
  1134. case no_attr_expr:
  1135. break;
  1136. default:
  1137. UNIMPLEMENTED;
  1138. }
  1139. }
  1140. void HqlCppTranslator::doFilterAssignments(BuildCtx & ctx, TransformBuilder * builder, HqlExprArray & assigns, IHqlExpression * expr)
  1141. {
  1142. if (expr->getOperator() == no_alias_scope)
  1143. {
  1144. ForEachChildFrom(i, expr, 1)
  1145. doFilterAssignment(ctx, builder, assigns, expr->queryChild(i));
  1146. doFilterAssignment(ctx, builder, assigns, expr->queryChild(0));
  1147. }
  1148. else
  1149. {
  1150. ForEachChild(i, expr)
  1151. doFilterAssignment(ctx, builder, assigns, expr->queryChild(i));
  1152. }
  1153. }
  1154. void HqlCppTranslator::filterExpandAssignments(BuildCtx & ctx, TransformBuilder * builder, HqlExprArray & assigns, IHqlExpression * rawExpr)
  1155. {
  1156. LinkedHqlExpr expr = rawExpr;
  1157. if (options.spotCSE)
  1158. expr.setown(spotScalarCSE(expr));
  1159. traceExpression("transform cse", expr);
  1160. // expandAliases(ctx, expr);
  1161. doFilterAssignments(ctx, builder, assigns, expr);
  1162. }
  1163. void HqlCppTranslator::associateCounter(BuildCtx & ctx, IHqlExpression * counterExpr, const char * name)
  1164. {
  1165. if (counterExpr)
  1166. {
  1167. OwnedHqlExpr counterVar = createVariable(name, LINK(counterType));
  1168. ctx.associateExpr(counterExpr, counterVar);
  1169. }
  1170. }
  1171. unsigned HqlCppTranslator::getConsistentUID(IHqlExpression * ptr)
  1172. {
  1173. if (!ptr)
  1174. return 0;
  1175. // Allocate consistent numbers helps to regression check the generated code
  1176. if (recordIndexCache.find(ptr) == NotFound)
  1177. recordIndexCache.append(ptr);
  1178. return recordIndexCache.find(ptr)+1;
  1179. }
  1180. unsigned HqlCppTranslator::cppIndexNextActivity(bool isChildActivity)
  1181. {
  1182. activitiesThisCpp++;
  1183. if (activitiesThisCpp > options.activitiesPerCpp)
  1184. {
  1185. //Allow 25% over the default number of activities per child in order to reduce the number of activities moved into
  1186. //the header file.
  1187. if (!isChildActivity || activitiesThisCpp > (options.activitiesPerCpp * 5 / 4))
  1188. {
  1189. curCppFile++;
  1190. activitiesThisCpp = 1;
  1191. }
  1192. }
  1193. return curCppFile;
  1194. }
  1195. //---------------------------------------------------------------------------
  1196. static IHqlExpression * createResultAttribute(IHqlExpression * seq, IHqlExpression * name)
  1197. {
  1198. //if a named user output then set seq to the name so that workunit reads from the named symbol get commoned up correctly
  1199. if (name && !name->queryType()->isInteger() && seq->queryValue()->getIntValue() >= 0)
  1200. seq = name;
  1201. return createAttribute(resultAtom, LINK(seq), LINK(name));
  1202. }
  1203. static void associateRemoteResult(BuildCtx & ctx, ABoundActivity * table, IHqlExpression * seq, IHqlExpression * name)
  1204. {
  1205. OwnedHqlExpr attr = createResultAttribute(seq, name);
  1206. OwnedHqlExpr unknown = createUnknown(no_attr, NULL, NULL, LINK(table));
  1207. ctx.associateExpr(attr, unknown);
  1208. }
  1209. void HqlCppTranslator::associateRemoteResult(ActivityInstance & instance, IHqlExpression * seq, IHqlExpression * name)
  1210. {
  1211. ::associateRemoteResult(*activeGraphCtx, instance.table, seq, name);
  1212. if (name && targetRoxie())
  1213. {
  1214. OwnedHqlExpr attr = createResultAttribute(seq, name);
  1215. globalFiles.append(* new GlobalFileTracker(attr, instance.graphNode));
  1216. }
  1217. }
  1218. void HqlCppTranslator::queryAddResultDependancy(ABoundActivity & whoAmIActivity, IHqlExpression * seq, IHqlExpression * name)
  1219. {
  1220. if (activeGraphCtx)
  1221. {
  1222. //Because of extend, we need to find all the possible matches, not just the last one.
  1223. AssociationIterator iter(*activeGraphCtx);
  1224. OwnedHqlExpr attr = createResultAttribute(seq, name);
  1225. ForEach(iter)
  1226. {
  1227. HqlExprAssociation & cur = iter.get();
  1228. if (cur.represents == attr)
  1229. {
  1230. ABoundActivity * match = (ABoundActivity *)cur.queryExpr()->queryUnknownExtra();
  1231. IHqlExpression * whoAmI = whoAmIActivity.queryBound();
  1232. OwnedHqlExpr dependency = createAttribute(dependencyAtom, LINK(whoAmI), LINK(match->queryBound()));
  1233. if (!activeGraphCtx->queryMatchExpr(dependency))
  1234. {
  1235. activeGraphCtx->associateExpr(dependency, dependency);
  1236. addDependency(*activeGraphCtx, match, &whoAmIActivity, dependencyAtom);
  1237. }
  1238. }
  1239. }
  1240. if (name && targetRoxie())
  1241. registerGlobalUsage(attr);
  1242. }
  1243. }
  1244. bool HqlCppTranslator::tempRowRequiresFinalize(IHqlExpression * record) const
  1245. {
  1246. if (recordRequiresDestructor(record) || options.finalizeAllRows)
  1247. return true;
  1248. if (isVariableSizeRecord(record))
  1249. return true;
  1250. return false;
  1251. }
  1252. BoundRow * HqlCppTranslator::createRowBuilder(BuildCtx & ctx, BoundRow * targetRow)
  1253. {
  1254. IHqlExpression * record = targetRow->queryRecord();
  1255. IHqlExpression * boundTarget = targetRow->queryBound();
  1256. bool targetIsOwnedRow = hasWrapperModifier(boundTarget->queryType());
  1257. StringBuffer builderName, rowName;
  1258. getUniqueId(builderName.append("b"));
  1259. rowName.append(builderName).append(".row()");
  1260. if (!targetIsOwnedRow && isFixedWidthDataset(record) && !options.alwaysCreateRowBuilder)
  1261. {
  1262. LinkedHqlExpr targetArg = boundTarget;
  1263. if (targetIsOwnedRow)
  1264. {
  1265. OwnedHqlExpr allocator = createRowAllocator(ctx, record);
  1266. StringBuffer valueText;
  1267. valueText.append("(byte *)");
  1268. generateExprCpp(valueText, allocator).append("->createRow()");
  1269. StringBuffer setText;
  1270. generateExprCpp(setText, boundTarget);
  1271. setText.append(".setown(").append(valueText).append(");");
  1272. ctx.addQuoted(setText);
  1273. targetArg.setown(getPointer(boundTarget));
  1274. }
  1275. BoundRow * self = bindSelf(ctx, targetRow->queryDataset(), targetArg, NULL);
  1276. return LINK(self);
  1277. }
  1278. if (targetIsOwnedRow)
  1279. {
  1280. OwnedHqlExpr allocator = createRowAllocator(ctx, record);
  1281. StringBuffer s;
  1282. s.clear().append("RtlDynamicRowBuilder ").append(builderName).append("(");
  1283. generateExprCpp(s, allocator).append(");");
  1284. ctx.addQuoted(s);
  1285. BoundRow * self = bindSelf(ctx, targetRow->queryDataset(), builderName);
  1286. return LINK(self);
  1287. }
  1288. else
  1289. {
  1290. StringBuffer s;
  1291. s.clear().append("RtlStaticRowBuilder ").append(builderName).append("(");
  1292. generateExprCpp(s, boundTarget);
  1293. s.append(",").append(getMaxRecordSize(record)).append(");");
  1294. ctx.addQuoted(s);
  1295. OwnedHqlExpr builder = createVariable(builderName, makeBoolType());
  1296. BoundRow * self = bindSelf(ctx, targetRow->queryDataset(), builderName);
  1297. return LINK(self);
  1298. }
  1299. }
  1300. BoundRow * HqlCppTranslator::declareLinkedRow(BuildCtx & ctx, IHqlExpression * expr, bool isMember)
  1301. {
  1302. assertex(expr->isDatarow());
  1303. StringBuffer rowName;
  1304. getUniqueId(rowName.append('r'));
  1305. IHqlExpression * record = expr->queryRecord();
  1306. Owned<ITypeInfo> rowType = makeRowType(record->getType());
  1307. rowType.setown(makeAttributeModifier(makeWrapperModifier(rowType.getClear()), getLinkCountedAttr()));
  1308. if (isMember)
  1309. rowType.setown(makeModifier(rowType.getClear(), typemod_member, NULL));
  1310. OwnedHqlExpr boundRow = createVariable(rowName, LINK(rowType));
  1311. //Ugly, but necessary. Conditional temporary rows will be accessed in a lifetime outside of the scope they are
  1312. //evaluated in - so the declaration needs to be in a scope where they will not be freed. For the moment make
  1313. //this the outer most scope (within a function)
  1314. ctx.setNextPriority(BuildCtx::OutermostScopePrio);
  1315. ctx.addDeclare(boundRow);
  1316. return createBoundRow(expr, boundRow);
  1317. }
  1318. BoundRow * HqlCppTranslator::declareStaticRow(BuildCtx & ctx, IHqlExpression * expr)
  1319. {
  1320. assertex(expr->isDatarow());
  1321. IHqlExpression * record = expr->queryRecord();
  1322. unsigned maxRecordSize = getMaxRecordSize(record);
  1323. StringBuffer rowName;
  1324. getUniqueId(rowName.append('r'));
  1325. Owned<ITypeInfo> rowType = makeRowType(record->getType());
  1326. BuildCtx * declarectx = &ctx;
  1327. if (maxRecordSize > options.maxLocalRowSize)
  1328. getInvariantMemberContext(ctx, &declarectx, NULL, false, false);
  1329. if (declarectx != &ctx)
  1330. rowType.setown(makeModifier(rowType.getClear(), typemod_member, NULL));
  1331. else
  1332. declarectx->setNextPriority(BuildCtx::OutermostScopePrio);
  1333. OwnedHqlExpr boundRow = createVariable(rowName, LINK(rowType));
  1334. StringBuffer s;
  1335. declarectx->addQuoted(s.append("byte ").append(rowName).append("[").append(maxRecordSize).append("];"));
  1336. return createBoundRow(expr, boundRow);
  1337. }
  1338. BoundRow * HqlCppTranslator::declareTempRow(BuildCtx & ctx, BuildCtx & codectx, IHqlExpression * expr)
  1339. {
  1340. assertex(expr->isDatarow());
  1341. IHqlExpression * record = expr->queryRecord();
  1342. //if maxRecordSize is too large, and cannot store it in a class, then allocate a pointer to it dynamically.
  1343. unsigned maxRecordSize = getMaxRecordSize(record);
  1344. bool createRowDynamically = tempRowRequiresFinalize(record) || (maxRecordSize > options.maxLocalRowSize);
  1345. if (createRowDynamically)
  1346. {
  1347. return declareLinkedRow(ctx, expr, &ctx != &codectx);
  1348. }
  1349. else
  1350. {
  1351. return declareStaticRow(ctx, expr);
  1352. }
  1353. }
  1354. BoundRow * HqlCppTranslator::declareTempAnonRow(BuildCtx & ctx, BuildCtx & codectx, IHqlExpression * record)
  1355. {
  1356. OwnedHqlExpr anon = createRow(no_self, LINK(record->queryRecord()), createUniqueId());
  1357. return declareTempRow(ctx, codectx, anon);
  1358. }
  1359. void HqlCppTranslator::finalizeTempRow(BuildCtx & ctx, BoundRow * row, BoundRow * builder)
  1360. {
  1361. IHqlExpression * targetRow = row->queryBound();
  1362. IHqlExpression * rowBuilder = builder->queryBound();
  1363. bool targetIsOwnedRow = hasWrapperModifier(targetRow->queryType());
  1364. IHqlExpression * record = rowBuilder->queryRecord();
  1365. if (builder->queryBuilder() && targetIsOwnedRow)
  1366. {
  1367. OwnedHqlExpr createdRowSize = getRecordSize(builder->querySelector());
  1368. HqlExprArray args;
  1369. args.append(*LINK(builder->queryBuilder()));
  1370. args.append(*LINK(createdRowSize));
  1371. OwnedHqlExpr call = bindFunctionCall(finalizeRowClearId, args, targetRow->queryType());
  1372. CHqlBoundTarget target;
  1373. target.expr.set(targetRow);
  1374. buildExprAssign(ctx, target, call);
  1375. CHqlBoundExpr bound;
  1376. buildExpr(ctx, createdRowSize, bound);
  1377. OwnedHqlExpr sizeofTarget = createSizeof(row->querySelector());
  1378. ctx.associateExpr(sizeofTarget, bound);
  1379. }
  1380. ctx.removeAssociation(builder);
  1381. }
  1382. //---------------------------------------------------------------------------
  1383. bool GlobalFileTracker::checkMatch(IHqlExpression * searchFilename)
  1384. {
  1385. if (searchFilename->queryBody() == filename.get())
  1386. {
  1387. usageCount++;
  1388. return true;
  1389. }
  1390. return false;
  1391. }
  1392. void GlobalFileTracker::writeToGraph()
  1393. {
  1394. if (usageCount && graphNode)
  1395. addGraphAttributeInt(graphNode, "_globalUsageCount", usageCount);
  1396. }
  1397. //---------------------------------------------------------------------------
  1398. MetaInstance::MetaInstance(HqlCppTranslator & translator, IHqlExpression * _record, bool _isGrouped)
  1399. {
  1400. setMeta(translator, _record, _isGrouped);
  1401. }
  1402. void MetaInstance::setMeta(HqlCppTranslator & translator, IHqlExpression * _record, bool _isGrouped)
  1403. {
  1404. record = _record;
  1405. grouped = _isGrouped;
  1406. assertex(!record || record->getOperator() == no_record);
  1407. searchKey.setown(::getMetaUniqueKey(record, grouped));
  1408. StringBuffer s,recordBase;
  1409. appendUniqueId(recordBase, translator.getConsistentUID(searchKey));
  1410. metaName.set(s.clear().append("mi").append(recordBase).str());
  1411. instanceName.set(s.clear().append("mx").append(recordBase).str());
  1412. //MORE: This function is only used by the fvsource code - getResultRecordSizeEntry
  1413. //It seems a bit of a waste generating it for something used infrequently.
  1414. metaFactoryName.set(s.clear().append("mf").append(recordBase).str());
  1415. }
  1416. //---------------------------------------------------------------------------
  1417. unsigned LocationArray::findLocation(IHqlExpression * location)
  1418. {
  1419. ISourcePath * sourcePath = location->querySourcePath();
  1420. unsigned line = location->getStartLine();
  1421. ForEachItem(i)
  1422. {
  1423. IHqlExpression & cur = item(i);
  1424. if ((cur.querySourcePath() == sourcePath) && (cur.getStartLine() == line))
  1425. return i;
  1426. }
  1427. return NotFound;
  1428. }
  1429. bool LocationArray::queryNewLocation(IHqlExpression * location)
  1430. {
  1431. if (findLocation(location) != NotFound)
  1432. return false;
  1433. append(*LINK(location));
  1434. return true;
  1435. }
  1436. IHqlDelayedCodeGenerator * ABoundActivity::createOutputCountCallback()
  1437. {
  1438. return new DelayedUnsignedGenerator(outputCount);
  1439. }
  1440. enum { createPrio = 1000, inputPrio = 3000, readyPrio = 4000, goPrio = 5000, donePrio = 7000, destroyPrio = 9000 };
  1441. ActivityInstance::ActivityInstance(HqlCppTranslator & _translator, BuildCtx & ctx, ThorActivityKind _kind, IHqlExpression * _dataset, const char * _activityArgName) :
  1442. HqlExprAssociation(activeActivityMarkerExpr),
  1443. translator(_translator), classctx(ctx), startctx(ctx), createctx(ctx), nestedctx(ctx), onstartctx(ctx)
  1444. {
  1445. dataset.set(_dataset);
  1446. kind = _kind;
  1447. node_operator op = dataset->getOperator();
  1448. isGrouped = isGroupedActivity(dataset);
  1449. isLocal = !isGrouped && isLocalActivity(dataset) && localChangesActivity(dataset) && !translator.targetHThor();
  1450. implementationClassName = NULL;
  1451. activityArgName.set(_activityArgName);
  1452. IHqlExpression * outputDataset = dataset;
  1453. if (outputDataset->isAction() && (getNumChildTables(outputDataset) == 1))
  1454. outputDataset = dataset->queryChild(0);
  1455. if (translator.targetRoxie())
  1456. {
  1457. if ((op == no_output) && dataset->hasAttribute(_spill_Atom) && queryRealChild(dataset, 1))
  1458. outputDataset = dataset->queryChild(0);
  1459. }
  1460. if ((op == no_setgraphresult) && translator.queryOptions().minimizeActivityClasses)
  1461. outputDataset = dataset->queryChild(0);
  1462. bool removeXpath = dataset->hasAttribute(noXpathAtom) || (op == no_output && translator.queryOptions().removeXpathFromOutput);
  1463. LinkedHqlExpr record = queryRecord(outputDataset);
  1464. if (removeXpath)
  1465. record.setown(removeAttributeFromFields(record, xpathAtom));
  1466. meta.setMeta(translator, record, ::isGrouped(outputDataset));
  1467. activityId = translator.nextActivityId();
  1468. StringBuffer s;
  1469. className.set(s.clear().append("cAc").append(activityId).str());
  1470. factoryName.set(s.clear().append("fAc").append(activityId).str());
  1471. instanceName.set(s.clear().append("iAc").append(activityId).str());
  1472. argsName.set(s.clear().append("oAc").append(activityId).str());
  1473. OwnedHqlExpr boundName = createVariable(instanceName, dataset->getType());
  1474. isMember = false;
  1475. instanceIsLocal = false;
  1476. classStmt = NULL;
  1477. classGroupStmt = NULL;
  1478. hasChildActivity = false;
  1479. includedInHeader = false;
  1480. isCoLocal = false;
  1481. isNoAccess = false;
  1482. executedRemotely = translator.targetThor();// && !translator.isNeverDistributed(dataset);
  1483. containerActivity = NULL;
  1484. subgraph = queryActiveSubGraph(ctx);
  1485. onCreateStmt = NULL;
  1486. onCreateMarker = 0;
  1487. //count index and count disk need to be swapped to the new (much simpler) mechanism
  1488. //until then, they need to be special cased.
  1489. activityLocalisation = GraphNoAccess;
  1490. containerActivity = translator.queryCurrentActivity(ctx);
  1491. parentEvalContext.set(translator.queryEvalContext(ctx));
  1492. parentExtract.set(static_cast<ParentExtract*>(ctx.queryFirstAssociation(AssocExtract)));
  1493. bool optimizeParentAccess = translator.queryOptions().optimizeParentAccess;
  1494. if (parentExtract)
  1495. {
  1496. GraphLocalisation localisation = parentExtract->queryLocalisation();
  1497. activityLocalisation = translator.isAlwaysCoLocal() ? GraphCoLocal : queryActivityLocalisation(dataset, optimizeParentAccess);
  1498. if (activityLocalisation == GraphNoAccess)
  1499. isNoAccess = true;
  1500. else if (activityLocalisation == GraphNeverAccess)
  1501. activityLocalisation = GraphNoAccess;
  1502. if (translator.targetThor() && !translator.insideChildQuery(ctx))
  1503. executedRemotely = true;
  1504. else
  1505. executedRemotely = ((activityLocalisation == GraphNonLocal) || (localisation == GraphRemote));
  1506. isCoLocal = false;
  1507. if (containerActivity && !executedRemotely && (localisation != GraphNonLocal))
  1508. {
  1509. // if we supported GraphNonCoLocal this test would not be needed
  1510. if (activityLocalisation != GraphNoAccess)
  1511. isCoLocal = true;
  1512. }
  1513. //if top level activity within a query library then need to force access to the parent extract
  1514. if (!containerActivity && translator.insideLibrary())
  1515. {
  1516. //there should be no colocal activity (container = null)
  1517. if (activityLocalisation != GraphNoAccess)
  1518. activityLocalisation = GraphNonLocal;
  1519. }
  1520. if (activityLocalisation == GraphNoAccess)
  1521. parentExtract.clear();
  1522. if (isCoLocal)
  1523. colocalMember.setown(createVariable("colocal", makeVoidType()));
  1524. }
  1525. else
  1526. {
  1527. if (executedRemotely)
  1528. {
  1529. GraphLocalisation localisation = queryActivityLocalisation(dataset, optimizeParentAccess);
  1530. if ((kind == TAKsimpleaction) || (localisation == GraphNeverAccess) || (localisation == GraphNoAccess))
  1531. executedRemotely = false;
  1532. }
  1533. }
  1534. if (!parentExtract && (translator.getTargetClusterType() == RoxieCluster))
  1535. executedRemotely = isNonLocal(dataset, false);
  1536. unsigned containerId = 0;
  1537. if (containerActivity)
  1538. {
  1539. containerActivity->hasChildActivity = true;
  1540. containerId = containerActivity->activityId;
  1541. }
  1542. table = new ThorBoundActivity(dataset, boundName, activityId, containerId, translator.curSubGraphId(ctx), kind);
  1543. }
  1544. ActivityInstance::~ActivityInstance()
  1545. {
  1546. table->Release();
  1547. }
  1548. void ActivityInstance::addBaseClass(const char * name, bool needLinkOverride)
  1549. {
  1550. baseClassExtra.append(", public ").append(name);
  1551. }
  1552. ABoundActivity * ActivityInstance::getBoundActivity()
  1553. {
  1554. return LINK(table);
  1555. }
  1556. BuildCtx & ActivityInstance::onlyEvalOnceContext()
  1557. {
  1558. return evalContext->onCreate.childctx;
  1559. }
  1560. bool ActivityInstance::isExternal()
  1561. {
  1562. return !isMember && !instanceIsLocal;
  1563. }
  1564. void ActivityInstance::addAttribute(const char * name, const char * value)
  1565. {
  1566. addGraphAttribute(graphNode, name, value);
  1567. }
  1568. void ActivityInstance::addAttributeInt(const char * name, __int64 value)
  1569. {
  1570. addGraphAttributeInt(graphNode, name, value);
  1571. }
  1572. void ActivityInstance::addAttributeBool(const char * name, bool value)
  1573. {
  1574. addGraphAttributeBool(graphNode, name, value);
  1575. }
  1576. void ActivityInstance::addLocationAttribute(IHqlExpression * location)
  1577. {
  1578. if (!translator.queryOptions().reportLocations)
  1579. return;
  1580. unsigned line = location->getStartLine();
  1581. if (line == 0)
  1582. return;
  1583. if (!locations.queryNewLocation(location))
  1584. return;
  1585. ISourcePath * sourcePath = location->querySourcePath();
  1586. unsigned column = location->getStartColumn();
  1587. StringBuffer s;
  1588. s.append(sourcePath->str()).append("(").append(line);
  1589. if (column)
  1590. s.append(",").append(column);
  1591. s.append(")");
  1592. addAttribute("definition", s.str());
  1593. }
  1594. void ActivityInstance::addNameAttribute(IHqlExpression * symbol)
  1595. {
  1596. //Not so sure about adding a location for a named symbol if there are other locations already present....
  1597. //We should probably perform some deduping instead.
  1598. addLocationAttribute(symbol);
  1599. IAtom * name = symbol->queryName();
  1600. if (!name)
  1601. return;
  1602. ForEachItemIn(i, names)
  1603. {
  1604. if (names.item(i).queryName() == name)
  1605. return;
  1606. }
  1607. names.append(*symbol);
  1608. addAttribute("name", name->str());
  1609. }
  1610. void ActivityInstance::removeAttribute(const char * name)
  1611. {
  1612. removeGraphAttribute(graphNode, name);
  1613. }
  1614. static void expandHintValue(StringBuffer & s, IHqlExpression * expr)
  1615. {
  1616. switch (expr->getOperator())
  1617. {
  1618. case no_constant:
  1619. expr->queryValue()->getStringValue(s);
  1620. break;
  1621. case no_comma:
  1622. expandHintValue(s, expr->queryChild(0));
  1623. expandHintValue(s.append(","), expr->queryChild(1));
  1624. break;
  1625. case no_range:
  1626. expandHintValue(s, expr->queryChild(0));
  1627. expandHintValue(s.append(".."), expr->queryChild(1));
  1628. break;
  1629. case no_rangefrom:
  1630. expandHintValue(s, expr->queryChild(0));
  1631. s.append("..");
  1632. break;
  1633. case no_rangeto:
  1634. expandHintValue(s.append(".."), expr->queryChild(0));
  1635. break;
  1636. case no_list:
  1637. {
  1638. s.append("[");
  1639. ForEachChild(i, expr)
  1640. {
  1641. if (i)
  1642. s.append(",");
  1643. expandHintValue(s, expr->queryChild(i));
  1644. }
  1645. s.append("]");
  1646. break;
  1647. }
  1648. case no_attr:
  1649. s.append(expr->queryName());
  1650. break;
  1651. default:
  1652. s.append("?");
  1653. break;
  1654. }
  1655. }
  1656. void ActivityInstance::processAnnotation(IHqlExpression * annotation)
  1657. {
  1658. switch (annotation->getAnnotationKind())
  1659. {
  1660. case annotate_meta:
  1661. {
  1662. unsigned i=0;
  1663. IHqlExpression * cur;
  1664. while ((cur = annotation->queryAnnotationParameter(i++)) != NULL)
  1665. {
  1666. IAtom * name = cur->queryName();
  1667. if (name == sectionAtom)
  1668. processSection(cur);
  1669. else if (name == hintAtom)
  1670. processHints(cur);
  1671. }
  1672. }
  1673. }
  1674. }
  1675. void ActivityInstance::processAnnotations(IHqlExpression * expr)
  1676. {
  1677. ForEachChild(iHint, expr)
  1678. {
  1679. IHqlExpression * cur = expr->queryChild(iHint);
  1680. if ((cur->queryName() == hintAtom) && cur->isAttribute())
  1681. processHints(cur);
  1682. }
  1683. IHqlExpression * cur = expr;
  1684. loop
  1685. {
  1686. IHqlExpression * body = cur->queryBody(true);
  1687. if (cur == body)
  1688. break;
  1689. processAnnotation(cur);
  1690. cur = body;
  1691. }
  1692. }
  1693. void ActivityInstance::processHint(IHqlExpression * attr)
  1694. {
  1695. IAtom * name = attr->queryName();
  1696. StringBuffer value;
  1697. ForEachChild(i, attr)
  1698. {
  1699. if (i)
  1700. value.append(",");
  1701. expandHintValue(value, attr->queryChild(i));
  1702. }
  1703. if (value.length() == 0)
  1704. value.append("1");
  1705. IPropertyTree * att = createPTree();
  1706. att->setProp("@name", name->str());
  1707. att->setProp("@value", value.str());
  1708. graphNode->addPropTree("hint", att);
  1709. }
  1710. void ActivityInstance::processSection(IHqlExpression * section)
  1711. {
  1712. StringBuffer sectionName;
  1713. getStringValue(sectionName, section->queryChild(0));
  1714. addAttribute("section", sectionName);
  1715. }
  1716. void ActivityInstance::processHints(IHqlExpression * hintAttr)
  1717. {
  1718. ForEachChild(i, hintAttr)
  1719. processHint(hintAttr->queryChild(i));
  1720. }
  1721. void ActivityInstance::changeActivityKind(ThorActivityKind newKind)
  1722. {
  1723. kind = newKind;
  1724. if (graphNode)
  1725. {
  1726. removeGraphAttribute(graphNode, "_kind");
  1727. addAttributeInt("_kind", kind);
  1728. }
  1729. if (table)
  1730. table->updateActivityKind(kind);
  1731. }
  1732. void ActivityInstance::setInternalSink(bool value)
  1733. {
  1734. if (value)
  1735. addAttributeBool("_internal", true);
  1736. else
  1737. removeAttribute("_internal");
  1738. }
  1739. void ActivityInstance::createGraphNode(IPropertyTree * defaultSubGraph, bool alwaysExecuted)
  1740. {
  1741. IPropertyTree * parentGraphNode = subgraph ? subgraph->tree.get() : defaultSubGraph;
  1742. if (!parentGraphNode)
  1743. return;
  1744. assertex(kind < TAKlast);
  1745. graphNode.set(parentGraphNode->addPropTree("node", createPTree()));
  1746. graphNode->setPropInt64("@id", activityId);
  1747. StringBuffer label;
  1748. if (isGrouped)
  1749. label.append("Grouped ");
  1750. else if (isLocal)
  1751. label.append("Local ");
  1752. label.append(getActivityText(kind));
  1753. graphNode->setProp("@label", graphLabel ? graphLabel.get() : label.str());
  1754. IHqlExpression * cur = dataset;
  1755. loop
  1756. {
  1757. IHqlExpression * body = cur->queryBody(true);
  1758. if (cur == body)
  1759. break;
  1760. switch (cur->getAnnotationKind())
  1761. {
  1762. case annotate_symbol:
  1763. addNameAttribute(cur);
  1764. break;
  1765. case annotate_location:
  1766. addLocationAttribute(cur);
  1767. break;
  1768. }
  1769. cur = body;
  1770. }
  1771. addAttributeInt("_kind", kind);
  1772. addAttributeBool("grouped", isGrouped);
  1773. addAttributeBool("local", isLocal);
  1774. #ifdef _DEBUG
  1775. // assertex(dataset->isAction() == isActivitySink(kind));
  1776. #endif
  1777. if (dataset->isAction())
  1778. {
  1779. if (alwaysExecuted)
  1780. markSubGraphAsRoot(parentGraphNode);
  1781. else
  1782. addAttributeBool("_internal", true);
  1783. }
  1784. if (containerActivity)
  1785. addAttributeInt("_parentActivity", containerActivity->activityId);
  1786. if (parentExtract && isCoLocal)
  1787. addAttributeBool("coLocal", true);
  1788. if (isNoAccess)
  1789. addAttributeBool("noAccess", true);
  1790. if (graphEclText.length() == 0)
  1791. toECL(dataset->queryBody(), graphEclText, false, true);
  1792. elideString(graphEclText, MAX_GRAPH_ECL_LENGTH);
  1793. if (strcmp(graphEclText.str(), "<>") != 0)
  1794. addAttribute("ecl", graphEclText.str());
  1795. if (translator.queryOptions().showSeqInGraph)
  1796. {
  1797. IHqlExpression * selSeq = querySelSeq(dataset);
  1798. if (selSeq)
  1799. addAttributeInt("selSeq", selSeq->querySequenceExtra());
  1800. }
  1801. if (translator.queryOptions().showMetaInGraph)
  1802. {
  1803. StringBuffer s;
  1804. if (translator.targetThor())
  1805. {
  1806. IHqlExpression * distribution = queryDistribution(dataset);
  1807. if (distribution && distribution->queryName() != localAtom)
  1808. addAttribute("metaDistribution", getExprECL(distribution, s.clear(), true).str());
  1809. }
  1810. IHqlExpression * grouping = queryGrouping(dataset);
  1811. if (grouping)
  1812. addAttribute("metaGrouping", getExprECL(grouping, s.clear(), true).str());
  1813. if (translator.targetThor())
  1814. {
  1815. IHqlExpression * globalSortOrder = queryGlobalSortOrder(dataset);
  1816. if (globalSortOrder)
  1817. addAttribute("metaGlobalSortOrder", getExprECL(globalSortOrder, s.clear(), true).str());
  1818. }
  1819. IHqlExpression * localSortOrder = queryLocalUngroupedSortOrder(dataset);
  1820. if (localSortOrder)
  1821. addAttribute("metaLocalSortOrder", getExprECL(localSortOrder, s.clear(), true).str());
  1822. IHqlExpression * groupSortOrder = queryGroupSortOrder(dataset);
  1823. if (groupSortOrder)
  1824. addAttribute("metaGroupSortOrder", getExprECL(groupSortOrder, s.clear(), true).str());
  1825. }
  1826. if (translator.queryOptions().noteRecordSizeInGraph)
  1827. {
  1828. IHqlExpression * record = dataset->queryRecord();
  1829. if (!record && (getNumChildTables(dataset) == 1))
  1830. record = dataset->queryChild(0)->queryRecord();
  1831. if (record)
  1832. {
  1833. size32_t maxSize = getMaxRecordSize(record, translator.getDefaultMaxRecordSize());
  1834. if (isVariableSizeRecord(record))
  1835. {
  1836. size32_t minSize = getMinRecordSize(record);
  1837. size32_t expectedSize = getExpectedRecordSize(record);
  1838. StringBuffer temp;
  1839. temp.append(minSize).append("..");
  1840. if (maxRecordSizeUsesDefault(record))
  1841. temp.append("?");
  1842. else
  1843. temp.append(maxSize);
  1844. temp.append("(").append(expectedSize).append(")");
  1845. addAttribute("recordSize", temp.str());
  1846. }
  1847. else
  1848. addAttributeInt("recordSize", maxSize);
  1849. }
  1850. }
  1851. if (translator.queryOptions().showRecordCountInGraph && !dataset->isAction())
  1852. {
  1853. StringBuffer text;
  1854. getRecordCountText(text, dataset);
  1855. addAttribute("recordCount", text);
  1856. }
  1857. processAnnotations(dataset);
  1858. }
  1859. void ActivityInstance::moveDefinitionToHeader()
  1860. {
  1861. if (!includedInHeader)
  1862. {
  1863. //remove this class from the c++ file and include it in the header file instead
  1864. includedInHeader = true;
  1865. classGroupStmt->setIncluded(false);
  1866. BuildCtx headerctx(*translator.code, parentHelpersAtom);
  1867. headerctx.addAlias(classStmt);
  1868. }
  1869. }
  1870. void ActivityInstance::noteChildActivityLocation(IHqlExpression * pass)
  1871. {
  1872. if (containerActivity && colocalMember)
  1873. containerActivity->noteChildActivityLocation(pass);
  1874. //A child helper has been generated in a different module =>
  1875. //remove this class from the c++ file and include it in the header file instead
  1876. if (translator.queryOptions().spanMultipleCpp && !includedInHeader && (pass != sourceFileSequence))
  1877. moveDefinitionToHeader();
  1878. }
  1879. void ActivityInstance::buildPrefix()
  1880. {
  1881. StringBuffer s;
  1882. sourceFileSequence.setown(getSizetConstant(translator.cppIndexNextActivity(isChildActivity())));
  1883. if (containerActivity && colocalMember)
  1884. containerActivity->noteChildActivityLocation(sourceFileSequence);
  1885. classctx.set(helperAtom);
  1886. classGroupStmt = classctx.addGroupPass(sourceFileSequence);
  1887. classctx.associate(*this);
  1888. classGroup = classctx.addGroup();
  1889. if (!implementationClassName)
  1890. {
  1891. s.clear().append("struct ").append(className).append(" : public CThor").append(activityArgName).append("Arg").append(baseClassExtra);
  1892. classStmt = classctx.addQuotedCompound(s, ";");
  1893. if (subgraph)
  1894. classctx.associate(*subgraph);
  1895. //Generate functions in the order i) always callable ii) after create iii) after start
  1896. nestedctx.set(classctx);
  1897. nestedctx.addGroup();
  1898. createctx.set(classctx);
  1899. createctx.setNextDestructor();
  1900. createctx.addGroup();
  1901. startctx.set(createctx);
  1902. startctx.setNextDestructor();
  1903. startctx.addGroup();
  1904. createctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  1905. evalContext.setown(new ActivityEvalContext(translator, this, parentExtract, parentEvalContext, colocalMember, createctx, startctx));
  1906. classctx.associate(*evalContext);
  1907. //virtual void onCreate(ICodeContext * ctx, IHThorArg * colocalParent, MemoryBuffer * serializedCreate)
  1908. BuildCtx oncreatectx(createctx);
  1909. if (parentExtract && isCoLocal && containerActivity)
  1910. {
  1911. oncreatectx.addQuotedCompound("virtual void onCreate(ICodeContext * _ctx, IHThorArg * _colocal, MemoryBuffer * in)");
  1912. oncreatectx.addQuoted(s.clear().append("colocal = (").append(containerActivity->className).append("*)_colocal;"));
  1913. }
  1914. else
  1915. {
  1916. onCreateStmt = oncreatectx.addQuotedCompound("virtual void onCreate(ICodeContext * _ctx, IHThorArg *, MemoryBuffer * in)");
  1917. }
  1918. oncreatectx.associateExpr(insideOnCreateMarker, NULL);
  1919. oncreatectx.addQuoted("ctx = _ctx;");
  1920. evalContext->onCreate.createFunctionStructure(translator, oncreatectx, true, executedRemotely ? "serializeCreateContext" : NULL);
  1921. if (onCreateStmt)
  1922. onCreateMarker = calcTotalChildren(onCreateStmt);
  1923. onstartctx.set(startctx);
  1924. if (parentExtract)
  1925. {
  1926. onstartctx.addQuotedCompoundOpt("virtual void onStart(const byte * pe, MemoryBuffer * in)");
  1927. parentExtract->beginChildActivity(startctx, onstartctx, activityLocalisation, colocalMember, false, false, containerActivity);
  1928. }
  1929. else
  1930. {
  1931. onstartctx.addQuotedCompoundOpt("virtual void onStart(const byte *, MemoryBuffer * in)");
  1932. }
  1933. onstartctx.associateExpr(insideOnStartMarker, NULL);
  1934. evalContext->onStart.createFunctionStructure(translator, onstartctx, true, executedRemotely ? "serializeStartContext" : NULL);
  1935. if (colocalMember)
  1936. {
  1937. s.clear().append(containerActivity->className).append(" * colocal;");
  1938. classctx.addQuoted(s);
  1939. }
  1940. if (baseClassExtra.length())
  1941. {
  1942. nestedctx.addQuoted(s.clear().append("virtual void Link() const { CThor").append(activityArgName).append("Arg::Link(); }"));
  1943. nestedctx.addQuoted(s.clear().append("virtual bool Release() const { return CThor").append(activityArgName).append("Arg::Release(); }"));
  1944. }
  1945. // if (!isMember)
  1946. // classGroupStmt->setIncomplete(true);
  1947. }
  1948. else
  1949. {
  1950. s.clear().append("// use library for ").append(className);
  1951. classctx.addQuoted(s);
  1952. assertex(isExternal());
  1953. nestedctx.set(classctx);
  1954. createctx.set(classctx);
  1955. startctx.set(createctx);
  1956. initialGroupMarker = classGroup->numChildren();
  1957. }
  1958. }
  1959. void ActivityInstance::buildSuffix()
  1960. {
  1961. //If onCreate() doesn't do anything special, then use an implementation in the base
  1962. if (onCreateStmt && (calcTotalChildren(onCreateStmt) == onCreateMarker))
  1963. onCreateStmt->setIncluded(false);
  1964. //Paranoid check to ensure that library classes aren't used when member functions were required
  1965. if (implementationClassName && (initialGroupMarker != classGroup->numChildren()))
  1966. throwUnexpectedX("Implementation class created, but member functions generated");
  1967. const HqlCppOptions & options = translator.queryOptions();
  1968. if (classStmt && (options.spotComplexClasses || options.showActivitySizeInGraph))
  1969. {
  1970. unsigned approxSize = calcTotalChildren(classStmt);
  1971. if (options.spotComplexClasses && (approxSize >= options.complexClassesThreshold))
  1972. {
  1973. if ((options.complexClassesActivityFilter == 0) || (kind == options.complexClassesActivityFilter))
  1974. translator.WARNING2(HQLWRN_ComplexHelperClass, activityId, approxSize);
  1975. }
  1976. if (options.showActivitySizeInGraph)
  1977. addAttributeInt("approxClassSize", approxSize);
  1978. }
  1979. // if (!isMember)
  1980. // classGroupStmt->setIncomplete(false);
  1981. if (parentExtract)
  1982. parentExtract->endChildActivity();
  1983. classctx.removeAssociation(this);
  1984. locations.kill();
  1985. names.kill();
  1986. if (isExternal())
  1987. {
  1988. BuildCtx globalctx(*translator.code, helperAtom);
  1989. globalctx.addGroupPass(sourceFileSequence);
  1990. if (implementationClassName)
  1991. {
  1992. //Meta is always the last parameter...
  1993. addConstructorMetaParameter();
  1994. StringBuffer s;
  1995. s.append("extern \"C\" ECL_API IHThorArg * ").append(factoryName).append("()");
  1996. globalctx.addQuotedCompound(s);
  1997. OwnedHqlExpr call = translator.bindFunctionCall(implementationClassName, constructorArgs);
  1998. //Don't call buildReturn because we're lying about the return type, and we don't want a boolean temporary created.
  1999. CHqlBoundExpr bound;
  2000. translator.buildExpr(globalctx, call, bound);
  2001. globalctx.addReturn(bound.expr);
  2002. //translator.buildReturn(globalctx, call);
  2003. }
  2004. else
  2005. {
  2006. StringBuffer s;
  2007. s.append("extern \"C\" ECL_API IHThorArg * ").append(factoryName).append("() { return new ").append(className).append("; }");
  2008. globalctx.addQuoted(s);
  2009. }
  2010. }
  2011. }
  2012. void ActivityInstance::buildMetaMember()
  2013. {
  2014. if (implementationClassName)
  2015. return;
  2016. translator.buildMetaInfo(meta);
  2017. if (meta.queryRecord())
  2018. {
  2019. StringBuffer s;
  2020. s.append("virtual IOutputMetaData * queryOutputMeta() { return &").append(meta.queryInstanceObject()).append("; }");
  2021. classctx.addQuoted(s);
  2022. }
  2023. }
  2024. void ActivityInstance::addConstructorMetaParameter()
  2025. {
  2026. translator.buildMetaInfo(meta);
  2027. if (meta.queryRecord())
  2028. {
  2029. StringBuffer s;
  2030. s.append("&").append(meta.queryInstanceObject());
  2031. OwnedHqlExpr metaExpr = createQuoted(s.str(), makeBoolType());
  2032. constructorArgs.append(*metaExpr.getClear());
  2033. }
  2034. }
  2035. ParentExtract * ActivityInstance::createNestedExtract()
  2036. {
  2037. if (!nestedExtract)
  2038. {
  2039. nestedExtract.setown(new ParentExtract(translator, PETnested, NULL, GraphCoLocal, evalContext));
  2040. nestedExtract->beginNestedExtract(startctx);
  2041. }
  2042. return LINK(nestedExtract);
  2043. }
  2044. //----------------------------------------------------------------------------------------------------
  2045. StringBuffer &expandLiteral(StringBuffer &s, const char *f)
  2046. {
  2047. const char * startLine = f;
  2048. char c;
  2049. s.append('"');
  2050. while ((c = *f++) != 0)
  2051. {
  2052. switch (c)
  2053. {
  2054. case '\t':
  2055. s.append("\\t");
  2056. break;
  2057. case '\r':
  2058. s.append("\\r");
  2059. break;
  2060. case '\n':
  2061. s.append("\\n\"\n\t\t\"");
  2062. startLine = f;
  2063. break;
  2064. case ',':
  2065. s.append(c);
  2066. if (f - startLine > 60)
  2067. {
  2068. s.append("\"\n\t\t\"");
  2069. startLine = f;
  2070. }
  2071. break;
  2072. case '\\':
  2073. case '\"':
  2074. case '\'':
  2075. s.append('\\');
  2076. // fall into...
  2077. default:
  2078. s.append(c);
  2079. break;
  2080. }
  2081. if (f - startLine > 120)
  2082. {
  2083. s.append("\"\n\t\t\"");
  2084. startLine = f;
  2085. }
  2086. }
  2087. return s.append("\"");
  2088. }
  2089. //---------------------------------------------------------------------------
  2090. ReferenceSelector::ReferenceSelector(HqlCppTranslator & _translator) : translator(_translator)
  2091. {
  2092. }
  2093. //---------------------------------------------------------------------------
  2094. /* In parms: _dataset, _path are NOT linked */
  2095. DatasetSelector::DatasetSelector(HqlCppTranslator & _translator, BoundRow * _row, IHqlExpression * _path)
  2096. : ReferenceSelector(_translator)
  2097. {
  2098. row = LINK(_row);
  2099. matchedDataset = false;
  2100. column = row->queryRootColumn();
  2101. column->Link();
  2102. path.set(_path);
  2103. if (!_path)
  2104. path.set(row->querySelector());
  2105. parent = NULL;
  2106. }
  2107. /* All in parms: NOT linked */
  2108. DatasetSelector::DatasetSelector(DatasetSelector * _parent, BoundRow * _row, AColumnInfo * _column, IHqlExpression * _path)
  2109. : ReferenceSelector(_parent->translator)
  2110. {
  2111. parent = LINK(_parent);
  2112. matchedDataset = _parent->matchedDataset;
  2113. column = LINK(_column);
  2114. path.set(_path);
  2115. row = LINK(_row);
  2116. }
  2117. DatasetSelector::~DatasetSelector()
  2118. {
  2119. ::Release(column);
  2120. ::Release(parent);
  2121. ::Release(row);
  2122. }
  2123. void DatasetSelector::assignTo(BuildCtx & ctx, const CHqlBoundTarget & target)
  2124. {
  2125. OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2126. if (mapped)
  2127. translator.buildExprAssign(ctx, target, mapped);
  2128. else
  2129. column->buildAssign(translator, ctx, this, target);
  2130. }
  2131. void DatasetSelector::buildAddress(BuildCtx & ctx, CHqlBoundExpr & target)
  2132. {
  2133. OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2134. if (mapped)
  2135. translator.buildAddress(ctx, mapped, target);
  2136. else
  2137. column->buildAddress(translator, ctx, this, target);
  2138. }
  2139. void DatasetSelector::buildClear(BuildCtx & ctx, int direction)
  2140. {
  2141. assertex(row->isModifyable());
  2142. column->buildClear(translator, ctx, this, direction);
  2143. }
  2144. bool DatasetSelector::isBinary()
  2145. {
  2146. return row->isBinary();
  2147. }
  2148. bool DatasetSelector::isRoot()
  2149. {
  2150. return parent == NULL;
  2151. }
  2152. /* _newCursor, _newColumn: not linked. newPathOwn: linked */
  2153. DatasetSelector * DatasetSelector::createChild(BoundRow * _newCursor, AColumnInfo * newColumn, IHqlExpression * newPath)
  2154. {
  2155. return new DatasetSelector(this, _newCursor, newColumn, newPath);
  2156. }
  2157. void DatasetSelector::get(BuildCtx & ctx, CHqlBoundExpr & bound)
  2158. {
  2159. OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2160. if (mapped)
  2161. translator.buildAnyExpr(ctx, mapped, bound);
  2162. else
  2163. column->buildExpr(translator, ctx, this, bound);
  2164. }
  2165. void DatasetSelector::getOffset(BuildCtx & ctx, CHqlBoundExpr & bound)
  2166. {
  2167. //OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2168. assertex(!row->isNonLocal());
  2169. column->buildOffset(translator, ctx, this, bound);
  2170. }
  2171. size32_t DatasetSelector::getContainerTrailingFixed()
  2172. {
  2173. assertex(!row->isNonLocal());
  2174. return column->getContainerTrailingFixed();
  2175. }
  2176. void DatasetSelector::getSize(BuildCtx & ctx, CHqlBoundExpr & bound)
  2177. {
  2178. //OwnedHqlExpr mapped = row->getMappedSelector(ctx, this);
  2179. assertex(!row->isNonLocal());
  2180. column->buildSizeOf(translator, ctx, this, bound);
  2181. }
  2182. bool DatasetSelector::isDataset()
  2183. {
  2184. switch (column->queryType()->getTypeCode())
  2185. {
  2186. case type_table:
  2187. case type_groupedtable:
  2188. return true;
  2189. }
  2190. return false;
  2191. }
  2192. bool DatasetSelector::isConditional()
  2193. {
  2194. return row->isConditional() || column->isConditional();
  2195. }
  2196. AColumnInfo * DatasetSelector::queryColumn()
  2197. {
  2198. return column;
  2199. }
  2200. BoundRow * DatasetSelector::queryRootRow()
  2201. {
  2202. return row;
  2203. }
  2204. IHqlExpression * DatasetSelector::queryExpr()
  2205. {
  2206. return path;
  2207. }
  2208. ITypeInfo * DatasetSelector::queryType()
  2209. {
  2210. if (parent)
  2211. return path->queryType();
  2212. return row->queryDataset()->queryType();
  2213. }
  2214. IHqlExpression * DatasetSelector::resolveChildDataset(IHqlExpression * searchDataset) const
  2215. {
  2216. searchDataset = searchDataset->queryNormalizedSelector();
  2217. IHqlExpression * compare = row->queryDataset()->queryNormalizedSelector();
  2218. if (searchDataset == compare)
  2219. return compare;
  2220. return NULL;
  2221. }
  2222. AColumnInfo * DatasetSelector::resolveField(IHqlExpression * search) const
  2223. {
  2224. AColumnInfo * nextColumn = column->lookupColumn(search);
  2225. if (nextColumn)
  2226. return nextColumn;
  2227. return NULL;
  2228. }
  2229. void DatasetSelector::set(BuildCtx & ctx, IHqlExpression * expr)
  2230. {
  2231. while (expr->getOperator() == no_compound)
  2232. {
  2233. translator.buildStmt(ctx, expr->queryChild(0));
  2234. expr = expr->queryChild(1);
  2235. }
  2236. assertex(row->isModifyable());
  2237. ITypeInfo * type = column->queryType();
  2238. if (!hasReferenceModifier(type))
  2239. {
  2240. switch (type->getTypeCode())
  2241. {
  2242. case type_row:
  2243. {
  2244. if (queryRecordType(queryType()) == expr->queryRecordType())
  2245. {
  2246. translator.buildRowAssign(ctx, this, expr);
  2247. }
  2248. else
  2249. {
  2250. Owned<IReferenceSelector> sourceRef = translator.buildNewRow(ctx, expr);
  2251. setRow(ctx, sourceRef);
  2252. }
  2253. return;
  2254. }
  2255. }
  2256. }
  2257. column->setColumn(translator, ctx, this, expr);
  2258. }
  2259. void DatasetSelector::setRow(BuildCtx & ctx, IReferenceSelector * rhs)
  2260. {
  2261. assertex(row->isModifyable());
  2262. column->setRow(translator, ctx, this, rhs);
  2263. }
  2264. void DatasetSelector::modifyOp(BuildCtx & ctx, IHqlExpression * expr, node_operator op)
  2265. {
  2266. assertex(row->isModifyable());
  2267. // IReferenceSelector * aliasedSelector = row->queryAlias();
  2268. // assertex(aliasedSelector);
  2269. if (column->modifyColumn(translator, ctx, this, expr, op))
  2270. return;
  2271. // OwnedHqlExpr sourceValue = aliasedSelector->queryRootRow()->bindToRow(path, row->querySelector());
  2272. OwnedHqlExpr sourceValue = LINK(path);
  2273. OwnedHqlExpr result;
  2274. switch (op)
  2275. {
  2276. case no_assign_addfiles:
  2277. result.setown(createDataset(no_addfiles, ensureOwned(sourceValue), LINK(expr)));
  2278. break;
  2279. #ifdef _THE_FOLLOWING_ARENT_YET_IMPLEMENTED_BUT_WOULD_BE_USEFUL
  2280. case no_assign_concat:
  2281. result.setown(createValue(no_concat, path->getType(), LINK(sourceValue), LINK(expr)));
  2282. break;
  2283. case no_assign_add:
  2284. result.setown(createValue(no_add, path->getType(), LINK(sourceValue), LINK(expr)));
  2285. break;
  2286. #endif
  2287. default:
  2288. throwError1(HQLERR_UnknownCompoundAssign, getOpString(op));
  2289. }
  2290. set(ctx, result);
  2291. }
  2292. void DatasetSelector::buildDeserialize(BuildCtx & ctx, IHqlExpression * helper, IAtom * serializeForm)
  2293. {
  2294. column->buildDeserialize(translator, ctx, this, helper, serializeForm);
  2295. }
  2296. void DatasetSelector::buildSerialize(BuildCtx & ctx, IHqlExpression * helper, IAtom * serializeForm)
  2297. {
  2298. column->buildSerialize(translator, ctx, this, helper, serializeForm);
  2299. }
  2300. /* In selector: not linked. Return: linked */
  2301. IReferenceSelector * DatasetSelector::select(BuildCtx & ctx, IHqlExpression * selectExpr)
  2302. {
  2303. // assertex(!isDataset());
  2304. OwnedHqlExpr selected;
  2305. //Optimize so don't create so many select expressions that already exist.
  2306. if (selectExpr->getOperator() != no_select)
  2307. selected.setown(createSelectExpr(LINK(path), LINK(selectExpr)));
  2308. else if (selectExpr->queryChild(0) == path)
  2309. selected.set(selectExpr);
  2310. else
  2311. selected.setown(createSelectExpr(LINK(path), LINK(selectExpr->queryChild(1))));
  2312. IHqlExpression * selectedField = selected->queryChild(1);
  2313. AColumnInfo * newColumn = resolveField(selectedField);
  2314. if (!newColumn)
  2315. {
  2316. //could be a dataset selector
  2317. IHqlExpression * selected = NULL;
  2318. if (!matchedDataset)
  2319. selected = resolveChildDataset(selectedField);
  2320. if (!selected)
  2321. {
  2322. #ifdef TraceTableFields
  2323. IHqlExpression * searchDataset = row->queryDataset(); // MORE what when children selected?
  2324. IHqlExpression * record = searchDataset->queryRecord()->queryBody();
  2325. unsigned numFields = record->numChildren();
  2326. unsigned idxc;
  2327. StringBuffer fields;
  2328. PrintLog("Fields:");
  2329. for (idxc = 0; idxc < numFields; idxc++)
  2330. {
  2331. IHqlExpression * field = record->queryChild(idxc);
  2332. IAtom * name = field->queryName();
  2333. fields.clear();
  2334. fields.appendf(" %20s [@%lx := %lx] ", name->str(), field, field->queryChild(0));
  2335. PrintLog(fields.str());
  2336. }
  2337. PrintLog("Search: %20s [@%lx])", selectedField->queryName()->str(),selectedField);
  2338. #endif
  2339. StringBuffer searchName, datasetName;
  2340. selectedField->toString(searchName);
  2341. if (path->queryName())
  2342. datasetName.append(path->queryName());
  2343. else
  2344. path->toString(datasetName);
  2345. throwError2(HQLERR_XDoesNotContainExpressionY, datasetName.str(), searchName.str());
  2346. }
  2347. DatasetSelector * next = createChild(row, column, selected);
  2348. next->matchedDataset = true;
  2349. return next;
  2350. }
  2351. return createChild(row, newColumn, selected);
  2352. }
  2353. BoundRow * DatasetSelector::getRow(BuildCtx & ctx)
  2354. {
  2355. if (isRoot())
  2356. return LINK(row);
  2357. CHqlBoundExpr bound;
  2358. buildAddress(ctx, bound);
  2359. Owned<ITypeInfo> type = makeReferenceModifier(LINK(queryType()));
  2360. OwnedHqlExpr address = createValue(no_implicitcast, type.getClear(), LINK(bound.expr));
  2361. return translator.createBoundRow(path, address);
  2362. }
  2363. IReferenceSelector * HqlCppTranslator::createSelfSelect(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * expr, IHqlExpression * rootSelector)
  2364. {
  2365. if (expr == rootSelector)
  2366. return LINK(target);
  2367. assertex(expr->getOperator() == no_select);
  2368. Owned<IReferenceSelector> parent = createSelfSelect(ctx, target, expr->queryChild(0), rootSelector);
  2369. return parent->select(ctx, expr);
  2370. }
  2371. void initBoundStringTarget(CHqlBoundTarget & target, ITypeInfo * type, const char * lenName, const char * dataName)
  2372. {
  2373. if (type->getSize() == UNKNOWN_LENGTH)
  2374. target.length.setown(createVariable(lenName, LINK(sizetType)));
  2375. target.expr.setown(createVariable(dataName, makeReferenceModifier(LINK(type))));
  2376. }
  2377. //---------------------------------------------------------------------------
  2378. GlobalClassBuilder::GlobalClassBuilder(HqlCppTranslator & _translator, BuildCtx & _ctx, const char * _className, const char * _baseName, const char * _accessorInterface)
  2379. : translator(_translator), classctx(_ctx), nestedctx(_ctx), startctx(_ctx), createctx(_ctx)
  2380. {
  2381. className.set(_className);
  2382. baseName.set(_baseName);
  2383. accessorInterface.set(_accessorInterface);
  2384. if (accessorInterface)
  2385. {
  2386. StringBuffer s;
  2387. accessorName.set(s.clear().append("cr").append(className).str());
  2388. }
  2389. onCreateStmt = NULL;
  2390. }
  2391. void GlobalClassBuilder::buildClass(unsigned priority)
  2392. {
  2393. StringBuffer s;
  2394. s.append("struct ").append(className);
  2395. if (baseName)
  2396. s.append(" : public ").append(baseName);
  2397. classctx.set(declareAtom);
  2398. if (priority)
  2399. classctx.setNextPriority(priority);
  2400. classStmt = classctx.addQuotedCompound(s, ";");
  2401. if (!baseName)
  2402. classctx.addQuoted("ICodeContext * ctx;");
  2403. classctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  2404. //Generate functions in the order i) always callable ii) after create iii) after start
  2405. nestedctx.set(classctx);
  2406. nestedctx.addGroup();
  2407. createctx.set(classctx);
  2408. createctx.setNextDestructor();
  2409. createctx.addGroup();
  2410. startctx.set(createctx);
  2411. evalContext.setown(new GlobalClassEvalContext(translator, parentExtract, parentEvalContext, createctx, startctx));
  2412. classctx.associate(*evalContext);
  2413. //virtual void onCreate(ICodeContext * ctx, IHThorArg * colocalParent, MemoryBuffer * serializedCreate)
  2414. BuildCtx oncreatectx(createctx);
  2415. onCreateStmt = oncreatectx.addQuotedCompound("void onCreate(ICodeContext * _ctx)");
  2416. oncreatectx.associateExpr(insideOnCreateMarker, NULL);
  2417. oncreatectx.addQuoted("ctx = _ctx;");
  2418. evalContext->onCreate.createFunctionStructure(translator, oncreatectx, true, NULL);
  2419. onCreateMarker = calcTotalChildren(onCreateStmt);
  2420. }
  2421. void GlobalClassBuilder::completeClass(unsigned priority)
  2422. {
  2423. if (onCreateStmt && (calcTotalChildren(onCreateStmt) == onCreateMarker))
  2424. onCreateStmt->setIncluded(false);
  2425. //MORE: This should be generated from a system function prototype somehow - so we can extend it to user functions later.
  2426. //arguments and parameters should also be configured similarly.
  2427. if (accessorInterface)
  2428. {
  2429. StringBuffer s, prototype;
  2430. prototype.append("extern ECL_API ").append(accessorInterface).append(" * ").append(accessorName).append("(ICodeContext * ctx, unsigned activityId)");
  2431. BuildCtx accessctx(classctx);
  2432. accessctx.set(declareAtom);
  2433. if (priority)
  2434. accessctx.setNextPriority(priority);
  2435. accessctx.addQuotedCompound(prototype);
  2436. accessctx.addQuoted(s.clear().append(className).append("* p = new ").append(className).append("(activityId); "));
  2437. accessctx.addQuoted("p->onCreate(ctx);");
  2438. accessctx.addQuoted("return p;");
  2439. if (translator.queryOptions().spanMultipleCpp)
  2440. {
  2441. BuildCtx protoctx(*translator.queryCode(), mainprototypesAtom);
  2442. protoctx.addQuoted(s.clear().append(prototype).append(";"));
  2443. }
  2444. }
  2445. }
  2446. //---------------------------------------------------------------------------
  2447. static bool expandThisPass(IHqlExpression * name, unsigned pass)
  2448. {
  2449. if (!name)
  2450. return pass == 1;
  2451. StringBuffer temp;
  2452. name->queryValue()->getStringValue(temp);
  2453. if (temp.length() && temp.charAt(0) =='@')
  2454. return pass == 0;
  2455. return pass == 1;
  2456. }
  2457. static bool anyXmlGeneratedForPass(IHqlExpression * expr, unsigned pass)
  2458. {
  2459. switch (expr->getOperator())
  2460. {
  2461. case no_field:
  2462. {
  2463. OwnedHqlExpr name;
  2464. extractXmlName(name, NULL, NULL, expr, NULL, false);
  2465. ITypeInfo * type = expr->queryType()->queryPromotedType();
  2466. switch (type->getTypeCode())
  2467. {
  2468. case type_row:
  2469. if (name)
  2470. return (pass == 1);
  2471. return anyXmlGeneratedForPass(queryRecord(type), pass);
  2472. case type_set:
  2473. return (pass==1);
  2474. case type_dictionary:
  2475. case type_table:
  2476. case type_groupedtable:
  2477. return (pass == 1);
  2478. default:
  2479. return expandThisPass(name, pass);
  2480. }
  2481. break;
  2482. }
  2483. case no_ifblock:
  2484. return anyXmlGeneratedForPass(expr->queryChild(1), pass);
  2485. case no_record:
  2486. {
  2487. ForEachChild(idx, expr)
  2488. if (anyXmlGeneratedForPass(expr->queryChild(idx), pass))
  2489. return true;
  2490. return false;
  2491. }
  2492. case no_attr:
  2493. case no_attr_expr:
  2494. case no_attr_link:
  2495. return false;
  2496. default:
  2497. UNIMPLEMENTED;
  2498. }
  2499. throwUnexpected(); // unreachable, but some compilers will complain about missing return
  2500. }
  2501. //---------------------------------------------------------------------------
  2502. bool HqlCppTranslator::insideOnCreate(BuildCtx & ctx)
  2503. {
  2504. return ctx.queryMatchExpr(insideOnCreateMarker) != NULL;
  2505. }
  2506. bool HqlCppTranslator::getInvariantMemberContext(BuildCtx & ctx, BuildCtx * * declarectx, BuildCtx * * initctx, bool isIndependentMaybeShared, bool invariantEachStart)
  2507. {
  2508. EvalContext * instance = queryEvalContext(ctx);
  2509. if (instance)
  2510. return instance->getInvariantMemberContext(&ctx, declarectx, initctx, isIndependentMaybeShared, invariantEachStart);
  2511. return false;
  2512. }
  2513. void getMemberClassName(StringBuffer & className, const char * member)
  2514. {
  2515. className.append((char)toupper(member[0])).append(member+1).append("Class");
  2516. }
  2517. void HqlCppTranslator::beginNestedClass(BuildCtx & ctx, const char * member, const char * bases, const char * memberExtra, ParentExtract * extract)
  2518. {
  2519. // ActivityInstance * activity = queryCurrentActivity(ctx);
  2520. // Owned<ParentExtract> nestedUse;
  2521. // if (activity)
  2522. // nestedUse.setown(extract ? LINK(extract) : activity->createNestedExtract());
  2523. StringBuffer begin,end;
  2524. StringBuffer className;
  2525. getMemberClassName(className, member);
  2526. begin.append("struct ").append((char)toupper(member[0])).append(member+1).append("Class");
  2527. if (bases)
  2528. begin.append(" : public ").append(bases);
  2529. end.append(" ").append(member).append(memberExtra).append(";");
  2530. ctx.addQuotedCompound(begin.str(), end.str());
  2531. OwnedHqlExpr colocalName = createVariable("activity", makeVoidType());
  2532. ActivityInstance * activity = queryCurrentActivity(ctx);
  2533. if (activity)
  2534. {
  2535. Owned<ParentExtract> nestedUse = extract ? LINK(extract) : activity->createNestedExtract();
  2536. NestedEvalContext * nested = new NestedEvalContext(*this, member, nestedUse, queryEvalContext(ctx), colocalName, ctx, ctx);
  2537. ctx.associateOwn(*nested);
  2538. nested->initContext();
  2539. }
  2540. }
  2541. void HqlCppTranslator::endNestedClass()
  2542. {
  2543. }
  2544. void HqlCppTranslator::pushMemberFunction(MemberFunction & func)
  2545. {
  2546. }
  2547. void HqlCppTranslator::popMemberFunction()
  2548. {
  2549. }
  2550. void HqlCppTranslator::doBuildFunctionReturn(BuildCtx & ctx, ITypeInfo * type, IHqlExpression * value)
  2551. {
  2552. bool returnByReference = false;
  2553. CHqlBoundTarget target;
  2554. OwnedHqlExpr returnValue;
  2555. switch (type->getTypeCode())
  2556. {
  2557. case type_varstring:
  2558. case type_varunicode:
  2559. if (type->getSize() == UNKNOWN_LENGTH)
  2560. break;
  2561. //fall through
  2562. case type_qstring:
  2563. case type_string:
  2564. case type_data:
  2565. case type_unicode:
  2566. case type_utf8:
  2567. case type_dictionary:
  2568. case type_table:
  2569. case type_groupedtable:
  2570. if (!hasStreamedModifier(type))
  2571. {
  2572. initBoundStringTarget(target, type, "__lenResult", "__result");
  2573. returnByReference = true;
  2574. }
  2575. break;
  2576. case type_row:
  2577. if (!hasLinkCountedModifier(type))
  2578. {
  2579. initBoundStringTarget(target, type, "__lenResult", "__result");
  2580. returnByReference = true;
  2581. }
  2582. break;
  2583. case type_transform:
  2584. {
  2585. OwnedHqlExpr dataset = createDataset(no_anon, LINK(::queryRecord(type)));
  2586. BoundRow * row = bindSelf(ctx, dataset, "__self");
  2587. target.expr.set(row->querySelector());
  2588. returnByReference = true;
  2589. //A transform also returns the size that was generated (which will be bound to a local variable)
  2590. returnValue.setown(getRecordSize(row->querySelector()));
  2591. break;
  2592. }
  2593. case type_set:
  2594. target.isAll.setown(createVariable("__isAllResult", makeBoolType()));
  2595. target.length.setown(createVariable("__lenResult", LINK(sizetType)));
  2596. target.expr.setown(createVariable("__result", makeReferenceModifier(LINK(type))));
  2597. returnByReference = true;
  2598. break;
  2599. }
  2600. if (returnByReference)
  2601. {
  2602. buildExprAssign(ctx, target, value);
  2603. if (returnValue)
  2604. buildReturn(ctx, returnValue);
  2605. }
  2606. else
  2607. buildReturn(ctx, value, type);
  2608. }
  2609. //MORE: Should have a generalized doBuildFunctionHeader(ctx, name, retType, HqlExprArray & parameters)
  2610. // for when we generate functions for aliases
  2611. void HqlCppTranslator::doBuildBoolFunction(BuildCtx & ctx, const char * name, bool value)
  2612. {
  2613. StringBuffer s;
  2614. s.append("virtual bool ").append(name).append("() { return ").append(TF[value]).append("; }");
  2615. ctx.addQuoted(s);
  2616. }
  2617. void HqlCppTranslator::doBuildDataFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2618. {
  2619. doBuildFunction(ctx, unknownDataType, name, value);
  2620. }
  2621. void HqlCppTranslator::doBuildStringFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2622. {
  2623. doBuildFunction(ctx, unknownStringType, name, value);
  2624. }
  2625. void HqlCppTranslator::doBuildVarStringFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2626. {
  2627. StringBuffer s;
  2628. BuildCtx funcctx(ctx);
  2629. funcctx.addQuotedCompound(s.append("virtual const char * ").append(name).append("()"));
  2630. if (value)
  2631. buildReturn(funcctx, value, constUnknownVarStringType);
  2632. else
  2633. funcctx.addReturn(queryQuotedNullExpr());
  2634. }
  2635. void HqlCppTranslator::doBuildBoolFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2636. {
  2637. doBuildFunction(ctx, queryBoolType(), name, value);
  2638. }
  2639. void HqlCppTranslator::doBuildUnsignedFunction(BuildCtx & ctx, const char * name, unsigned value)
  2640. {
  2641. StringBuffer s;
  2642. s.append("virtual unsigned ").append(name).append("() { return ").append(value).append("; }");
  2643. ctx.addQuoted(s);
  2644. }
  2645. void HqlCppTranslator::doBuildSizetFunction(BuildCtx & ctx, const char * name, size32_t value)
  2646. {
  2647. StringBuffer s;
  2648. s.append("virtual size32_t ").append(name).append("() { return ").append(value).append("; }");
  2649. ctx.addQuoted(s);
  2650. }
  2651. void HqlCppTranslator::doBuildUnsignedFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2652. {
  2653. doBuildFunction(ctx, unsignedType, name, value);
  2654. }
  2655. void HqlCppTranslator::doBuildDoubleFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2656. {
  2657. Owned<ITypeInfo> type = makeRealType(8);
  2658. doBuildFunction(ctx, doubleType, name, value);
  2659. }
  2660. void HqlCppTranslator::doBuildUnsigned64Function(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2661. {
  2662. Owned<ITypeInfo> type = makeIntType(8, false);
  2663. doBuildFunction(ctx, type, name, value);
  2664. }
  2665. void HqlCppTranslator::doBuildUnsignedFunction(BuildCtx & ctx, const char * name, const char * value)
  2666. {
  2667. if (value)
  2668. {
  2669. StringBuffer s;
  2670. s.append("virtual unsigned ").append(name).append("() { return ").append(value).append("; }");
  2671. ctx.addQuoted(s);
  2672. }
  2673. }
  2674. void HqlCppTranslator::doBuildSignedFunction(BuildCtx & ctx, const char * name, IHqlExpression * value)
  2675. {
  2676. doBuildFunction(ctx, signedType, name, value);
  2677. }
  2678. void HqlCppTranslator::doBuildFunction(BuildCtx & ctx, ITypeInfo * type, const char * name, IHqlExpression * value)
  2679. {
  2680. if (value)
  2681. {
  2682. LinkedHqlExpr cseValue = value;
  2683. if (options.spotCSE)
  2684. cseValue.setown(spotScalarCSE(cseValue));
  2685. BuildCtx funcctx(ctx);
  2686. if (false)
  2687. {
  2688. HqlExprArray parameters;
  2689. OwnedHqlExpr entrypoint = createAttribute(entrypointAtom, createConstant(name));
  2690. OwnedHqlExpr body = createValue(no_null, LINK(type), LINK(entrypoint));
  2691. OwnedHqlExpr formals = createSortList(parameters);
  2692. OwnedHqlExpr attrs = createAttribute(virtualAtom);
  2693. OwnedHqlExpr function = createFunctionDefinition(NULL, LINK(body), LINK(formals), NULL, LINK(attrs));
  2694. funcctx.addFunction(function);
  2695. }
  2696. else
  2697. {
  2698. StringBuffer s, returnParameters;
  2699. s.append("virtual ");
  2700. generateFunctionReturnType(s, returnParameters, type, NULL, options.targetCompiler);
  2701. s.append(" ").append(name).append("(").append(returnParameters).append(")");
  2702. funcctx.addQuotedCompound(s);
  2703. }
  2704. doBuildFunctionReturn(funcctx, type, cseValue);
  2705. }
  2706. }
  2707. void HqlCppTranslator::addFilenameConstructorParameter(ActivityInstance & instance, const char * name, IHqlExpression * expr)
  2708. {
  2709. OwnedHqlExpr folded = foldHqlExpression(expr);
  2710. instance.addConstructorParameter(folded);
  2711. noteFilename(instance, name, folded, false);
  2712. }
  2713. void HqlCppTranslator::buildFilenameFunction(ActivityInstance & instance, BuildCtx & classctx, const char * name, IHqlExpression * expr, bool isDynamic)
  2714. {
  2715. OwnedHqlExpr folded = foldHqlExpression(expr);
  2716. doBuildVarStringFunction(classctx, name, folded);
  2717. noteFilename(instance, name, folded, isDynamic);
  2718. }
  2719. void HqlCppTranslator::noteFilename(ActivityInstance & instance, const char * name, IHqlExpression * expr, bool isDynamic)
  2720. {
  2721. if (options.addFilesnamesToGraph)
  2722. {
  2723. StringBuffer propName;
  2724. const char * propNameBase = name;
  2725. if (memicmp(propNameBase, "get", 3) == 0)
  2726. propNameBase += 3;
  2727. else if (memicmp(propNameBase, "query", 3) == 0)
  2728. propNameBase += 5;
  2729. propName.append("_").append((char)tolower(*propNameBase)).append(propNameBase+1);
  2730. OwnedHqlExpr folded = foldHqlExpression(expr);
  2731. if (folded)
  2732. {
  2733. if (!folded->queryValue())
  2734. {
  2735. if (!isDynamic && !options.allowVariableRoxieFilenames && targetRoxie())
  2736. {
  2737. StringBuffer x;
  2738. folded->toString(x);
  2739. throwError1(HQLERR_RoxieExpectedConstantFilename, x.str());
  2740. }
  2741. }
  2742. else
  2743. {
  2744. StringBuffer propValue;
  2745. folded->queryValue()->getStringValue(propValue);
  2746. instance.addAttribute(propName, propValue);
  2747. }
  2748. }
  2749. if (isDynamic)
  2750. {
  2751. unsigned len = propName.length();
  2752. if ((len > 4) && (memicmp(propName.str() + len-4, "name", 4) == 0))
  2753. propName.setLength(len-4);
  2754. propName.append("_dynamic");
  2755. instance.addAttributeBool(propName.str(), true);
  2756. }
  2757. }
  2758. }
  2759. void HqlCppTranslator::buildRefFilenameFunction(ActivityInstance & instance, BuildCtx & classctx, const char * name, IHqlExpression * expr)
  2760. {
  2761. IHqlExpression * table = queryPhysicalRootTable(expr);
  2762. IHqlExpression * filename = NULL;
  2763. if (table)
  2764. {
  2765. switch (table->getOperator())
  2766. {
  2767. case no_keyindex:
  2768. filename = table->queryChild(2);
  2769. break;
  2770. case no_newkeyindex:
  2771. filename = table->queryChild(3);
  2772. break;
  2773. case no_table:
  2774. filename = table->queryChild(0);
  2775. break;
  2776. }
  2777. }
  2778. buildFilenameFunction(instance, classctx, name, filename, hasDynamicFilename(table));
  2779. }
  2780. void HqlCppTranslator::buildConnectInputOutput(BuildCtx & ctx, ActivityInstance * instance, ABoundActivity * table, unsigned outputIndex, unsigned inputIndex, const char * label, bool nWay)
  2781. {
  2782. #ifdef _GATHER_USAGE_STATS
  2783. activityCounts[table->queryActivityKind()][instance->kind]++;
  2784. #endif
  2785. outputIndex = table->nextOutputCount();
  2786. logGraphEdge(instance->querySubgraphNode(), table->queryActivityId(), instance->activityId, outputIndex, inputIndex, label, nWay);
  2787. }
  2788. void HqlCppTranslator::buildInstancePrefix(ActivityInstance * instance)
  2789. {
  2790. instance->buildPrefix();
  2791. activeActivities.append(*instance->getBoundActivity());
  2792. }
  2793. void HqlCppTranslator::buildInstanceSuffix(ActivityInstance * instance)
  2794. {
  2795. instance->buildMetaMember();
  2796. instance->buildSuffix();
  2797. activeActivities.pop();
  2798. }
  2799. IHqlExpression * HqlCppTranslator::getRecordSize(IHqlExpression * dataset)
  2800. {
  2801. IHqlExpression * ds = dataset->queryNormalizedSelector();
  2802. return createValue(no_sizeof, makeIntType(4, false), ensureActiveRow(ds));
  2803. }
  2804. /* In parms: not linked */
  2805. void HqlCppTranslator::getRecordSize(BuildCtx & ctx, IHqlExpression * dataset, CHqlBoundExpr & bound)
  2806. {
  2807. OwnedHqlExpr size = getRecordSize(dataset);
  2808. buildExpr(ctx, size, bound);
  2809. }
  2810. unsigned HqlCppTranslator::getMaxRecordSize(IHqlExpression * record)
  2811. {
  2812. ColumnToOffsetMap * map = queryRecordOffsetMap(record);
  2813. if (!map)
  2814. return 0;
  2815. return map->getMaxSize();
  2816. }
  2817. unsigned HqlCppTranslator::getCsvMaxLength(IHqlExpression * csvAttr)
  2818. {
  2819. if (options.testIgnoreMaxLength)
  2820. return 1;
  2821. HqlExprArray attrs;
  2822. if (csvAttr)
  2823. {
  2824. ForEachChild(idx, csvAttr)
  2825. csvAttr->queryChild(idx)->unwindList(attrs, no_comma);
  2826. }
  2827. IHqlExpression * maxLength = queryAttribute(maxLengthAtom, attrs);
  2828. if (maxLength)
  2829. return (unsigned)getIntValue(maxLength->queryChild(0), 0);
  2830. return MAX_CSV_RECORD_SIZE;
  2831. }
  2832. bool HqlCppTranslator::isFixedWidthDataset(IHqlExpression * dataset)
  2833. {
  2834. IHqlExpression * record = dataset->queryRecord();
  2835. return queryRecordOffsetMap(record)->isFixedWidth();
  2836. }
  2837. void HqlCppTranslator::createAccessFunctions(StringBuffer & helperFunc, BuildCtx & ctx, unsigned prio, const char * interfaceName, const char * object)
  2838. {
  2839. helperFunc.append("q").append(object);
  2840. StringBuffer s;
  2841. s.clear().append(interfaceName).append(" & ").append(helperFunc).append("() { ");
  2842. s.append("return ").append(object).append("; ");
  2843. s.append("}");
  2844. if (prio)
  2845. ctx.setNextPriority(prio);
  2846. ctx.addQuoted(s);
  2847. s.clear().append("extern ").append(interfaceName).append(" & ").append(helperFunc).append("();");
  2848. BuildCtx protoctx(*code, mainprototypesAtom);
  2849. protoctx.addQuoted(s);
  2850. }
  2851. void HqlCppTranslator::ensureRowAllocator(StringBuffer & allocatorName, BuildCtx & ctx, IHqlExpression * record, IHqlExpression * activityId)
  2852. {
  2853. OwnedHqlExpr marker = createAttribute(rowAllocatorMarkerAtom, LINK(record->queryBody()), LINK(activityId));
  2854. HqlExprAssociation * match = ctx.queryMatchExpr(marker);
  2855. if (match)
  2856. {
  2857. generateExprCpp(allocatorName, match->queryExpr());
  2858. return;
  2859. }
  2860. StringBuffer uid;
  2861. getUniqueId(uid.append("alloc"));
  2862. BuildCtx subctx(ctx);
  2863. BuildCtx * declarectx = &subctx;
  2864. BuildCtx * callctx = &subctx;
  2865. if (!getInvariantMemberContext(ctx, &declarectx, &callctx, true, false))
  2866. {
  2867. //The following will not currently work because not all compound statements are correctly marked as
  2868. //complete/incomplete
  2869. //subctx.selectOutermostScope();
  2870. }
  2871. StringBuffer s;
  2872. s.append("Owned<IEngineRowAllocator> ").append(uid).append(";");
  2873. declarectx->addQuoted(s);
  2874. StringBuffer decl;
  2875. s.clear().append(uid).append(".setown(ctx->getRowAllocator(&");
  2876. buildMetaForRecord(s, record);
  2877. s.append(",");
  2878. generateExprCpp(s, activityId).append(")");
  2879. s.append(");");
  2880. callctx->addQuoted(s);
  2881. OwnedHqlExpr value = createVariable(uid.str(), makeBoolType());
  2882. declarectx->associateExpr(marker, value);
  2883. allocatorName.append(uid);
  2884. }
  2885. IHqlExpression * HqlCppTranslator::createRowAllocator(BuildCtx & ctx, IHqlExpression * record)
  2886. {
  2887. StringBuffer allocatorName;
  2888. OwnedHqlExpr curActivityId = getCurrentActivityId(ctx);
  2889. ensureRowAllocator(allocatorName, ctx, record, curActivityId);
  2890. return createQuoted(allocatorName, makeBoolType());
  2891. }
  2892. void HqlCppTranslator::buildMetaSerializerClass(BuildCtx & ctx, IHqlExpression * record, const char * serializerName, IAtom * serializeForm)
  2893. {
  2894. StringBuffer s;
  2895. GlobalClassBuilder serializer(*this, ctx, serializerName, "COutputRowSerializer", "IOutputRowSerializer");
  2896. serializer.buildClass(RowMetaPrio);
  2897. serializer.setIncomplete(true);
  2898. BuildCtx & classctx = serializer.classctx;
  2899. s.clear().append("inline ").append(serializerName).append("(unsigned _activityId) : COutputRowSerializer(_activityId) {}");
  2900. classctx.addQuoted(s);
  2901. OwnedHqlExpr id = createVariable("activityId", LINK(sizetType));
  2902. serializer.classctx.associateExpr(queryActivityIdMarker(), id);
  2903. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  2904. {
  2905. BuildCtx serializectx(serializer.startctx);
  2906. serializectx.addQuotedCompound("virtual void serialize(IRowSerializerTarget & out, const byte * self)");
  2907. OwnedHqlExpr helper = createVariable("out", makeBoolType());
  2908. BoundRow * row = bindTableCursor(serializectx, dataset, "self");
  2909. OwnedHqlExpr size = getRecordSize(row->querySelector());
  2910. CHqlBoundExpr boundSize;
  2911. buildExpr(serializectx, size, boundSize);
  2912. if (recordRequiresSerialization(record, serializeForm))
  2913. {
  2914. Owned<IReferenceSelector> selector = buildActiveRow(serializectx, row->querySelector());
  2915. selector->buildSerialize(serializectx, helper, serializeForm);
  2916. }
  2917. else
  2918. {
  2919. HqlExprArray args;
  2920. args.append(*LINK(helper));
  2921. args.append(*LINK(boundSize.expr));
  2922. args.append(*LINK(row->queryBound()));
  2923. OwnedHqlExpr call = bindTranslatedFunctionCall(serializerPutId, args);
  2924. serializectx.addExpr(call);
  2925. }
  2926. }
  2927. serializer.setIncomplete(false);
  2928. serializer.completeClass(RowMetaPrio);
  2929. }
  2930. void HqlCppTranslator::buildMetaDeserializerClass(BuildCtx & ctx, IHqlExpression * record, const char * deserializerName, IAtom * serializeForm)
  2931. {
  2932. StringBuffer s;
  2933. GlobalClassBuilder deserializer(*this, ctx, deserializerName, "COutputRowDeserializer", "IOutputRowDeserializer");
  2934. deserializer.buildClass(RowMetaPrio);
  2935. deserializer.setIncomplete(true);
  2936. BuildCtx & classctx = deserializer.classctx;
  2937. s.clear().append("inline ").append(deserializerName).append("(unsigned _activityId) : COutputRowDeserializer(_activityId) {}");
  2938. classctx.addQuoted(s);
  2939. OwnedHqlExpr id = createVariable("activityId", LINK(sizetType));
  2940. deserializer.classctx.associateExpr(queryActivityIdMarker(), id);
  2941. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  2942. {
  2943. BuildCtx deserializectx(deserializer.startctx);
  2944. deserializectx.addQuotedCompound("virtual size32_t deserialize(ARowBuilder & crSelf, IRowDeserializerSource & in)");
  2945. BoundRow * row = bindSelf(deserializectx, dataset, "crSelf");
  2946. ensureRowAllocated(deserializectx, "crSelf");
  2947. OwnedHqlExpr helper = createVariable("in", makeBoolType());
  2948. Owned<IReferenceSelector> selector = buildActiveRow(deserializectx, row->querySelector());
  2949. selector->buildDeserialize(deserializectx, helper, serializeForm);
  2950. buildReturnRecordSize(deserializectx, row);
  2951. }
  2952. deserializer.setIncomplete(false);
  2953. deserializer.completeClass(RowMetaPrio);
  2954. }
  2955. bool HqlCppTranslator::buildMetaPrefetcherClass(BuildCtx & ctx, IHqlExpression * record, const char * prefetcherName)
  2956. {
  2957. StringBuffer s;
  2958. GlobalClassBuilder prefetcher(*this, ctx, prefetcherName, "CSourceRowPrefetcher", NULL);
  2959. prefetcher.buildClass(RowMetaPrio);
  2960. prefetcher.setIncomplete(true);
  2961. BuildCtx & classctx = prefetcher.classctx;
  2962. s.clear().append("inline ").append(prefetcherName).append("(unsigned _activityId) : CSourceRowPrefetcher(_activityId) {}");
  2963. classctx.addQuoted(s);
  2964. OwnedHqlExpr id = createVariable("activityId", LINK(sizetType));
  2965. prefetcher.classctx.associateExpr(queryActivityIdMarker(), id);
  2966. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  2967. bool ok;
  2968. {
  2969. BuildCtx prefetchctx(prefetcher.startctx);
  2970. IHqlStmt * stmt = prefetchctx.addQuotedCompound("virtual void readAhead(IRowDeserializerSource & in)");
  2971. OwnedHqlExpr helper = createVariable("in", makeBoolType());
  2972. ok = queryRecordOffsetMap(record)->buildReadAhead(*this, prefetchctx, helper);
  2973. }
  2974. if (ok)
  2975. {
  2976. prefetcher.setIncomplete(false);
  2977. prefetcher.completeClass(RowMetaPrio);
  2978. }
  2979. else
  2980. prefetcher.setIncluded(false);
  2981. return ok;
  2982. }
  2983. IHqlExpression * HqlCppTranslator::getRtlFieldKey(IHqlExpression * expr, IHqlExpression * rowRecord)
  2984. {
  2985. /*
  2986. Most field information is context independent - which make life much easier, there are a few exceptions though:
  2987. type_bitfield. The offset within the bitfield, and whether the bitfield is the last in the block depend on the other adjacent bitfields.
  2988. type_alien. Because it can refer to self in the parameters to the type definition it is dependent on the containing record
  2989. no_ifblock: Again because it references no_self, it is context dependent.
  2990. Theoretically with an inline record definition for a field it might be possible to make an ifblock dependent on something other than the most
  2991. immediate parent record, but it would be extremely pathological, and probably wouldn't work in lots of other ways.
  2992. */
  2993. bool contextDependent = false;
  2994. switch (expr->getOperator())
  2995. {
  2996. case no_field:
  2997. switch (expr->queryType()->getTypeCode())
  2998. {
  2999. case type_bitfield:
  3000. {
  3001. ColumnToOffsetMap * map = queryRecordOffsetMap(rowRecord);
  3002. AColumnInfo * root = map->queryRootColumn();
  3003. CBitfieldInfo * resolved = static_cast<CBitfieldInfo *>(root->lookupColumn(expr));
  3004. assertex(resolved);
  3005. unsigned offset = resolved->queryBitfieldOffset();
  3006. bool isLastBitfield = resolved->queryIsLastBitfield();
  3007. Linked<ITypeInfo> fieldType = expr->queryType();
  3008. fieldType.setown(makeAttributeModifier(LINK(fieldType), createAttribute(bitfieldOffsetAtom, getSizetConstant(offset))));
  3009. if (isLastBitfield)
  3010. fieldType.setown(makeAttributeModifier(LINK(fieldType), createAttribute(isLastBitfieldAtom)));
  3011. HqlExprArray args;
  3012. unwindChildren(args, expr);
  3013. return createField(expr->queryId(), LINK(fieldType), args);
  3014. }
  3015. break;
  3016. case type_alien:
  3017. //actually too strict - some alien data types are not context dependent.
  3018. contextDependent = true;
  3019. break;
  3020. }
  3021. break;
  3022. case no_ifblock:
  3023. contextDependent = true;
  3024. break;
  3025. }
  3026. if (contextDependent)
  3027. return createAttribute(rtlFieldKeyMarkerAtom, LINK(expr), LINK(rowRecord));
  3028. return LINK(expr);
  3029. }
  3030. unsigned HqlCppTranslator::buildRtlField(StringBuffer * instanceName, IHqlExpression * fieldKey)
  3031. {
  3032. BuildCtx declarectx(*code, declareAtom);
  3033. HqlExprAssociation * match = declarectx.queryMatchExpr(fieldKey);
  3034. if (match)
  3035. {
  3036. IHqlExpression * mapped = match->queryExpr();
  3037. if (instanceName)
  3038. mapped->queryChild(0)->toString(*instanceName);
  3039. return (unsigned)getIntValue(mapped->queryChild(1));
  3040. }
  3041. IHqlExpression * field = fieldKey;
  3042. IHqlExpression * rowRecord = NULL;
  3043. if (field->isAttribute())
  3044. {
  3045. field = fieldKey->queryChild(0);
  3046. rowRecord = fieldKey->queryChild(1);
  3047. }
  3048. StringBuffer name;
  3049. unsigned typeFlags = 0;
  3050. if (field->getOperator() == no_ifblock)
  3051. {
  3052. typeFlags = buildRtlIfBlockField(name, field, rowRecord);
  3053. }
  3054. else
  3055. {
  3056. Linked<ITypeInfo> fieldType = field->queryType();
  3057. switch (field->queryType()->getTypeCode())
  3058. {
  3059. case type_alien:
  3060. //MORE:::
  3061. break;
  3062. case type_row:
  3063. //Backward compatibility - should revisit
  3064. fieldType.set(fieldType->queryChildType());
  3065. break;
  3066. }
  3067. StringBuffer typeName;
  3068. typeFlags = buildRtlType(typeName, fieldType);
  3069. StringBuffer lowerName;
  3070. lowerName.append(field->queryName()).toLowerCase();
  3071. if (options.debugGeneratedCpp)
  3072. {
  3073. name.append("rf_");
  3074. convertToValidLabel(name, lowerName.str(), lowerName.length());
  3075. name.append("_").append(++nextFieldId);
  3076. }
  3077. else
  3078. name.append("rf").append(++nextFieldId);
  3079. StringBuffer xpathName, xpathItem;
  3080. switch (fieldType->getTypeCode())
  3081. {
  3082. case type_set:
  3083. extractXmlName(xpathName, &xpathItem, NULL, field, "Item", false);
  3084. break;
  3085. case type_dictionary:
  3086. case type_table:
  3087. case type_groupedtable:
  3088. extractXmlName(xpathName, &xpathItem, NULL, field, "Row", false);
  3089. //Following should be in the type processing, and the type should include the information
  3090. if (field->hasAttribute(sizeAtom) || field->hasAttribute(countAtom))
  3091. typeFlags |= RFTMinvalidxml;
  3092. break;
  3093. default:
  3094. extractXmlName(xpathName, NULL, NULL, field, NULL, false);
  3095. break;
  3096. }
  3097. if (xpathName.length() && (xpathName.charAt(0) == '@'))
  3098. typeFlags |= RFTMhasxmlattr;
  3099. //Format of the xpath field is (nested-item 0x01 repeated-item)
  3100. StringBuffer xpathFull, xpathCppText;
  3101. xpathFull.append(xpathName);
  3102. if (xpathItem.length())
  3103. xpathFull.append(xpathCompoundSeparatorChar).append(xpathItem);
  3104. if (strcmp(lowerName, xpathFull) != 0)
  3105. appendStringAsQuotedCPP(xpathCppText, xpathFull.length(), xpathFull.str(), false);
  3106. else
  3107. xpathCppText.append("NULL");
  3108. StringBuffer definition;
  3109. definition.append("const RtlFieldStrInfo ").append(name).append("(\"").append(lowerName).append("\",").append(xpathCppText).append(",&").append(typeName).append(");");
  3110. BuildCtx fieldctx(declarectx);
  3111. fieldctx.setNextPriority(TypeInfoPrio);
  3112. fieldctx.addQuoted(definition);
  3113. name.insert(0, "&");
  3114. }
  3115. OwnedHqlExpr nameExpr = createVariable(name.str(), makeBoolType());
  3116. OwnedHqlExpr mapped = createAttribute(fieldAtom, LINK(nameExpr), getSizetConstant(typeFlags));
  3117. declarectx.associateExpr(fieldKey, mapped);
  3118. if (instanceName)
  3119. instanceName->append(name);
  3120. return typeFlags;
  3121. }
  3122. unsigned HqlCppTranslator::buildRtlIfBlockField(StringBuffer & instanceName, IHqlExpression * ifblock, IHqlExpression * rowRecord)
  3123. {
  3124. StringBuffer typeName, s;
  3125. BuildCtx declarectx(*code, declareAtom);
  3126. //First generate a pseudo type entry for an ifblock.
  3127. unsigned fieldType = type_ifblock|RFTMcontainsifblock;
  3128. {
  3129. unsigned length = 0;
  3130. StringBuffer childTypeName;
  3131. unsigned childType = buildRtlRecordFields(childTypeName, ifblock->queryChild(1), rowRecord);
  3132. fieldType |= (childType & (RFTMcontainsunknown|RFTMinvalidxml|RFTMhasxmlattr));
  3133. StringBuffer className;
  3134. typeName.append("ty").append(++nextTypeId);
  3135. className.append("tyc").append(nextFieldId);
  3136. //The ifblock needs a unique instance of the class to evaluate the test
  3137. BuildCtx fieldclassctx(declarectx);
  3138. fieldclassctx.setNextPriority(TypeInfoPrio);
  3139. fieldclassctx.addQuotedCompound(s.clear().append("struct ").append(className).append(" : public RtlIfBlockTypeInfo"), ";");
  3140. fieldclassctx.addQuoted(s.clear().append(className).append("() : RtlIfBlockTypeInfo(0x").appendf("%x", fieldType).append(",").append(0).append(",").append(childTypeName).append(") {}"));
  3141. OwnedHqlExpr anon = createDataset(no_anon, LINK(rowRecord));
  3142. BuildCtx condctx(fieldclassctx);
  3143. condctx.addQuotedCompound("virtual bool getCondition(const byte * self) const");
  3144. BoundRow * self = bindTableCursor(condctx, anon, "self");
  3145. OwnedHqlExpr cond = self->bindToRow(ifblock->queryChild(0), querySelfReference());
  3146. buildReturn(condctx, cond);
  3147. s.clear().append("const ").append(className).append(" ").append(typeName).append(";");
  3148. BuildCtx typectx(declarectx);
  3149. typectx.setNextPriority(TypeInfoPrio);
  3150. typectx.addQuoted(s);
  3151. }
  3152. StringBuffer name;
  3153. name.append("rf").append(++nextFieldId);
  3154. //Now generate a pseudo field for the ifblock
  3155. s.clear().append("const RtlFieldStrInfo ").append(name).append("(NULL, NULL,&").append(typeName).append(");");
  3156. BuildCtx fieldctx(declarectx);
  3157. fieldctx.setNextPriority(TypeInfoPrio);
  3158. fieldctx.addQuoted(s);
  3159. instanceName.append("&").append(name);
  3160. return fieldType;
  3161. }
  3162. unsigned HqlCppTranslator::expandRtlRecordFields(StringBuffer & fieldListText, IHqlExpression * record, IHqlExpression * rowRecord)
  3163. {
  3164. unsigned fieldType = 0;
  3165. ForEachChild(i, record)
  3166. {
  3167. IHqlExpression * cur = record->queryChild(i);
  3168. StringBuffer next;
  3169. unsigned childType = 0;
  3170. switch (cur->getOperator())
  3171. {
  3172. case no_field:
  3173. case no_ifblock:
  3174. {
  3175. OwnedHqlExpr fieldKey = getRtlFieldKey(cur, rowRecord);
  3176. childType = buildRtlField(&fieldListText, fieldKey);
  3177. fieldListText.append(",");
  3178. break;
  3179. }
  3180. case no_record:
  3181. childType = expandRtlRecordFields(fieldListText, cur, rowRecord);
  3182. break;
  3183. }
  3184. fieldType |= (childType & (RFTMcontainsunknown|RFTMinvalidxml|RFTMhasxmlattr));
  3185. }
  3186. return fieldType;
  3187. }
  3188. unsigned HqlCppTranslator::buildRtlRecordFields(StringBuffer & instanceName, IHqlExpression * record, IHqlExpression * rowRecord)
  3189. {
  3190. StringBuffer fieldListText;
  3191. unsigned fieldFlags = expandRtlRecordFields(fieldListText, record, rowRecord);
  3192. StringBuffer name;
  3193. name.append("tl").append(++nextTypeId);
  3194. StringBuffer s;
  3195. s.append("const RtlFieldInfo * const ").append(name).append("[] = { ").append(fieldListText).append(" 0 };");
  3196. BuildCtx listctx(*code, declareAtom);
  3197. listctx.setNextPriority(TypeInfoPrio);
  3198. listctx.addQuoted(s);
  3199. instanceName.append(name);
  3200. return fieldFlags;
  3201. }
  3202. unsigned HqlCppTranslator::getRtlFieldInfo(StringBuffer & fieldInfoName, IHqlExpression * field, IHqlExpression * rowRecord)
  3203. {
  3204. OwnedHqlExpr fieldKey = getRtlFieldKey(field, rowRecord);
  3205. return buildRtlField(&fieldInfoName, fieldKey);
  3206. }
  3207. unsigned HqlCppTranslator::buildRtlType(StringBuffer & instanceName, ITypeInfo * type)
  3208. {
  3209. assertex(type);
  3210. type_t tc = type->getTypeCode();
  3211. if (tc == type_record)
  3212. type = queryUnqualifiedType(type);
  3213. OwnedHqlExpr search = createVariable("t", LINK(type));
  3214. BuildCtx declarectx(*code, declareAtom);
  3215. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  3216. if (match)
  3217. {
  3218. IHqlExpression * value = match->queryExpr();
  3219. value->queryChild(0)->toString(instanceName);
  3220. return (unsigned)getIntValue(value->queryChild(1));
  3221. }
  3222. StringBuffer name, className, arguments;
  3223. if (options.debugGeneratedCpp)
  3224. {
  3225. StringBuffer ecl;
  3226. type->getECLType(ecl);
  3227. name.append("ty_");
  3228. convertToValidLabel(name, ecl.str(), ecl.length());
  3229. name.append("_").append(++nextTypeId);
  3230. }
  3231. else
  3232. name.append("ty").append(++nextTypeId);
  3233. unsigned fieldType= 0;
  3234. if (tc == type_alien)
  3235. {
  3236. ITypeInfo * physicalType = queryAlienType(type)->queryPhysicalType();
  3237. if (physicalType->getSize() != UNKNOWN_LENGTH)
  3238. {
  3239. //Don't use the generated class for xml generation since it will generate physical rather than logical
  3240. fieldType |= (RFTMalien|RFTMinvalidxml);
  3241. type = physicalType;
  3242. tc = type->getTypeCode();
  3243. }
  3244. else
  3245. {
  3246. fieldType |= RFTMunknownsize;
  3247. //can't work out the size of the field - to keep it as unknown for the moment.
  3248. //until the alien field type is supported
  3249. }
  3250. }
  3251. fieldType |= tc;
  3252. unsigned length = type->getSize();
  3253. if (length == UNKNOWN_LENGTH)
  3254. {
  3255. fieldType |= RFTMunknownsize;
  3256. length = 0;
  3257. }
  3258. unsigned childType = 0;
  3259. switch (tc)
  3260. {
  3261. case type_boolean:
  3262. className.append("RtlBoolTypeInfo");
  3263. break;
  3264. case type_real:
  3265. className.append("RtlRealTypeInfo");
  3266. break;
  3267. case type_date:
  3268. case type_enumerated:
  3269. case type_int:
  3270. className.append("RtlIntTypeInfo");
  3271. if (!type->isSigned())
  3272. fieldType |= RFTMunsigned;
  3273. break;
  3274. case type_swapint:
  3275. className.append("RtlSwapIntTypeInfo");
  3276. if (!type->isSigned())
  3277. fieldType |= RFTMunsigned;
  3278. break;
  3279. case type_packedint:
  3280. className.append("RtlPackedIntTypeInfo");
  3281. if (!type->isSigned())
  3282. fieldType |= RFTMunsigned;
  3283. break;
  3284. case type_decimal:
  3285. className.append("RtlDecimalTypeInfo");
  3286. if (!type->isSigned())
  3287. fieldType |= RFTMunsigned;
  3288. length = type->getDigits() | (type->getPrecision() << 16);
  3289. break;
  3290. case type_char:
  3291. className.append("RtlCharTypeInfo");
  3292. break;
  3293. case type_data:
  3294. className.append("RtlDataTypeInfo");
  3295. break;
  3296. case type_qstring:
  3297. className.append("RtlQStringTypeInfo");
  3298. length = type->getStringLen();
  3299. break;
  3300. case type_varstring:
  3301. className.append("RtlVarStringTypeInfo");
  3302. if (type->queryCharset() && type->queryCharset()->queryName()==ebcdicAtom)
  3303. fieldType |= RFTMebcdic;
  3304. length = type->getStringLen();
  3305. break;
  3306. case type_string:
  3307. className.append("RtlStringTypeInfo");
  3308. if (type->queryCharset() && type->queryCharset()->queryName()==ebcdicAtom)
  3309. fieldType |= RFTMebcdic;
  3310. break;
  3311. case type_bitfield:
  3312. {
  3313. className.append("RtlBitfieldTypeInfo");
  3314. unsigned size = type->getSize();
  3315. unsigned bitsize = type->getBitSize();
  3316. unsigned offset = (unsigned)getIntValue(queryAttributeChild(type, bitfieldOffsetAtom, 0),-1);
  3317. bool isLastBitfield = (queryAttribute(type, isLastBitfieldAtom) != NULL);
  3318. if (isLastBitfield)
  3319. fieldType |= RFTMislastbitfield;
  3320. if (!type->isSigned())
  3321. fieldType |= RFTMunsigned;
  3322. length = size | (bitsize << 8) | (offset << 16);
  3323. break;
  3324. }
  3325. case type_record:
  3326. {
  3327. IHqlExpression * record = ::queryRecord(type);
  3328. className.append("RtlRecordTypeInfo");
  3329. arguments.append(",");
  3330. childType = buildRtlRecordFields(arguments, record, record);
  3331. // fieldType |= (childType & RFTMcontainsifblock);
  3332. length = getMaxRecordSize(record);
  3333. if (!isFixedRecordSize(record))
  3334. fieldType |= RFTMunknownsize;
  3335. break;
  3336. }
  3337. case type_row:
  3338. {
  3339. className.clear().append("RtlRowTypeInfo");
  3340. arguments.append(",&");
  3341. childType = buildRtlType(arguments, ::queryRecordType(type));
  3342. // fieldType |= (childType & RFTMcontainsifblock);
  3343. if (hasLinkCountedModifier(type))
  3344. fieldType |= RFTMlinkcounted;
  3345. break;
  3346. }
  3347. case type_table:
  3348. case type_groupedtable:
  3349. {
  3350. className.clear().append("RtlDatasetTypeInfo");
  3351. arguments.append(",&");
  3352. childType = buildRtlType(arguments, ::queryRecordType(type));
  3353. if (hasLinkCountedModifier(type))
  3354. fieldType |= RFTMlinkcounted;
  3355. break;
  3356. }
  3357. case type_dictionary:
  3358. {
  3359. className.clear().append("RtlDictionaryTypeInfo");
  3360. arguments.append(",&");
  3361. childType = buildRtlType(arguments, ::queryRecordType(type));
  3362. if (hasLinkCountedModifier(type))
  3363. fieldType |= RFTMlinkcounted;
  3364. StringBuffer lookupHelperName;
  3365. buildDictionaryHashClass(::queryRecord(type), lookupHelperName);
  3366. arguments.append(",&").append(lookupHelperName.str());
  3367. break;
  3368. }
  3369. case type_set:
  3370. className.clear().append("RtlSetTypeInfo");
  3371. arguments.append(",&");
  3372. childType = buildRtlType(arguments, type->queryChildType());
  3373. break;
  3374. case type_unicode:
  3375. className.clear().append("RtlUnicodeTypeInfo");
  3376. arguments.append(", \"").append(type->queryLocale()).append("\"").toLowerCase();
  3377. length = type->getStringLen();
  3378. break;
  3379. case type_varunicode:
  3380. className.clear().append("RtlVarUnicodeTypeInfo");
  3381. arguments.append(", \"").append(type->queryLocale()).append("\"").toLowerCase();
  3382. length = type->getStringLen();
  3383. break;
  3384. case type_utf8:
  3385. className.clear().append("RtlUtf8TypeInfo");
  3386. arguments.append(", \"").append(type->queryLocale()).append("\"").toLowerCase();
  3387. length = type->getStringLen();
  3388. break;
  3389. case type_blob:
  3390. case type_pointer:
  3391. case type_class:
  3392. case type_array:
  3393. case type_void:
  3394. case type_alien:
  3395. case type_none:
  3396. case type_any:
  3397. case type_pattern:
  3398. case type_rule:
  3399. case type_token:
  3400. case type_feature:
  3401. case type_event:
  3402. case type_null:
  3403. case type_scope:
  3404. case type_transform:
  3405. default:
  3406. className.append("RtlUnimplementedTypeInfo");
  3407. fieldType |= (RFTMcontainsunknown|RFTMinvalidxml);
  3408. break;
  3409. }
  3410. fieldType |= (childType & (RFTMcontainsunknown|RFTMinvalidxml|RFTMhasxmlattr));
  3411. StringBuffer definition;
  3412. definition.append("const ").append(className).append(" ").append(name).append("(0x").appendf("%x", fieldType).append(",").append(length).append(arguments).append(");");
  3413. BuildCtx typectx(declarectx);
  3414. typectx.setNextPriority(TypeInfoPrio);
  3415. typectx.addQuoted(definition);
  3416. OwnedHqlExpr nameExpr = createVariable(name.str(), makeVoidType());
  3417. OwnedHqlExpr mapped = createAttribute(fieldAtom, LINK(nameExpr), getSizetConstant(fieldType));
  3418. declarectx.associateExpr(search, mapped);
  3419. instanceName.append(name);
  3420. return fieldType;
  3421. }
  3422. void HqlCppTranslator::buildMetaInfo(MetaInstance & instance)
  3423. {
  3424. if (options.spanMultipleCpp)
  3425. {
  3426. StringBuffer queryFunctionName;
  3427. queryFunctionName.append("q").append(instance.instanceName).append("()");
  3428. instance.instanceObject.set(queryFunctionName);
  3429. }
  3430. BuildCtx declarectx(*code, declareAtom);
  3431. OwnedHqlExpr search = instance.getMetaUniqueKey();
  3432. // stop duplicate classes being generated.
  3433. // MORE: If this ever includes sorting/grouping, the dependence on a record will need to be revised
  3434. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  3435. if (match)
  3436. return;
  3437. bool savedContextAvailable = contextAvailable;
  3438. contextAvailable = false;
  3439. metas.append(*search.getLink());
  3440. StringBuffer s;
  3441. StringBuffer serializerName, deserializerName, prefetcherName, internalSerializerName, internalDeserializerName;
  3442. StringBuffer endText;
  3443. endText.append(" ").append(instance.instanceName).append(";");
  3444. BuildCtx metactx(declarectx);
  3445. IHqlExpression * record = instance.queryRecord();
  3446. ColumnToOffsetMap * map = queryRecordOffsetMap(record);
  3447. unsigned flags = MDFhasserialize; // we always generate a serialize since
  3448. bool useTypeForXML = false;
  3449. if (instance.isGrouped())
  3450. flags |= MDFgrouped;
  3451. if (map)
  3452. flags |= MDFhasxml;
  3453. if (record)
  3454. {
  3455. if (recordRequiresDestructor(record))
  3456. flags |= MDFneeddestruct;
  3457. if (recordRequiresSerialization(record, diskAtom))
  3458. flags |= MDFneedserializedisk;
  3459. if (recordRequiresSerialization(record, internalAtom))
  3460. flags |= MDFneedserializeinternal;
  3461. const unsigned serializeFlags = (flags & MDFneedserializemask);
  3462. if ((serializeFlags == MDFneedserializemask) && !recordSerializationDiffers(record, diskAtom, internalAtom))
  3463. flags |= MDFdiskmatchesinternal;
  3464. if (maxRecordSizeUsesDefault(record))
  3465. flags |= MDFunknownmaxlength;
  3466. useTypeForXML = true;
  3467. }
  3468. if (instance.isGrouped())
  3469. {
  3470. MetaInstance ungroupedMeta(*this, record, false);
  3471. buildMetaInfo(ungroupedMeta);
  3472. s.append("struct ").append(instance.metaName).append(" : public ").append(ungroupedMeta.metaName);
  3473. metactx.setNextPriority(RowMetaPrio);
  3474. metactx.addQuotedCompound(s, endText.str());
  3475. doBuildUnsignedFunction(metactx, "getMetaFlags", flags);
  3476. }
  3477. else
  3478. {
  3479. //Serialization classes need to be generated for all meta information - because they may be called by parent row classes
  3480. //however, the CFixedOutputMetaData base class contains a default implementation - reducing the required code.
  3481. if (map && (!map->isFixedWidth() || (flags & MDFneedserializemask)))
  3482. {
  3483. //Base class provides a default variable width implementation
  3484. if (flags & MDFneedserializedisk)
  3485. {
  3486. serializerName.append("s").append(instance.metaName);
  3487. buildMetaSerializerClass(declarectx, record, serializerName.str(), diskAtom);
  3488. }
  3489. bool needInternalSerializer = ((flags & MDFneedserializeinternal) && recordSerializationDiffers(record, diskAtom, internalAtom));
  3490. if (needInternalSerializer)
  3491. {
  3492. internalSerializerName.append("si").append(instance.metaName);
  3493. buildMetaSerializerClass(declarectx, record, internalSerializerName.str(), internalAtom);
  3494. }
  3495. //MORE:
  3496. //still generate a deserialize for the variable width case because it offers protection
  3497. //against accessing out of bounds data
  3498. deserializerName.append("d").append(instance.metaName);
  3499. buildMetaDeserializerClass(declarectx, record, deserializerName.str(), diskAtom);
  3500. if (needInternalSerializer)
  3501. {
  3502. internalDeserializerName.append("di").append(instance.metaName);
  3503. buildMetaDeserializerClass(declarectx, record, internalDeserializerName.str(), internalAtom);
  3504. }
  3505. //The base class implements prefetch using the serialized meta so no need to generate...
  3506. if (!(flags & MDFneedserializemask))
  3507. {
  3508. prefetcherName.append("p").append(instance.metaName);
  3509. if (!buildMetaPrefetcherClass(declarectx, record, prefetcherName))
  3510. prefetcherName.clear();
  3511. }
  3512. }
  3513. s.append("struct ").append(instance.metaName).append(" : public ");
  3514. if (!map)
  3515. s.append("CActionOutputMetaData");
  3516. else if (map->isFixedWidth())
  3517. s.append("CFixedOutputMetaData");
  3518. else
  3519. s.append("CVariableOutputMetaData");
  3520. metactx.setNextPriority(RowMetaPrio);
  3521. IHqlStmt * metaclass = metactx.addQuotedCompound(s, endText.str());
  3522. metaclass->setIncomplete(true);
  3523. if (map)
  3524. {
  3525. if (map->isFixedWidth())
  3526. {
  3527. unsigned fixedSize = map->getFixedRecordSize();
  3528. s.clear().append("inline ").append(instance.metaName).append("() : CFixedOutputMetaData(").append(fixedSize).append(") {}");
  3529. metactx.addQuoted(s);
  3530. }
  3531. else
  3532. {
  3533. unsigned minSize = getMinRecordSize(record);
  3534. unsigned maxLength = map->getMaxSize();
  3535. if (maxLength < minSize)
  3536. reportError(queryLocation(record), ECODETEXT(HQLERR_MaximumSizeLessThanMinimum_XY), maxLength, minSize);
  3537. #ifdef _DEBUG
  3538. //Paranoia check to ensure the two methods agree.
  3539. unsigned calcMinSize = map->getTotalMinimumSize();
  3540. assertex(minSize == calcMinSize);
  3541. #endif
  3542. //These use a CVariableOutputMetaData base class instead, and trade storage for number of virtuals
  3543. s.clear().append("inline ").append(instance.metaName).append("() : CVariableOutputMetaData(").append(minSize).append(") {}");
  3544. metactx.addQuoted(s);
  3545. if (options.testIgnoreMaxLength)
  3546. maxLength = minSize;
  3547. BuildCtx getctx(metactx);
  3548. s.clear().append("virtual size32_t getRecordSize(const void * data)");
  3549. getctx.addQuotedCompound(s);
  3550. s.clear().append("if (!data) return ").append(maxLength).append(";");
  3551. getctx.addQuoted(s.str());
  3552. getctx.addQuoted("const unsigned char * left = (const unsigned char *)data;");
  3553. OwnedHqlExpr selfDs = createDataset(no_null, LINK(instance.queryRecord()));
  3554. BoundRow * selfRow = bindTableCursorOrRow(getctx, selfDs, "left");
  3555. OwnedHqlExpr size = getRecordSize(selfRow->querySelector());
  3556. buildReturn(getctx, size);
  3557. }
  3558. assertex(!instance.isGrouped());
  3559. StringBuffer typeName;
  3560. unsigned recordTypeFlags = buildRtlType(typeName, record->queryType());
  3561. s.clear().append("virtual const RtlTypeInfo * queryTypeInfo() const { return &").append(typeName).append("; }");
  3562. metactx.addQuoted(s);
  3563. if (record->numChildren() != 0)
  3564. {
  3565. if (!useTypeForXML || (recordTypeFlags & (RFTMinvalidxml|RFTMhasxmlattr)))
  3566. {
  3567. OwnedHqlExpr anon = createDataset(no_anon, LINK(instance.queryRecord()));
  3568. buildXmlSerialize(metactx, anon, "toXML", true);
  3569. }
  3570. }
  3571. if (record)
  3572. generateMetaRecordSerialize(metactx, record, serializerName.str(), deserializerName.str(), internalSerializerName.str(), internalDeserializerName.str(), prefetcherName.str());
  3573. if (flags != (MDFhasserialize|MDFhasxml))
  3574. doBuildUnsignedFunction(metactx, "getMetaFlags", flags);
  3575. if (flags & MDFneedserializedisk)
  3576. {
  3577. OwnedHqlExpr serializedRecord = getSerializedForm(record, diskAtom);
  3578. MetaInstance serializedMeta(*this, serializedRecord, false);
  3579. buildMetaInfo(serializedMeta);
  3580. StringBuffer s;
  3581. s.append("virtual IOutputMetaData * querySerializedDiskMeta() { return &").append(serializedMeta.queryInstanceObject()).append("; }");
  3582. metactx.addQuoted(s);
  3583. }
  3584. }
  3585. metaclass->setIncomplete(false);
  3586. }
  3587. s.clear().append("extern \"C\" ECL_API IOutputMetaData * ").append(instance.metaFactoryName).append("() { ");
  3588. s.append(instance.instanceName).append(".Link(); ");
  3589. s.append("return &").append(instance.instanceName).append("; ");
  3590. s.append("}");
  3591. declarectx.setNextPriority(RowMetaPrio);
  3592. declarectx.addQuoted(s);
  3593. if (options.spanMultipleCpp)
  3594. {
  3595. StringBuffer temp;
  3596. createAccessFunctions(temp, declarectx, RowMetaPrio, "IOutputMetaData", instance.instanceName);
  3597. }
  3598. OwnedHqlExpr temp = createVariable(instance.metaName, makeVoidType());
  3599. declarectx.associateExpr(search, temp);
  3600. contextAvailable = savedContextAvailable;
  3601. }
  3602. class MetaMemberCallback
  3603. {
  3604. public:
  3605. MetaMemberCallback(HqlCppTranslator & _translator) : translator(_translator) {}
  3606. void callChildFunction(BuildCtx & ctx, IHqlExpression * selected)
  3607. {
  3608. MetaInstance childMeta(translator, selected->queryRecord(), false);
  3609. translator.buildMetaInfo(childMeta);
  3610. callChildFunction(ctx, selected, childMeta);
  3611. }
  3612. void walkRecord(BuildCtx & ctx, IHqlExpression * selector, IHqlExpression * record)
  3613. {
  3614. ForEachChild(i, record)
  3615. {
  3616. IHqlExpression * cur = record->queryChild(i);
  3617. switch (cur->getOperator())
  3618. {
  3619. case no_record:
  3620. walkRecord(ctx, selector, cur);
  3621. break;
  3622. case no_ifblock:
  3623. {
  3624. OwnedHqlExpr cond = replaceSelector(cur->queryChild(0), querySelfReference(), selector);
  3625. BuildCtx condctx(ctx);
  3626. translator.buildFilter(condctx, cond);
  3627. walkRecord(condctx, selector, cur->queryChild(1));
  3628. break;
  3629. }
  3630. case no_field:
  3631. {
  3632. ITypeInfo * type = cur->queryType();
  3633. switch (type->getTypeCode())
  3634. {
  3635. case type_alien:
  3636. //MORE: Allow for alien data types to have destructors.
  3637. break;
  3638. case type_row:
  3639. {
  3640. IHqlExpression * record = cur->queryRecord();
  3641. if (recordRequiresDestructor(record))
  3642. {
  3643. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  3644. callChildFunction(ctx, selected);
  3645. }
  3646. break;
  3647. }
  3648. case type_dictionary:
  3649. case type_table:
  3650. case type_groupedtable:
  3651. {
  3652. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  3653. IHqlExpression * record = cur->queryRecord();
  3654. if (cur->hasAttribute(_linkCounted_Atom))
  3655. {
  3656. //releaseRowset(ctx, count, rowset)
  3657. MetaInstance childMeta(translator, selected->queryRecord(), false);
  3658. translator.buildMetaInfo(childMeta);
  3659. processRowset(ctx, selected, childMeta);
  3660. }
  3661. else if (recordRequiresDestructor(record))
  3662. {
  3663. BuildCtx iterctx(ctx);
  3664. translator.buildDatasetIterate(iterctx, selected, false);
  3665. OwnedHqlExpr active = createRow(no_activerow, LINK(selected));
  3666. callChildFunction(iterctx, active);
  3667. }
  3668. break;
  3669. }
  3670. }
  3671. break;
  3672. }
  3673. }
  3674. }
  3675. }
  3676. protected:
  3677. virtual void callChildFunction(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta) = 0;
  3678. virtual void processRowset(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta) = 0;
  3679. protected:
  3680. HqlCppTranslator & translator;
  3681. };
  3682. class MetaDestructCallback : public MetaMemberCallback
  3683. {
  3684. public:
  3685. MetaDestructCallback(HqlCppTranslator & _translator) : MetaMemberCallback(_translator) {}
  3686. protected:
  3687. virtual void callChildFunction(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3688. {
  3689. HqlExprArray args;
  3690. args.append(*createQuoted(childMeta.queryInstanceObject(), makeBoolType()));
  3691. args.append(*LINK(selected));
  3692. translator.buildFunctionCall(ctx, destructMetaMemberId, args);
  3693. }
  3694. virtual void processRowset(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3695. {
  3696. HqlExprArray args;
  3697. args.append(*LINK(selected));
  3698. translator.buildFunctionCall(ctx, releaseRowsetId, args);
  3699. }
  3700. };
  3701. void HqlCppTranslator::doGenerateMetaDestruct(BuildCtx & ctx, IHqlExpression * selector, IHqlExpression * record)
  3702. {
  3703. MetaDestructCallback builder(*this);
  3704. builder.walkRecord(ctx, selector, record);
  3705. }
  3706. class MetaWalkIndirectCallback : public MetaMemberCallback
  3707. {
  3708. public:
  3709. MetaWalkIndirectCallback(HqlCppTranslator & _translator, IHqlExpression * _visitor)
  3710. : MetaMemberCallback(_translator), visitor(_visitor) {}
  3711. protected:
  3712. virtual void callChildFunction(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3713. {
  3714. HqlExprArray args;
  3715. args.append(*createQuoted(childMeta.queryInstanceObject(), makeBoolType()));
  3716. args.append(*LINK(selected));
  3717. args.append(*LINK(visitor));
  3718. translator.buildFunctionCall(ctx, walkIndirectMetaMemberId, args);
  3719. }
  3720. virtual void processRowset(BuildCtx & ctx, IHqlExpression * selected, MetaInstance & childMeta)
  3721. {
  3722. HqlExprArray args;
  3723. args.append(*LINK(visitor));
  3724. args.append(*LINK(selected));
  3725. translator.buildFunctionCall(ctx, IIndirectMemberVisitor_visitRowsetId, args);
  3726. }
  3727. protected:
  3728. LinkedHqlExpr visitor;
  3729. };
  3730. class MetaChildMetaCallback
  3731. {
  3732. public:
  3733. MetaChildMetaCallback(HqlCppTranslator & _translator, IHqlStmt * _switchStmt)
  3734. : translator(_translator), switchStmt(_switchStmt)
  3735. {
  3736. nextIndex = 0;
  3737. }
  3738. void walkRecord(BuildCtx & ctx, IHqlExpression * record)
  3739. {
  3740. ForEachChild(i, record)
  3741. {
  3742. IHqlExpression * cur = record->queryChild(i);
  3743. switch (cur->getOperator())
  3744. {
  3745. case no_record:
  3746. walkRecord(ctx, cur);
  3747. break;
  3748. case no_ifblock:
  3749. walkRecord(ctx, cur->queryChild(1));
  3750. break;
  3751. case no_field:
  3752. {
  3753. ITypeInfo * type = cur->queryType();
  3754. switch (type->getTypeCode())
  3755. {
  3756. case type_row:
  3757. walkRecord(ctx, queryRecord(cur));
  3758. break;
  3759. case type_dictionary:
  3760. case type_table:
  3761. case type_groupedtable:
  3762. {
  3763. IHqlExpression * record = cur->queryRecord()->queryBody();
  3764. if (!visited.contains(*record))
  3765. {
  3766. BuildCtx condctx(ctx);
  3767. OwnedHqlExpr branch = getSizetConstant(nextIndex++);
  3768. OwnedHqlExpr childMeta = translator.buildMetaParameter(record);
  3769. OwnedHqlExpr ret = createValue(no_address, makeBoolType(), LINK(childMeta));
  3770. condctx.addCase(switchStmt, branch);
  3771. condctx.addReturn(ret);
  3772. visited.append(*record);
  3773. }
  3774. break;
  3775. }
  3776. }
  3777. break;
  3778. }
  3779. }
  3780. }
  3781. }
  3782. protected:
  3783. HqlCppTranslator & translator;
  3784. IHqlStmt * switchStmt;
  3785. HqlExprCopyArray visited;
  3786. unsigned nextIndex;
  3787. };
  3788. void HqlCppTranslator::generateMetaRecordSerialize(BuildCtx & ctx, IHqlExpression * record, const char * diskSerializerName, const char * diskDeserializerName, const char * internalSerializerName, const char * internalDeserializerName, const char * prefetcherName)
  3789. {
  3790. OwnedHqlExpr dataset = createDataset(no_null, LINK(record));
  3791. if (recordRequiresDestructor(record))
  3792. {
  3793. BuildCtx destructctx(ctx);
  3794. destructctx.addQuotedCompound("virtual void destruct(byte * self)");
  3795. bindTableCursor(destructctx, dataset, "self");
  3796. MetaDestructCallback builder(*this);
  3797. builder.walkRecord(destructctx, dataset, record);
  3798. }
  3799. if (recordRequiresDestructor(record))
  3800. {
  3801. BuildCtx walkctx(ctx);
  3802. OwnedHqlExpr visitor = createVariable("visitor", makeBoolType()); // makeClassType("IIndirectMemberVisitor");
  3803. walkctx.addQuotedCompound("virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor)");
  3804. bindTableCursor(walkctx, dataset, "self");
  3805. MetaWalkIndirectCallback builder(*this, visitor);
  3806. builder.walkRecord(walkctx, dataset, record);
  3807. }
  3808. if (recordRequiresDestructor(record))
  3809. {
  3810. BuildCtx childmetactx(ctx);
  3811. OwnedHqlExpr switchVar = createVariable("i", makeIntType(4, false));
  3812. IHqlStmt * child = childmetactx.addQuotedCompound("virtual IOutputMetaData * queryChildMeta(unsigned i)");
  3813. BuildCtx switchctx(childmetactx);
  3814. IHqlStmt * switchStmt = switchctx.addSwitch(switchVar);
  3815. unsigned prevChildren = calcTotalChildren(child);
  3816. MetaChildMetaCallback builder(*this, switchStmt);
  3817. builder.walkRecord(childmetactx, record);
  3818. if (prevChildren != calcTotalChildren(child))
  3819. childmetactx.addReturn(queryQuotedNullExpr());
  3820. else
  3821. child->setIncluded(false);
  3822. }
  3823. if (diskSerializerName && *diskSerializerName)
  3824. {
  3825. BuildCtx serializectx(ctx);
  3826. serializectx.addQuotedCompound("virtual IOutputRowSerializer * createDiskSerializer(ICodeContext * ctx, unsigned activityId)");
  3827. StringBuffer s;
  3828. s.append("return cr").append(diskSerializerName).append("(ctx, activityId);");
  3829. serializectx.addQuoted(s);
  3830. }
  3831. if (diskDeserializerName && *diskDeserializerName)
  3832. {
  3833. BuildCtx deserializectx(ctx);
  3834. deserializectx.addQuotedCompound("virtual IOutputRowDeserializer * createDiskDeserializer(ICodeContext * ctx, unsigned activityId)");
  3835. StringBuffer s;
  3836. s.append("return cr").append(diskDeserializerName).append("(ctx, activityId);");
  3837. deserializectx.addQuoted(s);
  3838. }
  3839. if (internalSerializerName && *internalSerializerName)
  3840. {
  3841. BuildCtx serializectx(ctx);
  3842. serializectx.addQuotedCompound("virtual IOutputRowSerializer * createInternalSerializer(ICodeContext * ctx, unsigned activityId)");
  3843. StringBuffer s;
  3844. s.append("return cr").append(internalSerializerName).append("(ctx, activityId);");
  3845. serializectx.addQuoted(s);
  3846. }
  3847. if (internalDeserializerName && *internalDeserializerName)
  3848. {
  3849. BuildCtx deserializectx(ctx);
  3850. deserializectx.addQuotedCompound("virtual IOutputRowDeserializer * createInternalDeserializer(ICodeContext * ctx, unsigned activityId)");
  3851. StringBuffer s;
  3852. s.append("return cr").append(internalDeserializerName).append("(ctx, activityId);");
  3853. deserializectx.addQuoted(s);
  3854. }
  3855. if (prefetcherName && *prefetcherName)
  3856. {
  3857. BuildCtx deserializectx(ctx);
  3858. deserializectx.addQuotedCompound("virtual CSourceRowPrefetcher * doCreateDiskPrefetcher(unsigned activityId)");
  3859. StringBuffer s;
  3860. s.append("return new ").append(prefetcherName).append("(activityId);");
  3861. deserializectx.addQuoted(s);
  3862. }
  3863. }
  3864. IHqlExpression * HqlCppTranslator::buildMetaParameter(IHqlExpression * arg)
  3865. {
  3866. MetaInstance meta(*this, arg->queryRecord(), false);
  3867. buildMetaInfo(meta);
  3868. return createQuoted(meta.queryInstanceObject(), makeBoolType());
  3869. }
  3870. void HqlCppTranslator::buildMetaMember(BuildCtx & ctx, IHqlExpression * datasetOrRecord, bool grouped, const char * name)
  3871. {
  3872. MetaInstance meta(*this, ::queryRecord(datasetOrRecord), grouped);
  3873. StringBuffer s;
  3874. buildMetaInfo(meta);
  3875. s.append("virtual IOutputMetaData * ").append(name).append("() { return &").append(meta.queryInstanceObject()).append("; }");
  3876. ctx.addQuoted(s);
  3877. }
  3878. void HqlCppTranslator::buildMetaForRecord(StringBuffer & name, IHqlExpression * record)
  3879. {
  3880. MetaInstance meta(*this, record, false);
  3881. buildMetaInfo(meta);
  3882. name.append(meta.queryInstanceObject());
  3883. }
  3884. void HqlCppTranslator::buildMetaForSerializedRecord(StringBuffer & name, IHqlExpression * record, bool isGrouped)
  3885. {
  3886. if (isGrouped)
  3887. {
  3888. HqlExprArray args;
  3889. unwindChildren(args, record);
  3890. args.append(*createField(__eogId, makeBoolType(), NULL, NULL));
  3891. OwnedHqlExpr groupedRecord = record->clone(args);
  3892. buildMetaForRecord(name, groupedRecord);
  3893. }
  3894. else
  3895. buildMetaForRecord(name, record);
  3896. }
  3897. void HqlCppTranslator::ensureRowSerializer(StringBuffer & serializerName, BuildCtx & ctx, IHqlExpression * record, IAtom * format, IAtom * kind)
  3898. {
  3899. OwnedHqlExpr marker = createAttribute(serializerInstanceMarkerAtom, LINK(record->queryBody()), createAttribute(kind));
  3900. HqlExprAssociation * match = ctx.queryMatchExpr(marker);
  3901. if (match)
  3902. {
  3903. generateExprCpp(serializerName, match->queryExpr());
  3904. return;
  3905. }
  3906. StringBuffer uid;
  3907. getUniqueId(uid.append("ser"));
  3908. BuildCtx * declarectx = &ctx;
  3909. BuildCtx * callctx = &ctx;
  3910. getInvariantMemberContext(ctx, &declarectx, &callctx, true, false);
  3911. StringBuffer s;
  3912. const char * kindText = (kind == serializerAtom) ? "Serializer" : "Deserializer";
  3913. s.append("Owned<IOutputRow").append(kindText).append("> ").append(uid).append(";");
  3914. declarectx->addQuoted(s);
  3915. MetaInstance meta(*this, record, false);
  3916. buildMetaInfo(meta);
  3917. s.clear().append(uid).append(".setown(").append(meta.queryInstanceObject());
  3918. if (format == diskAtom)
  3919. s.append(".createDisk").append(kindText);
  3920. else if (format == internalAtom)
  3921. s.append(".createInternal").append(kindText);
  3922. else
  3923. throwUnexpected();
  3924. s.append("(ctx, ");
  3925. OwnedHqlExpr activityId = getCurrentActivityId(ctx);
  3926. generateExprCpp(s, activityId);
  3927. s.append("));");
  3928. callctx->addQuoted(s);
  3929. OwnedHqlExpr value = createVariable(uid.str(), makeBoolType());
  3930. declarectx->associateExpr(marker, value);
  3931. serializerName.append(uid);
  3932. }
  3933. void HqlCppTranslator::ensureRowPrefetcher(StringBuffer & prefetcherName, BuildCtx & ctx, IHqlExpression * record)
  3934. {
  3935. OwnedHqlExpr marker = createAttribute(prefetcherInstanceMarkerAtom, LINK(record->queryBody()));
  3936. HqlExprAssociation * match = ctx.queryMatchExpr(marker);
  3937. if (match)
  3938. {
  3939. generateExprCpp(prefetcherName, match->queryExpr());
  3940. return;
  3941. }
  3942. StringBuffer uid;
  3943. getUniqueId(uid.append("pf"));
  3944. BuildCtx * declarectx = &ctx;
  3945. BuildCtx * callctx = &ctx;
  3946. getInvariantMemberContext(ctx, &declarectx, &callctx, true, false);
  3947. StringBuffer s;
  3948. s.append("Owned<ISourceRowPrefetcher> ").append(uid).append(";");
  3949. declarectx->addQuoted(s);
  3950. MetaInstance meta(*this, record, false);
  3951. buildMetaInfo(meta);
  3952. s.clear().append(uid).append(".setown(").append(meta.queryInstanceObject());
  3953. s.append(".createDiskPrefetcher(ctx, ");
  3954. OwnedHqlExpr activityId = getCurrentActivityId(ctx);
  3955. generateExprCpp(s, activityId);
  3956. s.append("));");
  3957. callctx->addQuoted(s);
  3958. OwnedHqlExpr value = createVariable(uid.str(), makeBoolType());
  3959. declarectx->associateExpr(marker, value);
  3960. prefetcherName.append(uid);
  3961. }
  3962. IHqlExpression * HqlCppTranslator::createSerializer(BuildCtx & ctx, IHqlExpression * record, IAtom * form, IAtom * kind)
  3963. {
  3964. StringBuffer serializerName;
  3965. ensureRowSerializer(serializerName, ctx, record, form, kind);
  3966. return createQuoted(serializerName.str(), makeBoolType());
  3967. }
  3968. IHqlExpression * HqlCppTranslator::createResultName(IHqlExpression * name, bool expandLogicalName)
  3969. {
  3970. IHqlExpression * resultName = ::createResultName(name);
  3971. if (!expandLogicalName)
  3972. return resultName;
  3973. HqlExprArray args;
  3974. args.append(*resultName);
  3975. return bindFunctionCall(getExpandLogicalNameId, args);
  3976. }
  3977. bool HqlCppTranslator::registerGlobalUsage(IHqlExpression * filename)
  3978. {
  3979. bool matched = false;
  3980. ForEachItemIn(i, globalFiles)
  3981. {
  3982. if (globalFiles.item(i).checkMatch(filename))
  3983. matched = true;
  3984. }
  3985. return matched;
  3986. }
  3987. //---------------------------------------------------------------------------
  3988. IHqlExpression * HqlCppTranslator::convertBetweenCountAndSize(const CHqlBoundExpr & bound, bool getCount)
  3989. {
  3990. ITypeInfo * type = bound.expr->queryType();
  3991. if (getCount)
  3992. {
  3993. if (getIntValue(bound.length, 1) == 0)
  3994. return getSizetConstant(0);
  3995. }
  3996. else
  3997. {
  3998. if (getIntValue(bound.count, 1) == 0)
  3999. return getSizetConstant(0);
  4000. }
  4001. OwnedHqlExpr record;
  4002. switch (type->getTypeCode())
  4003. {
  4004. case type_dictionary:
  4005. case type_table:
  4006. case type_groupedtable:
  4007. record.set(bound.expr->queryRecord());
  4008. break;
  4009. case type_set:
  4010. case type_array:
  4011. {
  4012. ITypeInfo * elementType = type->queryChildType();
  4013. HqlExprArray fields;
  4014. fields.append(*createField(valueId, LINK(elementType), NULL));
  4015. record.setown(createRecord(fields));
  4016. break;
  4017. }
  4018. default:
  4019. UNIMPLEMENTED;
  4020. }
  4021. ColumnToOffsetMap * map = queryRecordOffsetMap(record);
  4022. if (map->isFixedWidth())
  4023. {
  4024. unsigned fixedSize = map->getFixedRecordSize();
  4025. if (fixedSize == 0)
  4026. throwError(HQLERR_ZeroLengthIllegal);
  4027. if (type->getTypeCode() == type_groupedtable)
  4028. fixedSize++;
  4029. if (getCount)
  4030. {
  4031. if (fixedSize == 1)
  4032. return LINK(bound.length);
  4033. IValue * value = bound.length->queryValue();
  4034. if (value)
  4035. return getSizetConstant((unsigned)value->getIntValue()/fixedSize);
  4036. return createValue(no_div, LINK(sizetType), LINK(bound.length), getSizetConstant(fixedSize));
  4037. }
  4038. else
  4039. {
  4040. if (fixedSize == 1)
  4041. return LINK(bound.count);
  4042. IValue * value = bound.count->queryValue();
  4043. if (value)
  4044. return getSizetConstant((unsigned)value->getIntValue() * fixedSize);
  4045. return createValue(no_mul, LINK(sizetType), LINK(bound.count), getSizetConstant(fixedSize));
  4046. }
  4047. }
  4048. StringBuffer metaInstanceName, s;
  4049. buildMetaForSerializedRecord(metaInstanceName, record, (type->getTypeCode() == type_groupedtable));
  4050. HqlExprArray args;
  4051. IIdAtom * func;
  4052. if (getCount)
  4053. {
  4054. args.append(*getBoundSize(bound));
  4055. args.append(*LINK(bound.expr));
  4056. func = countRowsId;
  4057. }
  4058. else
  4059. {
  4060. args.append(*LINK(bound.count));
  4061. args.append(*LINK(bound.expr));
  4062. func = countToSizeId;
  4063. }
  4064. args.append(*createQuoted(s.clear().append("&").append(metaInstanceName), makeBoolType()));
  4065. return bindTranslatedFunctionCall(func, args);
  4066. }
  4067. //---------------------------------------------------------------------------
  4068. void HqlCppTranslator::noteResultDefined(BuildCtx & ctx, ActivityInstance * activityInstance, IHqlExpression * seq, IHqlExpression * name, bool alwaysExecuted)
  4069. {
  4070. unsigned graph = curGraphSequence();
  4071. assertex(graph);
  4072. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  4073. assertex(activeSubgraph);
  4074. if (isInternalSeq(seq))
  4075. {
  4076. internalResults.append(* new InternalResultTracker(name, activeSubgraph->tree, graph, activityInstance));
  4077. }
  4078. else if (alwaysExecuted)
  4079. {
  4080. assertex(activeSubgraph->tree->hasProp("att[@name=\"rootGraph\"]"));
  4081. }
  4082. }
  4083. void HqlCppTranslator::noteResultAccessed(BuildCtx & ctx, IHqlExpression * seq, IHqlExpression * name)
  4084. {
  4085. if (isInternalSeq(seq))
  4086. {
  4087. unsigned graph = curGraphSequence();
  4088. ForEachItemIn(i, internalResults)
  4089. {
  4090. if (internalResults.item(i).noteUse(name, graph))
  4091. {
  4092. //Can't currently break because the same result might be generated more than once
  4093. //if an expression ends up in two different graphs.
  4094. //break;
  4095. }
  4096. }
  4097. }
  4098. }
  4099. void HqlCppTranslator::buildGetResultInfo(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * boundTarget, const CHqlBoundTarget * targetAssign)
  4100. {
  4101. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  4102. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  4103. if (!name)
  4104. name = queryAttributeChild(expr, nameAtom, 0);
  4105. noteResultAccessed(ctx, seq, name);
  4106. if (insideLibrary())
  4107. {
  4108. SCMStringBuffer libraryName;
  4109. getOutputLibraryName(libraryName, wu());
  4110. StringBuffer storedName;
  4111. getStoredDescription(storedName, seq, name, true);
  4112. throwError2(HQLERR_LibraryNoWorkunitRead, libraryName.str(), storedName.str());
  4113. }
  4114. __int64 seqValue = seq->queryValue()->getIntValue();
  4115. assertex(!expr->hasAttribute(internalAtom) && !expr->hasAttribute(_internal_Atom));
  4116. bool expandLogical = (seqValue == ResultSequencePersist) && !expr->hasAttribute(_internal_Atom);
  4117. HqlExprArray args;
  4118. args.append(*createResultName(name, expandLogical));
  4119. args.append(*LINK(seq));
  4120. IIdAtom * func;
  4121. ITypeInfo * type = expr->queryType();
  4122. type_t ttc = type->getTypeCode();
  4123. OwnedITypeInfo overrideType;
  4124. switch(ttc)
  4125. {
  4126. case type_int: func = getResultIntId; break;
  4127. case type_swapint: func = getResultIntId; break;
  4128. case type_boolean: func = getResultBoolId; break;
  4129. case type_data: func = getResultDataId; break;
  4130. case type_dictionary:
  4131. case type_table:
  4132. case type_groupedtable:
  4133. case type_set:
  4134. //MORE: type_row...
  4135. {
  4136. OwnedHqlExpr record;
  4137. bool ensureSerialized = true;
  4138. if (ttc == type_dictionary)
  4139. {
  4140. record.set(::queryRecord(type));
  4141. //NB: The result type will be overridden when this function is bound
  4142. ensureSerialized = false;
  4143. overrideType.setown(setLinkCountedAttr(type, true));
  4144. func = getResultDictionaryId;
  4145. }
  4146. else if (ttc != type_set)
  4147. {
  4148. overrideType.set(type);
  4149. record.set(::queryRecord(type));
  4150. //NB: The result type (including grouping) will be overridden when this function is bound
  4151. func = getResultDatasetId;
  4152. bool defaultLCR = targetAssign ? hasLinkedRow(targetAssign->queryType()) : true;
  4153. if (hasLinkCountedModifier(type) || defaultLCR)
  4154. {
  4155. ensureSerialized = false;
  4156. args.append(*createRowAllocator(ctx, record));
  4157. args.append(*createConstant(isGrouped(expr)));
  4158. overrideType.setown(setLinkCountedAttr(overrideType, true));
  4159. func = getResultRowsetId;
  4160. }
  4161. }
  4162. else
  4163. {
  4164. overrideType.set(type);
  4165. ITypeInfo * elementType = type->queryChildType();
  4166. OwnedHqlExpr field = createField(valueId, LINK(elementType), NULL);
  4167. record.setown(createRecord(field));
  4168. func = getResultSetId;
  4169. }
  4170. if (ensureSerialized && record)
  4171. record.setown(getSerializedForm(record, diskAtom));
  4172. if (record && (seqValue == ResultSequenceStored))
  4173. {
  4174. StringBuffer s;
  4175. OwnedHqlExpr ds = createDataset(no_anon, LINK(record));
  4176. StringBuffer xmlInstanceName, xmlFactoryName;
  4177. bool usesContents = false;
  4178. getUniqueId(xmlInstanceName.append("xml"));
  4179. buildXmlReadTransform(ds, xmlFactoryName, usesContents);
  4180. OwnedHqlExpr curActivityId = getCurrentActivityId(ctx);
  4181. s.append("Owned<IXmlToRowTransformer> ").append(xmlInstanceName).append(" = ").append(xmlFactoryName).append("(ctx,");
  4182. generateExprCpp(s, curActivityId).append(");");
  4183. ctx.addQuoted(s);
  4184. args.append(*createQuoted(xmlInstanceName, makeBoolType()));
  4185. StringBuffer csvInstanceName;
  4186. if (canReadFromCsv(record))
  4187. {
  4188. buildCsvReadTransformer(ds, csvInstanceName, NULL);
  4189. csvInstanceName.insert(0, "&");
  4190. }
  4191. else
  4192. {
  4193. csvInstanceName.clear().append("0");
  4194. }
  4195. args.append(*createQuoted(csvInstanceName, makeBoolType()));
  4196. }
  4197. else
  4198. {
  4199. args.append(*createQuoted("0", makeBoolType()));
  4200. args.append(*createQuoted("0", makeBoolType()));
  4201. }
  4202. if (ttc == type_dictionary)
  4203. {
  4204. StringBuffer lookupHelperName;
  4205. buildDictionaryHashClass(expr->queryRecord(), lookupHelperName);
  4206. lookupHelperName.insert(0, "&"); // MORE: Should this be passed by reference instead - it isn't optional
  4207. args.append(*createQuoted(lookupHelperName.str(), makeBoolType()));
  4208. }
  4209. break;
  4210. }
  4211. case type_string:
  4212. {
  4213. func = getResultStringId;
  4214. if ((type->queryCharset()->queryName() != asciiAtom) || !targetAssign)
  4215. break;
  4216. ITypeInfo * targetType = targetAssign->queryType();
  4217. if ((targetType->getTypeCode() != type_string) || (targetType->getSize() == UNKNOWN_LENGTH) ||
  4218. (targetType->queryCharset() != type->queryCharset()))
  4219. break;
  4220. //more: if (options.checkOverflow && queryUnqualifiedType(targetType) != queryUnqualifiedType(type)
  4221. args.add(*targetAssign->getTranslatedExpr(), 0);
  4222. buildFunctionCall(ctx, getResultStringFId, args);
  4223. return;
  4224. }
  4225. case type_qstring: func = getResultStringId; break;
  4226. case type_varstring:func = getResultVarStringId; break;
  4227. case type_unicode: func = getResultUnicodeId; break;
  4228. case type_varunicode:func = getResultVarUnicodeId; break;
  4229. case type_utf8: func = getResultUnicodeId; break;
  4230. case type_real: func = getResultRealId; break;
  4231. case type_decimal:
  4232. {
  4233. //Special case - need to bind the first parameter..., since not calling buildExpr on the call.
  4234. //sequence is always a constant, so no need to bind.
  4235. CHqlBoundExpr boundName;
  4236. buildExpr(ctx, &args.item(0), boundName);
  4237. args.replace(*LINK(boundName.expr), 0);
  4238. const CHqlBoundTarget * getTarget = targetAssign;
  4239. CHqlBoundTarget tempTarget;
  4240. if (!getTarget)
  4241. {
  4242. getTarget = &tempTarget;
  4243. createTempFor(ctx, expr, tempTarget);
  4244. }
  4245. args.add(*createConstant((int)type->getSize()), 0);
  4246. args.add(*getSizetConstant(type->getPrecision()),1);
  4247. args.add(*createConstant(type->isSigned()),2);
  4248. args.add(*getPointer(getTarget->expr), 3);
  4249. callProcedure(ctx, getResultDecimalId, args);
  4250. if (boundTarget)
  4251. boundTarget->setFromTarget(*getTarget);
  4252. return;
  4253. }
  4254. case type_row: UNIMPLEMENTED; break; //should be translated to rawData.
  4255. default:
  4256. PrintLog("%d", ttc);
  4257. throwUnexpectedX("No getResult defined for this type");
  4258. break;
  4259. }
  4260. OwnedHqlExpr function = bindFunctionCall(func, args, overrideType);
  4261. switch (ttc)
  4262. {
  4263. case type_qstring:
  4264. {
  4265. Owned<ITypeInfo> qstrType = makeQStringType(UNKNOWN_LENGTH);
  4266. function.setown(ensureExprType(function, type));
  4267. break;
  4268. }
  4269. case type_string:
  4270. case type_varstring:
  4271. {
  4272. if (type->queryCollation()->queryName() != asciiAtom)
  4273. function.setown(ensureExprType(function, type));
  4274. break;
  4275. }
  4276. }
  4277. if (boundTarget)
  4278. buildExpr(ctx, function, *boundTarget);
  4279. else
  4280. buildExprAssign(ctx, *targetAssign, function);
  4281. }
  4282. void HqlCppTranslator::buildSetXmlSerializer(StringBuffer & helper, ITypeInfo * valueType)
  4283. {
  4284. BuildCtx declarectx(*code, declareAtom);
  4285. OwnedHqlExpr search = createQuoted("setXmlHelper", LINK(valueType));
  4286. // stop duplicate classes being generated.
  4287. // MORE: If this ever includes sorting/grouping, the dependence on a record will need to be revised
  4288. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  4289. if (match)
  4290. {
  4291. match->queryExpr()->toString(helper);
  4292. return;
  4293. }
  4294. StringBuffer helperclass;
  4295. unique_id_t id = getUniqueId();
  4296. appendUniqueId(helper.append("r2x"), id);
  4297. appendUniqueId(helperclass.append("cr2x"), id);
  4298. BuildCtx r2xctx(declarectx);
  4299. r2xctx.setNextPriority(XmlTransformerPrio);
  4300. StringBuffer s, endText;
  4301. s.append("struct ").append(helperclass).append(" : public ISetToXmlTransformer");
  4302. endText.append(" ").append(helper).append(";");
  4303. r2xctx.addQuotedCompound(s, endText.str());
  4304. CHqlBoundExpr boundValue;
  4305. boundValue.isAll.setown(createVariable("isAll", makeBoolType()));
  4306. boundValue.length.setown(createVariable("length", LINK(sizetType)));
  4307. boundValue.expr.setown(createVariable("self", makeReferenceModifier(LINK(valueType))));
  4308. r2xctx.addQuotedCompound("virtual void toXML(bool isAll, size32_t length, const byte * self, IXmlWriter & out)");
  4309. OwnedHqlExpr itemName = createConstant("Item");
  4310. OwnedHqlExpr value = boundValue.getTranslatedExpr();
  4311. buildXmlSerializeSetValues(r2xctx, value, itemName, true);
  4312. if (options.spanMultipleCpp)
  4313. {
  4314. StringBuffer helperFunc;
  4315. createAccessFunctions(helperFunc, declarectx, XmlTransformerPrio, "ISetToXmlTransformer", helper);
  4316. helper.clear().append(helperFunc).append("()");
  4317. }
  4318. OwnedHqlExpr name = createVariable(helper, makeVoidType());
  4319. declarectx.associateExpr(search, name);
  4320. }
  4321. IWUResult * HqlCppTranslator::createWorkunitResult(int sequence, IHqlExpression * nameExpr)
  4322. {
  4323. switch(sequence)
  4324. {
  4325. case ResultSequenceStored:
  4326. {
  4327. assertex(nameExpr);
  4328. StringBuffer storedName;
  4329. getStringValue(storedName, nameExpr);
  4330. return wu()->updateVariableByName(storedName.str());
  4331. }
  4332. case ResultSequencePersist:
  4333. case ResultSequenceInternal:
  4334. case ResultSequenceOnce:
  4335. return NULL;
  4336. }
  4337. assertex(sequence >= 0);
  4338. StringBuffer resultName;
  4339. getStringValue(resultName, nameExpr);
  4340. if (resultName.length() == 0)
  4341. resultName.append("Result ").append(sequence+1);
  4342. Owned<IWUResult> result = wu()->updateResultBySequence(sequence);
  4343. result->setResultName(resultName);
  4344. return result.getClear();
  4345. }
  4346. void HqlCppTranslator::buildSetResultInfo(BuildCtx & ctx, IHqlExpression * originalExpr, IHqlExpression * value, ITypeInfo * type, bool isPersist, bool associateResult)
  4347. {
  4348. IHqlExpression * seq = queryAttributeChild(originalExpr, sequenceAtom, 0);
  4349. IHqlExpression * name = queryAttributeChild(originalExpr, namedAtom, 0);
  4350. if (insideLibrary())
  4351. {
  4352. SCMStringBuffer libraryName;
  4353. getOutputLibraryName(libraryName, wu());
  4354. StringBuffer storedName;
  4355. getStoredDescription(storedName, seq, name, true);
  4356. throwError2(HQLERR_LibraryNoWorkunitWrite, libraryName.str(), storedName.str());
  4357. }
  4358. ITypeInfo * resultType = type ? type->queryPromotedType() : value->queryType()->queryPromotedType();
  4359. Linked<ITypeInfo> schemaType = resultType;
  4360. type_t retType = schemaType->getTypeCode();
  4361. IIdAtom * func = NULL;
  4362. CHqlBoundExpr valueToSave;
  4363. LinkedHqlExpr castValue = value;
  4364. switch(retType)
  4365. {
  4366. case type_int:
  4367. case type_swapint:
  4368. {
  4369. bool isSigned = schemaType->isSigned();
  4370. func = isSigned ? setResultIntId : setResultUIntId;
  4371. schemaType.setown(makeIntType(8, isSigned));
  4372. break;
  4373. }
  4374. case type_boolean: func = setResultBoolId; break;
  4375. case type_string: func = setResultStringId; schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL)); break;
  4376. case type_unicode: func = setResultUnicodeId; schemaType.setown(makeUnicodeType(UNKNOWN_LENGTH, 0)); break;
  4377. case type_utf8: func = setResultUnicodeId; schemaType.setown(makeUnicodeType(UNKNOWN_LENGTH, 0)); castValue.setown(ensureExprType(value, schemaType)); associateResult = false; break;
  4378. case type_qstring: func = setResultStringId; schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL)); break;
  4379. case type_data: func = setResultDataId; schemaType.setown(makeDataType(UNKNOWN_LENGTH)); break;
  4380. case type_varstring:func = setResultVarStringId; schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL)); break;
  4381. case type_varunicode:func = setResultVarUnicodeId; schemaType.setown(makeUnicodeType(UNKNOWN_LENGTH, 0)); break;
  4382. case type_real: func = setResultRealId; schemaType.setown(makeRealType(8)); break;
  4383. case type_decimal: func = setResultDecimalId; break;
  4384. case type_row:
  4385. {
  4386. CHqlBoundExpr boundLength;
  4387. OwnedHqlExpr serialized = ::ensureSerialized(value, diskAtom);
  4388. func = setResultRawId;
  4389. Owned<IReferenceSelector> ds = buildNewRow(ctx, serialized);
  4390. OwnedHqlExpr size = createSizeof(ds->queryExpr());
  4391. buildExpr(ctx, size, boundLength);
  4392. ds->buildAddress(ctx, valueToSave);
  4393. valueToSave.length.set(boundLength.expr);
  4394. valueToSave.expr.setown(createValue(no_typetransfer, makeDataType(UNKNOWN_LENGTH), LINK(valueToSave.expr)));
  4395. schemaType.set(schemaType->queryChildType());
  4396. break;
  4397. }
  4398. case type_set:
  4399. {
  4400. func = setResultSetId;
  4401. ITypeInfo * elementType = LINK(schemaType->queryChildType());
  4402. if (!elementType)
  4403. elementType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  4404. schemaType.setown(makeSetType(elementType));
  4405. }
  4406. break;
  4407. case type_dictionary:
  4408. case type_table:
  4409. case type_groupedtable:
  4410. {
  4411. throwUnexpected();
  4412. #if 0
  4413. HqlExprArray args;
  4414. args.append(*LINK(value));
  4415. args.append(*createAttribute(sequenceAtom, LINK(seq)));
  4416. if (name)
  4417. args.append(*createAttribute(nameAtom, LINK(name)));
  4418. OwnedHqlExpr createFile = createValue(no_output, makeVoidType(), args);
  4419. buildStmt(ctx, createFile);
  4420. // MORE - the file name should be a unique temporary...
  4421. // MORE - associate a logical name with it
  4422. // MORE - save the logical name in the workunit
  4423. #endif
  4424. return;
  4425. }
  4426. case type_any:
  4427. //Someone has used error instead of fail. Don't do anything....
  4428. if (value->getOperator() == no_fail)
  4429. {
  4430. buildStmt(ctx, value);
  4431. return;
  4432. }
  4433. //fall through
  4434. default:
  4435. PrintLog("%d", retType);
  4436. throwError(HQLERR_InvalidSetResultType);
  4437. }
  4438. HqlExprArray args;
  4439. if (!valueToSave.expr)
  4440. {
  4441. LinkedHqlExpr cseValue = castValue;
  4442. if (options.spotCSE)
  4443. cseValue.setown(spotScalarCSE(cseValue));
  4444. if ((retType == type_set) && isComplexSet(resultType, false) && castValue->getOperator() == no_list && !isNullList(castValue))
  4445. {
  4446. CHqlBoundTarget tempTarget;
  4447. createTempFor(ctx, resultType, tempTarget, typemod_none, FormatBlockedDataset);
  4448. Owned<IHqlCppSetBuilder> builder = createTempSetBuilder(tempTarget.queryType()->queryChildType(), tempTarget.isAll);
  4449. builder->buildDeclare(ctx);
  4450. buildSetAssign(ctx, builder, castValue);
  4451. builder->buildFinish(ctx, tempTarget);
  4452. valueToSave.setFromTarget(tempTarget);
  4453. }
  4454. else
  4455. buildSimpleExpr(ctx, cseValue, valueToSave);
  4456. if (associateResult)
  4457. {
  4458. OwnedHqlExpr getResult = createGetResultFromSetResult(originalExpr);
  4459. ctx.associateExpr(getResult, valueToSave);
  4460. }
  4461. }
  4462. assertex(func);
  4463. OwnedHqlExpr nameText = createResultName(name, isPersist);
  4464. if (retType == type_decimal)
  4465. {
  4466. assertex(schemaType->getSize() != UNKNOWN_LENGTH);
  4467. //An ugly exception because it takes an arbitrary length decimal.
  4468. //This should be handled by having a decimal(unknown length) parameter to a function which passes size and precision
  4469. CHqlBoundExpr boundName;
  4470. buildExpr(ctx, nameText, boundName);
  4471. args.append(*LINK(boundName.expr));
  4472. args.append(*LINK(seq));
  4473. args.append(*getBoundSize(valueToSave));
  4474. args.append(*getSizetConstant(schemaType->getPrecision()));
  4475. args.append(*createConstant(schemaType->isSigned()));
  4476. args.append(*getPointer(valueToSave.expr));
  4477. buildTranslatedFunctionCall(ctx, func, args);
  4478. }
  4479. else
  4480. {
  4481. args.append(*nameText.getLink());
  4482. args.append(*LINK(seq));
  4483. args.append(*valueToSave.getTranslatedExpr());
  4484. if (func == setResultSetId)
  4485. {
  4486. StringBuffer helper, s;
  4487. buildSetXmlSerializer(helper, resultType);
  4488. s.clear().append("&").append(helper);
  4489. args.append(*createQuoted(s, makeBoolType()));
  4490. }
  4491. buildFunctionCall(ctx, func, args);
  4492. }
  4493. if(wu())
  4494. {
  4495. if (retType == type_row)
  4496. {
  4497. Owned<IWUResult> result = createDatasetResultSchema(seq, name, ::queryRecord(schemaType), false, false);
  4498. if (result)
  4499. result->setResultTotalRowCount(1);
  4500. }
  4501. else
  4502. {
  4503. // Bit of a mess - should split into two procedures
  4504. int sequence = (int) seq->queryValue()->getIntValue();
  4505. Owned<IWUResult> result = createWorkunitResult(sequence, name);
  4506. if(result)
  4507. {
  4508. StringBuffer fieldName;
  4509. SCMStringBuffer resultName;
  4510. result->getResultName(resultName);
  4511. const char * cur = resultName.str();
  4512. while (*cur)
  4513. {
  4514. unsigned char c = *cur++;
  4515. if (isalnum(c) || (c == '_'))
  4516. fieldName.append(c);
  4517. else if (isspace(c))
  4518. fieldName.append('_');
  4519. }
  4520. MemoryBuffer schema;
  4521. schema.append(fieldName.str());
  4522. schemaType->serialize(schema);
  4523. schema.append("").append((unsigned char) type_void);
  4524. schema.append((unsigned)0);
  4525. result->setResultSchemaRaw(schema.length(), schema.toByteArray());
  4526. StringBuffer xml;
  4527. {
  4528. XmlSchemaBuilder xmlbuilder(false);
  4529. xmlbuilder.addField(fieldName, *schemaType);
  4530. xmlbuilder.getXml(xml);
  4531. }
  4532. addSchemaResource(sequence, resultName.str(), xml.length()+1, xml.str());
  4533. }
  4534. }
  4535. }
  4536. }
  4537. void HqlCppTranslator::buildCompareClass(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4538. {
  4539. BuildCtx classctx(ctx);
  4540. beginNestedClass(classctx, name, "ICompare");
  4541. BuildCtx funcctx(classctx);
  4542. funcctx.addQuotedCompound("virtual int docompare(const void * _left, const void * _right) const");
  4543. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  4544. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  4545. funcctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4546. bindTableCursor(funcctx, datasetLeft, "left", no_left, selSeq);
  4547. bindTableCursor(funcctx, datasetRight, "right", no_right, selSeq);
  4548. if (orderExpr->getOperator() == no_order)
  4549. doBuildReturnCompare(funcctx, orderExpr, no_order, false);
  4550. else
  4551. buildReturn(funcctx, orderExpr);
  4552. endNestedClass();
  4553. }
  4554. void HqlCppTranslator::buildCompareMemberLR(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4555. {
  4556. StringBuffer s;
  4557. s.clear().append("virtual ICompare * query").append(name).append("() { return &").append(name).append("; }");
  4558. ctx.addQuoted(s);
  4559. buildCompareClass(ctx, name, orderExpr, datasetLeft, datasetRight, selSeq);
  4560. }
  4561. void HqlCppTranslator::buildCompareMember(BuildCtx & ctx, const char * name, IHqlExpression * cond, const DatasetReference & dataset)
  4562. {
  4563. //MORE:Support multiple comparison fields.
  4564. IHqlExpression * datasetExpr = dataset.queryDataset();
  4565. OwnedHqlExpr seq = createDummySelectorSequence();
  4566. OwnedHqlExpr leftSelect = createSelector(no_left, datasetExpr, seq);
  4567. OwnedHqlExpr rightSelect = createSelector(no_right, datasetExpr, seq);
  4568. IHqlExpression * left = dataset.mapCompound(cond, leftSelect);
  4569. IHqlExpression * right = dataset.mapCompound(cond, rightSelect);
  4570. OwnedHqlExpr compare = createValue(no_order, LINK(signedType), left, right);
  4571. buildCompareMemberLR(ctx, name, compare, datasetExpr, datasetExpr, seq);
  4572. }
  4573. void HqlCppTranslator::buildCompareEqClass(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4574. {
  4575. BuildCtx classctx(ctx);
  4576. beginNestedClass(classctx, name, "ICompareEq");
  4577. BuildCtx funcctx(classctx);
  4578. funcctx.addQuotedCompound("virtual bool match(const void * _left, const void * _right) const");
  4579. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  4580. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  4581. funcctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4582. bindTableCursor(funcctx, datasetLeft, "left", no_left, selSeq);
  4583. bindTableCursor(funcctx, datasetRight, "right", no_right, selSeq);
  4584. if (orderExpr->getOperator() == no_order)
  4585. doBuildReturnCompare(funcctx, orderExpr, no_eq, true);
  4586. else
  4587. buildReturn(funcctx, orderExpr);
  4588. endNestedClass();
  4589. }
  4590. void HqlCppTranslator::buildCompareEqMemberLR(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, IHqlExpression * datasetLeft, IHqlExpression * datasetRight, IHqlExpression * selSeq)
  4591. {
  4592. StringBuffer s;
  4593. s.clear().append("virtual ICompareEq * query").append(name).append("() { return &").append(name).append("; }");
  4594. ctx.addQuoted(s);
  4595. buildCompareEqClass(ctx, name, orderExpr, datasetLeft, datasetRight, selSeq);
  4596. }
  4597. void HqlCppTranslator::buildNaryCompareClass(BuildCtx & ctx, const char * name, IHqlExpression * expr, IHqlExpression * dataset, IHqlExpression * selSeq, IHqlExpression * rowsid)
  4598. {
  4599. BuildCtx classctx(ctx);
  4600. beginNestedClass(classctx, name, "INaryCompareEq");
  4601. BuildCtx funcctx(classctx);
  4602. funcctx.addQuotedCompound("virtual bool match(unsigned numRows, const void * * _rows) const");
  4603. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _rows[0];");
  4604. funcctx.addQuoted("unsigned char * * rows = (unsigned char * *) _rows;");
  4605. funcctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4606. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  4607. bindRows(funcctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", false);
  4608. buildReturn(funcctx, expr);
  4609. endNestedClass();
  4610. }
  4611. void HqlCppTranslator::buildNaryCompareMember(BuildCtx & ctx, const char * name, IHqlExpression * expr, IHqlExpression * datasetLeft, IHqlExpression * selSeq, IHqlExpression * rowsid)
  4612. {
  4613. StringBuffer s;
  4614. s.clear().append("virtual INaryCompareEq * query").append(name).append("() { return &").append(name).append("; }");
  4615. ctx.addQuoted(s);
  4616. buildNaryCompareClass(ctx, name, expr, datasetLeft, selSeq, rowsid);
  4617. }
  4618. void HqlCppTranslator::buildCompareEqMember(BuildCtx & ctx, const char * name, IHqlExpression * cond, const DatasetReference & dataset)
  4619. {
  4620. //MORE:Support multiple comparison fields.
  4621. IHqlExpression * datasetExpr = dataset.queryDataset();
  4622. OwnedHqlExpr seq = createDummySelectorSequence();
  4623. OwnedHqlExpr leftSelect = createSelector(no_left, datasetExpr, seq);
  4624. OwnedHqlExpr rightSelect = createSelector(no_right, datasetExpr, seq);
  4625. IHqlExpression * left = dataset.mapCompound(cond, leftSelect);
  4626. IHqlExpression * right = dataset.mapCompound(cond, rightSelect);
  4627. OwnedHqlExpr compare = createValue(no_order, LINK(signedType), left, right);
  4628. buildCompareEqMemberLR(ctx, name, compare, datasetExpr, datasetExpr, seq);
  4629. }
  4630. void HqlCppTranslator::buildOrderedCompare(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * sorts, CHqlBoundExpr & bound, IHqlExpression * leftDataset, IHqlExpression * rightDataset)
  4631. {
  4632. //MORE: This needs to be more intelligent to deal with related datasets (child datasets will work ok).
  4633. //MORE: Should create a member function if a member of a class.
  4634. //Otherwise a function + generate an error if it uses fields outside of the context?
  4635. //Would also need to pass in parent cursors for a global function since parent will not be available.
  4636. //MORE:Support multiple comparison fields.
  4637. OwnedHqlExpr compare = createOrderFromSortList(DatasetReference(dataset), sorts, leftDataset, rightDataset);
  4638. buildTempExpr(ctx, compare, bound);
  4639. }
  4640. void HqlCppTranslator::buildHashClass(BuildCtx & ctx, const char * name, IHqlExpression * orderExpr, const DatasetReference & dataset)
  4641. {
  4642. StringBuffer s;
  4643. s.clear().append("virtual IHash * query").append(name).append("() { return &").append(name).append("; }");
  4644. ctx.addQuoted(s);
  4645. BuildCtx classctx(ctx);
  4646. beginNestedClass(classctx, name, "IHash");
  4647. BuildCtx funcctx(classctx);
  4648. s.clear().append("virtual unsigned hash(const void * _self)");
  4649. funcctx.addQuotedCompound(s);
  4650. s.clear().append("const unsigned char * self = (const unsigned char *) _self;");
  4651. funcctx.addQuoted(s);
  4652. bindTableCursor(funcctx, dataset.queryDataset(), "self", dataset.querySide(), dataset.querySelSeq());
  4653. OwnedITypeInfo returnType = makeIntType(4, false);
  4654. buildReturn(funcctx, orderExpr, returnType);
  4655. endNestedClass();
  4656. }
  4657. void HqlCppTranslator::buildCompareClass(BuildCtx & ctx, const char * name, IHqlExpression * sortList, const DatasetReference & dataset)
  4658. {
  4659. BuildCtx comparectx(ctx);
  4660. beginNestedClass(comparectx, name, "ICompare");
  4661. BuildCtx funcctx(comparectx);
  4662. funcctx.addQuotedCompound("virtual int docompare(const void * _left, const void * _right) const");
  4663. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  4664. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  4665. funcctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  4666. buildReturnOrder(funcctx, sortList, dataset);
  4667. endNestedClass();
  4668. }
  4669. void HqlCppTranslator::buildHashOfExprsClass(BuildCtx & ctx, const char * name, IHqlExpression * cond, const DatasetReference & dataset, bool compareToSelf)
  4670. {
  4671. IHqlExpression * attr = compareToSelf ? createAttribute(internalAtom) : NULL;
  4672. OwnedHqlExpr hash = createValue(no_hash32, LINK(unsignedType), LINK(cond), attr);
  4673. buildHashClass(ctx, name, hash, dataset);
  4674. }
  4675. void HqlCppTranslator::buildDictionaryHashClass(IHqlExpression *record, StringBuffer &funcName)
  4676. {
  4677. BuildCtx declarectx(*code, declareAtom);
  4678. OwnedHqlExpr attr = createAttribute(lookupAtom, LINK(record));
  4679. HqlExprAssociation * match = declarectx.queryMatchExpr(attr);
  4680. if (match)
  4681. match->queryExpr()->toString(funcName);
  4682. else
  4683. {
  4684. StringBuffer lookupHelperName;
  4685. appendUniqueId(lookupHelperName.append("lu"), getConsistentUID(record));
  4686. BuildCtx classctx(declarectx);
  4687. //I suspect all the priorities should be killed. This is here because you can have type info constructors accessing the
  4688. //dictionary hash functions.
  4689. classctx.setNextPriority(HashFunctionPrio);
  4690. beginNestedClass(classctx, lookupHelperName, "IHThorHashLookupInfo");
  4691. OwnedHqlExpr searchRecord = getDictionarySearchRecord(record);
  4692. OwnedHqlExpr keyRecord = getDictionaryKeyRecord(record);
  4693. HqlExprArray keyedSourceFields;
  4694. HqlExprArray keyedDictFields;
  4695. OwnedHqlExpr source = createDataset(no_null, LINK(searchRecord));
  4696. DatasetReference sourceRef(source, no_none, NULL);
  4697. OwnedHqlExpr dict = createDataset(no_null, LINK(record));
  4698. DatasetReference dictRef(dict, no_none, NULL);
  4699. ForEachChild(idx, searchRecord)
  4700. {
  4701. IHqlExpression *child = searchRecord->queryChild(idx);
  4702. if (!child->isAttribute())
  4703. keyedSourceFields.append(*createSelectExpr(LINK(source->queryNormalizedSelector()), LINK(child)));
  4704. }
  4705. ForEachChild(idx2, keyRecord)
  4706. {
  4707. IHqlExpression *child = keyRecord->queryChild(idx2);
  4708. if (!child->isAttribute())
  4709. keyedDictFields.append(*createSelectExpr(LINK(dict->queryNormalizedSelector()), LINK(child)));
  4710. }
  4711. OwnedHqlExpr keyedSourceList = createValueSafe(no_sortlist, makeSortListType(NULL), keyedSourceFields);
  4712. OwnedHqlExpr keyedDictList = createValueSafe(no_sortlist, makeSortListType(NULL), keyedDictFields);
  4713. buildHashOfExprsClass(classctx, "HashLookup", keyedSourceList, sourceRef, false);
  4714. buildHashOfExprsClass(classctx, "Hash", keyedDictList, dictRef, false);
  4715. OwnedHqlExpr seq = createDummySelectorSequence();
  4716. OwnedHqlExpr leftSelect = createSelector(no_left, source, seq);
  4717. OwnedHqlExpr rightSelect = createSelector(no_right, dict, seq);
  4718. IHqlExpression * left = sourceRef.mapCompound(keyedSourceList, leftSelect);
  4719. IHqlExpression * right = dictRef.mapCompound(keyedDictList, rightSelect);
  4720. OwnedHqlExpr compare = createValue(no_order, LINK(signedType), left, right);
  4721. buildCompareMemberLR(classctx, "CompareLookup", compare, source, dict, seq);
  4722. buildCompareMember(classctx, "Compare", keyedDictList, dictRef);
  4723. endNestedClass();
  4724. if (queryOptions().spanMultipleCpp)
  4725. {
  4726. createAccessFunctions(funcName, declarectx, BuildCtx::NormalPrio, "IHThorHashLookupInfo", lookupHelperName);
  4727. funcName.append("()");
  4728. }
  4729. else
  4730. funcName.append(lookupHelperName);
  4731. OwnedHqlExpr func = createVariable(funcName, makeVoidType());
  4732. declarectx.associateExpr(attr, func);
  4733. }
  4734. }
  4735. void HqlCppTranslator::buildDictionaryHashMember(BuildCtx & ctx, IHqlExpression *dictionary, const char * memberName)
  4736. {
  4737. StringBuffer lookupHelperName;
  4738. buildDictionaryHashClass(dictionary->queryRecord(), lookupHelperName);
  4739. BuildCtx funcctx(ctx);
  4740. StringBuffer s;
  4741. s.append("virtual IHThorHashLookupInfo * ").append(memberName).append("() { return &").append(lookupHelperName).append("; }");
  4742. funcctx.addQuoted(s);
  4743. }
  4744. //---------------------------------------------------------------------------
  4745. IHqlExpression * queryImplementationInterface(IHqlExpression * moduleFunc)
  4746. {
  4747. IHqlExpression * module = moduleFunc->queryChild(0);
  4748. IHqlExpression * library = module->queryAttribute(libraryAtom);
  4749. if (library)
  4750. return library->queryChild(0);
  4751. return moduleFunc;
  4752. }
  4753. bool isLibraryScope(IHqlExpression * expr)
  4754. {
  4755. while (expr->getOperator() == no_comma)
  4756. expr = expr->queryChild(1);
  4757. return expr->isScope();
  4758. }
  4759. bool HqlCppTranslator::prepareToGenerate(HqlQueryContext & query, WorkflowArray & actions, bool isEmbeddedLibrary)
  4760. {
  4761. bool createLibrary = isLibraryScope(query.expr);
  4762. if (createLibrary)
  4763. {
  4764. if (query.expr->getOperator() != no_funcdef)
  4765. throwError(HQLERR_LibraryMustBeFunctional);
  4766. ::Release(outputLibrary);
  4767. outputLibrary = NULL;
  4768. outputLibraryId.setown(createAttribute(graphAtom, getSizetConstant(nextActivityId())));
  4769. outputLibrary = new HqlCppLibraryImplementation(*this, queryImplementationInterface(query.expr), outputLibraryId, targetClusterType);
  4770. if (!isEmbeddedLibrary)
  4771. {
  4772. SCMStringBuffer libraryName;
  4773. wu()->getJobName(libraryName);
  4774. wu()->setLibraryInformation(libraryName.str(), outputLibrary->getInterfaceHash(), getLibraryCRC(query.expr));
  4775. }
  4776. }
  4777. else
  4778. {
  4779. if (options.applyInstantEclTransformations)
  4780. query.expr.setown(doInstantEclTransformations(query.expr, options.applyInstantEclTransformationsLimit));
  4781. }
  4782. if (!transformGraphForGeneration(query, actions))
  4783. return false;
  4784. return true;
  4785. }
  4786. void HqlCppTranslator::updateClusterType()
  4787. {
  4788. const char * clusterTypeText="?";
  4789. switch (targetClusterType)
  4790. {
  4791. case ThorLCRCluster:
  4792. clusterTypeText = "thorlcr";
  4793. break;
  4794. case HThorCluster:
  4795. clusterTypeText = "hthor";
  4796. break;
  4797. case RoxieCluster:
  4798. clusterTypeText = "roxie";
  4799. break;
  4800. }
  4801. //ensure targetClusterType is consistently set in the work unit - so library code can use it.
  4802. wu()->setDebugValue("targetClusterType", clusterTypeText, true);
  4803. }
  4804. struct CountEntry : public CInterface
  4805. {
  4806. ThorActivityKind from;
  4807. ThorActivityKind to;
  4808. unsigned cnt;
  4809. };
  4810. int compareItems(CInterface * * _l, CInterface * * _r)
  4811. {
  4812. CountEntry * l = (CountEntry *)*_l;
  4813. CountEntry * r = (CountEntry *)*_r;
  4814. return (int)(r->cnt - l->cnt);
  4815. }
  4816. void dumpActivityCounts()
  4817. {
  4818. #ifdef _GATHER_USAGE_STATS
  4819. CIArray items;
  4820. for (unsigned i = TAKnone; i < TAKlast; i++)
  4821. {
  4822. for (unsigned j = TAKnone; j < TAKlast; j++)
  4823. {
  4824. if (activityCounts[i][j])
  4825. {
  4826. CountEntry & next = * new CountEntry;
  4827. next.from = (ThorActivityKind)i;
  4828. next.to = (ThorActivityKind)j;
  4829. next.cnt = activityCounts[i][j];
  4830. items.append(next);
  4831. }
  4832. }
  4833. }
  4834. items.sort(compareItems);
  4835. FILE * out = fopen("stats.txt", "w");
  4836. if (!out)
  4837. return;
  4838. fprintf(out, "-Count- Source -> Sink\n");
  4839. ForEachItemIn(k, items)
  4840. {
  4841. CountEntry & cur = (CountEntry &)items.item(k);
  4842. fprintf(out, "%8d %s -> %s\n", cur.cnt, getActivityText(cur.from), getActivityText(cur.to));
  4843. }
  4844. fclose(out);
  4845. #endif
  4846. }
  4847. bool HqlCppTranslator::buildCode(HqlQueryContext & query, const char * embeddedLibraryName, bool isEmbeddedLibrary)
  4848. {
  4849. unsigned time = msTick();
  4850. WorkflowArray workflow;
  4851. bool ok = prepareToGenerate(query, workflow, isEmbeddedLibrary);
  4852. if (ok)
  4853. {
  4854. //This is done late so that pickBestEngine has decided which engine we are definitely targeting.
  4855. if (!isEmbeddedLibrary)
  4856. updateClusterType();
  4857. updateTimer("workunit;tree transform", msTick()-time);
  4858. if (insideLibrary())
  4859. {
  4860. //always do these checks for consistency
  4861. OwnedHqlExpr graph;
  4862. ForEachItemIn(i, workflow)
  4863. {
  4864. WorkflowItem & cur = workflow.item(i);
  4865. if (!cur.isFunction())
  4866. {
  4867. assertex(!graph);
  4868. HqlExprArray & exprs = cur.queryExprs();
  4869. assertex(exprs.ordinality() == 1);
  4870. graph.set(&exprs.item(0));
  4871. assertex(graph->getOperator() == no_thor);
  4872. }
  4873. }
  4874. //More: this should be cleaned up - with a flag in the workflow items to indicate a library graph instead...
  4875. if (embeddedLibraryName)
  4876. {
  4877. ForEachItemIn(i, workflow)
  4878. {
  4879. WorkflowItem & cur = workflow.item(i);
  4880. if (cur.isFunction())
  4881. {
  4882. OwnedHqlExpr function = cur.getFunction();
  4883. buildFunctionDefinition(function);
  4884. }
  4885. }
  4886. BuildCtx ctx(*code, goAtom);
  4887. buildLibraryGraph(ctx, graph, embeddedLibraryName);
  4888. }
  4889. else
  4890. buildWorkflow(workflow);
  4891. }
  4892. else
  4893. buildWorkflow(workflow);
  4894. if (options.calculateComplexity)
  4895. {
  4896. unsigned time = msTick();
  4897. StringBuffer complexityText;
  4898. complexityText.append(getComplexity(workflow));
  4899. wu()->setDebugValue("__Calculated__Complexity__", complexityText, true);
  4900. updateTimer("workunit;calculate complexity", msTick()-time);
  4901. }
  4902. }
  4903. ::Release(outputLibrary);
  4904. outputLibrary = NULL;
  4905. outputLibraryId.clear();
  4906. return ok;
  4907. }
  4908. bool HqlCppTranslator::buildCpp(IHqlCppInstance & _code, HqlQueryContext & query)
  4909. {
  4910. if (!internalScope)
  4911. return false;
  4912. try
  4913. {
  4914. unsigned time = msTick();
  4915. wu()->setCodeVersion(ACTIVITY_INTERFACE_VERSION,BUILD_TAG,LANGUAGE_VERSION);
  4916. cacheOptions();
  4917. useLibrary(ECLRTL_LIB);
  4918. useInclude("eclrtl.hpp");
  4919. HqlExprArray internalLibraries;
  4920. query.expr.setown(separateLibraries(query.expr, internalLibraries));
  4921. //General internal libraries first, in dependency order
  4922. ForEachItemIn(i, internalLibraries)
  4923. {
  4924. IHqlExpression & cur = internalLibraries.item(i);
  4925. assertex(cur.getOperator() == no_funcdef);
  4926. IHqlExpression * moduleExpr = cur.queryChild(0);
  4927. IHqlExpression * definition = queryAttributeChild(moduleExpr, internalAtom, 0);
  4928. IHqlExpression * name = queryAttributeChild(moduleExpr, nameAtom, 0);
  4929. StringBuffer internalLibraryName;
  4930. name->queryValue()->getStringValue(internalLibraryName);
  4931. overrideOptionsForLibrary();
  4932. HqlQueryContext libraryQuery;
  4933. libraryQuery.expr.set(definition);
  4934. if (!buildCode(libraryQuery, internalLibraryName.str(), true))
  4935. return false;
  4936. }
  4937. if (isLibraryScope(query.expr))
  4938. overrideOptionsForLibrary();
  4939. else
  4940. overrideOptionsForQuery();
  4941. if (!buildCode(query, NULL, false))
  4942. return false;
  4943. //Return early if iteratively generating the field usage statistics
  4944. if (getDebugFlag("generateFullFieldUsage", false))
  4945. return false;
  4946. #ifdef _GATHER_USAGE_STATS
  4947. if (getDebugFlag("dumpActivityCounts", false))
  4948. dumpActivityCounts();
  4949. #endif
  4950. ForEachItemIn(i1, globalFiles)
  4951. globalFiles.item(i1).writeToGraph();
  4952. //Have to submit graphs to work unit right at the end so that globalUsage counts etc. can be updated in them.
  4953. ForEachItemIn(i2, graphs)
  4954. {
  4955. GeneratedGraphInfo & cur = graphs.item(i2);
  4956. Owned<IWUGraph> wug = wu()->updateGraph(cur.name);
  4957. wug->setXGMMLTree(cur.xgmml.getClear());
  4958. wug->setType(GraphTypeActivities);
  4959. wug->setLabel(cur.label);
  4960. }
  4961. code->processIncludes();
  4962. if (options.peephole)
  4963. {
  4964. cycle_t time = msTick();
  4965. peepholeOptimize(*code, *this);
  4966. updateTimer("workunit;peephole optimize", msTick()-time);
  4967. }
  4968. }
  4969. catch (IException * e)
  4970. {
  4971. ensureWorkUnitUpdated();
  4972. if (e->errorCode() != HQLERR_ErrorAlreadyReported)
  4973. throw;
  4974. e->Release();
  4975. return false;
  4976. }
  4977. catch (...)
  4978. {
  4979. ensureWorkUnitUpdated();
  4980. throw;
  4981. }
  4982. ensureWorkUnitUpdated();
  4983. return true;
  4984. }
  4985. class WuTimingUpdater : implements ITimeReportInfo
  4986. {
  4987. public:
  4988. WuTimingUpdater(IWorkUnit * _wu) { wu = _wu; }
  4989. virtual void report(const char * scope, const char * description, const __int64 totaltime, const __int64 maxtime, const unsigned count)
  4990. {
  4991. updateWorkunitTiming(wu, "eclcc", scope, description, milliToNano(totaltime), count, milliToNano(maxtime));
  4992. }
  4993. protected:
  4994. IWorkUnit * wu;
  4995. };
  4996. void HqlCppTranslator::ensureWorkUnitUpdated()
  4997. {
  4998. if (timeReporter && options.addTimingToWorkunit)
  4999. {
  5000. WuTimingUpdater updater(wu());
  5001. timeReporter->report(updater);
  5002. }
  5003. }
  5004. double HqlCppTranslator::getComplexity(IHqlExpression * expr, ClusterType cluster)
  5005. {
  5006. double complexity = 0;
  5007. switch (expr->getOperator())
  5008. {
  5009. case no_sequential:
  5010. case no_comma:
  5011. case no_compound:
  5012. case no_parallel:
  5013. case no_actionlist:
  5014. case no_orderedactionlist:
  5015. break;
  5016. case no_thor:
  5017. {
  5018. OwnedHqlExpr resourced = getResourcedGraph(expr->queryChild(0), NULL);
  5019. lockTransformMutex();
  5020. complexity = getComplexity(resourced, targetClusterType);
  5021. unlockTransformMutex();
  5022. return complexity;
  5023. }
  5024. case no_subgraph:
  5025. return getComplexity(expr->queryChild(0), cluster);
  5026. case no_selfjoin:
  5027. case no_join:
  5028. if (isLocalActivity(expr) || !isThorCluster(cluster))
  5029. complexity = 1;
  5030. else
  5031. complexity = 5;
  5032. break;
  5033. case no_distribute:
  5034. if (isThorCluster(cluster))
  5035. complexity = 5;
  5036. break;
  5037. case no_subsort:
  5038. complexity = 1;
  5039. break;
  5040. case no_sort:
  5041. if (isLocalActivity(expr) || !isThorCluster(cluster))
  5042. complexity = 2;
  5043. else
  5044. complexity = 5;
  5045. break;
  5046. case no_ensureresult:
  5047. if (options.freezePersists)
  5048. return 0;
  5049. if (expr->queryChild(0)->queryType()->getTypeCode() == type_void)
  5050. return getComplexity(expr->queryChild(0), cluster);
  5051. //fall through..
  5052. case no_setresult:
  5053. {
  5054. if (cluster == NoCluster)
  5055. return 0.05;
  5056. return 1;
  5057. }
  5058. case no_split:
  5059. //Only count the parents of a splitter once
  5060. if (expr->queryTransformExtra())
  5061. return 0;
  5062. expr->setTransformExtraUnlinked(expr);
  5063. complexity = 1;
  5064. break;
  5065. case no_forcelocal:
  5066. return getComplexity(expr->queryChild(0), cluster);
  5067. default:
  5068. complexity = 1;
  5069. break;
  5070. }
  5071. ForEachChildActivity(i, expr)
  5072. complexity += getComplexity(queryChildActivity(expr, i), cluster);
  5073. return complexity;
  5074. }
  5075. double HqlCppTranslator::getComplexity(IHqlCppInstance & _code, IHqlExpression * exprlist)
  5076. {
  5077. WorkflowArray workflow;
  5078. HqlQueryContext query;
  5079. query.expr.set(exprlist);
  5080. if (!prepareToGenerate(query, workflow, false))
  5081. return 0;
  5082. return getComplexity(workflow);
  5083. }
  5084. double HqlCppTranslator::getComplexity(WorkflowArray & workflow)
  5085. {
  5086. double complexity = 0;
  5087. ForEachItemIn(i, workflow)
  5088. complexity += getComplexity(workflow.item(i).queryExprs());
  5089. return complexity;
  5090. }
  5091. double HqlCppTranslator::getComplexity(HqlExprArray & exprs)
  5092. {
  5093. double complexity = 0;
  5094. ForEachItemIn(idx, exprs)
  5095. complexity += getComplexity(&exprs.item(idx), NoCluster);
  5096. return complexity;
  5097. }
  5098. //---------------------------------------------------------------------------------------------------------------------
  5099. static int compareTrackedSourceByName(CInterface * * _left, CInterface * * _right)
  5100. {
  5101. SourceFieldUsage & left = static_cast<SourceFieldUsage &>(**_left);
  5102. SourceFieldUsage & right = static_cast<SourceFieldUsage &>(**_right);
  5103. const char * leftName = left.queryFilenameText();
  5104. const char * rightName = right.queryFilenameText();
  5105. return stricmp(leftName, rightName);
  5106. }
  5107. IPropertyTree * HqlCppTranslator::gatherFieldUsage(const char * varient, const IPropertyTree * exclude)
  5108. {
  5109. Owned<IPropertyTree> sources = createPTree("usedsources");
  5110. sources->setProp("@varient", varient);
  5111. trackedSources.sort(compareTrackedSourceByName);
  5112. ForEachItemIn(i, trackedSources)
  5113. {
  5114. IPropertyTree * next = trackedSources.item(i).createReport(options.reportFieldUsage, exclude);
  5115. if (next)
  5116. sources->addPropTree(next->queryName(), next);
  5117. }
  5118. return sources.getClear();
  5119. }
  5120. SourceFieldUsage * HqlCppTranslator::querySourceFieldUsage(IHqlExpression * expr)
  5121. {
  5122. if (!(options.reportFieldUsage || options.reportFileUsage) || !expr)
  5123. return NULL;
  5124. if (expr->hasAttribute(_spill_Atom) || expr->hasAttribute(jobTempAtom))
  5125. return NULL;
  5126. OwnedHqlExpr normalized = removeAttribute(expr, _uid_Atom);
  5127. IHqlExpression * original = normalized->queryAttribute(_original_Atom);
  5128. if (original)
  5129. {
  5130. OwnedHqlExpr normalTable = removeAttribute(original->queryChild(0), _uid_Atom);
  5131. OwnedHqlExpr normalOriginal = replaceChild(original, 0, normalTable);
  5132. normalized.setown(replaceOwnedAttribute(normalized, normalOriginal.getClear()));
  5133. }
  5134. ForEachItemIn(i, trackedSources)
  5135. {
  5136. SourceFieldUsage & cur = trackedSources.item(i);
  5137. if (cur.matches(normalized))
  5138. return &cur;
  5139. }
  5140. SourceFieldUsage * next = new SourceFieldUsage(normalized);
  5141. trackedSources.append(*next);
  5142. return next;
  5143. }
  5144. void HqlCppTranslator::noteAllFieldsUsed(IHqlExpression * expr)
  5145. {
  5146. SourceFieldUsage * match = querySourceFieldUsage(expr);
  5147. if (match)
  5148. match->noteAll();
  5149. }
  5150. void HqlCppTranslator::writeFieldUsage(const char * targetDir, IPropertyTree * source, const char * variant)
  5151. {
  5152. if (source)
  5153. {
  5154. StringBuffer fullname;
  5155. addDirectoryPrefix(fullname, targetDir).append(soName).append("_fieldusage");
  5156. if (variant)
  5157. fullname.append("_").append(variant);
  5158. fullname.append(".xml");
  5159. saveXML(fullname, source);
  5160. Owned<IWUQuery> query = wu()->updateQuery();
  5161. associateLocalFile(query, FileTypeXml, fullname, "FieldUsage", 0);
  5162. ctxCallback->registerFile(fullname.str(), "FieldUsage");
  5163. }
  5164. }
  5165. void HqlCppTranslator::generateStatistics(const char * targetDir, const char * varient)
  5166. {
  5167. if ((options.reportFieldUsage || options.reportFileUsage) && trackedSources.ordinality())
  5168. {
  5169. Owned<IPropertyTree> sources = gatherFieldUsage(varient, NULL);
  5170. writeFieldUsage(targetDir, sources, NULL);
  5171. }
  5172. }
  5173. //---------------------------------------------------------------------------------------------------------------------
  5174. BoundRow * HqlCppTranslator::resolveDatasetRequired(BuildCtx & ctx, IHqlExpression * expr)
  5175. {
  5176. BoundRow * cursor = resolveSelectorDataset(ctx, expr);
  5177. if (!cursor)
  5178. {
  5179. StringBuffer tablename;
  5180. tablename.append(expr->queryName());
  5181. if (tablename.length() == 0)
  5182. getExprECL(expr, tablename);
  5183. if (ctx.queryFirstAssociation(AssocCursor))
  5184. throwError1(HQLERR_CouldNotFindDataset, tablename.str());
  5185. throwError1(HQLERR_CouldNotAnyDatasetX, tablename.str());
  5186. }
  5187. return cursor;
  5188. }
  5189. IReferenceSelector * HqlCppTranslator::buildActiveReference(BuildCtx & ctx, IHqlExpression * expr)
  5190. {
  5191. ITypeInfo * type = expr->queryType();
  5192. assertex(type);
  5193. switch (type->getTypeCode())
  5194. {
  5195. case type_row:
  5196. return buildActiveRow(ctx, expr);
  5197. }
  5198. return buildReference(ctx, expr);
  5199. }
  5200. IReferenceSelector * HqlCppTranslator::createReferenceSelector(BoundRow * cursor, IHqlExpression * path)
  5201. {
  5202. return new DatasetSelector(*this, cursor, path);
  5203. }
  5204. IReferenceSelector * HqlCppTranslator::createReferenceSelector(BoundRow * cursor)
  5205. {
  5206. return new DatasetSelector(*this, cursor, cursor->querySelector());
  5207. }
  5208. IReferenceSelector * HqlCppTranslator::buildReference(BuildCtx & ctx, IHqlExpression * expr)
  5209. {
  5210. ITypeInfo * type = expr->queryType();
  5211. assertex(type);
  5212. switch (type->getTypeCode())
  5213. {
  5214. case type_row:
  5215. return buildNewRow(ctx, expr);
  5216. }
  5217. const node_operator op = expr->getOperator();
  5218. switch (op)
  5219. {
  5220. case no_variable:
  5221. case no_field:
  5222. case no_ifblock:
  5223. throwUnexpectedOp(op);
  5224. case no_select:
  5225. {
  5226. IHqlExpression * ds = expr->queryChild(0);
  5227. IHqlExpression * field = expr->queryChild(1);
  5228. Owned<IReferenceSelector> selector;
  5229. if (isNewSelector(expr))
  5230. {
  5231. //could optimize selection from a project of an in-scope dataset.
  5232. if (((ds->getOperator() == no_newusertable) || (ds->getOperator() == no_hqlproject)) &&
  5233. isAlwaysActiveRow(ds->queryChild(0)))
  5234. {
  5235. //MORE: could optimize selection from a project of an in-scope dataset.
  5236. }
  5237. selector.setown(buildNewRow(ctx, ds));
  5238. }
  5239. else
  5240. selector.setown(buildActiveRow(ctx, ds));
  5241. return selector->select(ctx, expr);
  5242. }
  5243. }
  5244. BoundRow * cursor = resolveDatasetRequired(ctx, expr);
  5245. IReferenceSelector * alias = cursor->queryAlias();
  5246. if (alias)
  5247. return LINK(alias);
  5248. IHqlExpression * dataset = cursor->queryDataset();
  5249. return createReferenceSelector(cursor, dataset);
  5250. }
  5251. ABoundActivity * HqlCppTranslator::buildActivity(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  5252. {
  5253. checkAbort();
  5254. WarningProcessor::OnWarningStateBlock saved(warningProcessor);
  5255. //Process any annotations first - but still pass the original expr to the doBuildActivtyXXX functions.
  5256. IHqlExpression * cur = expr;
  5257. loop
  5258. {
  5259. IHqlExpression * body = cur->queryBody(true);
  5260. if (cur == body)
  5261. break;
  5262. switch (cur->getAnnotationKind())
  5263. {
  5264. case annotate_meta:
  5265. warningProcessor.processMetaAnnotation(cur);
  5266. break;
  5267. case annotate_symbol:
  5268. {
  5269. #ifdef SPOT_POTENTIAL_COMMON_ACTIVITIES
  5270. if (cur->getStartLine() && cur->queryName()->str()[0] != '_')
  5271. {
  5272. unsigned match = savedActivityLocations.findLocation(cur);
  5273. if (match == NotFound)
  5274. {
  5275. savedActivityLocations.append(*LINK(cur));
  5276. savedActivities.append(*LINK(expr));
  5277. }
  5278. else
  5279. {
  5280. debugFindFirstDifference(cur, &savedActivities.item(match));
  5281. //MORE: Could add some kind of comment.
  5282. }
  5283. }
  5284. #endif
  5285. warningProcessor.setSymbol(cur);
  5286. break;
  5287. }
  5288. }
  5289. cur = body;
  5290. }
  5291. if (isCompoundSource(expr))
  5292. {
  5293. OwnedHqlExpr mapped = normalizeAnyDatasetAliases(expr);
  5294. if (mapped != expr)
  5295. return buildActivity(ctx, mapped, isRoot);
  5296. }
  5297. ABoundActivity * result;
  5298. try
  5299. {
  5300. node_operator op = expr->getOperator();
  5301. switch (op)
  5302. {
  5303. case no_merge:
  5304. result = doBuildActivityMerge(ctx, expr);
  5305. break;
  5306. case no_nwaymerge:
  5307. result = doBuildActivityNWayMerge(ctx, expr);
  5308. break;
  5309. case no_mergejoin:
  5310. case no_nwayjoin:
  5311. result = doBuildActivityNWayMergeJoin(ctx, expr);
  5312. break;
  5313. case no_rowsetrange:
  5314. result = doBuildActivityRowsetRange(ctx, expr);
  5315. break;
  5316. case no_rowsetindex:
  5317. result = doBuildActivityRowsetIndex(ctx, expr);
  5318. break;
  5319. case no_datasetlist:
  5320. {
  5321. OwnedHqlExpr allExpr = createValue(no_all, makeSetType(LINK(sizetType)));
  5322. result = doBuildActivityRowsetRange(ctx, expr, expr, allExpr);
  5323. break;
  5324. }
  5325. case no_addfiles:
  5326. // result = doBuildActivityChildDataset(ctx, expr);
  5327. // break;
  5328. result = doBuildActivityConcat(ctx, expr);
  5329. break;
  5330. case no_regroup:
  5331. result = doBuildActivityRegroup(ctx, expr);
  5332. break;
  5333. case no_nonempty:
  5334. result = doBuildActivityNonEmpty(ctx, expr);
  5335. break;
  5336. case no_combine:
  5337. result = doBuildActivityCombine(ctx, expr);
  5338. break;
  5339. case no_combinegroup:
  5340. result = doBuildActivityCombineGroup(ctx, expr);
  5341. break;
  5342. case no_rollupgroup:
  5343. result = doBuildActivityRollupGroup(ctx, expr);
  5344. break;
  5345. case no_filtergroup:
  5346. result = doBuildActivityFilterGroup(ctx, expr);
  5347. break;
  5348. case no_cachealias:
  5349. result = doBuildActivityCacheAlias(ctx, expr);
  5350. break;
  5351. case no_cloned:
  5352. result = doBuildActivityCloned(ctx, expr);
  5353. break;
  5354. case no_distribute:
  5355. case no_assertdistributed:
  5356. result = doBuildActivityDistribute(ctx, expr);
  5357. break;
  5358. case no_keyeddistribute:
  5359. result = doBuildActivityKeyedDistribute(ctx, expr);
  5360. break;
  5361. case no_select:
  5362. if (isNewSelector(expr))
  5363. result = doBuildActivitySelectNew(ctx, expr);
  5364. else
  5365. result = doBuildActivityChildDataset(ctx, expr);
  5366. break;
  5367. //Items in this list need to also be in the list inside doBuildActivityChildDataset
  5368. case no_call:
  5369. case no_externalcall:
  5370. if (expr->isAction())
  5371. result = doBuildActivityAction(ctx, expr, isRoot);
  5372. else if (hasStreamedModifier(expr->queryType()))
  5373. {
  5374. result = doBuildActivityStreamedCall(ctx, expr);
  5375. }
  5376. else if (hasLinkCountedModifier(expr->queryType()))
  5377. {
  5378. result = doBuildActivityLinkedRawChildDataset(ctx, expr);
  5379. }
  5380. else
  5381. result = doBuildActivityChildDataset(ctx, expr);
  5382. break;
  5383. case no_left:
  5384. case no_right:
  5385. case no_top:
  5386. case no_id2blob:
  5387. case no_typetransfer:
  5388. case no_rows:
  5389. case no_xmlproject:
  5390. case no_libraryinput:
  5391. case no_activetable:
  5392. case no_translated:
  5393. result = doBuildActivityChildDataset(ctx, expr);
  5394. break;
  5395. case no_compound_inline:
  5396. result = doBuildActivityChildDataset(ctx, expr->queryChild(0));
  5397. break;
  5398. case no_dataset_from_transform:
  5399. result = doBuildActivityCountTransform(ctx, expr);
  5400. break;
  5401. case no_table:
  5402. result = doBuildActivityTable(ctx, expr);
  5403. break;
  5404. case no_compound_diskread:
  5405. result = doBuildActivityDiskRead(ctx, expr);
  5406. break;
  5407. case no_compound_diskaggregate:
  5408. case no_compound_diskcount:
  5409. result = doBuildActivityDiskAggregate(ctx, expr);
  5410. break;
  5411. case no_compound_diskgroupaggregate:
  5412. result = doBuildActivityDiskGroupAggregate(ctx, expr);
  5413. break;
  5414. case no_compound_disknormalize:
  5415. result = doBuildActivityDiskNormalize(ctx, expr);
  5416. break;
  5417. case no_compound_childread:
  5418. case no_compound_childnormalize:
  5419. result = doBuildActivityChildNormalize(ctx, expr);
  5420. break;
  5421. case no_compound_childaggregate:
  5422. case no_compound_childcount:
  5423. result = doBuildActivityChildAggregate(ctx, expr);
  5424. break;
  5425. case no_compound_childgroupaggregate:
  5426. result = doBuildActivityChildGroupAggregate(ctx, expr);
  5427. break;
  5428. case no_compound_selectnew:
  5429. result = doBuildActivityCompoundSelectNew(ctx, expr);
  5430. break;
  5431. case no_denormalize:
  5432. case no_denormalizegroup:
  5433. result = doBuildActivityDenormalize(ctx, expr);
  5434. break;
  5435. case no_datasetfromrow:
  5436. {
  5437. OwnedHqlExpr row = expr->cloneAllAnnotations(expr->queryChild(0)); // preserve any position information....
  5438. if ((getNumActivityArguments(expr) == 0) && canProcessInline(&ctx, row))
  5439. result = doBuildActivityCreateRow(ctx, row, false);
  5440. else
  5441. result = buildCachedActivity(ctx, row);
  5442. break;
  5443. }
  5444. case no_datasetfromdictionary:
  5445. result = doBuildActivityChildDataset(ctx, expr);
  5446. break;
  5447. case no_temptable:
  5448. result = doBuildActivityTempTable(ctx, expr);
  5449. break;
  5450. case no_inlinetable:
  5451. result = doBuildActivityInlineTable(ctx, expr);
  5452. break;
  5453. case no_temprow:
  5454. throwUnexpected();
  5455. break;
  5456. case no_workunit_dataset:
  5457. if (targetRoxie() && queryCurrentActivity(ctx))
  5458. result = doBuildActivityChildDataset(ctx, expr);
  5459. else
  5460. result = doBuildActivityWorkunitRead(ctx, expr);
  5461. break;
  5462. case no_fail:
  5463. if (expr->isAction())
  5464. result = doBuildActivityAction(ctx, expr, isRoot);
  5465. else
  5466. result = doBuildActivitySideEffect(ctx, expr, isRoot, true);
  5467. break;
  5468. case no_null:
  5469. if (expr->isDatarow())
  5470. result = doBuildActivityCreateRow(ctx, expr, false);
  5471. else
  5472. result = doBuildActivityNull(ctx, expr, isRoot);
  5473. break;
  5474. case no_split:
  5475. result = doBuildActivitySplit(ctx, expr);
  5476. break;
  5477. case no_apply:
  5478. result = doBuildActivityApply(ctx, expr, isRoot);
  5479. break;
  5480. case no_output:
  5481. result = doBuildActivityOutput(ctx, expr, isRoot);
  5482. break;
  5483. case no_extractresult:
  5484. case no_setresult:
  5485. result = doBuildActivitySetResult(ctx, expr, isRoot);
  5486. break;
  5487. case no_returnresult:
  5488. result = doBuildActivityReturnResult(ctx, expr, isRoot);
  5489. break;
  5490. case no_getgraphresult:
  5491. //Use the get graph result activity if we are generating the correct level graph.
  5492. //otherwise it needs to be serialized from the parent activity
  5493. {
  5494. IHqlExpression * graphId = expr->queryChild(1);
  5495. bool canAccessResultDirectly = isCurrentActiveGraph(ctx, graphId);
  5496. if (!canAccessResultDirectly)
  5497. {
  5498. //Sometimes results for the parent graph can be accessed from a child graph (e.g., loops).
  5499. //The test for Thor is temporary - roxie and hthor should both allow access to outer results
  5500. //from inside a loop.
  5501. //In fact roxie/hthor could access parent results directly from a child query if the parent
  5502. //activity is always on the master. (Thor could if it knew to access the entire result.)
  5503. if (getTargetClusterType() == ThorLCRCluster)
  5504. {
  5505. ParentExtract * extract = static_cast<ParentExtract*>(ctx.queryFirstAssociation(AssocExtract));
  5506. if (extract)
  5507. canAccessResultDirectly = extract->areGraphResultsAccessible(graphId);
  5508. }
  5509. }
  5510. if (canAccessResultDirectly)
  5511. result = doBuildActivityGetGraphResult(ctx, expr);
  5512. else
  5513. result = doBuildActivityChildDataset(ctx, expr);
  5514. break;
  5515. }
  5516. case no_getgraphloopresult:
  5517. //Use the get graph result activity if we are generating the correct level graph.
  5518. //otherwise it needs to be serialized from the parent activity
  5519. {
  5520. if (isCurrentActiveGraph(ctx, expr->queryChild(1)))
  5521. result = doBuildActivityGetGraphLoopResult(ctx, expr);
  5522. else
  5523. throwError(HQLERR_GraphInputAccessedChild);
  5524. break;
  5525. }
  5526. case no_setgraphresult:
  5527. case no_spillgraphresult:
  5528. result = doBuildActivitySetGraphResult(ctx, expr, isRoot);
  5529. break;
  5530. case no_setgraphloopresult:
  5531. result = doBuildActivitySetGraphLoopResult(ctx, expr);
  5532. break;
  5533. case no_spill:
  5534. result = doBuildActivitySpill(ctx, expr);
  5535. break;
  5536. case no_buildindex:
  5537. result = doBuildActivityOutputIndex(ctx, expr, isRoot);
  5538. break;
  5539. case no_distribution:
  5540. result = doBuildActivityDistribution(ctx, expr, isRoot);
  5541. break;
  5542. case no_keydiff:
  5543. result = doBuildActivityKeyDiff(ctx, expr, isRoot);
  5544. break;
  5545. case no_keypatch:
  5546. result = doBuildActivityKeyPatch(ctx, expr, isRoot);
  5547. break;
  5548. case no_if:
  5549. result = doBuildActivityIf(ctx, expr, isRoot);
  5550. break;
  5551. case no_case:
  5552. case no_map:
  5553. result = doBuildActivityCase(ctx, expr, isRoot);
  5554. break;
  5555. case no_chooseds:
  5556. case no_choose:
  5557. result = doBuildActivityChoose(ctx, expr, isRoot);
  5558. break;
  5559. case no_iterate:
  5560. result = doBuildActivityIterate(ctx, expr);
  5561. break;
  5562. case no_process:
  5563. result = doBuildActivityProcess(ctx, expr);
  5564. break;
  5565. case no_group:
  5566. //Special case group(subsort) which will be mapped to group(group(sort(group))) to remove
  5567. //the redundant group
  5568. if (!options.supportsSubSortActivity && (expr->queryChild(0)->getOperator() == no_subsort))
  5569. {
  5570. IHqlExpression * subsort = expr->queryChild(0);
  5571. OwnedHqlExpr groupedSort = convertSubSortToGroupedSort(subsort);
  5572. assertex(groupedSort->getOperator() == no_group);
  5573. OwnedHqlExpr newGroup = replaceChild(expr, 0, groupedSort->queryChild(0));
  5574. result = doBuildActivityGroup(ctx, newGroup);
  5575. }
  5576. else
  5577. result = doBuildActivityGroup(ctx, expr);
  5578. break;
  5579. case no_cogroup:
  5580. case no_assertgrouped:
  5581. result = doBuildActivityGroup(ctx, expr);
  5582. break;
  5583. case no_normalize:
  5584. result = doBuildActivityNormalize(ctx, expr);
  5585. break;
  5586. case no_normalizegroup:
  5587. result = doBuildActivityNormalizeGroup(ctx, expr);
  5588. break;
  5589. case no_sorted:
  5590. case no_distributed:
  5591. case no_preservemeta:
  5592. case no_grouped:
  5593. case no_nofold:
  5594. case no_nohoist:
  5595. case no_globalscope:
  5596. case no_thisnode:
  5597. case no_forcegraph:
  5598. case no_keyed:
  5599. result = buildCachedActivity(ctx, expr->queryChild(0));
  5600. break;
  5601. case no_dataset_alias:
  5602. if (!expr->hasAttribute(_normalized_Atom))
  5603. {
  5604. OwnedHqlExpr uniqueChild = normalizeDatasetAlias(expr);
  5605. result = buildCachedActivity(ctx, uniqueChild);
  5606. }
  5607. else
  5608. result = buildCachedActivity(ctx, expr->queryChild(0));
  5609. break;
  5610. case no_alias_scope:
  5611. case no_alias:
  5612. result = buildCachedActivity(ctx, expr->queryChild(0));
  5613. break;
  5614. case no_section:
  5615. result = doBuildActivitySection(ctx, expr);
  5616. break;
  5617. case no_sectioninput:
  5618. result = doBuildActivitySectionInput(ctx, expr);
  5619. break;
  5620. case no_forcelocal:
  5621. result = doBuildActivityForceLocal(ctx, expr);
  5622. break;
  5623. case no_preload:
  5624. {
  5625. StringBuffer s;
  5626. DBGLOG("%s", getExprECL(expr, s).str());
  5627. throwError(HQLERR_TooComplicatedToPreload);
  5628. }
  5629. case no_sub:
  5630. result = doBuildActivitySub(ctx, expr);
  5631. break;
  5632. case no_subsort:
  5633. if (!options.supportsSubSortActivity)
  5634. {
  5635. OwnedHqlExpr groupedSort = convertSubSortToGroupedSort(expr);
  5636. result = buildCachedActivity(ctx, groupedSort);
  5637. }
  5638. else
  5639. result = doBuildActivitySort(ctx, expr);
  5640. break;
  5641. case no_sort:
  5642. case no_cosort:
  5643. case no_topn:
  5644. case no_assertsorted:
  5645. result = doBuildActivitySort(ctx, expr);
  5646. break;
  5647. case no_dedup:
  5648. result = doBuildActivityDedup(ctx, expr);
  5649. break;
  5650. case no_enth:
  5651. result = doBuildActivityEnth(ctx, expr);
  5652. break;
  5653. case no_pipe:
  5654. result = doBuildActivityPipeThrough(ctx, expr);
  5655. break;
  5656. case no_sample:
  5657. result = doBuildActivitySample(ctx, expr);
  5658. break;
  5659. case no_filter:
  5660. result = doBuildActivityFilter(ctx, expr);
  5661. break;
  5662. case no_limit:
  5663. result = doBuildActivityLimit(ctx, expr);
  5664. break;
  5665. case no_catchds:
  5666. result = doBuildActivityCatch(ctx, expr);
  5667. break;
  5668. case no_keyedlimit:
  5669. {
  5670. traceExpression("keyed fail", expr);
  5671. StringBuffer s;
  5672. getExprECL(expr->queryChild(1), s);
  5673. throwError1(HQLERR_KeyedLimitNotKeyed, s.str());
  5674. }
  5675. case no_index:
  5676. case no_selectnth:
  5677. result = doBuildActivitySelectNth(ctx, expr);
  5678. break;
  5679. case no_selectmap:
  5680. result = doBuildActivityCreateRow(ctx, expr, false);
  5681. break;
  5682. case no_join:
  5683. case no_selfjoin:
  5684. result = doBuildActivityJoin(ctx, expr);
  5685. break;
  5686. case no_fetch:
  5687. case no_compound_fetch:
  5688. result = doBuildActivityFetch(ctx, expr);
  5689. break;
  5690. case no_rollup:
  5691. result = doBuildActivityRollup(ctx, expr);
  5692. break;
  5693. case no_hqlproject:
  5694. case no_transformascii:
  5695. case no_transformebcdic:
  5696. case no_projectrow:
  5697. result = doBuildActivityProject(ctx, expr);
  5698. break;
  5699. case no_createrow:
  5700. result = doBuildActivityCreateRow(ctx, expr, false);
  5701. break;
  5702. case no_newusertable:
  5703. result = doBuildActivityProject(ctx, expr);
  5704. break;
  5705. case no_aggregate:
  5706. case no_newaggregate:
  5707. case no_throughaggregate:
  5708. result = doBuildActivityAggregate(ctx, expr);
  5709. break;
  5710. case no_metaactivity:
  5711. result = doBuildActivityMetaActivity(ctx, expr);
  5712. break;
  5713. case no_choosen:
  5714. result = doBuildActivityFirstN(ctx, expr);
  5715. break;
  5716. case no_choosesets:
  5717. result = doBuildActivityChooseSets(ctx, expr);
  5718. break;
  5719. case no_newkeyindex:
  5720. case no_compound_indexread:
  5721. result = doBuildActivityIndexRead(ctx, expr);
  5722. break;
  5723. case no_compound_indexcount:
  5724. case no_compound_indexaggregate:
  5725. result = doBuildActivityIndexAggregate(ctx, expr);
  5726. break;
  5727. case no_compound_indexgroupaggregate:
  5728. result = doBuildActivityIndexGroupAggregate(ctx, expr);
  5729. break;
  5730. case no_compound_indexnormalize:
  5731. result = doBuildActivityIndexNormalize(ctx, expr);
  5732. break;
  5733. case no_compound:
  5734. buildStmt(ctx, expr->queryChild(0));
  5735. result = buildCachedActivity(ctx, expr->queryChild(1));
  5736. break;
  5737. case no_newparse:
  5738. result = doBuildActivityParse(ctx, expr);
  5739. break;
  5740. case no_newxmlparse:
  5741. result = doBuildActivityXmlParse(ctx, expr);
  5742. break;
  5743. case no_httpcall:
  5744. result = doBuildActivityHTTP(ctx, expr, (expr->isAction()), isRoot);
  5745. break;
  5746. case no_newsoapcall:
  5747. case no_newsoapcall_ds:
  5748. case no_newsoapaction_ds:
  5749. result = doBuildActivitySOAP(ctx, expr, (expr->isAction()), isRoot);
  5750. break;
  5751. case no_parallel:
  5752. case no_sequential:
  5753. case no_actionlist:
  5754. case no_orderedactionlist:
  5755. result = doBuildActivitySequentialParallel(ctx, expr, isRoot);
  5756. break;
  5757. case no_activerow:
  5758. {
  5759. OwnedHqlExpr row = createDatasetFromRow(LINK(expr));
  5760. return buildCachedActivity(ctx, row);
  5761. }
  5762. case no_assert_ds:
  5763. result = doBuildActivityAssert(ctx, expr);
  5764. break;
  5765. case no_loop:
  5766. result = doBuildActivityLoop(ctx, expr);
  5767. break;
  5768. case no_graphloop:
  5769. result = doBuildActivityGraphLoop(ctx, expr);
  5770. break;
  5771. case no_allnodes:
  5772. result = doBuildActivityRemote(ctx, expr, isRoot);
  5773. break;
  5774. case no_libraryselect:
  5775. result = doBuildActivityLibrarySelect(ctx, expr);
  5776. break;
  5777. case no_libraryscopeinstance:
  5778. result = doBuildActivityLibraryInstance(ctx, expr);
  5779. break;
  5780. case no_serialize:
  5781. case no_deserialize:
  5782. result = doBuildActivitySerialize(ctx, expr);
  5783. break;
  5784. case no_definesideeffect:
  5785. result = doBuildActivityDefineSideEffect(ctx, expr);
  5786. break;
  5787. case no_callsideeffect:
  5788. result = doBuildActivityCallSideEffect(ctx, expr);
  5789. break;
  5790. case no_executewhen:
  5791. result = doBuildActivityExecuteWhen(ctx, expr, isRoot);
  5792. break;
  5793. case no_thor:
  5794. UNIMPLEMENTED;
  5795. break;
  5796. default:
  5797. if (expr->isAction())
  5798. return doBuildActivityAction(ctx, expr, isRoot);
  5799. if (expr->isDatarow())
  5800. {
  5801. OwnedHqlExpr row = createDatasetFromRow(LINK(expr));
  5802. return buildCachedActivity(ctx, row);
  5803. }
  5804. else
  5805. {
  5806. UNIMPLEMENTED_XY("Activity", getOpString(op));
  5807. }
  5808. }
  5809. }
  5810. catch (IException * e)
  5811. {
  5812. if (dynamic_cast<IECLError *>(e))
  5813. throw;
  5814. IHqlExpression * location = queryActiveActivityLocation();
  5815. if (location)
  5816. {
  5817. IECLError * error = annotateExceptionWithLocation(e, location);
  5818. e->Release();
  5819. throw error;
  5820. }
  5821. throw;
  5822. }
  5823. return result;
  5824. }
  5825. ABoundActivity * HqlCppTranslator::buildCachedActivity(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  5826. {
  5827. switch (expr->getOperator())
  5828. {
  5829. case no_split:
  5830. case no_libraryscopeinstance:
  5831. {
  5832. ActivityAssociation * match = static_cast<ActivityAssociation *>(ctx.queryAssociation(expr, AssocActivity, NULL));
  5833. if (match)
  5834. return LINK(match->activity);
  5835. break;
  5836. }
  5837. case no_if:
  5838. {
  5839. if (options.recreateMapFromIf && !expr->isAction())
  5840. {
  5841. OwnedHqlExpr converted = combineIfsToMap(expr);
  5842. if (converted)
  5843. return buildCachedActivity(ctx, converted);
  5844. }
  5845. break;
  5846. }
  5847. }
  5848. //NB: ActivityExprStack is purely used for improving the error reporting
  5849. activityExprStack.append(*LINK(expr));
  5850. try
  5851. {
  5852. //Don't modify aliases in child queries - otherwise they can fail to match the aliases generated in the parent
  5853. OwnedHqlExpr optimized = insideChildOrLoopGraph(ctx) ? LINK(expr) : optimizeActivityAliasReferences(expr);
  5854. ThorBoundActivity * bound = (ThorBoundActivity *)buildActivity(ctx, optimized, isRoot);
  5855. activityExprStack.pop();
  5856. ActivityAssociation * table = new ActivityAssociation(expr->queryBody(), bound);
  5857. ctx.associateOwn(*table);
  5858. return bound;
  5859. }
  5860. catch (IException *)
  5861. {
  5862. activityExprStack.pop();
  5863. throw;
  5864. }
  5865. }
  5866. void HqlCppTranslator::buildRootActivity(BuildCtx & ctx, IHqlExpression * expr)
  5867. {
  5868. WarningProcessor::OnWarningStateBlock saved(warningProcessor);
  5869. ::Release(buildCachedActivity(ctx, expr, true));
  5870. }
  5871. void HqlCppTranslator::buildRecordSerializeExtract(BuildCtx & ctx, IHqlExpression * memoryRecord)
  5872. {
  5873. OwnedHqlExpr serializedRecord = getSerializedForm(memoryRecord, diskAtom);
  5874. OwnedHqlExpr serializedDataset = createDataset(no_null, LINK(serializedRecord));
  5875. OwnedHqlExpr memoryDataset = createDataset(no_anon, LINK(memoryRecord));
  5876. MetaInstance meta(*this, memoryRecord, false);
  5877. buildMetaInfo(meta);
  5878. if (recordTypesMatch(memoryRecord, serializedRecord))
  5879. {
  5880. StringBuffer s;
  5881. if (isFixedRecordSize(memoryRecord))
  5882. {
  5883. ctx.addQuoted(s.append("size32_t size = ").append(getFixedRecordSize(memoryRecord)).append(";"));
  5884. }
  5885. else
  5886. {
  5887. ctx.addQuoted(s.append("size32_t size = ").append(meta.queryInstanceObject()).append(".getRecordSize(_left);"));
  5888. }
  5889. ctx.addQuoted("byte * self = crSelf.ensureCapacity(size, NULL);");
  5890. ctx.addQuoted("memcpy(crSelf.row(), _left, size);");
  5891. ctx.addQuoted("return size;");
  5892. }
  5893. else
  5894. {
  5895. ctx.addQuoted("const byte * left = (const byte *)_left;");
  5896. BoundRow * self = bindSelf(ctx, serializedDataset, "crSelf");
  5897. BoundRow * left = bindTableCursor(ctx, memoryDataset, "left");
  5898. OwnedHqlExpr rhs = ensureActiveRow(left->querySelector());
  5899. OwnedHqlExpr serializedRow = ::ensureSerialized(rhs, diskAtom); // Ensure this is always accessed as disk serialized
  5900. buildAssign(ctx, self->querySelector(), serializedRow);
  5901. buildReturnRecordSize(ctx, self);
  5902. }
  5903. }
  5904. //---------------------------------------------------------------------------
  5905. BoundRow * HqlCppTranslator::bindTableCursor(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq)
  5906. {
  5907. BoundRow * cursor = createTableCursor(dataset, bound, side, selSeq);
  5908. ctx.associateOwn(*cursor);
  5909. return cursor;
  5910. }
  5911. BoundRow * HqlCppTranslator::bindTableCursor(BuildCtx & ctx, IHqlExpression * dataset, const char * name, bool isLinkCounted, node_operator side, IHqlExpression * selSeq)
  5912. {
  5913. Owned<ITypeInfo> type = makeRowReferenceType(NULL);
  5914. if (isLinkCounted)
  5915. type.setown(makeAttributeModifier(type.getClear(), getLinkCountedAttr()));
  5916. Owned<IHqlExpression> bound = createVariable(name, type.getClear());
  5917. // Owned<IHqlExpression> bound = createVariable(name, makeRowReferenceType(dataset));
  5918. return bindTableCursor(ctx, dataset, bound, side, selSeq);
  5919. }
  5920. BoundRow * HqlCppTranslator::rebindTableCursor(BuildCtx & ctx, IHqlExpression * dataset, BoundRow * row, node_operator side, IHqlExpression * selSeq)
  5921. {
  5922. BoundRow * cursor = recreateTableCursor(dataset, row, side, selSeq);
  5923. ctx.associateOwn(*cursor);
  5924. return cursor;
  5925. }
  5926. BoundRow * HqlCppTranslator::createTableCursor(IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq)
  5927. {
  5928. return new BoundRow(dataset, bound, queryRecordOffsetMap(dataset->queryRecord()), side, selSeq);
  5929. }
  5930. BoundRow * HqlCppTranslator::recreateTableCursor(IHqlExpression * dataset, BoundRow * row, node_operator side, IHqlExpression * selSeq)
  5931. {
  5932. return new BoundRow(row, dataset, side, selSeq);
  5933. }
  5934. BoundRow * HqlCppTranslator::createTableCursor(IHqlExpression * dataset, const char * name, bool isLinkCounted, node_operator side, IHqlExpression * selSeq)
  5935. {
  5936. Owned<ITypeInfo> type = makeRowReferenceType(NULL);
  5937. if (isLinkCounted)
  5938. type.setown(makeAttributeModifier(type.getClear(), getLinkCountedAttr()));
  5939. Owned<IHqlExpression> bound = createVariable(name, type.getClear());
  5940. return createTableCursor(dataset, bound, side, selSeq);
  5941. }
  5942. BoundRow * HqlCppTranslator::bindXmlTableCursor(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq, bool translateVirtuals)
  5943. {
  5944. Owned<ColumnToOffsetMap> xmlMap = new XmlColumnToOffsetMap(dataset->queryRecord(), getDefaultMaxRecordSize(), translateVirtuals);
  5945. xmlMap->init(recordMap);
  5946. BoundRow * cursor = new BoundRow(dataset, bound, xmlMap, side, selSeq);
  5947. ctx.associateOwn(*cursor);
  5948. return cursor;
  5949. }
  5950. BoundRow * HqlCppTranslator::bindXmlTableCursor(BuildCtx & ctx, IHqlExpression * dataset, const char * name, node_operator side, IHqlExpression * selSeq, bool translateVirtuals)
  5951. {
  5952. OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(NULL));
  5953. // OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(dataset));
  5954. return bindXmlTableCursor(ctx, dataset, bound, side, selSeq, translateVirtuals);
  5955. }
  5956. BoundRow * HqlCppTranslator::bindCsvTableCursor(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * bound, node_operator side, IHqlExpression * selSeq, bool translateVirtuals, IAtom * encoding)
  5957. {
  5958. Owned<ColumnToOffsetMap> csvMap = new CsvColumnToOffsetMap(dataset->queryRecord(), getDefaultMaxRecordSize(), translateVirtuals, encoding);
  5959. csvMap->init(recordMap);
  5960. BoundRow * cursor = new BoundRow(dataset, bound, csvMap, side, selSeq);
  5961. ctx.associateOwn(*cursor);
  5962. return cursor;
  5963. }
  5964. BoundRow * HqlCppTranslator::bindCsvTableCursor(BuildCtx & ctx, IHqlExpression * dataset, const char * name, node_operator side, IHqlExpression * selSeq, bool translateVirtuals, IAtom * encoding)
  5965. {
  5966. OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(NULL));
  5967. // OwnedHqlExpr bound = createVariable(name, makeRowReferenceType(dataset));
  5968. return bindCsvTableCursor(ctx, dataset, bound, side, selSeq, translateVirtuals, encoding);
  5969. }
  5970. BoundRow * HqlCppTranslator::bindSelf(BuildCtx & ctx, IHqlExpression * dataset, const char * builderName)
  5971. {
  5972. StringBuffer bound;
  5973. bound.append(builderName).append(".row()");
  5974. BoundRow * row = bindTableCursor(ctx, dataset, bound, false, no_self, NULL);
  5975. OwnedHqlExpr builder = createVariable(builderName, makeBoolType());
  5976. row->setBuilder(builder);
  5977. return row;
  5978. }
  5979. BoundRow * HqlCppTranslator::bindSelf(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * expr, IHqlExpression * builder)
  5980. {
  5981. BoundRow * row = bindTableCursor(ctx, dataset, expr, no_self, NULL);
  5982. row->setBuilder(builder);
  5983. return row;
  5984. }
  5985. BoundRow * HqlCppTranslator::bindRow(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * bound)
  5986. {
  5987. BoundRow * row = createBoundRow(expr, bound);
  5988. ctx.associateOwn(*row);
  5989. return row;
  5990. }
  5991. BoundRow * HqlCppTranslator::bindRow(BuildCtx & ctx, IHqlExpression * expr, const char * name)
  5992. {
  5993. Owned<IHqlExpression> bound = createVariable(name, makeRowReferenceType(NULL));
  5994. return bindRow(ctx, expr, bound);
  5995. }
  5996. BoundRow * HqlCppTranslator::bindTableCursorOrRow(BuildCtx & ctx, IHqlExpression * expr, const char * name)
  5997. {
  5998. if (expr->getOperator() == no_activerow)
  5999. expr = expr->queryChild(0);
  6000. if (expr->isDatarow())
  6001. return bindRow(ctx, expr, name);
  6002. else
  6003. return bindTableCursor(ctx, expr, name);
  6004. }
  6005. BoundRow * HqlCppTranslator::createBoundRow(IHqlExpression * dataset, IHqlExpression * bound)
  6006. {
  6007. return new BoundRow(dataset->queryBody(), bound, queryRecordOffsetMap(dataset->queryRecord()));
  6008. }
  6009. BoundRow * HqlCppTranslator::bindSelectorAsSelf(BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * expr)
  6010. {
  6011. BoundRow * rootRow = selector->queryRootRow();
  6012. if (!rootRow->queryBuilder())
  6013. {
  6014. if (options.alwaysCreateRowBuilder || !isFixedWidthDataset(rootRow->queryRecord()))
  6015. UNIMPLEMENTED_X("expected a row builder");
  6016. }
  6017. if (selector->isRoot())
  6018. {
  6019. if (rootRow->querySide() == no_self)
  6020. {
  6021. ctx.associate(*rootRow);
  6022. return rootRow;
  6023. }
  6024. return bindSelf(ctx, expr, rootRow->queryBound(), rootRow->queryBuilder());
  6025. }
  6026. //Need to bind a delta address to a new variable.
  6027. // throwUnexpected(); // check this is actually called
  6028. CHqlBoundExpr offset;
  6029. selector->getOffset(ctx, offset);
  6030. CHqlBoundExpr address;
  6031. selector->buildAddress(ctx, address);
  6032. OwnedHqlExpr row = createValue(no_typetransfer, makeReferenceModifier(LINK(selector->queryType())), LINK(address.expr));
  6033. unsigned trailingFixed = selector->getContainerTrailingFixed();
  6034. StringBuffer builderName;
  6035. {
  6036. getUniqueId(builderName.append("b"));
  6037. StringBuffer s;
  6038. s.append("RtlNestedRowBuilder ").append(builderName).append("(");
  6039. generateExprCpp(s, rootRow->queryBuilder()).append(",");
  6040. generateExprCpp(s, offset.expr).append(",").append(trailingFixed).append(");");
  6041. ctx.addQuoted(s);
  6042. }
  6043. BoundRow * selfRow = bindSelf(ctx, expr, builderName);
  6044. selfRow->setAlias(selector);
  6045. return selfRow;
  6046. }
  6047. void HqlCppTranslator::finishSelf(BuildCtx & ctx, BoundRow * self, BoundRow * target)
  6048. {
  6049. if (target)
  6050. {
  6051. OwnedHqlExpr sizeofSelf = createSizeof(self->querySelector());
  6052. CHqlBoundExpr bound;
  6053. buildExpr(ctx, sizeofSelf, bound);
  6054. OwnedHqlExpr sizeofTarget = createSizeof(target->querySelector());
  6055. ctx.associateExpr(sizeofTarget, bound);
  6056. }
  6057. ctx.removeAssociation(self);
  6058. }
  6059. void HqlCppTranslator::ensureRowAllocated(BuildCtx & ctx, const char * builder)
  6060. {
  6061. StringBuffer s;
  6062. s.append(builder).append(".getSelf();");
  6063. ctx.addQuoted(s);
  6064. }
  6065. void HqlCppTranslator::ensureRowAllocated(BuildCtx & ctx, BoundRow * row)
  6066. {
  6067. assertex(row->queryBuilder());
  6068. StringBuffer s;
  6069. generateExprCpp(s, row->queryBuilder()).append(".getSelf();");
  6070. ctx.addQuoted(s);
  6071. }
  6072. //---------------------------------------------------------------------------
  6073. BoundRow * HqlCppTranslator::bindSelectorAsRootRow(BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * expr)
  6074. {
  6075. BoundRow * rootRow = selector->queryRootRow();
  6076. assertex(!rootRow->queryBuilder());
  6077. if (selector->isRoot())
  6078. {
  6079. ctx.associate(*rootRow);
  6080. return rootRow;
  6081. }
  6082. //Need to bind a delta address to a new variable.
  6083. CHqlBoundExpr address;
  6084. selector->buildAddress(ctx, address);
  6085. OwnedHqlExpr row = createValue(no_typetransfer, makeReferenceModifier(LINK(selector->queryType())), LINK(address.expr));
  6086. BoundRow * childRow = bindTableCursor(ctx, expr, row);
  6087. childRow->setAlias(selector);
  6088. return childRow;
  6089. }
  6090. //---------------------------------------------------------------------------
  6091. BoundRow * HqlCppTranslator::resolveSelectorDataset(BuildCtx & ctx, IHqlExpression * dataset)
  6092. {
  6093. return static_cast<BoundRow *>(ctx.queryAssociation(dataset->queryNormalizedSelector(), AssocCursor, NULL));
  6094. }
  6095. //---------------------------------------------------------------------------
  6096. void HqlCppTranslator::addDependency(BuildCtx & ctx, ABoundActivity * sourceActivity, IPropertyTree * sinkGraphTree, ABoundActivity * sinkActivity, IAtom * kind, const char * label, unsigned inputIndex, int whenId)
  6097. {
  6098. IPropertyTree * graphTree = NULL;
  6099. if (sinkActivity->queryGraphId() == sourceActivity->queryGraphId())
  6100. {
  6101. if (targetHThor())
  6102. throwError1(HQLERR_DependencyWithinGraph, sinkActivity->queryGraphId());
  6103. graphTree = sinkGraphTree;
  6104. }
  6105. unsigned outputIndex = 0;
  6106. if (kind != childAtom)
  6107. outputIndex = sourceActivity->nextOutputCount();
  6108. StringBuffer idText;
  6109. idText.append(sourceActivity->queryActivityId()).append('_').append(sinkActivity->queryActivityId());
  6110. IPropertyTree *edge = createPTree();
  6111. edge->setProp("@id", idText.str());
  6112. if (label)
  6113. edge->setProp("@label", label);
  6114. if (targetRoxie())
  6115. {
  6116. if (outputIndex)
  6117. addGraphAttributeInt(edge, "_sourceIndex", outputIndex);
  6118. }
  6119. if (inputIndex)
  6120. addGraphAttributeInt(edge, "_targetIndex", inputIndex);
  6121. if (kind == childAtom)
  6122. {
  6123. addGraphAttributeBool(edge, "_childGraph", true);
  6124. }
  6125. else if (kind == dependencyAtom)
  6126. {
  6127. addGraphAttributeBool(edge, "_dependsOn", true);
  6128. }
  6129. else if (sourceActivity->queryContainerId() != sinkActivity->queryContainerId())
  6130. {
  6131. //mark as a dependency if the source and target aren't at the same depth
  6132. addGraphAttributeBool(edge, "_dependsOn", true);
  6133. }
  6134. if (whenId)
  6135. addGraphAttributeInt(edge, "_when", whenId);
  6136. if (graphTree)
  6137. {
  6138. edge->setPropInt64("@target", sinkActivity->queryActivityId());
  6139. edge->setPropInt64("@source", sourceActivity->queryActivityId());
  6140. graphTree->addPropTree("edge", edge);
  6141. }
  6142. else
  6143. {
  6144. edge->setPropInt64("@target", sinkActivity->queryGraphId());
  6145. edge->setPropInt64("@source", sourceActivity->queryGraphId());
  6146. addGraphAttributeInt(edge, "_sourceActivity", sourceActivity->queryActivityId());
  6147. addGraphAttributeInt(edge, "_targetActivity", sinkActivity->queryActivityId());
  6148. activeGraph->xgmml->addPropTree("edge", edge);
  6149. }
  6150. }
  6151. void HqlCppTranslator::addDependency(BuildCtx & ctx, ABoundActivity * element, ABoundActivity * dependent, IAtom * kind, const char * label)
  6152. {
  6153. unsigned whenId = 0;
  6154. addDependency(ctx, element, NULL, dependent, kind, label, 0, whenId);
  6155. }
  6156. void HqlCppTranslator::addDependency(BuildCtx & ctx, ABoundActivity * element, ActivityInstance * instance, IAtom * kind, const char * label)
  6157. {
  6158. unsigned whenId = 0;
  6159. addDependency(ctx, element, instance->querySubgraphNode(), instance->queryBoundActivity(), kind, label, 0, whenId);
  6160. }
  6161. void HqlCppTranslator::addActionConnection(BuildCtx & ctx, ABoundActivity * element, ActivityInstance * instance, IAtom * kind, const char * label, unsigned inputIndex, int whenId)
  6162. {
  6163. addDependency(ctx, element, instance->querySubgraphNode(), instance->queryBoundActivity(), kind, label, inputIndex, whenId);
  6164. }
  6165. void HqlCppTranslator::buildClearRecord(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * record, int direction)
  6166. {
  6167. Owned<IReferenceSelector> selector = buildActiveRow(ctx, dataset);
  6168. selector->buildClear(ctx, direction);
  6169. }
  6170. IHqlExpression * HqlCppTranslator::getClearRecordFunction(IHqlExpression * record, int direction)
  6171. {
  6172. IHqlExpression * dirExpr = getSizetConstant((size32_t)direction);
  6173. OwnedHqlExpr search = createAttribute(__clearHelperAtom, LINK(record->queryBody()), dirExpr);
  6174. BuildCtx declarectx(*code, declareAtom);
  6175. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  6176. if (match)
  6177. return LINK(match->queryExpr());
  6178. StringBuffer functionName;
  6179. getUniqueId(functionName.append("clearRow"));
  6180. BuildCtx clearctx(declarectx);
  6181. StringBuffer s;
  6182. s.append("size32_t ").append(functionName).append("(ARowBuilder & crSelf, IResourceContext * ctx)");
  6183. clearctx.setNextPriority(RowMetaPrio);
  6184. if (record)
  6185. {
  6186. IHqlStmt * func = clearctx.addQuotedCompound(s);
  6187. func->setIncomplete(true);
  6188. OwnedHqlExpr dataset = createDataset(no_anon, LINK(record));
  6189. BoundRow * cursor = bindSelf(clearctx, dataset, "crSelf");
  6190. ensureRowAllocated(clearctx, "crSelf");
  6191. buildClearRecord(clearctx, cursor->querySelector(), record, direction);
  6192. buildReturnRecordSize(clearctx, cursor);
  6193. func->setIncomplete(false);
  6194. }
  6195. else
  6196. clearctx.addQuotedCompound(s.append(" {}"));
  6197. if (options.spanMultipleCpp)
  6198. {
  6199. s.clear().append("extern size32_t ").append(functionName).append("(ARowBuilder & crSelf, IResourceContext * ctx);");
  6200. BuildCtx protoctx(*code, mainprototypesAtom);
  6201. protoctx.addQuoted(s);
  6202. }
  6203. OwnedHqlExpr temp = createVariable(functionName, makeVoidType());
  6204. declarectx.associateExpr(search, temp);
  6205. return temp.getLink();
  6206. }
  6207. void HqlCppTranslator::buildClearRecordMember(BuildCtx & ctx, const char * name, IHqlExpression * dataset)
  6208. {
  6209. BuildCtx clearCtx(ctx);
  6210. StringBuffer s;
  6211. s.append("virtual size32_t createDefault").append(name).append("(ARowBuilder & crSelf)");
  6212. if (dataset && dataset->queryRecord()->numChildren())
  6213. {
  6214. OwnedHqlExpr func = getClearRecordFunction(dataset->queryRecord());
  6215. generateExprCpp(s.append(" { return "), func).append("(crSelf, ctx); }");
  6216. clearCtx.addQuoted(s);
  6217. }
  6218. else
  6219. clearCtx.addQuoted(s.append(" { return 0; }"));
  6220. }
  6221. void HqlCppTranslator::doBuildExprEvaluate(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6222. {
  6223. IHqlExpression * dataset = expr->queryChild(0);
  6224. IHqlExpression * field = expr->queryChild(1);
  6225. BoundRow * boundRow = resolveSelectorDataset(ctx, dataset);
  6226. if (boundRow)
  6227. {
  6228. //E.g. EVALUATE(LEFT, attribute). Need to make sure field refs are unambiguous.
  6229. BuildCtx subctx(ctx);
  6230. subctx.addGroup();
  6231. bindTableCursor(subctx, boundRow->queryDataset(), boundRow->queryBound());
  6232. buildExpr(subctx, field, tgt);
  6233. }
  6234. else
  6235. {
  6236. switch (dataset->queryType()->getTypeCode())
  6237. {
  6238. case type_row:
  6239. BuildCtx subctx(ctx);
  6240. subctx.addGroup();
  6241. Owned<IReferenceSelector> selector = buildNewRow(subctx, dataset);
  6242. Owned<BoundRow> boundRow = selector->getRow(subctx);
  6243. //subctx.associateOwn???
  6244. bindTableCursor(subctx, boundRow->queryDataset(), boundRow->queryBound());
  6245. buildExpr(subctx, field, tgt);
  6246. return;
  6247. }
  6248. throwError(HQLERR_EvaluateTableNotInScope);
  6249. }
  6250. }
  6251. void HqlCppTranslator::doBuildExprCounter(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6252. {
  6253. if (buildExprInCorrectContext(ctx, expr, tgt, false))
  6254. return;
  6255. throwError(HQLERR_CounterNotValid);
  6256. }
  6257. //---------------------------------------------------------------------------
  6258. void HqlCppTranslator::doBuildSerialize(BuildCtx & ctx, IIdAtom * name, IHqlExpression * length, CHqlBoundExpr & bound, const char * bufferName)
  6259. {
  6260. HqlExprArray args;
  6261. if (length)
  6262. args.append(*LINK(length));
  6263. else
  6264. {
  6265. args.append(*getBoundSize(bound));
  6266. }
  6267. args.append(*getPointer(bound.expr));
  6268. args.append(*createVariable(bufferName, makeBoolType()));
  6269. callProcedure(ctx, name, args);
  6270. }
  6271. void HqlCppTranslator::ensureSerialized(const CHqlBoundTarget & variable, BuildCtx & serializectx, BuildCtx & deserializectx, const char * inBufferName, const char * outBufferName, IAtom * serializeForm)
  6272. {
  6273. CHqlBoundExpr value;
  6274. value.setFromTarget(variable);
  6275. while (isCast(value.expr))
  6276. value.expr.set(value.expr->queryChild(0));
  6277. ITypeInfo * type = value.expr->queryType();
  6278. if ((type->getSize() == UNKNOWN_LENGTH) || hasLinkCountedModifier(type) || hasWrapperModifier(type))
  6279. {
  6280. HqlExprArray serializeArgs;
  6281. serializeArgs.append(*value.getTranslatedExpr());
  6282. HqlExprArray deserializeArgs;
  6283. IIdAtom * serializeName;
  6284. IIdAtom * deserializeName;
  6285. OwnedITypeInfo serializedType;
  6286. type_t tc = type->getTypeCode();
  6287. switch (tc)
  6288. {
  6289. case type_varstring:
  6290. serializeName = serializeCStringXId;
  6291. deserializeName = deserializeCStringXId;
  6292. break;
  6293. case type_string:
  6294. serializeName = serializeStringXId;
  6295. deserializeName = deserializeStringXId;
  6296. break;
  6297. case type_data:
  6298. serializeName = serializeDataXId;
  6299. deserializeName = deserializeDataXId;
  6300. break;
  6301. case type_set:
  6302. serializeName = serializeSetId;
  6303. deserializeName = deserializeSetId;
  6304. break;
  6305. case type_qstring:
  6306. serializeName = serializeQStrXId;
  6307. deserializeName = deserializeQStrXId;
  6308. break;
  6309. case type_unicode:
  6310. serializeName = serializeUnicodeXId;
  6311. deserializeName = deserializeUnicodeXId;
  6312. break;
  6313. case type_varunicode:
  6314. serializeName = serializeUnicodeXId;
  6315. deserializeName = deserializeVUnicodeXId;
  6316. break;
  6317. case type_utf8:
  6318. serializeName = serializeUtf8XId;
  6319. deserializeName = deserializeUtf8XId;
  6320. break;
  6321. case type_dictionary:
  6322. case type_table:
  6323. case type_groupedtable:
  6324. {
  6325. IHqlExpression * record = ::queryRecord(type);
  6326. if (hasLinkCountedModifier(type))
  6327. {
  6328. deserializeArgs.append(*createSerializer(deserializectx, record, serializeForm, deserializerAtom));
  6329. serializeArgs.append(*createSerializer(serializectx, record, serializeForm, serializerAtom));
  6330. if (tc == type_dictionary)
  6331. {
  6332. serializeName = serializeDictionaryXId;
  6333. deserializeName = deserializeDictionaryXId;
  6334. }
  6335. else if (tc == type_groupedtable)
  6336. {
  6337. serializeName = serializeGroupedRowsetXId;
  6338. deserializeName = deserializeGroupedRowsetXId;
  6339. }
  6340. else
  6341. {
  6342. serializeName = serializeRowsetXId;
  6343. deserializeName = deserializeRowsetXId;
  6344. }
  6345. }
  6346. else
  6347. {
  6348. assertex(!recordRequiresSerialization(record, serializeForm));
  6349. if (tc == type_dictionary)
  6350. {
  6351. throwUnexpected();
  6352. }
  6353. else if (tc == type_groupedtable)
  6354. {
  6355. serializeName = serializeGroupedDatasetXId;
  6356. deserializeName = deserializeGroupedDatasetXId;
  6357. }
  6358. else
  6359. {
  6360. serializeName = serializeDatasetXId;
  6361. deserializeName = deserializeDatasetXId;
  6362. }
  6363. }
  6364. serializedType.set(type);
  6365. break;
  6366. }
  6367. case type_row:
  6368. {
  6369. IHqlExpression * record = ::queryRecord(type);
  6370. assertex(hasWrapperModifier(type));
  6371. serializeArgs.append(*createSerializer(serializectx, record, serializeForm, serializerAtom));
  6372. serializeArgs.append(*createVariable(outBufferName, makeBoolType()));
  6373. buildFunctionCall(serializectx, serializeRowId, serializeArgs);
  6374. deserializeArgs.append(*createSerializer(deserializectx, record, serializeForm, deserializerAtom));
  6375. deserializeArgs.append(*createVariable(inBufferName, makeBoolType()));
  6376. Owned<ITypeInfo> resultType = makeReferenceModifier(makeAttributeModifier(makeRowType(record->getType()), getLinkCountedAttr()));
  6377. OwnedHqlExpr call = bindFunctionCall(deserializeRowId, deserializeArgs, resultType);
  6378. buildExprAssign(deserializectx, variable, call);
  6379. return;
  6380. }
  6381. default:
  6382. UNIMPLEMENTED;
  6383. }
  6384. serializeArgs.append(*createVariable(outBufferName, makeBoolType()));
  6385. deserializeArgs.append(*createVariable(inBufferName, makeBoolType()));
  6386. buildFunctionCall(serializectx, serializeName, serializeArgs);
  6387. OwnedHqlExpr deserializeCall = bindFunctionCall(deserializeName, deserializeArgs, serializedType);
  6388. buildExprAssign(deserializectx, variable, deserializeCall);
  6389. }
  6390. else
  6391. {
  6392. OwnedHqlExpr length;
  6393. switch (type->getTypeCode())
  6394. {
  6395. case type_int:
  6396. case type_swapint:
  6397. case type_packedint:
  6398. switch (type->getSize())
  6399. {
  6400. case 3: case 5: case 6: case 7:
  6401. if (isLittleEndian(type))
  6402. buildClear(deserializectx, variable);
  6403. else
  6404. {
  6405. unsigned newSize = (type->getSize() == 3) ? 4 : 8;
  6406. length.setown(getSizetConstant(newSize));
  6407. }
  6408. break;
  6409. }
  6410. break;
  6411. case type_row:
  6412. {
  6413. //MORE: This will cause problems if rows are dynamically allocated
  6414. if (hasReferenceModifier(type))
  6415. length.setown(getSizetConstant(sizeof(void*)));
  6416. else
  6417. {
  6418. IHqlExpression * record = ::queryRecord(type);
  6419. ColumnToOffsetMap * map = queryRecordOffsetMap(record);
  6420. length.setown(getSizetConstant(map->getMaxSize()));
  6421. }
  6422. break;
  6423. }
  6424. case type_bitfield:
  6425. UNIMPLEMENTED;
  6426. }
  6427. doBuildSerialize(serializectx, serializeRawId, length, value, outBufferName);
  6428. doBuildSerialize(deserializectx, deserializeRawId, length, value, inBufferName);
  6429. }
  6430. }
  6431. void HqlCppTranslator::ensureSerialized(BuildCtx & ctx, const CHqlBoundTarget & variable)
  6432. {
  6433. EvalContext * instance = queryEvalContext(ctx);
  6434. assertex(instance);
  6435. instance->tempCompatiablityEnsureSerialized(variable);
  6436. }
  6437. bool HqlCppTranslator::checkGetResultContext(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6438. {
  6439. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  6440. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  6441. if (!name)
  6442. name = queryAttributeChild(expr, nameAtom, 0);
  6443. if (!contextAvailable)
  6444. {
  6445. StringBuffer s;
  6446. getStoredDescription(s, seq, name, true);
  6447. ::throwError1(HQLERR_InvalidAcessStoredVariable, s.str());
  6448. }
  6449. if (!insideOnCreate(ctx) && !ctx.queryMatchExpr(globalContextMarkerExpr) && !matchesConstantValue(seq, ResultSequenceOnce))
  6450. {
  6451. if (queryEvalContext(ctx))
  6452. {
  6453. doBuildAliasValue(ctx, expr, tgt);
  6454. return true;
  6455. }
  6456. StringBuffer s;
  6457. getStoredDescription(s, seq, name, true);
  6458. ::throwError1(HQLERR_CannotAccessStoredVariable, s.str());
  6459. }
  6460. if (ctx.getMatchExpr(expr, tgt))
  6461. return true;
  6462. //Use top activity, rather than queryCurrentActivity() - since we want the dependency to the child (for graph display)
  6463. if (activeActivities.ordinality())
  6464. queryAddResultDependancy(activeActivities.tos(), seq, name);
  6465. else if (name && targetRoxie())
  6466. {
  6467. OwnedHqlExpr attr = createResultAttribute(seq, name);
  6468. registerGlobalUsage(attr);
  6469. }
  6470. return false;
  6471. }
  6472. void HqlCppTranslator::doBuildExprGetResult(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6473. {
  6474. if (checkGetResultContext(ctx, expr, tgt))
  6475. return;
  6476. ITypeInfo * exprType = expr->queryType();
  6477. CHqlBoundTarget tempTarget;
  6478. createTempFor(ctx, exprType, tempTarget, typemod_none, FormatLinkedDataset);
  6479. buildGetResultInfo(ctx, expr, NULL, &tempTarget);
  6480. tgt.setFromTarget(tempTarget);
  6481. ctx.associateExpr(expr, tgt);
  6482. }
  6483. void HqlCppTranslator::doBuildAssignGetResult(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6484. {
  6485. CHqlBoundExpr bound;
  6486. if (checkGetResultContext(ctx, expr, bound))
  6487. {
  6488. assign(ctx, target, bound);
  6489. return;
  6490. }
  6491. buildGetResultInfo(ctx, expr, NULL, &target);
  6492. }
  6493. void HqlCppTranslator::pushCluster(BuildCtx & ctx, IHqlExpression * cluster)
  6494. {
  6495. HqlExprArray args;
  6496. args.append(*LINK(cluster));
  6497. buildFunctionCall(ctx, selectClusterId, args);
  6498. StringBuffer clusterText;
  6499. getStringValue(clusterText, cluster);
  6500. if (clusterText.length())
  6501. ctxCallback->noteCluster(clusterText.str());
  6502. }
  6503. void HqlCppTranslator::popCluster(BuildCtx & ctx)
  6504. {
  6505. HqlExprArray args;
  6506. callProcedure(ctx, restoreClusterId, args);
  6507. }
  6508. void HqlCppTranslator::doBuildStmtSetResult(BuildCtx & ctx, IHqlExpression * expr)
  6509. {
  6510. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  6511. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  6512. IHqlExpression * persist = expr->queryAttribute(_workflowPersist_Atom);
  6513. IHqlExpression * cluster = expr->queryAttribute(clusterAtom);
  6514. BuildCtx subctx(ctx);
  6515. LinkedHqlExpr value;
  6516. if (expr->getOperator() == no_extractresult)
  6517. {
  6518. IHqlExpression * ds = expr->queryChild(0);
  6519. OwnedHqlExpr row = removeDatasetWrapper(ds);
  6520. OwnedHqlExpr newDs = (row->getOperator() == no_activerow) ? LINK(row) : createRow(no_newrow, LINK(row));
  6521. value.setown(replaceSelector(expr->queryChild(1), ds, newDs));
  6522. }
  6523. else
  6524. value.set(expr->queryChild(0));
  6525. if (matchesConstantValue(seq, ResultSequenceStored) || matchesConstantValue(seq, ResultSequencePersist))
  6526. {
  6527. StringBuffer text;
  6528. text.append("Create ");
  6529. getStoredDescription(text, seq, name, true);
  6530. graphLabel.set(text.str());
  6531. }
  6532. if (cluster)
  6533. pushCluster(subctx, cluster->queryChild(0));
  6534. switch (value->queryType()->getTypeCode())
  6535. {
  6536. case type_void:
  6537. {
  6538. buildStmt(subctx, value);
  6539. IHqlExpression * result = queryBoolExpr(true);
  6540. if (expr->queryAttribute(checkpointAtom))
  6541. {
  6542. IHqlExpression * search = value;
  6543. if (search->getOperator() == no_thor)
  6544. search = search->queryChild(0);
  6545. if ((search->getOperator() == no_output) && search->queryChild(1))
  6546. {
  6547. BuildCtx atendctx(*code, goAtom);
  6548. atendctx.setNextDestructor();
  6549. HqlExprArray args;
  6550. args.append(*LINK(search->queryChild(1)));
  6551. callProcedure(atendctx, deleteFileId, args);
  6552. }
  6553. }
  6554. if (!expr->hasAttribute(noSetAtom))
  6555. buildSetResultInfo(subctx, expr, result, NULL, (persist != NULL), false);
  6556. }
  6557. break;
  6558. case type_set:
  6559. {
  6560. ITypeInfo * setType = NULL;
  6561. IHqlExpression * original = queryAttributeChild(expr, _original_Atom, 0);
  6562. if (original)
  6563. setType = original->queryType();
  6564. OwnedHqlExpr normalized = normalizeListCasts(value);
  6565. buildSetResultInfo(subctx, expr, normalized, setType, (persist != NULL), true);
  6566. break;
  6567. }
  6568. case type_dictionary:
  6569. case type_table:
  6570. case type_groupedtable:
  6571. switch (value->getOperator())
  6572. {
  6573. case no_null:
  6574. {
  6575. HqlExprArray args;
  6576. args.append(*createResultName(name, false));
  6577. args.append(*LINK(seq));
  6578. args.append(*createValue(no_translated, makeSetType(NULL), createValue(no_nullptr, makeSetType(NULL)), getSizetConstant(0)));
  6579. args.append(*createTranslatedOwned(createValue(no_nullptr, makeBoolType())));
  6580. buildFunctionCall(subctx, setResultSetId, args);
  6581. Owned<IWUResult> result = createDatasetResultSchema(seq, name, value->queryRecord(), true, false);
  6582. break;
  6583. }
  6584. default:
  6585. assertex(!"Should never occur - should have been transformed to an OUTPUT()");
  6586. }
  6587. break;
  6588. default:
  6589. buildSetResultInfo(subctx, expr, value, NULL, (persist != NULL), true);
  6590. break;
  6591. }
  6592. if (cluster)
  6593. popCluster(subctx);
  6594. if (matchesConstantValue(seq, ResultSequenceStored) || matchesConstantValue(seq, ResultSequencePersist))
  6595. graphLabel.clear();
  6596. }
  6597. static bool isFilePersist(IHqlExpression * expr)
  6598. {
  6599. loop
  6600. {
  6601. switch (expr->getOperator())
  6602. {
  6603. case no_thor:
  6604. expr = expr->queryChild(0);
  6605. break;
  6606. case no_compound:
  6607. expr = expr->queryChild(1);
  6608. break;
  6609. case no_output:
  6610. return (queryRealChild(expr, 1) != NULL);
  6611. case no_actionlist:
  6612. case no_orderedactionlist:
  6613. expr = expr->queryChild(expr->numChildren()-1);
  6614. break;
  6615. default:
  6616. return false;
  6617. }
  6618. }
  6619. }
  6620. IHqlExpression * HqlCppTranslator::calculatePersistInputCrc(BuildCtx & ctx, IHqlExpression * expr)
  6621. {
  6622. DependenciesUsed dependencies(true);
  6623. gatherDependencies(expr, dependencies, GatherAll);
  6624. dependencies.removeInternalReads();
  6625. return calculatePersistInputCrc(ctx, dependencies);
  6626. }
  6627. IHqlExpression * HqlCppTranslator::calculatePersistInputCrc(BuildCtx & ctx, DependenciesUsed & dependencies)
  6628. {
  6629. Owned<ITypeInfo> crcType = makeIntType(8, false);
  6630. OwnedHqlExpr zero = createNullExpr(crcType);
  6631. if ((dependencies.tablesRead.ordinality() == 0) && (dependencies.resultsRead.ordinality() == 0))
  6632. return zero.getClear();
  6633. OwnedHqlExpr crcExpr = ctx.getTempDeclare(crcType, zero);
  6634. ForEachItemIn(idx1, dependencies.tablesRead)
  6635. {
  6636. IHqlExpression & cur = dependencies.tablesRead.item(idx1);
  6637. HqlExprArray args;
  6638. args.append(OLINK(cur));
  6639. args.append(*LINK(crcExpr));
  6640. OwnedHqlExpr function = bindFunctionCall(getDatasetHashId, args);
  6641. buildAssignToTemp(ctx, crcExpr, function);
  6642. }
  6643. ForEachItemIn(idx2, dependencies.resultsRead)
  6644. {
  6645. IHqlExpression & cur = dependencies.resultsRead.item(idx2);
  6646. IHqlExpression * seq = cur.queryChild(0);
  6647. IHqlExpression * name = cur.queryChild(1);
  6648. //Not sure if we need to do this if the result is internal. Leave on for the moment.
  6649. //if (seq->queryValue()->getIntValue() != ResultSequenceInternal)
  6650. bool expandLogical = matchesConstantValue(seq, ResultSequencePersist) && !cur.hasAttribute(_internal_Atom);
  6651. HqlExprArray args;
  6652. args.append(*createResultName(name, expandLogical));
  6653. args.append(*LINK(seq));
  6654. OwnedHqlExpr call = bindFunctionCall(getResultHashId, args);
  6655. OwnedHqlExpr value = createValue(no_bxor, crcExpr->getType(), LINK(crcExpr), ensureExprType(call, crcExpr->queryType()));
  6656. buildAssignToTemp(ctx, crcExpr, value);
  6657. }
  6658. return crcExpr.getClear();
  6659. }
  6660. void HqlCppTranslator::doBuildStmtEnsureResult(BuildCtx & ctx, IHqlExpression * expr)
  6661. {
  6662. IHqlExpression * value = expr->queryChild(0);
  6663. IHqlExpression * seq = queryAttributeChild(expr, sequenceAtom, 0);
  6664. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  6665. OwnedHqlExpr resultName = ::createResultName(name);
  6666. resultName.setown(ensureExprType(resultName, unknownVarStringType));
  6667. HqlExprArray args;
  6668. args.append(*LINK(resultName));
  6669. args.append(*LINK(seq));
  6670. OwnedHqlExpr checkExists = createValue(no_not, makeBoolType(), bindFunctionCall(isResultId, args));
  6671. if ((value->getOperator() == no_thor) && (value->queryChild(0)->getOperator() == no_output))
  6672. {
  6673. IHqlExpression * filename = queryRealChild(value->queryChild(0), 1);
  6674. if (filename)
  6675. {
  6676. args.append(*LINK(filename));
  6677. OwnedHqlExpr fileExists = createValue(no_not, makeBoolType(), bindFunctionCall(fileExistsId, args));
  6678. checkExists.setown(createBoolExpr(no_or, checkExists.getClear(), fileExists.getClear()));
  6679. }
  6680. }
  6681. BuildCtx subctx(ctx);
  6682. buildFilter(subctx, checkExists);
  6683. doBuildStmtSetResult(subctx, expr);
  6684. }
  6685. //---------------------------------------------------------------------------
  6686. void HqlCppTranslator::doBuildEvalOnce(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * bound)
  6687. {
  6688. IHqlExpression * value = expr->queryChild(0);
  6689. CHqlBoundExpr result;
  6690. doBuildAliasValue(ctx, value, result);
  6691. if (target)
  6692. {
  6693. OwnedHqlExpr translated = result.getTranslatedExpr();
  6694. buildExprAssign(ctx, *target, translated);
  6695. }
  6696. else if (bound)
  6697. bound->set(result);
  6698. }
  6699. //---------------------------------------------------------------------------
  6700. void HqlCppTranslator::doBuildExprSizeof(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6701. {
  6702. if (ctx.getMatchExpr(expr, tgt))
  6703. return;
  6704. IHqlExpression * child = expr->queryChild(0);
  6705. IHqlExpression * limitExpr = expr->queryChild(1);
  6706. ITypeInfo * type = child->queryType();
  6707. if (expr->hasAttribute(maxAtom))
  6708. {
  6709. if (type)
  6710. {
  6711. unsigned size = UNKNOWN_LENGTH;
  6712. switch (type->getTypeCode())
  6713. {
  6714. case type_dictionary:
  6715. case type_table:
  6716. case type_groupedtable:
  6717. case type_record:
  6718. case type_row:
  6719. {
  6720. OwnedHqlExpr record = getSerializedForm(child->queryRecord(), diskAtom);
  6721. ColumnToOffsetMap * map = queryRecordOffsetMap(record);
  6722. if (map->isFixedWidth())
  6723. size = map->getFixedRecordSize();
  6724. else
  6725. size = map->getMaxSize();
  6726. }
  6727. break;
  6728. case type_alien:
  6729. {
  6730. IHqlAlienTypeInfo * alien = queryAlienType(type);
  6731. size = alien->getMaxSize();
  6732. break;
  6733. }
  6734. default:
  6735. size = type->getSize();
  6736. break;
  6737. }
  6738. if (size == UNKNOWN_LENGTH)
  6739. throwError(HQLERR_CouldNotDetermineMaxSize);
  6740. tgt.expr.setown(getSizetConstant(size));
  6741. return;
  6742. }
  6743. }
  6744. if (expr->hasAttribute(minAtom))
  6745. {
  6746. if (type)
  6747. {
  6748. unsigned size = UNKNOWN_LENGTH;
  6749. switch (type->getTypeCode())
  6750. {
  6751. case type_dictionary:
  6752. case type_table:
  6753. case type_groupedtable:
  6754. case type_record:
  6755. case type_row:
  6756. {
  6757. OwnedHqlExpr record = getSerializedForm(child->queryRecord(), diskAtom);
  6758. size = getMinRecordSize(record);
  6759. }
  6760. break;
  6761. default:
  6762. size = type->getSize();
  6763. break;
  6764. }
  6765. if (size == UNKNOWN_LENGTH)
  6766. throwError(HQLERR_CouldNotDetermineMinSize);
  6767. tgt.expr.setown(getSizetConstant(size));
  6768. return;
  6769. }
  6770. }
  6771. #if 0
  6772. if (limitExpr)
  6773. {
  6774. OwnedHqlExpr other = createValue(no_sizeof, expr->getType(), LINK(child));
  6775. HqlExprAssociation * match = ctx.getMatchExpr(other);
  6776. if (match)
  6777. {
  6778. tgt.expr.set(match->expr);
  6779. return;
  6780. }
  6781. }
  6782. #endif
  6783. // Size calculation needs to only come in to play if the field/record can't be found in scope
  6784. // otherwise sizeof(field) is wrong if it is inside an ifblock.
  6785. Owned<IReferenceSelector> selector;
  6786. try
  6787. {
  6788. selector.setown(buildReference(ctx, child));
  6789. selector->getSize(ctx, tgt);
  6790. //cache non-constant values in a temporary variable...
  6791. if (!tgt.expr->queryValue())
  6792. {
  6793. if (!isSimpleLength(tgt.expr))
  6794. {
  6795. IHqlExpression * temp = ctx.getTempDeclare(expr->queryType(), tgt.expr);
  6796. tgt.expr.setown(temp);
  6797. }
  6798. ctx.associateExpr(expr, tgt);
  6799. }
  6800. }
  6801. catch (IException * e)
  6802. {
  6803. switch (child->getOperator())
  6804. {
  6805. case no_translated:
  6806. {
  6807. CHqlBoundExpr bound;
  6808. buildExpr(ctx, child, bound);
  6809. tgt.expr.setown(getBoundSize(bound));
  6810. return;
  6811. }
  6812. }
  6813. // Size calculation needs to only come in to play if the field/record can't be found in scope
  6814. // otherwise sizeof(field) is wrong if it is inside an ifblock.
  6815. if (type)
  6816. {
  6817. if (type->getTypeCode() == type_alien)
  6818. {
  6819. IHqlAlienTypeInfo * alien = queryAlienType(type);
  6820. type = alien->queryPhysicalType();
  6821. }
  6822. switch (type->getTypeCode())
  6823. {
  6824. case type_dictionary:
  6825. case type_table:
  6826. case type_groupedtable:
  6827. case type_record:
  6828. case type_row:
  6829. {
  6830. e->Release();
  6831. OwnedHqlExpr record = getSerializedForm(child->queryRecord(), diskAtom);
  6832. ColumnToOffsetMap * map = queryRecordOffsetMap(record);
  6833. if (map->isFixedWidth())
  6834. {
  6835. tgt.expr.setown(getSizetConstant(map->getFixedRecordSize()));
  6836. return;
  6837. }
  6838. throwError(HQLERR_CannotDetermineSizeVar);
  6839. }
  6840. break;
  6841. case type_void:
  6842. break;
  6843. default:
  6844. if ((type->getSize() != UNKNOWN_LENGTH) && (!selector || !selector->isConditional()))
  6845. {
  6846. tgt.expr.setown(getSizetConstant(type->getSize()));
  6847. e->Release();
  6848. return;
  6849. }
  6850. }
  6851. }
  6852. throw; // really an internal error - the parse should not have let it through....
  6853. }
  6854. }
  6855. void HqlCppTranslator::doBuildExprRowDiff(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, IHqlExpression * rightRecord, IHqlExpression * leftSelector, IHqlExpression * rightSelector, StringBuffer & selectorText, bool isCount)
  6856. {
  6857. switch (expr->getOperator())
  6858. {
  6859. case no_field:
  6860. {
  6861. IIdAtom * id = expr->queryId();
  6862. IHqlSimpleScope * rightScope = rightRecord->querySimpleScope();
  6863. OwnedHqlExpr match = rightScope ? rightScope->lookupSymbol(id) : NULL;
  6864. if (!match)
  6865. return;
  6866. OwnedHqlExpr left = createSelectExpr(LINK(leftSelector), LINK(expr));
  6867. OwnedHqlExpr right = createSelectExpr(LINK(rightSelector), LINK(match));
  6868. ITypeInfo * leftType = expr->queryType()->queryPromotedType();
  6869. switch (leftType->getTypeCode())
  6870. {
  6871. case type_record:
  6872. case type_row:
  6873. {
  6874. StringBuffer subSelectorText;
  6875. subSelectorText.append(selectorText).append(expr->queryName()).append(".");
  6876. IHqlExpression * record = ::queryRecord(leftType);
  6877. doBuildExprRowDiff(ctx, target, record, left, right->queryRecord(), right, subSelectorText, isCount);
  6878. return;
  6879. }
  6880. break;
  6881. case type_dictionary:
  6882. case type_table:
  6883. case type_groupedtable:
  6884. UNIMPLEMENTED;
  6885. }
  6886. StringBuffer fullName;
  6887. fullName.append(selectorText).append(id->str());
  6888. ITypeInfo * rightType = right->queryType()->queryPromotedType();
  6889. if (!leftType->assignableFrom(rightType))
  6890. throwError1(HQLERR_MismatchRowDiffType, fullName.str());
  6891. Owned<ITypeInfo> compareType = ::getPromotedECLType(leftType, rightType);
  6892. OwnedHqlExpr test = createBoolExpr(no_ne, ensureExprType(left, compareType), ensureExprType(right, compareType));
  6893. HqlExprArray args;
  6894. CHqlBoundExpr bound;
  6895. buildExpr(ctx, test, bound);
  6896. StringBuffer specialText;
  6897. generateExprCpp(specialText, target.length).append(",");
  6898. generateExprCpp(specialText, target.expr).append(".refextendstr()");
  6899. OwnedHqlExpr special = createQuoted(specialText.str(), makeBoolType());
  6900. BuildCtx condctx(ctx);
  6901. IHqlStmt * cond = condctx.addFilter(bound.expr);
  6902. //if differ...
  6903. args.append(*LINK(special));
  6904. if (isCount)
  6905. args.append(*createConstant(",1"));
  6906. else
  6907. {
  6908. StringBuffer temp;
  6909. temp.append(",").append(fullName);
  6910. args.append(*createConstant(temp));
  6911. }
  6912. buildFunctionCall(condctx, concatExtendId, args);
  6913. //else if same...
  6914. if (isCount)
  6915. {
  6916. condctx.selectElse(cond);
  6917. args.append(*LINK(special));
  6918. args.append(*createConstant(",0"));
  6919. buildFunctionCall(condctx, concatExtendId, args);
  6920. }
  6921. break;
  6922. }
  6923. case no_ifblock:
  6924. {
  6925. doBuildExprRowDiff(ctx, target, expr->queryChild(1), leftSelector, rightRecord, rightSelector, selectorText, isCount);
  6926. break;
  6927. }
  6928. case no_record:
  6929. {
  6930. ForEachChild(idx, expr)
  6931. doBuildExprRowDiff(ctx, target, expr->queryChild(idx), leftSelector, rightRecord, rightSelector, selectorText, isCount);
  6932. break;
  6933. }
  6934. case no_attr:
  6935. case no_attr_expr:
  6936. case no_attr_link:
  6937. break;
  6938. default:
  6939. UNIMPLEMENTED;
  6940. }
  6941. }
  6942. IHqlExpression * HqlCppTranslator::queryRecord(BuildCtx & ctx, IHqlExpression * expr)
  6943. {
  6944. return expr->queryRecord();
  6945. }
  6946. void HqlCppTranslator::doBuildExprRowDiff(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6947. {
  6948. CHqlBoundTarget tempTarget;
  6949. createTempFor(ctx, expr, tempTarget);
  6950. StringBuffer selectorText;
  6951. IHqlExpression * left = expr->queryChild(0);
  6952. IHqlExpression * leftRecord = queryRecord(ctx, left);
  6953. IHqlExpression * right = expr->queryChild(1);
  6954. IHqlExpression * rightRecord = queryRecord(ctx, right);
  6955. ctx.addAssign(tempTarget.length, queryZero());
  6956. doBuildExprRowDiff(ctx, tempTarget, leftRecord, left, rightRecord, right, selectorText, expr->hasAttribute(countAtom));
  6957. OwnedHqlExpr result = createValue(no_substring, LINK(unknownStringType), tempTarget.getTranslatedExpr(), createValue(no_rangefrom, makeVoidType(), createConstant(2)));
  6958. buildExpr(ctx, result, tgt);
  6959. }
  6960. //---------------------------------------------------------------------------
  6961. ABoundActivity * HqlCppTranslator::doBuildActivityCacheAlias(BuildCtx & ctx, IHqlExpression * expr)
  6962. {
  6963. IHqlExpression * dataset = expr->queryChild(1);
  6964. return buildCachedActivity(ctx, dataset);
  6965. }
  6966. //---------------------------------------------------------------------------
  6967. // no_cloned
  6968. ABoundActivity * HqlCppTranslator::doBuildActivityCloned(BuildCtx & ctx, IHqlExpression * expr)
  6969. {
  6970. IHqlExpression * dataset = expr->queryChild(0);
  6971. return buildCachedActivity(ctx, dataset);
  6972. }
  6973. //---------------------------------------------------------------------------
  6974. // no_addfiles
  6975. static void unwindAddFiles(HqlExprArray & args, IHqlExpression * expr, bool isOrdered, bool isOrderedPull)
  6976. {
  6977. if ((expr->getOperator() == no_addfiles) && (expr->hasAttribute(_ordered_Atom) == isOrdered) && (expr->hasAttribute(_orderedPull_Atom) == isOrderedPull))
  6978. {
  6979. unwindAddFiles(args, expr->queryChild(0), isOrdered, isOrderedPull);
  6980. unwindAddFiles(args, expr->queryChild(1), isOrdered, isOrderedPull);
  6981. }
  6982. else
  6983. args.append(*LINK(expr));
  6984. }
  6985. ABoundActivity * HqlCppTranslator::doBuildActivityConcat(BuildCtx & ctx, IHqlExpression * expr)
  6986. {
  6987. HqlExprArray inExprs;
  6988. bool ordered = expr->hasAttribute(_ordered_Atom);
  6989. bool orderedPull = expr->hasAttribute(_orderedPull_Atom);
  6990. unwindAddFiles(inExprs, expr, ordered, orderedPull);
  6991. //If all coming from disk, probably better to pull them in order.
  6992. bool allFromDisk = options.orderDiskFunnel;
  6993. CIArray bound;
  6994. ForEachItemIn(idx, inExprs)
  6995. {
  6996. IHqlExpression * cur = &inExprs.item(idx);
  6997. bound.append(*buildCachedActivity(ctx, cur));
  6998. loop
  6999. {
  7000. node_operator curOp = cur->getOperator();
  7001. if ((curOp != no_nofold) && (curOp != no_section) && (curOp != no_sectioninput) && (curOp != no_preservemeta))
  7002. break;
  7003. cur = cur->queryChild(0);
  7004. }
  7005. switch (cur->getOperator())
  7006. {
  7007. case no_compound_diskread:
  7008. case no_compound_disknormalize:
  7009. case no_compound_diskaggregate:
  7010. case no_compound_diskcount:
  7011. case no_compound_diskgroupaggregate:
  7012. break;
  7013. case no_temptable:
  7014. case no_inlinetable:
  7015. case no_temprow:
  7016. case no_datasetfromrow:
  7017. case no_projectrow:
  7018. case no_createrow:
  7019. case no_typetransfer:
  7020. break;
  7021. case no_table:
  7022. switch (cur->queryChild(2)->getOperator())
  7023. {
  7024. case no_thor: case no_flat:
  7025. break;
  7026. default:
  7027. allFromDisk = false;
  7028. break;
  7029. }
  7030. break;
  7031. default:
  7032. allFromDisk = false;
  7033. break;
  7034. }
  7035. }
  7036. if (orderedPull || (allFromDisk && !targetRoxie()))
  7037. ordered = true;
  7038. bool useImplementationClass = options.minimizeActivityClasses && targetRoxie();
  7039. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfunnel, expr, "Funnel");
  7040. if (useImplementationClass)
  7041. instance->setImplementationClass(newFunnelArgId);
  7042. buildActivityFramework(instance);
  7043. buildInstancePrefix(instance);
  7044. if (!useImplementationClass)
  7045. {
  7046. if (ordered)
  7047. doBuildBoolFunction(instance->classctx, "isOrdered", true);
  7048. if (orderedPull)
  7049. doBuildBoolFunction(instance->classctx, "pullSequentially", orderedPull);
  7050. }
  7051. else
  7052. {
  7053. instance->addConstructorParameter(queryBoolExpr(ordered));
  7054. instance->addConstructorParameter(queryBoolExpr(orderedPull));
  7055. }
  7056. buildInstanceSuffix(instance);
  7057. ForEachItemIn(idx2, bound)
  7058. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  7059. return instance->getBoundActivity();
  7060. }
  7061. ABoundActivity * HqlCppTranslator::doBuildActivityMerge(BuildCtx & ctx, IHqlExpression * expr)
  7062. {
  7063. CIArrayOf<ABoundActivity> inputs;
  7064. ForEachChild(idx, expr)
  7065. {
  7066. IHqlExpression *cur = expr->queryChild(idx);
  7067. if (!cur->isAttribute())
  7068. inputs.append(*buildCachedActivity(ctx, cur));
  7069. }
  7070. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKmerge, expr, "Merge");
  7071. buildActivityFramework(instance);
  7072. buildInstancePrefix(instance);
  7073. IHqlExpression * dataset = expr->queryChild(0);
  7074. IHqlExpression * sortAttr = expr->queryAttribute(sortedAtom);
  7075. HqlExprArray sorts;
  7076. unwindChildren(sorts, sortAttr);
  7077. if (sorts.ordinality() != 0)
  7078. {
  7079. OwnedHqlExpr sortOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  7080. instance->startctx.addQuoted("virtual ICompare * queryCompare() { return &compare; }");
  7081. DatasetReference dsRef(dataset, no_activetable, NULL);
  7082. buildCompareClass(instance->nestedctx, "compare", sortOrder, dsRef);
  7083. if (!instance->isLocal)
  7084. generateSerializeKey(instance->nestedctx, no_none, dsRef, sorts, !instance->isChildActivity(), true, false);
  7085. }
  7086. else
  7087. throwError(HQLERR_InputMergeNotSorted);
  7088. if (expr->hasAttribute(dedupAtom))
  7089. doBuildBoolFunction(instance->classctx, "dedup", true);
  7090. buildInstanceSuffix(instance);
  7091. ForEachItemIn(idx2, inputs)
  7092. buildConnectInputOutput(ctx, instance, &inputs.item(idx2), 0, idx2);
  7093. return instance->getBoundActivity();
  7094. }
  7095. ABoundActivity * HqlCppTranslator::doBuildActivityRegroup(BuildCtx & ctx, IHqlExpression * expr)
  7096. {
  7097. HqlExprArray inExprs;
  7098. expr->unwindList(inExprs, no_regroup);
  7099. CIArray bound;
  7100. ForEachItemIn(idx, inExprs)
  7101. {
  7102. IHqlExpression & cur = inExprs.item(idx);
  7103. bound.append(*buildCachedActivity(ctx, &cur));
  7104. }
  7105. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKregroup, expr, "Regroup");
  7106. buildActivityFramework(instance);
  7107. buildInstancePrefix(instance);
  7108. buildInstanceSuffix(instance);
  7109. ForEachItemIn(idx2, bound)
  7110. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  7111. return instance->getBoundActivity();
  7112. }
  7113. static void unwindNonEmpty(HqlExprCopyArray & args, IHqlExpression * expr, bool isLocal)
  7114. {
  7115. if ((expr->getOperator() == no_nonempty) && (expr->hasAttribute(localAtom) == isLocal))
  7116. {
  7117. ForEachChild(i, expr)
  7118. unwindNonEmpty(args, expr->queryChild(i), isLocal);
  7119. }
  7120. else
  7121. args.append(*expr);
  7122. }
  7123. ABoundActivity * HqlCppTranslator::doBuildActivityNonEmpty(BuildCtx & ctx, IHqlExpression * expr)
  7124. {
  7125. HqlExprCopyArray inExprs;
  7126. unwindNonEmpty(inExprs, expr, expr->hasAttribute(localAtom));
  7127. CIArray bound;
  7128. ForEachItemIn(idx, inExprs)
  7129. {
  7130. IHqlExpression * cur = &inExprs.item(idx);
  7131. if (!cur->isAttribute())
  7132. bound.append(*buildCachedActivity(ctx, cur));
  7133. }
  7134. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnonempty, expr, "NonEmpty");
  7135. buildActivityFramework(instance);
  7136. buildInstancePrefix(instance);
  7137. buildInstanceSuffix(instance);
  7138. ForEachItemIn(idx2, bound)
  7139. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  7140. return instance->getBoundActivity();
  7141. }
  7142. ABoundActivity * HqlCppTranslator::doBuildActivitySplit(BuildCtx & ctx, IHqlExpression * expr)
  7143. {
  7144. IHqlExpression * dataset = expr->queryChild(0);
  7145. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7146. bool useImplementationClass = options.minimizeActivityClasses;
  7147. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsplit, expr, "Split");
  7148. if (useImplementationClass)
  7149. instance->setImplementationClass(newSplitArgId);
  7150. buildActivityFramework(instance);
  7151. buildInstancePrefix(instance);
  7152. //IHqlExpression * numWays = expr->queryChild(1);
  7153. OwnedHqlExpr numWaysCallback = createUnknown(no_callback, LINK(sizetType), countAtom, instance->createOutputCountCallback());
  7154. OwnedHqlExpr numWays = createTranslated(numWaysCallback);
  7155. bool balanced = expr->hasAttribute(balancedAtom);
  7156. if (!useImplementationClass)
  7157. {
  7158. if (!matchesConstantValue(numWays, 2))
  7159. doBuildUnsignedFunction(instance->classctx, "numBranches", numWays);
  7160. if (balanced)
  7161. doBuildBoolFunction(instance->classctx, "isBalanced", true);
  7162. }
  7163. else
  7164. {
  7165. instance->addConstructorParameter(numWays);
  7166. instance->addConstructorParameter(queryBoolExpr(balanced));
  7167. }
  7168. buildInstanceSuffix(instance);
  7169. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7170. return instance->getBoundActivity();
  7171. }
  7172. ABoundActivity * HqlCppTranslator::doBuildActivitySpill(BuildCtx & ctx, IHqlExpression * expr)
  7173. {
  7174. return doBuildActivityOutput(ctx, expr, false);
  7175. }
  7176. bool HqlCppTranslator::isCurrentActiveGraph(BuildCtx & ctx, IHqlExpression * graphTag)
  7177. {
  7178. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7179. assertex(activeSubgraph);
  7180. return (graphTag == activeSubgraph->graphTag);
  7181. }
  7182. IHqlExpression * HqlCppTranslator::createLoopSubquery(IHqlExpression * dataset, IHqlExpression * selSeq, IHqlExpression * rowsid, IHqlExpression * body, IHqlExpression * filter, IHqlExpression * again, IHqlExpression * counter, bool multiInstance, unsigned & loopAgainResult)
  7183. {
  7184. //Now need to generate the body of the loop.
  7185. //output dataset is result 0
  7186. //input dataset is fed in using result 1
  7187. //counter (if required) is fed in using <result-2>[0].counter;
  7188. ChildGraphExprBuilder graphBuilder(2);
  7189. IHqlExpression * graphid = graphBuilder.queryRepresents();
  7190. LinkedHqlExpr transformedBody = body;
  7191. LinkedHqlExpr transformedAgain = again;
  7192. //Result 1 is the input dataset.
  7193. HqlExprArray args;
  7194. args.append(*LINK(dataset->queryRecord()));
  7195. args.append(*LINK(graphid));
  7196. args.append(*getSizetConstant(1));
  7197. if (isGrouped(dataset))
  7198. args.append(*createAttribute(groupedAtom));
  7199. args.append(*createAttribute(_loop_Atom));
  7200. if (multiInstance)
  7201. args.append(*createAttribute(_streaming_Atom));
  7202. if (targetThor()) // MORE: && !isChildQuery(ctx)..
  7203. args.append(*createAttribute(_distributed_Atom));
  7204. OwnedHqlExpr inputResult= createDataset(no_getgraphresult, args);
  7205. //Result 2 is the counter - if present
  7206. OwnedHqlExpr counterResult;
  7207. if (counter)
  7208. {
  7209. OwnedHqlExpr select = createCounterAsGraphResult(counter, graphid, 2);
  7210. transformedBody.setown(replaceExpression(transformedBody, counter, select));
  7211. if (transformedAgain)
  7212. {
  7213. //The COUNTER for the global termination condition is whether to execute iteration COUNTER, 1=1st iter
  7214. //Since we're evaluating the condition in the previous iteration it needs to be increased by 1.
  7215. OwnedHqlExpr nextCounter = adjustValue(select, 1);
  7216. transformedAgain.setown(replaceExpression(transformedAgain, counter, nextCounter));
  7217. }
  7218. graphBuilder.addInput();
  7219. }
  7220. //first create the result...
  7221. //Need to replace ROWS(LEFT) with the result1
  7222. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  7223. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(left), LINK(rowsid));
  7224. transformedBody.setown(replaceExpression(transformedBody, rowsExpr, inputResult));
  7225. OwnedHqlExpr result = createValue(no_setgraphresult, makeVoidType(), LINK(transformedBody), LINK(graphid), getSizetConstant(0), createAttribute(_loop_Atom));
  7226. graphBuilder.addAction(result);
  7227. if (transformedAgain)
  7228. {
  7229. LinkedHqlExpr nextLoopDataset = transformedBody;
  7230. if (filter)
  7231. {
  7232. //If there is a loop filter then the global condition is applied to dataset filtered by that.
  7233. OwnedHqlExpr mappedFilter = replaceSelector(filter, left, nextLoopDataset);
  7234. nextLoopDataset.setown(createDataset(no_filter, nextLoopDataset.getClear(), LINK(mappedFilter)));
  7235. }
  7236. transformedAgain.setown(replaceExpression(transformedAgain, rowsExpr, nextLoopDataset));
  7237. loopAgainResult = graphBuilder.addInput();
  7238. //MORE: Add loopAgainResult as an attribute on the no_childquery rather than using a reference parameter
  7239. OwnedHqlExpr againResult = convertScalarToGraphResult(transformedAgain, queryBoolType(), graphid, loopAgainResult);
  7240. graphBuilder.addAction(againResult);
  7241. }
  7242. return graphBuilder.getGraph();
  7243. }
  7244. ABoundActivity * HqlCppTranslator::doBuildActivityLoop(BuildCtx & ctx, IHqlExpression * expr)
  7245. {
  7246. IHqlExpression * dataset = expr->queryChild(0);
  7247. IHqlExpression * count = queryRealChild(expr, 1);
  7248. IHqlExpression * filter = queryRealChild(expr, 2);
  7249. IHqlExpression * loopCond = queryRealChild(expr, 3);
  7250. IHqlExpression * body = expr->queryChild(4);
  7251. assertex(body->getOperator() == no_loopbody);
  7252. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  7253. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  7254. IHqlExpression * selSeq = querySelSeq(expr);
  7255. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7256. ThorActivityKind kind = TAKnone;
  7257. //LOOP(dataset, count[, rowFilter])
  7258. //LOOP(dataset, <dataset-filter>, <rowfilter>)
  7259. //LOOP(dataset, <dataset-filter|rowfilter>
  7260. if (count)
  7261. kind = TAKloopcount;
  7262. else if (loopCond)
  7263. kind = TAKloopdataset;
  7264. else
  7265. kind = TAKlooprow;
  7266. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "Loop");
  7267. buildActivityFramework(instance);
  7268. buildInstancePrefix(instance);
  7269. if (filter)
  7270. {
  7271. BuildCtx funcctx(instance->startctx);
  7272. funcctx.addQuotedCompound("virtual bool sendToLoop(unsigned counter, const void * _self)");
  7273. funcctx.addQuoted("unsigned char * self = (unsigned char *) _self;");
  7274. associateCounter(funcctx, counter, "counter");
  7275. bindTableCursor(funcctx, dataset, "self", no_left, selSeq);
  7276. buildReturn(funcctx, filter);
  7277. }
  7278. if (count)
  7279. doBuildUnsignedFunction(instance->startctx, "numIterations", count);
  7280. if (loopCond)
  7281. {
  7282. BuildCtx funcctx(instance->startctx);
  7283. funcctx.addQuotedCompound("virtual bool loopAgain(unsigned counter, unsigned numRows, const void * * _rows)");
  7284. funcctx.addQuoted("unsigned char * * rows = (unsigned char * *) _rows;");
  7285. associateCounter(funcctx, counter, "counter");
  7286. bindRows(funcctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  7287. buildReturn(funcctx, loopCond);
  7288. }
  7289. IHqlExpression * loopFirst = queryAttributeChild(expr, _loopFirst_Atom, 0);
  7290. if (loopFirst)
  7291. doBuildBoolFunction(instance->startctx, "loopFirstTime", loopFirst);
  7292. IHqlExpression * parallel = expr->queryAttribute(parallelAtom);
  7293. if (parallel && (targetHThor() || !count || loopCond))
  7294. parallel = NULL;
  7295. if (parallel)
  7296. {
  7297. IHqlExpression * arg0 = parallel->queryChild(0);
  7298. IHqlExpression * arg1 = parallel->queryChild(1);
  7299. LinkedHqlExpr parallelList;
  7300. LinkedHqlExpr numThreads;
  7301. if (arg0)
  7302. {
  7303. if (arg1)
  7304. {
  7305. parallelList.set(arg0);
  7306. numThreads.set(arg1);
  7307. }
  7308. else if (arg0->isList())
  7309. parallelList.set(arg0);
  7310. else
  7311. numThreads.set(arg0);
  7312. }
  7313. if (numThreads)
  7314. doBuildUnsignedFunction(instance->startctx, "defaultParallelIterations", numThreads);
  7315. if (parallelList)
  7316. {
  7317. Owned<ITypeInfo> setType = makeSetType(LINK(unsignedType));
  7318. BuildCtx funcctx(instance->startctx);
  7319. funcctx.addQuotedCompound("virtual void numParallelIterations(size32_t & __lenResult, void * & __result)");
  7320. funcctx.addQuoted("bool __isAllResult;");
  7321. doBuildFunctionReturn(funcctx, setType, parallelList);
  7322. }
  7323. }
  7324. StringBuffer flags;
  7325. if (counter) flags.append("|LFcounter");
  7326. if (parallel) flags.append("|LFparallel");
  7327. if (filter) flags.append("|LFfiltered");
  7328. if (loopFirst) flags.append("|LFnewloopagain");
  7329. if (flags.length())
  7330. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  7331. BuildCtx subctx(instance->startctx);
  7332. subctx.addQuotedCompound("virtual void createParentExtract(rtlRowBuilder & builder)");
  7333. //Now need to generate the body of the loop.
  7334. unsigned loopAgainResult = 0;
  7335. OwnedHqlExpr childquery = createLoopSubquery(dataset, selSeq, rowsid, body->queryChild(0), filter, loopCond, counter, (parallel != NULL), loopAgainResult);
  7336. ChildGraphBuilder builder(*this, childquery);
  7337. unique_id_t loopId = builder.buildLoopBody(subctx, (parallel != NULL));
  7338. instance->addAttributeInt("_loopid", loopId);
  7339. if (loopAgainResult)
  7340. doBuildUnsignedFunction(instance->startctx, "loopAgainResult", loopAgainResult);
  7341. buildInstanceSuffix(instance);
  7342. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7343. return instance->getBoundActivity();
  7344. }
  7345. //---------------------------------------------------------------------------
  7346. ABoundActivity * HqlCppTranslator::doBuildActivityGraphLoop(BuildCtx & ctx, IHqlExpression * expr)
  7347. {
  7348. IHqlExpression * dataset = expr->queryChild(0);
  7349. IHqlExpression * count = expr->queryChild(1);
  7350. IHqlExpression * body = expr->queryChild(2);
  7351. assertex(body->getOperator() == no_loopbody);
  7352. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  7353. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  7354. IHqlExpression * selSeq = querySelSeq(expr);
  7355. IHqlExpression * parallel = expr->queryAttribute(parallelAtom);
  7356. if (parallel && targetHThor())
  7357. parallel = NULL;
  7358. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7359. ThorActivityKind kind = parallel ? TAKparallelgraphloop : TAKgraphloop;
  7360. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "GraphLoop");
  7361. buildActivityFramework(instance);
  7362. buildInstancePrefix(instance);
  7363. doBuildUnsignedFunction(instance->startctx, "numIterations", count);
  7364. StringBuffer flags;
  7365. if (counter) flags.append("|GLFcounter");
  7366. if (parallel) flags.append("|GLFparallel");
  7367. if (flags.length())
  7368. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  7369. BuildCtx subctx(instance->startctx);
  7370. subctx.addQuotedCompound("virtual void createParentExtract(rtlRowBuilder & builder)");
  7371. //Now need to generate the body of the loop.
  7372. //output dataset is result 0
  7373. //input dataset is fed in using result 1
  7374. //counter (if required) is fed in using result 2[0].counter;
  7375. unique_id_t loopId = buildGraphLoopSubgraph(subctx, dataset, selSeq, rowsid, body->queryChild(0), counter, (parallel != NULL));
  7376. instance->addAttributeInt("_loopid", loopId);
  7377. buildInstanceSuffix(instance);
  7378. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7379. return instance->getBoundActivity();
  7380. }
  7381. //---------------------------------------------------------------------------
  7382. ABoundActivity * HqlCppTranslator::doBuildActivityRemote(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  7383. {
  7384. IHqlExpression * child = expr->queryChild(0);
  7385. if (targetHThor() || (targetThor() && !insideChildQuery(ctx)))
  7386. {
  7387. if (!options.alwaysAllowAllNodes)
  7388. throwError(HQLERR_RemoteNoMeaning);
  7389. }
  7390. if (isGrouped(child))
  7391. throwError(HQLERR_RemoteGrouped);
  7392. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKremotegraph, expr, "Remote");
  7393. buildActivityFramework(instance, isRoot);
  7394. buildInstancePrefix(instance);
  7395. IHqlExpression * dataset = expr->queryChild(0);
  7396. IHqlExpression * rowlimit = expr->queryAttribute(rowLimitAtom);
  7397. if (rowlimit)
  7398. {
  7399. doBuildUnsigned64Function(instance->startctx, "getRowLimit", rowlimit->queryChild(0));
  7400. IHqlExpression * fail = queryChildOperator(no_fail, rowlimit);
  7401. if (fail)
  7402. {
  7403. BuildCtx ctx(instance->startctx);
  7404. ctx.addQuotedCompound("virtual void onLimitExceeded()");
  7405. buildStmt(ctx, fail);
  7406. }
  7407. }
  7408. BuildCtx subctx(instance->startctx);
  7409. subctx.addQuotedCompound("virtual void createParentExtract(rtlRowBuilder & builder)");
  7410. //output dataset is result 0
  7411. unique_id_t remoteId = buildRemoteSubgraph(subctx, dataset);
  7412. instance->addAttributeInt("_graphid", remoteId);
  7413. buildInstanceSuffix(instance);
  7414. return instance->getBoundActivity();
  7415. }
  7416. //---------------------------------------------------------------------------
  7417. // no_update
  7418. void HqlCppTranslator::doBuildStmtUpdate(BuildCtx & ctx, IHqlExpression * expr)
  7419. {
  7420. // MJH - CODE TO DO UPDATE GOES HERE
  7421. PrintLog("in HqlCppTranslator::doBuildStmtUpdate()");
  7422. }
  7423. IHqlExpression * HqlCppTranslator::createClearRowCall(BuildCtx & ctx, BoundRow * self)
  7424. {
  7425. IHqlExpression * record = self->querySelector()->queryRecord();
  7426. OwnedHqlExpr clearFunc = getClearRecordFunction(record, 0);
  7427. StringBuffer s;
  7428. ensureContextAvailable(ctx);
  7429. IHqlExpression * boundRow = self->queryBound();
  7430. OwnedHqlExpr rowPointer = getPointer(boundRow);
  7431. generateExprCpp(s, clearFunc).append("(");
  7432. if (self->queryBuilder())
  7433. {
  7434. generateExprCpp(s, self->queryBuilder());
  7435. }
  7436. else
  7437. {
  7438. StringBuffer builderName;
  7439. getUniqueId(builderName.append("rb"));
  7440. StringBuffer temp;
  7441. temp.append("RtlStaticRowBuilder ").append(builderName).append("(");
  7442. if (ctx.queryMatchExpr(constantMemberMarkerExpr))
  7443. temp.append("(byte *)");
  7444. generateExprCpp(temp, rowPointer);
  7445. temp.append(",").append(getMaxRecordSize(record)).append(");");
  7446. ctx.addQuoted(temp);
  7447. s.append(builderName);
  7448. }
  7449. s.append(", ctx)");
  7450. return createQuoted(s.str(), makeVoidType());
  7451. }
  7452. void HqlCppTranslator::associateSkipReturnMarker(BuildCtx & ctx, IHqlExpression * value, BoundRow * self)
  7453. {
  7454. ctx.associateExpr(skipReturnMarker, value);
  7455. }
  7456. void HqlCppTranslator::doBuildStmtSkip(BuildCtx & ctx, IHqlExpression * expr, bool * canReachFollowing)
  7457. {
  7458. HqlExprAssociation * match = ctx.queryMatchExpr(skipActionMarker);
  7459. IHqlExpression * cond = expr->queryChild(0);
  7460. if (cond && cond->isRecord())
  7461. cond = NULL;
  7462. if (canReachFollowing)
  7463. *canReachFollowing = true;
  7464. BuildCtx subctx(ctx);
  7465. if (match)
  7466. {
  7467. IHqlCodeCallback * callback = static_cast<IHqlCodeCallback *>(match->queryExpr()->queryUnknownExtra());
  7468. if (cond)
  7469. buildFilter(subctx, cond);
  7470. callback->buildCode(*this, subctx);
  7471. }
  7472. else
  7473. {
  7474. match = ctx.queryMatchExpr(skipReturnMarker);
  7475. if (match)
  7476. {
  7477. if (cond)
  7478. buildFilteredReturn(ctx, cond, match->queryExpr());
  7479. else
  7480. {
  7481. buildReturn(ctx, match->queryExpr());
  7482. if (canReachFollowing)
  7483. *canReachFollowing = false;
  7484. }
  7485. }
  7486. else
  7487. throwError(HQLERR_SkipNotValidHere);
  7488. }
  7489. }
  7490. void HqlCppTranslator::doBuildStmtAssert(BuildCtx & ctx, IHqlExpression * expr)
  7491. {
  7492. if (!options.checkAsserts)
  7493. return;
  7494. IHqlExpression * cond = expr->queryChild(0);
  7495. LinkedHqlExpr locationAttr = expr->queryAttribute(_location_Atom);
  7496. if (!locationAttr)
  7497. {
  7498. IHqlExpression * activeNamedActivity = queryActiveNamedActivity();
  7499. if (activeNamedActivity)
  7500. {
  7501. ISourcePath * sourcePath = activeNamedActivity->querySourcePath();
  7502. if (sourcePath)
  7503. locationAttr.setown(createLocationAttr(sourcePath, 0, 0, 0));
  7504. }
  7505. }
  7506. LinkedHqlExpr msg = queryRealChild(expr, 1);
  7507. if (!msg)
  7508. msg.setown(createDefaultAssertMessage(cond));
  7509. if (expr->hasAttribute(constAtom))
  7510. {
  7511. IValue * condValue = cond->queryValue();
  7512. assertex(condValue && msg->queryValue());
  7513. if (condValue->getBoolValue())
  7514. return;
  7515. StringBuffer msgText;
  7516. getStringValue(msgText, msg);
  7517. reportErrorDirect(locationAttr, ERR_ASSERTION_FAILS, msgText.str(), false);
  7518. return;
  7519. }
  7520. BuildCtx condctx(ctx);
  7521. OwnedHqlExpr inverse = getInverse(cond);
  7522. buildFilter(condctx, inverse);
  7523. OwnedHqlExpr action;
  7524. HqlExprArray args;
  7525. args.append(*getSizetConstant(ERR_ASSERTION_FAILS));
  7526. args.append(*LINK(msg));
  7527. ECLlocation location;
  7528. if (locationAttr)
  7529. location.extractLocationAttr(locationAttr);
  7530. if (location.sourcePath)
  7531. args.append(*createConstant(location.sourcePath->str()));
  7532. else
  7533. args.append(*getNullStringPointer(true));
  7534. args.append(*getSizetConstant(location.lineno));
  7535. args.append(*getSizetConstant(location.column));
  7536. args.append(*createConstant(expr->hasAttribute(failAtom)));
  7537. action.setown(bindFunctionCall(addWorkunitAssertFailureId, args));
  7538. buildStmt(condctx, action);
  7539. }
  7540. void HqlCppTranslator::doBuildStmtCluster(BuildCtx & ctx, IHqlExpression * expr)
  7541. {
  7542. pushCluster(ctx, expr->queryChild(1));
  7543. buildStmt(ctx, expr->queryChild(0));
  7544. popCluster(ctx);
  7545. }
  7546. //---------------------------------------------------------------------------
  7547. // no_apply
  7548. void HqlCppTranslator::doBuildSequenceFunc(BuildCtx & ctx, IHqlExpression * seq, bool ignoreInternal)
  7549. {
  7550. if (ignoreInternal && isInternalSeq(seq))
  7551. return;
  7552. //virtual unsigned getSequence() = 0;
  7553. StringBuffer s;
  7554. s.append("virtual int getSequence() { return ");
  7555. if (seq)
  7556. generateExprCpp(s, seq);
  7557. else
  7558. s.append("-1");
  7559. s.append("; }");
  7560. ctx.addQuoted(s);
  7561. }
  7562. class ApplyStmtBuilder
  7563. {
  7564. public:
  7565. ApplyStmtBuilder(HqlCppTranslator & _translator) : translator(_translator) {}
  7566. // ~ApplyStmtBuilder() { assertex(!builder); } // don't do this because throwing exceptions inside destructors is very messy
  7567. void flush(BuildCtx & ctx)
  7568. {
  7569. if (builder)
  7570. {
  7571. OwnedHqlExpr childquery = builder->getGraph(no_orderedactionlist);
  7572. translator.buildStmt(ctx, childquery);
  7573. builder.clear();
  7574. }
  7575. }
  7576. bool requiresGraph(BuildCtx & ctx, IHqlExpression * expr)
  7577. {
  7578. if (!expr) return false;
  7579. switch (expr->getOperator())
  7580. {
  7581. case NO_ACTION_REQUIRES_GRAPH:
  7582. return true;
  7583. case no_parallel:
  7584. case no_sequential:
  7585. case no_actionlist:
  7586. case no_orderedactionlist:
  7587. case no_compound:
  7588. {
  7589. ForEachChild(idx, expr)
  7590. {
  7591. if (requiresGraph(ctx, expr->queryChild(idx)))
  7592. return true;
  7593. }
  7594. break;
  7595. }
  7596. case no_if:
  7597. return requiresGraph(ctx, expr->queryChild(1)) || requiresGraph(ctx, expr->queryChild(2));
  7598. }
  7599. return false;
  7600. }
  7601. void addGraphStmt(BuildCtx & ctx, IHqlExpression * expr)
  7602. {
  7603. if (!builder)
  7604. builder.setown(new ChildGraphExprBuilder(0));
  7605. builder->addAction(expr);
  7606. }
  7607. void buildStmt(BuildCtx & ctx, IHqlExpression * expr)
  7608. {
  7609. node_operator op = expr->getOperator();
  7610. switch (expr->getOperator())
  7611. {
  7612. case NO_ACTION_REQUIRES_GRAPH:
  7613. addGraphStmt(ctx, expr);
  7614. break;
  7615. case no_parallel:
  7616. case no_sequential:
  7617. case no_actionlist:
  7618. case no_orderedactionlist:
  7619. case no_compound:
  7620. {
  7621. ForEachChild(idx, expr)
  7622. {
  7623. buildStmt(ctx, expr->queryChild(idx));
  7624. if (op == no_sequential)
  7625. flush(ctx);
  7626. }
  7627. break;
  7628. }
  7629. case no_attr:
  7630. case no_attr_link:
  7631. case no_attr_expr:
  7632. break;
  7633. case no_if:
  7634. if (requiresGraph(ctx, expr))
  7635. addGraphStmt(ctx, expr);
  7636. else
  7637. translator.buildStmt(ctx, expr);
  7638. break;
  7639. default:
  7640. translator.buildStmt(ctx, expr);
  7641. break;
  7642. }
  7643. }
  7644. protected:
  7645. HqlCppTranslator & translator;
  7646. Owned<ChildGraphExprBuilder> builder;
  7647. };
  7648. ABoundActivity * HqlCppTranslator::doBuildActivityApply(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  7649. {
  7650. StringBuffer s;
  7651. IHqlExpression * dataset = expr->queryChild(0);
  7652. IHqlExpression * action = expr->queryChild(1);
  7653. IHqlExpression * start = expr->queryAttribute(beforeAtom);
  7654. IHqlExpression * end = expr->queryAttribute(afterAtom);
  7655. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  7656. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKapply, expr, "Apply");
  7657. buildActivityFramework(instance, isRoot);
  7658. buildInstancePrefix(instance);
  7659. doBuildSequenceFunc(instance->classctx, querySequence(expr), false);
  7660. BuildCtx transformctx(instance->startctx);
  7661. transformctx.addQuotedCompound("virtual void apply(const void * _self)");
  7662. s.clear().append("unsigned char * self = (unsigned char *) _self;");
  7663. transformctx.addQuoted(s);
  7664. bindTableCursor(transformctx, dataset, "self");
  7665. unsigned max = expr->numChildren();
  7666. ApplyStmtBuilder builder(*this);
  7667. for (unsigned i=1; i < max; i++)
  7668. builder.buildStmt(transformctx, expr->queryChild(i));
  7669. builder.flush(transformctx);
  7670. if (start)
  7671. {
  7672. BuildCtx startctx(instance->startctx);
  7673. startctx.addQuotedCompound("virtual void start()");
  7674. builder.buildStmt(startctx, start->queryChild(0));
  7675. builder.flush(startctx);
  7676. }
  7677. if (end)
  7678. {
  7679. BuildCtx endctx(instance->startctx);
  7680. endctx.addQuotedCompound("virtual void end()");
  7681. builder.buildStmt(endctx, end->queryChild(0));
  7682. builder.flush(endctx);
  7683. }
  7684. buildInstanceSuffix(instance);
  7685. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  7686. return instance->getBoundActivity();
  7687. }
  7688. //---------------------------------------------------------------------------
  7689. //-- no_thor --
  7690. ActivityInstance * HqlCppTranslator::queryCurrentActivity(BuildCtx & ctx)
  7691. {
  7692. return static_cast<ActivityInstance *>(ctx.queryFirstAssociation(AssocActivityInstance));
  7693. }
  7694. unique_id_t HqlCppTranslator::queryCurrentActivityId(BuildCtx & ctx)
  7695. {
  7696. ActivityInstance * activeActivity = queryCurrentActivity(ctx);
  7697. if (activeActivity)
  7698. return activeActivity->activityId;
  7699. HqlExprAssociation * match = ctx.queryMatchExpr(queryActivityIdMarker());
  7700. if (match)
  7701. return getIntValue(match->queryExpr());
  7702. return 0;
  7703. }
  7704. IHqlExpression * HqlCppTranslator::getCurrentActivityId(BuildCtx & ctx)
  7705. {
  7706. ActivityInstance * activeActivity = queryCurrentActivity(ctx);
  7707. if (activeActivity)
  7708. return getSizetConstant(activeActivity->activityId);
  7709. HqlExprAssociation * match = ctx.queryMatchExpr(queryActivityIdMarker());
  7710. if (match)
  7711. return LINK(match->queryExpr());
  7712. return getSizetConstant(0);
  7713. }
  7714. bool HqlCppTranslator::insideRemoteGraph(BuildCtx & ctx)
  7715. {
  7716. //Dubious... how about a remote child query?
  7717. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7718. if (!activeSubgraph)
  7719. return false;
  7720. return (activeSubgraph->type == SubGraphRemote);
  7721. }
  7722. bool HqlCppTranslator::insideChildOrLoopGraph(BuildCtx & ctx)
  7723. {
  7724. FilteredAssociationIterator iter(ctx, AssocSubGraph);
  7725. ForEach(iter)
  7726. {
  7727. SubGraphInfo & cur = static_cast<SubGraphInfo &>(iter.get());
  7728. if ((cur.type == SubGraphChild) || (cur.type == SubGraphLoop))
  7729. return true;
  7730. }
  7731. return false;
  7732. }
  7733. bool HqlCppTranslator::insideChildQuery(BuildCtx & ctx)
  7734. {
  7735. ParentExtract * extract = static_cast<ParentExtract*>(ctx.queryFirstAssociation(AssocExtract));
  7736. if (extract)
  7737. return extract->insideChildQuery();
  7738. EvalContext * instance = queryEvalContext(ctx);
  7739. if (instance)
  7740. return instance->insideChildQuery();
  7741. return false;
  7742. }
  7743. unsigned HqlCppTranslator::curSubGraphId(BuildCtx & ctx)
  7744. {
  7745. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7746. return activeSubgraph ? activeSubgraph->id : 0;
  7747. }
  7748. unsigned HqlCppTranslator::doBuildThorChildSubGraph(BuildCtx & ctx, IHqlExpression * expr, SubGraphType kind, unsigned reservedId, IHqlExpression * graphTag)
  7749. {
  7750. //NB: Need to create the graph in the correct order so the references to property trees we retain
  7751. // remain live..
  7752. unsigned thisId = reservedId ? reservedId : nextActivityId();
  7753. unsigned graphId = thisId;
  7754. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  7755. IPropertyTree * node = createPTree("node");
  7756. if (activeSubgraph)
  7757. {
  7758. if (!graphTag)
  7759. graphTag = activeSubgraph->graphTag;
  7760. node = activeSubgraph->tree->addPropTree("node", node);
  7761. if (activeSubgraph->graphTag == graphTag)
  7762. graphId = activeSubgraph->graphId;
  7763. }
  7764. else
  7765. node = activeGraph->xgmml->addPropTree("node", node);
  7766. node->setPropInt("@id", thisId);
  7767. IPropertyTree * graphAttr = node->addPropTree("att", createPTree("att"));
  7768. IPropertyTree * subGraph = graphAttr->addPropTree("graph", createPTree("graph"));
  7769. Owned<SubGraphInfo> graphInfo = new SubGraphInfo(subGraph, thisId, graphId, graphTag, kind);
  7770. ctx.associate(*graphInfo);
  7771. IHqlExpression * numResultsAttr = expr->queryAttribute(numResultsAtom);
  7772. if (numResultsAttr)
  7773. addGraphAttributeInt(subGraph, "_numResults", getIntValue(numResultsAttr->queryChild(0), 0));
  7774. if (expr->hasAttribute(multiInstanceAtom))
  7775. subGraph->setPropBool("@multiInstance", true);
  7776. if (expr->hasAttribute(delayedAtom))
  7777. subGraph->setPropBool("@delayed", true);
  7778. if (expr->queryAttribute(childAtom))
  7779. subGraph->setPropBool("@child", true);
  7780. if (expr->hasAttribute(sequentialAtom))
  7781. subGraph->setPropBool("@sequential", true);
  7782. if (insideChildOrLoopGraph(ctx))
  7783. {
  7784. graphAttr->setProp("@name", "_kind");
  7785. graphAttr->setPropInt("@value", TAKsubgraph);
  7786. ActivityInstance * curActivityInstance = queryCurrentActivity(ctx);
  7787. if (curActivityInstance)
  7788. addGraphAttributeInt(node, "_parentActivity", curActivityInstance->activityId);
  7789. }
  7790. OwnedHqlExpr idExpr = createConstant((__int64)thisId);
  7791. ctx.associateExpr(expr, idExpr);
  7792. if (thisId == options.subgraphToRegeneate)
  7793. {
  7794. StringBuffer ecl;
  7795. regenerateECL(expr, ecl);
  7796. ecl.replaceString("\r","");
  7797. fputs(ecl.str(), stdout);
  7798. fflush(stdout);
  7799. }
  7800. BuildCtx subctx(ctx);
  7801. ForEachChild(idx, expr)
  7802. {
  7803. IHqlExpression * cur = expr->queryChild(idx);
  7804. switch (cur->getOperator())
  7805. {
  7806. case no_subgraph:
  7807. doBuildThorChildSubGraph(ctx, cur, SubGraphChild, 0, graphTag);
  7808. break;
  7809. case no_attr:
  7810. case no_attr_expr:
  7811. case no_attr_link:
  7812. break;
  7813. default:
  7814. buildRootActivity(subctx, cur);
  7815. break;
  7816. }
  7817. }
  7818. ctx.removeAssociation(graphInfo);
  7819. return thisId;
  7820. }
  7821. unsigned HqlCppTranslator::doBuildThorSubGraph(BuildCtx & ctx, IHqlExpression * expr, SubGraphType kind, unsigned reservedId, IHqlExpression * graphTag)
  7822. {
  7823. BuildCtx graphctx(ctx);
  7824. graphctx.addGroup();
  7825. bool needToCreateGraph = !activeGraph;
  7826. if (!graphTag && outputLibraryId)
  7827. graphTag = outputLibraryId;
  7828. if (needToCreateGraph)
  7829. beginGraph();
  7830. unsigned thisId = doBuildThorChildSubGraph(graphctx, expr, kind, reservedId, graphTag);
  7831. if (needToCreateGraph)
  7832. endGraph();
  7833. return thisId;
  7834. }
  7835. void HqlCppTranslator::beginGraph(const char * _graphName)
  7836. {
  7837. if (activeGraph)
  7838. throwError(HQLERR_NestedThorNodes);
  7839. graphSeqNumber++;
  7840. StringBuffer graphName;
  7841. if (!_graphName)
  7842. graphName.append("graph").append(graphSeqNumber);
  7843. else
  7844. graphName.append(_graphName);
  7845. activeGraph.setown(new GeneratedGraphInfo(graphName, graphLabel));
  7846. graphLabel.clear();
  7847. if (insideLibrary())
  7848. activeGraph->xgmml->setPropBool("@library", true);
  7849. }
  7850. void HqlCppTranslator::endGraph()
  7851. {
  7852. graphs.append(*activeGraph.getClear());
  7853. }
  7854. void HqlCppTranslator::clearGraph()
  7855. {
  7856. activeGraph.clear();
  7857. }
  7858. /*
  7859. Tricky getting this in the correct order, problems are:
  7860. 1. generally best to move limits over projects and everything else
  7861. 2. Don't move a limit over a project if that will be part of a compound disk/index read.
  7862. 3. Need to make sure preloaded items aren't messed up by the resourcing.
  7863. 4. Resourcing ensures that shared items are explicitly shared if needed, it also ensures that
  7864. index-reads are not shared if it would be inefficient.
  7865. 5. Worth optimizing the graph before resourcing because it may move split points - e.g.,
  7866. moving a filter/choosen over a sort/spill greatly reducing the time taken.
  7867. 6. Optimizing may move items over conditions which can improve the executed code. E.g.,
  7868. where it allows a limit to be added to something.
  7869. */
  7870. IHqlExpression * HqlCppTranslator::optimizeCompoundSource(IHqlExpression * expr, unsigned flags)
  7871. {
  7872. unsigned time = msTick();
  7873. CompoundSourceTransformer transformer(*this, flags);
  7874. OwnedHqlExpr ret = transformer.process(expr);
  7875. updateTimer("workunit;tree transform: optimize disk read", msTick()-time);
  7876. return ret.getClear();
  7877. }
  7878. IHqlExpression * HqlCppTranslator::optimizeGraphPostResource(IHqlExpression * expr, unsigned csfFlags)
  7879. {
  7880. LinkedHqlExpr resourced = expr;
  7881. // Second attempt to spot compound disk reads - this time of spill files for thor.
  7882. resourced.setown(optimizeCompoundSource(resourced, csfFlags));
  7883. checkNormalized(resourced);
  7884. //insert projects after compound created...
  7885. if (options.optimizeResourcedProjects)
  7886. {
  7887. cycle_t time = msTick();
  7888. OwnedHqlExpr optimized = insertImplicitProjects(*this, resourced.get(), options.optimizeSpillProject);
  7889. updateTimer("workunit;implicit projects", msTick()-time);
  7890. traceExpression("AfterResourcedImplicit", resourced);
  7891. checkNormalized(optimized);
  7892. if (optimized != resourced)
  7893. resourced.setown(optimizeCompoundSource(optimized, csfFlags));
  7894. }
  7895. //Now call the optimizer again - the main purpose is to move projects over limits and into compound index/disk reads
  7896. if (options.optimizeGraph)
  7897. {
  7898. unsigned time = msTick();
  7899. traceExpression("BeforeOptimize2", resourced);
  7900. resourced.setown(optimizeHqlExpression(resourced, getOptimizeFlags()|HOOcompoundproject));
  7901. traceExpression("AfterOptimize2", resourced);
  7902. updateTimer("workunit;optimize graph", msTick()-time);
  7903. }
  7904. resourced.setown(optimizeCompoundSource(resourced, csfFlags));
  7905. return resourced.getClear();
  7906. }
  7907. IHqlExpression * HqlCppTranslator::getResourcedGraph(IHqlExpression * expr, IHqlExpression * graphIdExpr)
  7908. {
  7909. LinkedHqlExpr resourced = expr;
  7910. unsigned csfFlags = CSFindex|options.optimizeDiskFlag;
  7911. if (!targetRoxie())
  7912. csfFlags |= CSFcompoundSpill;
  7913. //Convert queries on preloaded into compound activities - before resourcing so keyed gets done correctly
  7914. checkNormalized(expr);
  7915. traceExpression("BeforeCompound", resourced);
  7916. if (true)
  7917. resourced.setown(optimizeCompoundSource(resourced, CSFpreload|csfFlags));
  7918. // Call optimizer before resourcing so items get moved over conditions, and remove other items
  7919. // which would otherwise cause extra spills.
  7920. traceExpression("BeforeOptimize", resourced);
  7921. unsigned optFlags = getOptimizeFlags();
  7922. checkNormalized(resourced);
  7923. if (options.optimizeGraph)
  7924. {
  7925. unsigned time = msTick();
  7926. resourced.setown(optimizeHqlExpression(resourced, optFlags|HOOfiltersharedproject));
  7927. //have the following on an "aggressive fold" option? If no_selects extract constants it can be quite impressive (jholt22.hql)
  7928. //resourced.setown(foldHqlExpression(resourced));
  7929. updateTimer("workunit;optimize graph", msTick()-time);
  7930. }
  7931. traceExpression("AfterOptimize", resourced);
  7932. checkNormalized(resourced);
  7933. if (true)
  7934. resourced.setown(optimizeCompoundSource(resourced, CSFpreload|csfFlags));
  7935. //Now resource the graph....
  7936. unsigned numNodes = 0;
  7937. if (options.specifiedClusterSize != 0)
  7938. numNodes = options.specifiedClusterSize;
  7939. traceExpression("BeforeResourcing", resourced);
  7940. cycle_t time = msTick();
  7941. if (outputLibraryId)
  7942. {
  7943. unsigned numResults = outputLibrary->numResultsUsed();
  7944. resourced.setown(resourceLibraryGraph(*this, resourced, targetClusterType, numNodes, outputLibraryId, numResults));
  7945. resourced.setown(appendAttribute(resourced, multiInstanceAtom)); // since can be called from multiple places.
  7946. }
  7947. else
  7948. resourced.setown(resourceThorGraph(*this, resourced, targetClusterType, numNodes, graphIdExpr));
  7949. if (!resourced)
  7950. return NULL;
  7951. updateTimer("workunit;resource graph", msTick()-time);
  7952. traceExpression("AfterResourcing", resourced);
  7953. if (options.regressionTest)
  7954. checkDependencyConsistency(resourced);
  7955. checkNormalized(resourced);
  7956. resourced.setown(optimizeGraphPostResource(resourced, csfFlags));
  7957. if (options.optimizeSpillProject)
  7958. {
  7959. resourced.setown(convertSpillsToActivities(resourced));
  7960. resourced.setown(optimizeGraphPostResource(resourced, csfFlags));
  7961. }
  7962. checkNormalized(resourced);
  7963. //Finally create a couple of special compound activities.
  7964. //e.g., filtered fetch, limited keyed join
  7965. {
  7966. unsigned time = msTick();
  7967. CompoundActivityTransformer transformer(targetClusterType);
  7968. resourced.setown(transformer.transformRoot(resourced));
  7969. traceExpression("AfterCompoundActivity", resourced);
  7970. updateTimer("workunit;tree transform: compound activity", msTick()-time);
  7971. }
  7972. resourced.setown(spotTableInvariant(resourced));
  7973. traceExpression("TableInvariant", resourced);
  7974. checkNormalized(resourced);
  7975. return resourced.getClear();
  7976. }
  7977. void HqlCppTranslator::doBuildThorGraph(BuildCtx & ctx, IHqlExpression * expr)
  7978. {
  7979. assertex(expr->queryType()->getTypeCode() == type_void);
  7980. if (outputLibrary)
  7981. buildLibraryGraph(ctx, expr, NULL);
  7982. else
  7983. {
  7984. beginGraph();
  7985. unsigned id = 0;
  7986. OwnedHqlExpr graphTag = createAttribute(graphAtom, createUniqueId());
  7987. OwnedHqlExpr resourced = getResourcedGraph(expr->queryChild(0), graphTag);
  7988. if (resourced)
  7989. {
  7990. traceExpression("beforeGenerate", resourced);
  7991. BuildCtx graphctx(ctx);
  7992. graphctx.addGroup();
  7993. Owned<SubGraphInfo> graphInfo = new SubGraphInfo(activeGraph->xgmml, 0, 0, graphTag, SubGraphRoot);
  7994. graphctx.associate(*graphInfo);
  7995. activeGraphCtx = &graphctx;
  7996. buildStmt(graphctx, resourced);
  7997. activeGraphCtx = NULL;
  7998. graphctx.removeAssociation(graphInfo);
  7999. HqlExprArray args;
  8000. args.append(*createConstant(activeGraph->name));
  8001. args.append(*createConstant(targetThor()));
  8002. args.append(*createConstant(0));
  8003. args.append(*createValue(no_nullptr, makeReferenceModifier(makeRowType(queryNullRecord()->getType()))));
  8004. callProcedure(ctx, executeGraphId, args);
  8005. }
  8006. endGraph();
  8007. }
  8008. }
  8009. void HqlCppTranslator::buildReturnCsvValue(BuildCtx & ctx, IHqlExpression * _expr)
  8010. {
  8011. LinkedHqlExpr expr = _expr;
  8012. IValue * value = expr->queryValue();
  8013. if (value && isUnicodeType(value->queryType()))
  8014. {
  8015. StringBuffer temp;
  8016. value->getUTF8Value(temp);
  8017. expr.setown(createConstant(createStringValue(temp.str(), temp.length())));
  8018. }
  8019. buildReturn(ctx, expr, constUnknownVarStringType);
  8020. }
  8021. void HqlCppTranslator::buildCsvListFunc(BuildCtx & classctx, const char * func, IHqlExpression * attr, const char * defaultValue)
  8022. {
  8023. BuildCtx funcctx(classctx);
  8024. StringBuffer s;
  8025. s.clear().append("virtual const char * ").append(func).append("(unsigned idx)");
  8026. funcctx.addQuotedCompound(s);
  8027. if (attr || defaultValue)
  8028. {
  8029. OwnedHqlExpr idxVar = createVariable("idx", LINK(unsignedType));
  8030. IHqlExpression * value = attr ? attr->queryChild(0) : NULL;
  8031. if (!value || !isEmptyList(value))
  8032. {
  8033. IHqlStmt * caseStmt = funcctx.addSwitch(idxVar);
  8034. if (value)
  8035. {
  8036. if (!value->isList())
  8037. {
  8038. OwnedHqlExpr label = createConstant((__int64)0);
  8039. funcctx.addCase(caseStmt, label);
  8040. buildReturnCsvValue(funcctx, value);
  8041. }
  8042. else
  8043. {
  8044. ForEachChild(idx, value)
  8045. {
  8046. OwnedHqlExpr label = createConstant((__int64)idx);
  8047. funcctx.addCase(caseStmt, label);
  8048. buildReturnCsvValue(funcctx, value->queryChild(idx));
  8049. }
  8050. }
  8051. }
  8052. else
  8053. {
  8054. unsigned entry = 0;
  8055. const char * start = defaultValue;
  8056. loop
  8057. {
  8058. const char * end = strchr(start, '|');
  8059. if (!end) end = start+strlen(start);
  8060. s.clear().append("case ").append(entry++).append(": return ");
  8061. appendStringAsQuotedCPP(s, end-start, start, false);
  8062. s.append(";");
  8063. funcctx.addQuoted(s);
  8064. if (!*end)
  8065. break;
  8066. start = end+1;
  8067. }
  8068. }
  8069. funcctx.addDefault(caseStmt);
  8070. }
  8071. }
  8072. funcctx.addReturn(queryQuotedNullExpr());
  8073. }
  8074. static void expandDefaultString(StringBuffer & out, IHqlExpression * property, const char * defaultValue)
  8075. {
  8076. IHqlExpression * value = property ? property->queryChild(0) : NULL;
  8077. if (value && value->queryValue())
  8078. value->queryValue()->getStringValue(out);
  8079. else
  8080. out.append(defaultValue);
  8081. }
  8082. void HqlCppTranslator::buildCsvParameters(BuildCtx & subctx, IHqlExpression * csvAttr, IHqlExpression * record, bool isReading)
  8083. {
  8084. HqlExprArray attrs;
  8085. if (csvAttr)
  8086. unwindChildren(attrs, csvAttr);
  8087. BuildCtx classctx(subctx);
  8088. StringBuffer s;
  8089. beginNestedClass(classctx, "csv", "ICsvParameters");
  8090. doBuildBoolFunction(classctx, "queryEBCDIC", queryAttribute(ebcdicAtom, attrs)!=NULL);
  8091. bool singleHeader = false;
  8092. bool manyHeader = false;
  8093. IHqlExpression * headerAttr = queryAttribute(headingAtom, attrs);
  8094. IHqlExpression * terminator = queryAttribute(terminatorAtom, attrs);
  8095. IHqlExpression * separator = queryAttribute(separatorAtom, attrs);
  8096. IHqlExpression * escape = queryAttribute(escapeAtom, attrs);
  8097. if (headerAttr)
  8098. {
  8099. IHqlExpression * header = queryRealChild(headerAttr, 0);
  8100. if (header)
  8101. {
  8102. if (header->queryType()->isInteger())
  8103. {
  8104. classctx.addQuoted("virtual const char * getHeader() { return NULL; }");
  8105. doBuildUnsignedFunction(classctx, "queryHeaderLen", header);
  8106. }
  8107. else
  8108. {
  8109. doBuildVarStringFunction(classctx, "getHeader", header);
  8110. classctx.addQuoted("virtual unsigned queryHeaderLen() { return 1; }");
  8111. }
  8112. }
  8113. else
  8114. {
  8115. StringBuffer names;
  8116. if (!isReading)
  8117. {
  8118. StringBuffer comma;
  8119. expandDefaultString(comma, separator, ",");
  8120. expandFieldNames(names, record, comma.str(), queryAttributeChild(headerAttr, formatAtom, 0));
  8121. expandDefaultString(names, terminator, "\n");
  8122. }
  8123. OwnedHqlExpr namesExpr = createConstant(names.str());
  8124. doBuildVarStringFunction(classctx, "getHeader", namesExpr);
  8125. classctx.addQuoted("virtual unsigned queryHeaderLen() { return 1; }");
  8126. }
  8127. if (isReading)
  8128. {
  8129. manyHeader = headerAttr->hasAttribute(manyAtom) && !headerAttr->hasAttribute(singleAtom);
  8130. singleHeader = !manyHeader;
  8131. }
  8132. else
  8133. {
  8134. if (queryRealChild(headerAttr, 1))
  8135. doBuildVarStringFunction(classctx, "getFooter", headerAttr->queryChild(1));
  8136. if (headerAttr->hasAttribute(singleAtom))
  8137. singleHeader = true;
  8138. else
  8139. manyHeader = true;
  8140. }
  8141. }
  8142. else
  8143. {
  8144. classctx.addQuoted("virtual const char * getHeader() { return NULL; }");
  8145. classctx.addQuoted("virtual unsigned queryHeaderLen() { return 0; }");
  8146. }
  8147. doBuildSizetFunction(classctx, "queryMaxSize", getCsvMaxLength(csvAttr));
  8148. buildCsvListFunc(classctx, "getQuote", queryAttribute(quoteAtom, attrs), isReading ? "'" : NULL);
  8149. buildCsvListFunc(classctx, "getSeparator", separator, ",");
  8150. buildCsvListFunc(classctx, "getTerminator", terminator, isReading ? "\r\n|\n" : "\n");
  8151. buildCsvListFunc(classctx, "getEscape", escape, NULL);
  8152. StringBuffer flags;
  8153. if (!queryAttribute(quoteAtom, attrs)) flags.append("|defaultQuote");
  8154. if (!queryAttribute(separatorAtom, attrs)) flags.append("|defaultSeparate");
  8155. if (!queryAttribute(terminatorAtom, attrs)) flags.append("|defaultTerminate");
  8156. if (!queryAttribute(escapeAtom, attrs)) flags.append("|defaultEscape");
  8157. if (singleHeader) flags.append("|singleHeaderFooter");
  8158. if (manyHeader) flags.append("|manyHeaderFooter");
  8159. if (queryAttribute(noTrimAtom, attrs)) flags.append("|preserveWhitespace");
  8160. if (flags.length() == 0) flags.append("|0");
  8161. doBuildUnsignedFunction(classctx, "getFlags", flags.str()+1);
  8162. endNestedClass();
  8163. subctx.addQuoted("virtual ICsvParameters * queryCsvParameters() { return &csv; }");
  8164. }
  8165. void HqlCppTranslator::buildCsvWriteScalar(BuildCtx & ctx, IHqlExpression * expr, IAtom * encoding)
  8166. {
  8167. ITypeInfo * type = expr->queryType()->queryPromotedType();
  8168. type_t tc = type->getTypeCode();
  8169. LinkedHqlExpr value = expr;
  8170. IIdAtom * func;
  8171. if (type->isInteger() || tc == type_boolean)
  8172. {
  8173. if (type->isSigned())
  8174. func = writeSignedId;
  8175. else
  8176. func = writeUnsignedId;
  8177. }
  8178. else if (tc == type_real)
  8179. func = writeRealId;
  8180. else if (tc == type_utf8)
  8181. {
  8182. func = writeUtf8Id;
  8183. value.setown(createValue(no_trim, makeUtf8Type(UNKNOWN_LENGTH, NULL), LINK(value)));
  8184. }
  8185. else if (isUnicodeType(type))
  8186. {
  8187. func = writeUnicodeId;
  8188. value.setown(createValue(no_trim, makeUnicodeType(UNKNOWN_LENGTH, NULL), LINK(value)));
  8189. }
  8190. else
  8191. {
  8192. func = writeStringId;
  8193. value.setown(createValue(no_trim, LINK(unknownStringType), ensureExprType(value, unknownStringType)));
  8194. }
  8195. if (encoding == asciiAtom)
  8196. {
  8197. func = writeStringId;
  8198. Owned<ITypeInfo> type = makeStringType(UNKNOWN_LENGTH, getCharset(asciiAtom), NULL);
  8199. value.setown(ensureExprType(value, type));
  8200. }
  8201. else if (encoding == ebcdicAtom)
  8202. {
  8203. func = writeEbcdicId;
  8204. Owned<ITypeInfo> type = makeStringType(UNKNOWN_LENGTH, getCharset(ebcdicAtom), NULL);
  8205. value.setown(ensureExprType(value, type));
  8206. }
  8207. else if (encoding == unicodeAtom)
  8208. {
  8209. func = writeUnicodeId;
  8210. Owned<ITypeInfo> type = makeUnicodeType(UNKNOWN_LENGTH, NULL);
  8211. value.setown(ensureExprType(value, type));
  8212. }
  8213. HqlExprArray args;
  8214. args.append(*createVariable("out", makeBoolType()));
  8215. args.append(*LINK(value));
  8216. buildFunctionCall(ctx, func, args);
  8217. }
  8218. void HqlCppTranslator::buildCsvWriteTransform(BuildCtx & subctx, IHqlExpression * expr, IHqlExpression * selector, IAtom * encoding)
  8219. {
  8220. switch (expr->getOperator())
  8221. {
  8222. case no_field:
  8223. {
  8224. ITypeInfo * type = expr->queryType()->queryPromotedType();
  8225. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(expr));
  8226. if (type->getTypeCode() == type_row)
  8227. {
  8228. buildCsvWriteTransform(subctx, expr->queryRecord(), selected, encoding);
  8229. break;
  8230. }
  8231. if (expr->isDataset())
  8232. {
  8233. //May as well output datasets in csv in some way - a count followed by the expanded fields...
  8234. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(subctx, selected);
  8235. CHqlBoundExpr boundCount;
  8236. cursor->buildCount(subctx, boundCount);
  8237. OwnedHqlExpr translatedCount = boundCount.getTranslatedExpr();
  8238. buildCsvWriteScalar(subctx, translatedCount, encoding);
  8239. BuildCtx loopctx(subctx);
  8240. BoundRow * row = cursor->buildIterateLoop(loopctx, false);
  8241. buildCsvWriteTransform(loopctx, expr->queryRecord(), selected, encoding);
  8242. return;
  8243. }
  8244. else if (type->getTypeCode() == type_set)
  8245. {
  8246. BuildCtx condctx(subctx);
  8247. Owned<IHqlCppSetCursor> cursor = createSetSelector(condctx, selected);
  8248. CHqlBoundExpr isAll;
  8249. cursor->buildIsAll(condctx, isAll);
  8250. IHqlStmt * stmt = condctx.addFilter(isAll.expr);
  8251. OwnedHqlExpr allText = createConstant("ALL");
  8252. buildCsvWriteScalar(condctx, allText, encoding);
  8253. condctx.selectElse(stmt);
  8254. CHqlBoundExpr boundCurElement;
  8255. cursor->buildIterateLoop(condctx, boundCurElement, false);
  8256. OwnedHqlExpr curElement = boundCurElement.getTranslatedExpr();
  8257. buildCsvWriteScalar(condctx, curElement, encoding);
  8258. }
  8259. else
  8260. buildCsvWriteScalar(subctx, selected, encoding);
  8261. break;
  8262. }
  8263. case no_ifblock:
  8264. {
  8265. OwnedHqlExpr cond = replaceSelector(expr->queryChild(0), querySelfReference(), selector);
  8266. BuildCtx condctx(subctx);
  8267. buildFilter(condctx, cond);
  8268. buildCsvWriteTransform(condctx, expr->queryChild(1), selector, encoding);
  8269. break;
  8270. }
  8271. case no_record:
  8272. {
  8273. ForEachChild(idx, expr)
  8274. buildCsvWriteTransform(subctx, expr->queryChild(idx), selector, encoding);
  8275. break;
  8276. }
  8277. case no_attr:
  8278. case no_attr_expr:
  8279. case no_attr_link:
  8280. break;
  8281. }
  8282. }
  8283. void HqlCppTranslator::buildCsvWriteTransform(BuildCtx & subctx, IHqlExpression * dataset, IAtom * encoding)
  8284. {
  8285. BuildCtx funcctx(subctx);
  8286. funcctx.addQuotedCompound("void writeRow(const byte * self, ITypedOutputStream * out)");
  8287. BoundRow * cursor = bindTableCursor(funcctx, dataset, "self");
  8288. buildCsvWriteTransform(funcctx, dataset->queryRecord(), cursor->querySelector(), encoding);
  8289. }
  8290. void HqlCppTranslator::buildExpiryHelper(BuildCtx & ctx, IHqlExpression * expireAttr)
  8291. {
  8292. if (expireAttr)
  8293. {
  8294. LinkedHqlExpr num = expireAttr->queryChild(0);
  8295. if (!num)
  8296. num.setown(getSizetConstant(options.defaultExpiry));
  8297. doBuildUnsignedFunction(ctx, "getExpiryDays", num);
  8298. }
  8299. }
  8300. void HqlCppTranslator::buildEncryptHelper(BuildCtx & ctx, IHqlExpression * encryptAttr, const char * funcname)
  8301. {
  8302. if (encryptAttr)
  8303. {
  8304. if (!funcname) funcname = "getEncryptKey";
  8305. doBuildDataFunction(ctx, funcname, encryptAttr->queryChild(0));
  8306. }
  8307. }
  8308. void HqlCppTranslator::buildUpdateHelper(BuildCtx & ctx, ActivityInstance & instance, IHqlExpression * input, IHqlExpression * updateAttr)
  8309. {
  8310. if (updateAttr)
  8311. {
  8312. BuildCtx subctx(ctx);
  8313. subctx.addQuotedCompound("virtual void getUpdateCRCs(unsigned & eclCrc, unsigned __int64 & totalCRC)");
  8314. OwnedHqlExpr eclCrcVar = createVariable("eclCrc", LINK(unsignedType));
  8315. OwnedHqlExpr totalCrcVar = createVariable("totalCRC", makeIntType(8, false));
  8316. IHqlExpression * originalCrc = updateAttr->queryChild(0);
  8317. DependenciesUsed dependencies(true);
  8318. IHqlExpression * filesRead = updateAttr->queryAttribute(_files_Atom);
  8319. if (filesRead)
  8320. {
  8321. ForEachChild(i, filesRead)
  8322. dependencies.tablesRead.append(*getNormalizedFilename(filesRead->queryChild(i)));
  8323. }
  8324. IHqlExpression * resultsRead = updateAttr->queryAttribute(_results_Atom);
  8325. if (resultsRead)
  8326. unwindChildren(dependencies.resultsRead, resultsRead);
  8327. OwnedHqlExpr crcExpr = calculatePersistInputCrc(subctx, dependencies);
  8328. buildAssignToTemp(subctx, eclCrcVar, originalCrc);
  8329. buildAssignToTemp(subctx, totalCrcVar, crcExpr);
  8330. if (!updateAttr->hasAttribute(alwaysAtom))
  8331. instance.addAttributeBool("_updateIfChanged", true);
  8332. }
  8333. }
  8334. void HqlCppTranslator::buildClusterHelper(BuildCtx & ctx, IHqlExpression * expr)
  8335. {
  8336. IHqlExpression * cluster = expr->queryAttribute(clusterAtom);
  8337. if (!cluster)
  8338. return;
  8339. BuildCtx funcctx(ctx);
  8340. funcctx.addQuotedCompound("virtual const char * getCluster(unsigned idx)");
  8341. BuildCtx switchctx(funcctx);
  8342. OwnedHqlExpr var = createVariable("idx", LINK(unsignedType));
  8343. IHqlStmt * switchStmt = switchctx.addSwitch(var);
  8344. unsigned count = 0;
  8345. ForEachChild(i, cluster)
  8346. {
  8347. IHqlExpression * cur = queryRealChild(cluster, i);
  8348. if (cur)
  8349. {
  8350. BuildCtx casectx(switchctx);
  8351. OwnedHqlExpr label = getSizetConstant(count++);
  8352. casectx.addCase(switchStmt, label);
  8353. buildReturn(casectx, cur, constUnknownVarStringType);
  8354. // 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)
  8355. //if (logger)
  8356. //{
  8357. // OwnedHqlExpr folded = foldHqlExpression(cur);
  8358. // if (folded->queryValue())
  8359. // {
  8360. // StringBuffer clusterText;
  8361. // folded->queryValue()->getStringValue(clusterText);
  8362. // logger->noteCluster(clusterText.str());
  8363. // }
  8364. //}
  8365. }
  8366. }
  8367. funcctx.addReturn(queryQuotedNullExpr());
  8368. }
  8369. void HqlCppTranslator::buildRecordEcl(BuildCtx & subctx, IHqlExpression * dataset, const char * methodName)
  8370. {
  8371. StringBuffer eclFuncName;
  8372. StringBuffer s;
  8373. //Ensure the ECL for the record reflects its serialized form, not the internal form
  8374. OwnedHqlExpr record = getSerializedForm(dataset->queryRecord(), diskAtom);
  8375. appendUniqueId(eclFuncName.append("ecl"), getConsistentUID(record));
  8376. BuildCtx declarectx(*code, declareAtom);
  8377. OwnedHqlExpr attr = createAttribute(eclAtom, LINK(record));
  8378. HqlExprAssociation * match = declarectx.queryMatchExpr(attr);
  8379. if (!match)
  8380. {
  8381. StringBuffer eclText;
  8382. getRecordECL(record, eclText);
  8383. BuildCtx funcctx(declarectx);
  8384. funcctx.setNextPriority(EclTextPrio);
  8385. s.append("const char * ").append(eclFuncName).append("(ICodeContext * ctx)");
  8386. funcctx.addQuotedCompound(s);
  8387. OwnedHqlExpr v = addStringLiteral(eclText);
  8388. funcctx.addReturn(v);
  8389. OwnedHqlExpr temp = createVariable(eclFuncName.str(), makeVoidType());
  8390. declarectx.associateExpr(attr, temp);
  8391. if (options.spanMultipleCpp)
  8392. {
  8393. s.clear().append("extern const char * ").append(eclFuncName).append("(ICodeContext * ctx);");
  8394. BuildCtx protoctx(*code, mainprototypesAtom);
  8395. protoctx.addQuoted(s);
  8396. }
  8397. }
  8398. s.clear().append("virtual const char * ").append(methodName).append("() { return ").append(eclFuncName).append("(ctx); }");
  8399. subctx.addQuoted(s);
  8400. }
  8401. void HqlCppTranslator::buildFormatCrcFunction(BuildCtx & ctx, const char * name, IHqlExpression * dataset, IHqlExpression * expr, unsigned payloadDelta)
  8402. {
  8403. IHqlExpression * payload = expr ? expr->queryAttribute(_payload_Atom) : NULL;
  8404. OwnedHqlExpr exprToCrc = getSerializedForm(dataset->queryRecord(), diskAtom);
  8405. unsigned payloadSize = 1;
  8406. if (payload)
  8407. payloadSize = (unsigned)getIntValue(payload->queryChild(0)) + payloadDelta;
  8408. exprToCrc.setown(createComma(exprToCrc.getClear(), getSizetConstant(payloadSize)));
  8409. traceExpression("crc:", exprToCrc);
  8410. OwnedHqlExpr crc = getSizetConstant(getExpressionCRC(exprToCrc));
  8411. doBuildUnsignedFunction(ctx, name, crc);
  8412. }
  8413. static void createOutputIndexRecord(HqlMapTransformer & mapper, HqlExprArray & fields, IHqlExpression * record, bool isMainRecord, bool allowTranslate)
  8414. {
  8415. unsigned numFields = record->numChildren();
  8416. unsigned max = isMainRecord ? numFields-1 : numFields;
  8417. for (unsigned idx=0; idx < max; idx++)
  8418. {
  8419. IHqlExpression * cur = record->queryChild(idx);
  8420. IHqlExpression * newField = NULL;
  8421. switch (cur->getOperator())
  8422. {
  8423. case no_attr:
  8424. case no_attr_link:
  8425. case no_attr_expr:
  8426. newField = LINK(cur);
  8427. break;
  8428. case no_ifblock:
  8429. {
  8430. HqlExprArray newFields;
  8431. createOutputIndexRecord(mapper, newFields, cur->queryChild(1), false, false);
  8432. newField = createValue(no_ifblock, makeNullType(), mapper.transformRoot(cur->queryChild(0)), createRecord(newFields));
  8433. break;
  8434. }
  8435. case no_record:
  8436. {
  8437. HqlExprArray newFields;
  8438. createOutputIndexRecord(mapper, newFields, cur, false, allowTranslate);
  8439. newField = createRecord(newFields);
  8440. break;
  8441. }
  8442. case no_field:
  8443. if (cur->hasAttribute(blobAtom))
  8444. {
  8445. newField = createField(cur->queryId(), makeIntType(8, false), NULL, NULL);
  8446. }
  8447. else if (allowTranslate)
  8448. {
  8449. if (cur->isDatarow() && !isInPayload())
  8450. {
  8451. HqlMapTransformer childMapper;
  8452. HqlExprArray newFields;
  8453. createOutputIndexRecord(childMapper, newFields, cur->queryRecord(), false, allowTranslate);
  8454. OwnedHqlExpr newRecord = createRecord(newFields);
  8455. HqlExprArray args;
  8456. unwindChildren(args, cur);
  8457. newField = createField(cur->queryId(), newRecord->getType(), args);
  8458. }
  8459. else
  8460. {
  8461. OwnedHqlExpr select = createSelectExpr(getActiveTableSelector(), LINK(cur));
  8462. OwnedHqlExpr value = getHozedKeyValue(select);
  8463. ITypeInfo * newType = value->getType();
  8464. newField = createField(cur->queryId(), newType, NULL, extractFieldAttrs(cur));
  8465. //Now set up the mappings for ifblocks
  8466. OwnedHqlExpr selfSelect = createSelectExpr(LINK(querySelfReference()), LINK(cur));
  8467. OwnedHqlExpr physicalSelect = createSelectExpr(LINK(querySelfReference()), LINK(newField));
  8468. OwnedHqlExpr keyValue = convertIndexPhysical2LogicalValue(cur, physicalSelect, true);
  8469. mapper.setMapping(selfSelect, keyValue);
  8470. }
  8471. }
  8472. else
  8473. newField = LINK(cur);
  8474. break;
  8475. }
  8476. fields.append(*newField);
  8477. }
  8478. }
  8479. static void createOutputIndexTransform(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * tgtRecord, IHqlExpression * srcRecord, IHqlExpression* srcDataset, bool isMainRecord, bool allowTranslate)
  8480. {
  8481. unsigned numFields = srcRecord->numChildren();
  8482. unsigned max = isMainRecord ? numFields-1 : numFields;
  8483. for (unsigned idx=0; idx < max; idx++)
  8484. {
  8485. IHqlExpression * cur = srcRecord->queryChild(idx);
  8486. IHqlExpression * curNew = tgtRecord->queryChild(idx);
  8487. switch (cur->getOperator())
  8488. {
  8489. case no_ifblock:
  8490. createOutputIndexTransform(assigns, self, curNew->queryChild(1), cur->queryChild(1), srcDataset, false, false);
  8491. break;
  8492. case no_record:
  8493. createOutputIndexTransform(assigns, self, curNew, cur, srcDataset, false, allowTranslate);
  8494. break;
  8495. case no_field:
  8496. {
  8497. OwnedHqlExpr select = createSelectExpr(LINK(srcDataset), LINK(cur));
  8498. OwnedHqlExpr value;
  8499. if (cur->hasAttribute(blobAtom))
  8500. {
  8501. value.setown(createValue(no_blob2id, curNew->getType(), LINK(select)));
  8502. }
  8503. else if (cur->isDatarow() && !isInPayload())
  8504. {
  8505. OwnedHqlExpr childSelf = createSelectExpr(LINK(self), LINK(curNew));
  8506. createOutputIndexTransform(assigns, childSelf, curNew->queryRecord(), cur->queryRecord(), select, false, allowTranslate);
  8507. }
  8508. else
  8509. {
  8510. if (allowTranslate)
  8511. value.setown(getHozedKeyValue(select));
  8512. else
  8513. value.set(select);
  8514. }
  8515. if (value)
  8516. assigns.append(*createAssign(createSelectExpr(LINK(self), LINK(curNew)), LINK(value)));
  8517. break;
  8518. }
  8519. }
  8520. }
  8521. }
  8522. void HqlCppTranslator::doBuildIndexOutputTransform(BuildCtx & ctx, IHqlExpression * record, SharedHqlExpr & rawRecord)
  8523. {
  8524. OwnedHqlExpr srcDataset = createDataset(no_anon, LINK(record));
  8525. HqlExprArray fields;
  8526. HqlExprArray assigns;
  8527. HqlMapTransformer mapper;
  8528. createOutputIndexRecord(mapper, fields, record, true, true);
  8529. OwnedHqlExpr newRecord = createRecord(fields);
  8530. rawRecord.set(newRecord);
  8531. OwnedHqlExpr self = getSelf(newRecord);
  8532. createOutputIndexTransform(assigns, self, newRecord, record, srcDataset, true, true);
  8533. OwnedHqlExpr tgtDataset = createDataset(no_anon, newRecord.getLink());
  8534. OwnedHqlExpr transform = createValue(no_newtransform, makeTransformType(newRecord->getType()), assigns);
  8535. BuildCtx subctx(ctx);
  8536. subctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IBlobCreator * blobs, unsigned __int64 & filepos)");
  8537. ensureRowAllocated(subctx, "crSelf");
  8538. subctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  8539. associateBlobHelper(subctx, srcDataset, "blobs");
  8540. BoundRow * selfCursor = bindSelf(subctx, tgtDataset, "crSelf");
  8541. bindTableCursor(subctx, srcDataset, "left");
  8542. associateSkipReturnMarker(subctx, queryZero(), selfCursor);
  8543. doTransform(subctx, transform, selfCursor);
  8544. OwnedHqlExpr fposVar = createVariable("filepos", makeIntType(8, false));
  8545. OwnedHqlExpr fposField = createSelectExpr(LINK(srcDataset), LINK(queryLastField(record)));
  8546. buildAssignToTemp(subctx, fposVar, fposField);
  8547. buildReturnRecordSize(subctx, selfCursor);
  8548. buildMetaMember(ctx, tgtDataset, false, "queryDiskRecordSize");
  8549. }
  8550. class TranslatorMaxSizeCallback : public IMaxSizeCallback
  8551. {
  8552. public:
  8553. enum { sizeofFposField = 8 };
  8554. TranslatorMaxSizeCallback(HqlCppTranslator & _translator) : translator(_translator) {}
  8555. virtual size32_t getMaxSize(IHqlExpression * record)
  8556. {
  8557. bool isKnownSize, usedDefaultMaxSize;
  8558. size32_t maxSize = getMaxRecordSize(record, translator.getDefaultMaxRecordSize(), isKnownSize, usedDefaultMaxSize);
  8559. if (usedDefaultMaxSize)
  8560. maxSize += sizeofFposField; //adjust maximum size for the fileposition, so consistent with raw record size
  8561. return maxSize;
  8562. }
  8563. protected:
  8564. HqlCppTranslator & translator;
  8565. };
  8566. static HqlTransformerInfo cHqlBlobTransformerInfo("CHqlBlobTransformer");
  8567. class CHqlBlobTransformer : public QuickHqlTransformer
  8568. {
  8569. public:
  8570. CHqlBlobTransformer() : QuickHqlTransformer(cHqlBlobTransformerInfo, NULL) {}
  8571. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  8572. {
  8573. OwnedHqlExpr transformed = QuickHqlTransformer::createTransformed(expr);
  8574. if ((expr->getOperator() == no_field) && expr->hasAttribute(blobAtom))
  8575. return appendOwnedOperand(transformed, createAttribute(_isBlobInIndex_Atom));
  8576. return transformed.getClear();
  8577. }
  8578. };
  8579. IHqlExpression * annotateIndexBlobs(IHqlExpression * expr)
  8580. {
  8581. CHqlBlobTransformer transformer;
  8582. return transformer.transform(expr);
  8583. }
  8584. IDefRecordElement * HqlCppTranslator::createMetaRecord(IHqlExpression * record)
  8585. {
  8586. TranslatorMaxSizeCallback callback(*this);
  8587. return ::createMetaRecord(record, &callback);
  8588. }
  8589. IHqlExpression * HqlCppTranslator::getSerializedLayoutFunction(IHqlExpression * record, unsigned numKeyedFields)
  8590. {
  8591. OwnedHqlExpr serializedRecord = getSerializedForm(record, diskAtom);
  8592. OwnedHqlExpr search = createAttribute(indexLayoutMarkerAtom, LINK(serializedRecord), getSizetConstant(numKeyedFields));
  8593. BuildCtx declarectx(*code, declareAtom);
  8594. HqlExprAssociation * match = declarectx.queryMatchExpr(search);
  8595. if (match)
  8596. return LINK(match->queryExpr());
  8597. //Modify the record, so that blob fields are tagged as represented as they are in the index
  8598. OwnedHqlExpr indexRecord = annotateIndexBlobs(serializedRecord);
  8599. Owned<IDefRecordElement> re = createMetaRecord(indexRecord);
  8600. if (!re)
  8601. return NULL;
  8602. StringBuffer functionName;
  8603. getUniqueId(functionName.append("getLayout"));
  8604. BuildCtx layoutctx(declarectx);
  8605. StringBuffer s;
  8606. s.append("void ").append(functionName).append("(size32_t & __lenResult, void * & __result, IResourceContext * ctx)");
  8607. layoutctx.setNextPriority(RowMetaPrio);
  8608. layoutctx.addQuotedCompound(s);
  8609. Owned<IDefRecordMeta> meta = createDefRecordMeta(re, numKeyedFields);
  8610. MemoryBuffer serialized;
  8611. serializeRecordMeta(serialized, meta, true);
  8612. OwnedHqlExpr metaExpr = createConstant(createDataValue(serialized.toByteArray(), serialized.length()));
  8613. Owned<ITypeInfo> type = makeDataType(UNKNOWN_LENGTH);
  8614. doBuildFunctionReturn(layoutctx, type, metaExpr);
  8615. if (options.showMetaText)
  8616. {
  8617. s.clear().append("/*").newline();
  8618. getRecordMetaAsString(s, meta);
  8619. s.append("*/");
  8620. layoutctx.addQuoted(s.str());
  8621. }
  8622. if (options.spanMultipleCpp)
  8623. {
  8624. s.clear().append("extern void ").append(functionName).append("(size32_t & __lenResult, void * & __result, IResourceContext * ctx);");
  8625. BuildCtx protoctx(*code, mainprototypesAtom);
  8626. protoctx.addQuoted(s);
  8627. }
  8628. OwnedHqlExpr temp = createVariable(functionName, makeVoidType());
  8629. declarectx.associateExpr(search, temp);
  8630. return temp.getLink();
  8631. }
  8632. void HqlCppTranslator::buildSerializedLayoutMember(BuildCtx & ctx, IHqlExpression * record, const char * name, unsigned numKeyedFields)
  8633. {
  8634. OwnedHqlExpr func = getSerializedLayoutFunction(record, numKeyedFields);
  8635. if (func)
  8636. {
  8637. StringBuffer s;
  8638. s.append("virtual bool ").append(name).append("(size32_t & __lenResult, void * & __result) { ");
  8639. generateExprCpp(s, func).append("(__lenResult, __result, ctx); return true; }");
  8640. ctx.addQuoted(s);
  8641. }
  8642. }
  8643. ABoundActivity * HqlCppTranslator::doBuildActivityOutputIndex(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  8644. {
  8645. IHqlExpression * dataset = expr->queryChild(0);
  8646. IHqlExpression * filename = queryRealChild(expr, 1);
  8647. IHqlExpression * record = dataset->queryRecord();
  8648. IHqlDataset * baseTable = dataset->queryDataset()->queryRootTable();
  8649. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  8650. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKindexwrite, expr, "IndexWrite");
  8651. buildActivityFramework(instance, isRoot);
  8652. buildInstancePrefix(instance);
  8653. //virtual const char * getFileName() { return "x.d00"; }
  8654. buildFilenameFunction(*instance, instance->startctx, "getFileName", filename, hasDynamicFilename(expr));
  8655. //virtual const char * getDatasetName() { return "x.d00"; }
  8656. IHqlExpression * tableName = expr->queryAttribute(nameAtom);
  8657. if (tableName)
  8658. doBuildVarStringFunction(instance->startctx, "getDatasetName", tableName->queryChild(0));
  8659. //virtual unsigned getFlags() = 0;
  8660. IHqlExpression * updateAttr = expr->queryAttribute(updateAtom);
  8661. IHqlExpression * compressAttr = expr->queryAttribute(compressedAtom);
  8662. IHqlExpression * widthExpr = queryAttributeChild(expr, widthAtom, 0);
  8663. bool hasTLK = !expr->hasAttribute(noRootAtom);
  8664. bool singlePart = expr->hasAttribute(fewAtom);
  8665. if (matchesConstantValue(widthExpr, 1))
  8666. {
  8667. singlePart = true;
  8668. widthExpr = NULL;
  8669. }
  8670. StringBuffer s;
  8671. StringBuffer flags;
  8672. if (expr->hasAttribute(overwriteAtom)) flags.append("|TIWoverwrite");
  8673. if (expr->hasAttribute(noOverwriteAtom)) flags.append("|TIWnooverwrite");
  8674. if (expr->hasAttribute(backupAtom)) flags.append("|TIWbackup");
  8675. if (!filename->isConstant()) flags.append("|TIWvarfilename");
  8676. if (singlePart) flags.append("|TIWsmall");
  8677. if (updateAttr) flags.append("|TIWupdatecrc");
  8678. if (updateAttr && !updateAttr->queryAttribute(alwaysAtom)) flags.append("|TIWupdate");
  8679. if (!hasTLK && !singlePart) flags.append("|TIWlocal");
  8680. if (expr->hasAttribute(expireAtom)) flags.append("|TIWexpires");
  8681. if (compressAttr)
  8682. {
  8683. if (compressAttr->hasAttribute(rowAtom)) flags.append("|TIWrowcompress");
  8684. if (!compressAttr->hasAttribute(lzwAtom)) flags.append("|TIWnolzwcompress");
  8685. }
  8686. if (widthExpr) flags.append("|TIWhaswidth");
  8687. if (flags.length())
  8688. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  8689. IHqlExpression * indexNameAttr = expr->queryAttribute(indexAtom);
  8690. if (indexNameAttr)
  8691. buildFilenameFunction(*instance, instance->startctx, "getDistributeIndexName", indexNameAttr->queryChild(0), hasDynamicFilename(expr));
  8692. buildExpiryHelper(instance->createctx, expr->queryAttribute(expireAtom));
  8693. buildUpdateHelper(instance->createctx, *instance, dataset, updateAttr);
  8694. buildClusterHelper(instance->classctx, expr);
  8695. // virtual unsigned getKeyedSize()
  8696. HqlExprArray fields;
  8697. unwindChildren(fields, record);
  8698. removeAttributes(fields);
  8699. fields.popn(numPayloadFields(expr));
  8700. OwnedHqlExpr keyedRecord = createRecord(fields); // must be fixed length => no maxlength
  8701. if (expr->hasAttribute(_payload_Atom))
  8702. instance->classctx.addQuoted(s.clear().append("virtual unsigned getKeyedSize() { return ").append(getFixedRecordSize(keyedRecord)).append("; }"));
  8703. else
  8704. instance->classctx.addQuoted(s.clear().append("virtual unsigned getKeyedSize() { return (unsigned) -1; }"));
  8705. //virtual const char * queryRecordECL() = 0;
  8706. buildRecordEcl(instance->createctx, dataset, "queryRecordECL");
  8707. doBuildSequenceFunc(instance->classctx, querySequence(expr), false);
  8708. Owned<IWUResult> result = createDatasetResultSchema(querySequence(expr), queryResultName(expr), dataset->queryRecord(), false, true);
  8709. if (expr->hasAttribute(setAtom))
  8710. {
  8711. BuildCtx subctx(instance->startctx);
  8712. subctx.addQuotedCompound("virtual bool getIndexMeta(size32_t & lenName, char * & name, size32_t & lenValue, char * & value, unsigned idx)");
  8713. CHqlBoundTarget nameTarget, valueTarget;
  8714. initBoundStringTarget(nameTarget, unknownStringType, "lenName", "name");
  8715. //more should probably be utf-8 rather than string
  8716. initBoundStringTarget(valueTarget, unknownStringType, "lenValue", "value");
  8717. OwnedHqlExpr idxVar = createVariable("idx", LINK(sizetType));
  8718. BuildCtx casectx(subctx);
  8719. IHqlStmt * switchStmt = casectx.addSwitch(idxVar);
  8720. unsigned count = 0;
  8721. ForEachChild(i, expr)
  8722. {
  8723. IHqlExpression * cur = expr->queryChild(i);
  8724. if (cur->isAttribute() && cur->queryName() == setAtom)
  8725. {
  8726. OwnedHqlExpr label = getSizetConstant(count++);
  8727. casectx.addCase(switchStmt, label);
  8728. buildExprAssign(casectx, nameTarget, cur->queryChild(0));
  8729. buildExprAssign(casectx, valueTarget, cur->queryChild(1));
  8730. buildReturn(casectx, queryBoolExpr(true));
  8731. }
  8732. }
  8733. buildReturn(subctx, queryBoolExpr(false));
  8734. }
  8735. OwnedHqlExpr rawRecord;
  8736. doBuildIndexOutputTransform(instance->startctx, record, rawRecord);
  8737. buildFormatCrcFunction(instance->classctx, "getFormatCrc", rawRecord, expr, 0);
  8738. if (compressAttr && compressAttr->hasAttribute(rowAtom))
  8739. {
  8740. if (!isFixedWidthDataset(rawRecord))
  8741. throwError(HQLERR_RowCompressRequireFixedSize);
  8742. }
  8743. if (!expr->hasAttribute(fixedAtom))
  8744. buildSerializedLayoutMember(instance->classctx, record, "getIndexLayout", fields.ordinality());
  8745. if (widthExpr)
  8746. {
  8747. doBuildUnsignedFunction(instance->startctx, "getWidth", widthExpr);
  8748. if (!hasTLK)
  8749. {
  8750. HqlExprArray sorts;
  8751. gatherIndexBuildSortOrder(sorts, expr, options.sortIndexPayload);
  8752. OwnedHqlExpr sortOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  8753. instance->startctx.addQuoted("virtual ICompare * queryCompare() { return &compare; }");
  8754. DatasetReference dsRef(dataset);
  8755. buildCompareClass(instance->nestedctx, "compare", sortOrder, dsRef);
  8756. }
  8757. }
  8758. buildInstanceSuffix(instance);
  8759. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  8760. OwnedHqlExpr dependency = createAttribute(fileAtom, getNormalizedFilename(filename));
  8761. Owned<ABoundActivity> bound = instance->getBoundActivity();
  8762. OwnedHqlExpr boundUnknown = createUnknown(no_attr, NULL, NULL, LINK(bound));
  8763. ctx.associateExpr(dependency, boundUnknown);
  8764. return instance->getBoundActivity();
  8765. }
  8766. void HqlCppTranslator::buildCsvWriteMembers(ActivityInstance * instance, IHqlExpression * dataset, IHqlExpression * csvAttr)
  8767. {
  8768. buildCsvParameters(instance->nestedctx, csvAttr, dataset->queryRecord(), false);
  8769. buildCsvWriteTransform(instance->startctx, dataset, queryCsvEncoding(csvAttr));
  8770. }
  8771. void HqlCppTranslator::buildXmlWriteMembers(ActivityInstance * instance, IHqlExpression * dataset, IHqlExpression * xmlAttr)
  8772. {
  8773. buildXmlSerialize(instance->startctx, dataset, "toXML", false);
  8774. IHqlExpression * rowAttr = xmlAttr->queryAttribute(rowAtom);
  8775. if (rowAttr)
  8776. doBuildVarStringFunction(instance->startctx, "getXmlIteratorPath", rowAttr->queryChild(0));
  8777. IHqlExpression * headerAttr = xmlAttr->queryAttribute(headingAtom);
  8778. if (headerAttr)
  8779. {
  8780. doBuildVarStringFunction(instance->startctx, "getHeader", headerAttr->queryChild(0));
  8781. doBuildVarStringFunction(instance->startctx, "getFooter", headerAttr->queryChild(1));
  8782. }
  8783. StringBuffer xmlFlags;
  8784. if (xmlAttr->hasAttribute(trimAtom))
  8785. xmlFlags.append("|XWFtrim");
  8786. if (xmlAttr->hasAttribute(optAtom))
  8787. xmlFlags.append("|XWFopt");
  8788. if (xmlFlags.length())
  8789. {
  8790. StringBuffer s;
  8791. s.append("virtual unsigned getXmlFlags() { return ").append(xmlFlags.str()+1).append("; }");
  8792. instance->classctx.addQuoted(s);
  8793. }
  8794. }
  8795. ABoundActivity * HqlCppTranslator::doBuildActivityOutput(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  8796. {
  8797. IHqlExpression * dataset = expr->queryChild(0);
  8798. IHqlExpression * rawFilename = queryRealChild(expr, 1);
  8799. if (dataset->isDictionary())
  8800. {
  8801. //OUTPUT(dictionary,,'filename') should never be generated - it should go via a dataset
  8802. assertex(!rawFilename);
  8803. return doBuildActivityDictionaryWorkunitWrite(ctx, expr, isRoot);
  8804. }
  8805. if (!rawFilename)
  8806. return doBuildActivityOutputWorkunit(ctx, expr, isRoot);
  8807. OwnedHqlExpr filename = foldHqlExpression(rawFilename);
  8808. IHqlExpression * program = queryRealChild(expr, 2);
  8809. IHqlExpression * csvAttr = expr->queryAttribute(csvAtom);
  8810. IHqlExpression * xmlAttr = expr->queryAttribute(xmlAtom);
  8811. LinkedHqlExpr expireAttr = expr->queryAttribute(expireAtom);
  8812. IHqlExpression * seq = querySequence(expr);
  8813. IHqlExpression *pipe = NULL;
  8814. if (program)
  8815. {
  8816. if (program->getOperator()==no_pipe)
  8817. pipe = program->queryChild(0);
  8818. }
  8819. else if (filename->getOperator()==no_pipe)
  8820. pipe = filename->queryChild(0);
  8821. if (pipe)
  8822. checkPipeAllowed();
  8823. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  8824. ThorActivityKind kind = TAKdiskwrite;
  8825. const char * activity = "DiskWrite";
  8826. if (expr->getOperator() == no_spill)
  8827. {
  8828. kind = TAKspill;
  8829. activity = "Spill";
  8830. }
  8831. else if (pipe)
  8832. {
  8833. kind = TAKpipewrite;
  8834. activity = "PipeWrite";
  8835. }
  8836. else if (csvAttr)
  8837. {
  8838. kind = TAKcsvwrite;
  8839. activity = "CsvWrite";
  8840. }
  8841. else if (xmlAttr)
  8842. {
  8843. kind = TAKxmlwrite;
  8844. activity = "XmlWrite";
  8845. }
  8846. bool useImplementationClass = options.minimizeActivityClasses && targetRoxie() && expr->hasAttribute(_spill_Atom);
  8847. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, activity);
  8848. //Output to a variable filename is either a user result, or a computed workflow spill, both need evaluating.
  8849. if (useImplementationClass)
  8850. instance->setImplementationClass(newMemorySpillSplitArgId);
  8851. if ((kind == TAKdiskwrite) && filename->queryValue())
  8852. {
  8853. StringBuffer s;
  8854. s.append(getActivityText(kind));
  8855. if (expr->hasAttribute(_spill_Atom))
  8856. s.append("\nSpill File");
  8857. else
  8858. filename->toString(s.append("\n"));
  8859. instance->graphLabel.set(s.str());
  8860. }
  8861. if (pipe)
  8862. {
  8863. if (csvAttr)
  8864. instance->addBaseClass("IHThorCsvWriteExtra", true);
  8865. else if (xmlAttr)
  8866. instance->addBaseClass("IHThorXmlWriteExtra", true);
  8867. }
  8868. buildActivityFramework(instance, isRoot && !isInternalSeq(seq));
  8869. buildInstancePrefix(instance);
  8870. noteResultDefined(ctx, instance, seq, filename, isRoot);
  8871. //virtual const char * getFileName() { return "x.d00"; }
  8872. OwnedHqlExpr tempCount;
  8873. if (expr->hasAttribute(_spill_Atom) || expr->hasAttribute(jobTempAtom))
  8874. {
  8875. IPropertyTree * graphNode = NULL;
  8876. if (targetRoxie() && expr->hasAttribute(jobTempAtom))
  8877. graphNode = instance->graphNode;
  8878. GlobalFileTracker * tracker = new GlobalFileTracker(filename, graphNode);
  8879. globalFiles.append(*tracker);
  8880. OwnedHqlExpr callback = createUnknown(no_callback, LINK(unsignedType), globalAtom, LINK(tracker));
  8881. tempCount.setown(createTranslated(callback));
  8882. }
  8883. if (!useImplementationClass)
  8884. {
  8885. if (pipe)
  8886. {
  8887. //MORE or pipe name is dependent on the input dataset - !constant is not sufficient
  8888. if (expr->hasAttribute(repeatAtom))
  8889. {
  8890. //virtual const char * getPipeProgram() { return "grep"; }
  8891. instance->startctx.addQuoted("virtual const char * getPipeProgram() { return NULL; }");
  8892. BuildCtx pipeCtx(instance->startctx);
  8893. pipeCtx.addQuotedCompound("virtual char * getNameFromRow(const void * _self)");
  8894. pipeCtx.addQuoted("const unsigned char * self = (const unsigned char *) _self;");
  8895. bindTableCursor(pipeCtx, dataset, "self");
  8896. buildReturn(pipeCtx, pipe, unknownVarStringType);
  8897. }
  8898. else
  8899. {
  8900. //virtual const char * getPipeProgram() { return "grep"; }
  8901. BuildCtx pipeCtx(instance->startctx);
  8902. pipeCtx.addQuotedCompound("virtual const char * getPipeProgram()");
  8903. buildReturn(pipeCtx, pipe, unknownVarStringType);
  8904. }
  8905. if (csvAttr)
  8906. instance->classctx.addQuoted("virtual IHThorCsvWriteExtra * queryCsvOutput() { return this; }");
  8907. if (xmlAttr)
  8908. instance->classctx.addQuoted("virtual IHThorXmlWriteExtra * queryXmlOutput() { return this; }");
  8909. StringBuffer flags;
  8910. if (expr->hasAttribute(repeatAtom))
  8911. flags.append("|TPFrecreateeachrow");
  8912. if (expr->hasAttribute(optAtom))
  8913. flags.append("|TPFnofail");
  8914. if (csvAttr)
  8915. flags.append("|TPFwritecsvtopipe");
  8916. if (xmlAttr)
  8917. flags.append("|TPFwritexmltopipe");
  8918. if (flags.length())
  8919. doBuildUnsignedFunction(instance->classctx, "getPipeFlags", flags.str()+1);
  8920. }
  8921. else
  8922. {
  8923. bool constFilename = true;
  8924. //virtual const char * getFileName() = 0;
  8925. if (filename && filename->getOperator() != no_pipe)
  8926. {
  8927. buildFilenameFunction(*instance, instance->startctx, "getFileName", filename, hasDynamicFilename(expr));
  8928. if (!filename->isConstant())
  8929. constFilename = false;
  8930. }
  8931. else
  8932. {
  8933. BuildCtx getNameCtx(instance->startctx);
  8934. getNameCtx.addQuotedCompound("virtual const char * getFileName()");
  8935. getNameCtx.addReturn(queryQuotedNullExpr());
  8936. }
  8937. //Expire if explicit, or if a persisted output, and persists default to expiring
  8938. bool expires = expireAttr || (expr->hasAttribute(_workflowPersist_Atom) && options.expirePersists);
  8939. if (expires && !expireAttr && options.defaultPersistExpiry)
  8940. expireAttr.setown(createExprAttribute(expireAtom, getSizetConstant(options.defaultPersistExpiry)));
  8941. //virtual unsigned getFlags() = 0;
  8942. IHqlExpression * updateAttr = expr->queryAttribute(updateAtom);
  8943. StringBuffer s;
  8944. StringBuffer flags;
  8945. if (expr->hasAttribute(_spill_Atom)) flags.append("|TDXtemporary");
  8946. if (expr->hasAttribute(groupedAtom)) flags.append("|TDXgrouped");
  8947. if (expr->hasAttribute(compressedAtom)) flags.append("|TDWnewcompress");
  8948. if (expr->hasAttribute(__compressed__Atom)) flags.append("|TDXcompress");
  8949. if (expr->hasAttribute(extendAtom)) flags.append("|TDWextend");
  8950. if (expr->hasAttribute(overwriteAtom)) flags.append("|TDWoverwrite");
  8951. if (expr->hasAttribute(noOverwriteAtom)) flags.append("|TDWnooverwrite");
  8952. if (expr->hasAttribute(_workflowPersist_Atom)) flags.append("|TDWpersist");
  8953. if (expr->hasAttribute(_noReplicate_Atom)) flags.append("|TDWnoreplicate");
  8954. if (expr->hasAttribute(backupAtom)) flags.append("|TDWbackup");
  8955. if (expr->hasAttribute(resultAtom)) flags.append("|TDWowned|TDWresult");
  8956. if (expr->hasAttribute(ownedAtom)) flags.append("|TDWowned");
  8957. if (!constFilename) flags.append("|TDXvarfilename");
  8958. if (hasDynamicFilename(expr)) flags.append("|TDXdynamicfilename");
  8959. if (expr->hasAttribute(jobTempAtom)) flags.append("|TDXjobtemp");
  8960. if (updateAttr) flags.append("|TDWupdatecrc");
  8961. if (updateAttr && !updateAttr->queryAttribute(alwaysAtom)) flags.append("|TDWupdate");
  8962. if (expires) flags.append("|TDWexpires");
  8963. if (flags.length())
  8964. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  8965. //virtual const char * queryRecordECL() = 0;
  8966. buildRecordEcl(instance->createctx, dataset, "queryRecordECL");
  8967. buildExpiryHelper(instance->createctx, expireAttr);
  8968. buildUpdateHelper(instance->createctx, *instance, dataset, updateAttr);
  8969. }
  8970. doBuildSequenceFunc(instance->classctx, seq, true);
  8971. if (tempCount)
  8972. {
  8973. if ((kind != TAKspill) || !matchesConstantValue(tempCount, 1))
  8974. {
  8975. BuildCtx ctx1(instance->classctx);
  8976. ctx1.addQuotedCompound("virtual unsigned getTempUsageCount()");
  8977. buildReturn(ctx1, tempCount, unsignedType);
  8978. }
  8979. }
  8980. IHqlExpression * outputRecord = instance->meta.queryRecord();
  8981. OwnedHqlExpr outputDs = createDataset(no_null, LINK(outputRecord));
  8982. Owned<IWUResult> result = createDatasetResultSchema(seq, queryResultName(expr), outputRecord, (kind != TAKcsvwrite) && (kind != TAKxmlwrite), true);
  8983. if (expr->hasAttribute(resultAtom))
  8984. result->setResultRowLimit(-1);
  8985. buildFormatCrcFunction(instance->classctx, "getFormatCrc", dataset, NULL, 0);
  8986. bool grouped = isGrouped(dataset);
  8987. bool ignoreGrouped = !expr->hasAttribute(groupedAtom);
  8988. if ((kind != TAKspill) || (dataset->queryType() != expr->queryType()) || (grouped && ignoreGrouped))
  8989. buildMetaMember(instance->classctx, dataset, grouped && !ignoreGrouped, "queryDiskRecordSize");
  8990. buildClusterHelper(instance->classctx, expr);
  8991. //Both csv write and pipe with csv/xml format
  8992. if (csvAttr)
  8993. buildCsvWriteMembers(instance, outputDs, csvAttr);
  8994. if (xmlAttr)
  8995. buildXmlWriteMembers(instance, outputDs, xmlAttr);
  8996. buildEncryptHelper(instance->startctx, expr->queryAttribute(encryptAtom));
  8997. }
  8998. else
  8999. {
  9000. assertex(tempCount.get() && !hasDynamic(expr));
  9001. instance->addConstructorParameter(tempCount);
  9002. addFilenameConstructorParameter(*instance, "getFileName", filename);
  9003. }
  9004. instance->addAttributeBool("_isSpill", expr->hasAttribute(_spill_Atom));
  9005. if (targetRoxie())
  9006. instance->addAttributeBool("_isSpillGlobal", expr->hasAttribute(jobTempAtom));
  9007. buildInstanceSuffix(instance);
  9008. if (boundDataset)
  9009. {
  9010. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9011. }
  9012. OwnedHqlExpr dependency = createAttribute(fileAtom, getNormalizedFilename(filename));
  9013. Owned<ABoundActivity> bound = instance->getBoundActivity();
  9014. OwnedHqlExpr boundUnknown = createUnknown(no_attr, NULL, NULL, LINK(bound));
  9015. activeGraphCtx->associateExpr(dependency, boundUnknown);
  9016. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  9017. if (name)
  9018. associateRemoteResult(*instance, seq, name);
  9019. return instance->getBoundActivity();
  9020. }
  9021. void HqlCppTranslator::addSchemaField(IHqlExpression *field, MemoryBuffer &schema, IHqlExpression *selector)
  9022. {
  9023. IAtom * name = field->queryName();
  9024. StringBuffer schemaName;
  9025. if (name)
  9026. {
  9027. schemaName.append(name->str());
  9028. }
  9029. else
  9030. {
  9031. schemaName.append("unknown_name");
  9032. getUniqueId(schemaName);
  9033. }
  9034. schemaName.toLowerCase();
  9035. StringBuffer funcname;
  9036. Linked<ITypeInfo> schemaType = queryUnqualifiedType(field->queryType());
  9037. switch(schemaType->getTypeCode())
  9038. {
  9039. case type_alien:
  9040. schemaType.set(schemaType->queryChildType());
  9041. break;
  9042. case type_bitfield:
  9043. schemaType.set(schemaType->queryPromotedType());
  9044. //fall through;
  9045. case type_dictionary:
  9046. case type_table:
  9047. case type_groupedtable:
  9048. case type_row:
  9049. schemaType.setown(makeStringType(UNKNOWN_LENGTH, NULL, NULL));
  9050. break;
  9051. }
  9052. schema.append(schemaName.str());
  9053. schemaType->serialize(schema);
  9054. }
  9055. void HqlCppTranslator::doAddSchemaFields(IHqlExpression * record, MemoryBuffer &schema, IHqlExpression *selector)
  9056. {
  9057. assertex(record->getOperator() == no_record);
  9058. ForEachChild(idx, record)
  9059. {
  9060. IHqlExpression *field = record->queryChild(idx);
  9061. switch (field->getOperator())
  9062. {
  9063. case no_ifblock:
  9064. doAddSchemaFields(field->queryChild(1), schema, selector);
  9065. break;
  9066. case no_record:
  9067. doAddSchemaFields(field, schema, selector);
  9068. break;
  9069. case no_field:
  9070. if (field->isDatarow())
  9071. {
  9072. // MORE - should I record this nesting in the schema?
  9073. // MORE - this does not yet work...
  9074. OwnedHqlExpr subselector = createSelectExpr(LINK(selector), LINK(field));
  9075. doAddSchemaFields(field->queryRecord(), schema, subselector);
  9076. }
  9077. else
  9078. addSchemaField(field, schema, selector);
  9079. break;
  9080. }
  9081. }
  9082. }
  9083. void HqlCppTranslator::getRecordECL(IHqlExpression * deserializedRecord, StringBuffer & eclText)
  9084. {
  9085. OwnedHqlExpr record = getSerializedForm(deserializedRecord, diskAtom);
  9086. if ((options.maxRecordSize != MAX_RECORD_SIZE) && maxRecordSizeUsesDefault(record))
  9087. {
  9088. //Add an explicit record size if default max record size
  9089. size32_t maxSize = getMaxRecordSize(record);
  9090. HqlExprArray args;
  9091. unwindChildren(args, record);
  9092. args.append(*createExprAttribute(maxLengthAtom, getSizetConstant(maxSize)));
  9093. OwnedHqlExpr annotatedRecord = record->clone(args);
  9094. ::getRecordECL(annotatedRecord, eclText);
  9095. }
  9096. else
  9097. ::getRecordECL(record, eclText);
  9098. }
  9099. void HqlCppTranslator::addSchemaFields(IHqlExpression * record, MemoryBuffer &schema, IHqlExpression *selector)
  9100. {
  9101. doAddSchemaFields(record, schema, selector);
  9102. schema.append("").append((unsigned char) type_void);
  9103. StringBuffer eclText;
  9104. getRecordECL(record, eclText);
  9105. schema.append((unsigned)eclText.length());
  9106. schema.append(eclText.length(), eclText.str()); // could compress at this point...
  9107. }
  9108. void HqlCppTranslator::addSchemaResource(int seq, const char * name, IHqlExpression * record)
  9109. {
  9110. StringBuffer xml;
  9111. getRecordXmlSchema(xml, record, true);
  9112. addSchemaResource(seq, name, xml.length()+1, xml.str());
  9113. }
  9114. void HqlCppTranslator::addSchemaResource(int seq, const char * name, unsigned len, const char * schemaXml)
  9115. {
  9116. Owned<IPropertyTree> manifestEntry = createPTree("Resource");
  9117. manifestEntry->setProp("@name", name);
  9118. manifestEntry->setPropInt("@seq", seq);
  9119. code->addCompressResource("RESULT_XSD", len, schemaXml, manifestEntry);
  9120. }
  9121. void HqlCppTranslator::finalizeResources()
  9122. {
  9123. }
  9124. IWUResult * HqlCppTranslator::createDatasetResultSchema(IHqlExpression * sequenceExpr, IHqlExpression * name, IHqlExpression * record, bool createTransformer, bool isFile)
  9125. {
  9126. //Some spills have no sequence attached
  9127. if (!sequenceExpr)
  9128. return NULL;
  9129. int sequence = (int)getIntValue(sequenceExpr);
  9130. Owned<IWUResult> result = createWorkunitResult(sequence, name);
  9131. if (!result)
  9132. return NULL;
  9133. MemoryBuffer schema;
  9134. OwnedHqlExpr self = getSelf(record);
  9135. addSchemaFields(record, schema, self);
  9136. SCMStringBuffer resultName;
  9137. result->getResultName(resultName);
  9138. addSchemaResource(sequence, resultName.str(), record);
  9139. result->setResultSchemaRaw(schema.length(), schema.toByteArray());
  9140. result->setResultScalar(false);
  9141. OwnedHqlExpr serialRecord = getSerializedForm(record, diskAtom);
  9142. OwnedHqlExpr ds = createDataset(no_anon, LINK(serialRecord));
  9143. MetaInstance meta(*this, serialRecord, false);
  9144. buildMetaInfo(meta);
  9145. result->setResultRecordSizeEntry(meta.metaFactoryName);
  9146. if (targetRoxie() && (sequence >= 0) && !isFile)
  9147. result->setResultFormat(ResultFormatXml);
  9148. if (createTransformer)
  9149. {
  9150. OwnedHqlExpr noVirtualRecord = removeVirtualAttributes(serialRecord);
  9151. Owned<IHqlExpression> transformedRecord = getFileViewerRecord(noVirtualRecord, false);
  9152. if (transformedRecord)
  9153. {
  9154. OwnedHqlExpr ds = createDataset(no_anon, LINK(noVirtualRecord));
  9155. OwnedHqlExpr seq = createDummySelectorSequence();
  9156. OwnedHqlExpr leftSelect = createSelector(no_left, ds, seq);
  9157. OwnedHqlExpr transform = getSimplifiedTransform(transformedRecord, noVirtualRecord, leftSelect);
  9158. OwnedHqlExpr tds = createDataset(no_anon, LINK(transformedRecord));
  9159. StringBuffer s, name;
  9160. getUniqueId(name.append("tf"));
  9161. BuildCtx transformctx(*code, declareAtom);
  9162. transformctx.setNextPriority(RecordTranslatorPrio);
  9163. s.clear().append("extern \"C\" ECL_API size32_t ").append(name).append("(ARowBuilder & crSelf, const byte * src)");
  9164. transformctx.addQuotedCompound(s);
  9165. BoundRow * selfCursor = bindSelf(transformctx, tds, "crSelf");
  9166. bindTableCursor(transformctx, ds, "src", no_left, seq);
  9167. associateSkipReturnMarker(transformctx, queryZero(), selfCursor);
  9168. ensureRowAllocated(transformctx, "crSelf");
  9169. doTransform(transformctx, transform, selfCursor);
  9170. buildReturnRecordSize(transformctx, selfCursor);
  9171. result->setResultTransformerEntry(name.str());
  9172. }
  9173. }
  9174. return result.getClear();
  9175. }
  9176. //-------------------------------------------------------------------------------------------------------------------
  9177. void HqlCppTranslator::buildXmlSerializeSetValues(BuildCtx & ctx, IHqlExpression * value, IHqlExpression * itemName, bool includeAll)
  9178. {
  9179. OwnedHqlExpr simpleValue = simplifyFixedLengthList(value);
  9180. BuildCtx subctx(ctx);
  9181. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, simpleValue);
  9182. if (includeAll)
  9183. {
  9184. CHqlBoundExpr isAll;
  9185. cursor->buildIsAll(ctx, isAll);
  9186. IHqlStmt * stmt = subctx.addFilter(isAll.expr);
  9187. HqlExprArray args;
  9188. args.append(*createVariable("out", makeBoolType()));
  9189. callProcedure(subctx, outputXmlSetAllId, args);
  9190. subctx.selectElse(stmt);
  9191. }
  9192. CHqlBoundExpr boundCurElement;
  9193. cursor->buildIterateLoop(subctx, boundCurElement, false);
  9194. OwnedHqlExpr curElement = boundCurElement.getTranslatedExpr();
  9195. buildXmlSerializeScalar(subctx, curElement, itemName);
  9196. }
  9197. void HqlCppTranslator::buildXmlSerializeBeginNested(BuildCtx & ctx, IHqlExpression * name, bool doIndent)
  9198. {
  9199. if (name)
  9200. {
  9201. HqlExprArray args;
  9202. args.append(*createVariable("out", makeBoolType()));
  9203. args.append(*LINK(name));
  9204. args.append(*createConstant(false));
  9205. callProcedure(ctx, outputXmlBeginNestedId, args);
  9206. }
  9207. }
  9208. void HqlCppTranslator::buildXmlSerializeEndNested(BuildCtx & ctx, IHqlExpression * name)
  9209. {
  9210. if (name)
  9211. {
  9212. HqlExprArray args;
  9213. args.append(*createVariable("out", makeBoolType()));
  9214. args.append(*LINK(name));
  9215. callProcedure(ctx, outputXmlEndNestedId, args);
  9216. }
  9217. }
  9218. void HqlCppTranslator::buildXmlSerializeBeginArray(BuildCtx & ctx, IHqlExpression * name)
  9219. {
  9220. if (name)
  9221. {
  9222. HqlExprArray args;
  9223. args.append(*createVariable("out", makeBoolType()));
  9224. args.append(*LINK(name));
  9225. callProcedure(ctx, outputXmlBeginArrayId, args);
  9226. }
  9227. }
  9228. void HqlCppTranslator::buildXmlSerializeEndArray(BuildCtx & ctx, IHqlExpression * name)
  9229. {
  9230. if (name)
  9231. {
  9232. HqlExprArray args;
  9233. args.append(*createVariable("out", makeBoolType()));
  9234. args.append(*LINK(name));
  9235. callProcedure(ctx, outputXmlEndArrayId, args);
  9236. }
  9237. }
  9238. void HqlCppTranslator::buildXmlSerializeSet(BuildCtx & ctx, IHqlExpression * field, IHqlExpression * value)
  9239. {
  9240. OwnedHqlExpr name, itemName;
  9241. extractXmlName(name, &itemName, NULL, field, "Item", false);
  9242. HqlExprArray args;
  9243. buildXmlSerializeBeginNested(ctx, name, false);
  9244. buildXmlSerializeBeginArray(ctx, itemName);
  9245. buildXmlSerializeSetValues(ctx, value, itemName, (name != NULL));
  9246. buildXmlSerializeEndArray(ctx, itemName);
  9247. buildXmlSerializeEndNested(ctx, name);
  9248. }
  9249. void HqlCppTranslator::buildXmlSerializeDataset(BuildCtx & ctx, IHqlExpression * field, IHqlExpression * value, HqlExprArray * assigns)
  9250. {
  9251. OwnedHqlExpr name, rowName;
  9252. extractXmlName(name, &rowName, NULL, field, "Row", false);
  9253. HqlExprArray args;
  9254. buildXmlSerializeBeginNested(ctx, name, false);
  9255. buildXmlSerializeBeginArray(ctx, rowName);
  9256. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, value);
  9257. BuildCtx subctx(ctx);
  9258. BoundRow * sourceRow = cursor->buildIterateLoop(subctx, false);
  9259. buildXmlSerializeBeginNested(subctx, rowName, true);
  9260. StringBuffer boundRowText;
  9261. generateExprCpp(boundRowText, sourceRow->queryBound());
  9262. buildXmlSerializeUsingMeta(subctx, field, boundRowText.str());
  9263. buildXmlSerializeEndNested(subctx, rowName);
  9264. buildXmlSerializeEndArray(ctx, rowName);
  9265. buildXmlSerializeEndNested(ctx, name);
  9266. }
  9267. void HqlCppTranslator::buildXmlSerializeScalar(BuildCtx & ctx, IHqlExpression * selected, IHqlExpression * name)
  9268. {
  9269. ITypeInfo * type = selected->queryType()->queryPromotedType();
  9270. LinkedHqlExpr value = selected;
  9271. IIdAtom * func;
  9272. switch (type->getTypeCode())
  9273. {
  9274. case type_boolean:
  9275. func = outputXmlBoolId;
  9276. break;
  9277. case type_string:
  9278. case type_varstring:
  9279. func = outputXmlStringId;
  9280. break;
  9281. case type_qstring:
  9282. func = outputXmlQStringId;
  9283. break;
  9284. case type_data:
  9285. func = outputXmlDataId;
  9286. break;
  9287. case type_unicode:
  9288. case type_varunicode:
  9289. func = outputXmlUnicodeId;
  9290. break;
  9291. case type_utf8:
  9292. func = outputXmlUtf8Id;
  9293. break;
  9294. case type_real:
  9295. func = outputXmlRealId;
  9296. break;
  9297. case type_int:
  9298. case type_swapint:
  9299. case type_packedint:
  9300. case type_bitfield:
  9301. if (type->isSigned())
  9302. func = outputXmlIntId;
  9303. else
  9304. func = outputXmlUIntId;
  9305. break;
  9306. case type_decimal:
  9307. value.setown(ensureExprType(value, unknownStringType));
  9308. func = outputXmlStringId;
  9309. break;
  9310. default:
  9311. UNIMPLEMENTED;
  9312. }
  9313. HqlExprArray args;
  9314. args.append(*createVariable("out", makeBoolType()));
  9315. args.append(*value.getLink());
  9316. if (name)
  9317. args.append(*LINK(name));
  9318. else
  9319. args.append(*getNullStringPointer(true));
  9320. buildFunctionCall(ctx, func, args);
  9321. }
  9322. void HqlCppTranslator::buildXmlSerialize(BuildCtx & subctx, IHqlExpression * expr, IHqlExpression * selector, HqlExprArray * assigns, unsigned pass, unsigned & expectedIndex)
  9323. {
  9324. if (anyXmlGeneratedForPass(expr, pass))
  9325. {
  9326. switch (expr->getOperator())
  9327. {
  9328. case no_field:
  9329. {
  9330. OwnedHqlExpr name;
  9331. extractXmlName(name, NULL, NULL, expr, NULL, false);
  9332. LinkedHqlExpr value;
  9333. OwnedHqlExpr selected;
  9334. ITypeInfo * type = expr->queryType()->queryPromotedType();
  9335. if (assigns)
  9336. {
  9337. OwnedHqlExpr match = getExtractMatchingAssign(*assigns, expr, expectedIndex, selector);
  9338. if (!match)
  9339. {
  9340. StringBuffer s;
  9341. expr->toString(s);
  9342. throwError2(HQLERR_MissingTransformAssignXX, s.str(), expr);
  9343. }
  9344. selected.set(match->queryChild(0));
  9345. value.setown(ensureExprType(match->queryChild(1), type));
  9346. }
  9347. else
  9348. {
  9349. selected.setown(createSelectExpr(LINK(selector), LINK(expr)));
  9350. value.set(selected);
  9351. }
  9352. switch (type->getTypeCode())
  9353. {
  9354. case type_row:
  9355. {
  9356. IHqlExpression * record = queryOriginalRecord(type);
  9357. buildXmlSerializeBeginNested(subctx, name, false);
  9358. if (assigns)
  9359. {
  9360. if (value->getOperator() == no_createrow)
  9361. {
  9362. HqlExprArray childAssigns;
  9363. filterExpandAssignments(subctx, NULL, childAssigns, value->queryChild(0));
  9364. OwnedHqlExpr childSelf = createSelector(no_self, value, NULL);
  9365. if (name)
  9366. buildXmlSerialize(subctx, record, childSelf, &childAssigns);
  9367. else
  9368. buildXmlSerialize(subctx, record, childSelf, &childAssigns, pass, expectedIndex);
  9369. }
  9370. else
  9371. {
  9372. CHqlBoundExpr bound;
  9373. Owned<IReferenceSelector> ref = buildNewRow(subctx, value);
  9374. if (name)
  9375. buildXmlSerialize(subctx, record, value, NULL);
  9376. else
  9377. buildXmlSerialize(subctx, record, value, NULL, pass, expectedIndex);
  9378. }
  9379. }
  9380. else
  9381. {
  9382. if (name)
  9383. buildXmlSerialize(subctx, record, selected, assigns);
  9384. else
  9385. buildXmlSerialize(subctx, record, selected, assigns, pass, expectedIndex);
  9386. }
  9387. buildXmlSerializeEndNested(subctx, name);
  9388. return;
  9389. }
  9390. break;
  9391. case type_set:
  9392. buildXmlSerializeSet(subctx, expr, value);
  9393. break;
  9394. case type_dictionary:
  9395. case type_table:
  9396. case type_groupedtable:
  9397. buildXmlSerializeDataset(subctx, expr, value, assigns);
  9398. break;
  9399. default:
  9400. buildXmlSerializeScalar(subctx, value, name);
  9401. break;
  9402. }
  9403. }
  9404. break;
  9405. case no_ifblock:
  9406. {
  9407. OwnedHqlExpr cond = replaceSelector(expr->queryChild(0), querySelfReference(), selector);
  9408. BuildCtx condctx(subctx);
  9409. buildFilter(condctx, cond);
  9410. buildXmlSerialize(condctx, expr->queryChild(1), selector, assigns, pass, expectedIndex);
  9411. }
  9412. break;
  9413. case no_record:
  9414. {
  9415. ForEachChild(idx, expr)
  9416. buildXmlSerialize(subctx, expr->queryChild(idx), selector, assigns, pass, expectedIndex);
  9417. }
  9418. break;
  9419. case no_attr:
  9420. case no_attr_expr:
  9421. case no_attr_link:
  9422. break;
  9423. default:
  9424. UNIMPLEMENTED;
  9425. }
  9426. }
  9427. }
  9428. void HqlCppTranslator::buildXmlSerialize(BuildCtx & subctx, IHqlExpression * expr, IHqlExpression * selector, HqlExprArray * assigns)
  9429. {
  9430. unsigned expectedIndex = 0;
  9431. buildXmlSerialize(subctx, expr, selector, assigns, 0, expectedIndex);
  9432. expectedIndex = 0;
  9433. buildXmlSerialize(subctx, expr, selector, assigns, 1, expectedIndex);
  9434. }
  9435. void HqlCppTranslator::buildXmlSerialize(BuildCtx & ctx, IHqlExpression * dataset, const char * funcName, bool isMeta)
  9436. {
  9437. StringBuffer s;
  9438. BuildCtx funcctx(ctx);
  9439. funcctx.addQuotedCompound(s.append("virtual void ").append(funcName).append("(const byte * self, IXmlWriter & out)"));
  9440. if (!isMeta)
  9441. {
  9442. buildXmlSerializeUsingMeta(funcctx, dataset, "self");
  9443. }
  9444. else
  9445. {
  9446. BoundRow * selfCursor = bindTableCursor(funcctx, dataset, "self");
  9447. buildXmlSerialize(funcctx, dataset->queryRecord(), selfCursor->querySelector(), NULL);
  9448. }
  9449. }
  9450. void HqlCppTranslator::buildXmlSerializeUsingMeta(BuildCtx & ctx, IHqlExpression * dataset, const char * self)
  9451. {
  9452. MetaInstance meta(*this, dataset->queryRecord(), false);
  9453. buildMetaInfo(meta);
  9454. StringBuffer s;
  9455. ctx.addQuoted(s.append(meta.queryInstanceObject()).append(".toXML(").append(self).append(", out);"));
  9456. }
  9457. //-------------------------------------------------------------------------------------------------------------------
  9458. ABoundActivity * HqlCppTranslator::doBuildActivityOutputWorkunit(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  9459. {
  9460. IHqlExpression * dataset = expr->queryChild(0);
  9461. IHqlExpression * record = dataset->queryRecord();
  9462. IHqlExpression * seq = querySequence(expr);
  9463. IHqlExpression * name = queryResultName(expr);
  9464. int sequence = (int)getIntValue(seq, ResultSequenceInternal);
  9465. if (expr->hasAttribute(diskAtom))
  9466. {
  9467. StringBuffer suffix;
  9468. suffix.append("_").append(sequence);
  9469. IHqlExpression * newName = createConstant("~result::");
  9470. newName = createValue(no_concat, LINK(unknownStringType), newName, createValue(no_wuid, LINK(unknownStringType)));
  9471. newName = createValue(no_concat, LINK(unknownStringType), newName, createConstant(suffix));
  9472. HqlExprArray args;
  9473. unwindChildren(args, expr);
  9474. args.add(*newName, 1);
  9475. args.append(*createAttribute(overwriteAtom));
  9476. args.append(*createAttribute(resultAtom));
  9477. OwnedHqlExpr outputToTemp = expr->clone(args);
  9478. return buildActivity(ctx, outputToTemp, isRoot);
  9479. }
  9480. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9481. StringBuffer graphLabel;
  9482. bool useImplementationClass = options.minimizeActivityClasses && (sequence == ResultSequenceInternal);
  9483. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKworkunitwrite, expr, "WorkUnitWrite");
  9484. if (useImplementationClass)
  9485. instance->setImplementationClass(newWorkUnitWriteArgId);
  9486. graphLabel.append(getActivityText(instance->kind)).append("\n");
  9487. getStoredDescription(graphLabel, seq, name, true);
  9488. instance->graphLabel.set(graphLabel.str());
  9489. buildActivityFramework(instance, isRoot && !isInternalSeq(seq));
  9490. buildInstancePrefix(instance);
  9491. noteResultDefined(ctx, instance, seq, name, isRoot);
  9492. //virtual unsigned getFlags()
  9493. StringBuffer flags;
  9494. if (expr->hasAttribute(extendAtom))
  9495. flags.append("|POFextend");
  9496. if (expr->hasAttribute(groupedAtom))
  9497. flags.append("|POFgrouped");
  9498. if (!useImplementationClass)
  9499. {
  9500. doBuildSequenceFunc(instance->classctx, seq, true);
  9501. if (name)
  9502. {
  9503. BuildCtx namectx(instance->startctx);
  9504. namectx.addQuotedCompound("virtual const char * queryName()");
  9505. buildReturn(namectx, name, constUnknownVarStringType);
  9506. }
  9507. IHqlExpression * outputRecord = instance->meta.queryRecord();
  9508. Owned<IWUResult> result = createDatasetResultSchema(seq, name, outputRecord, true, false);
  9509. if (result)
  9510. {
  9511. result->setResultRowLimit(-1);
  9512. if (sequence >= 0)
  9513. {
  9514. OwnedHqlExpr outputDs = createDataset(no_null, LINK(outputRecord));
  9515. buildXmlSerialize(instance->startctx, outputDs, "serializeXml", false);
  9516. }
  9517. }
  9518. if (flags.length())
  9519. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  9520. }
  9521. else
  9522. {
  9523. if (flags.length() == 0)
  9524. flags.append("|0");
  9525. OwnedHqlExpr flagsExpr = createQuoted(flags.str()+1, LINK(unsignedType));
  9526. instance->addConstructorParameter(name);
  9527. instance->addConstructorParameter(flagsExpr);
  9528. }
  9529. buildInstanceSuffix(instance);
  9530. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9531. associateRemoteResult(*instance, seq, name);
  9532. return instance->getBoundActivity();
  9533. }
  9534. void HqlCppTranslator::doBuildStmtOutput(BuildCtx & ctx, IHqlExpression * expr)
  9535. {
  9536. if (queryCurrentActivity(ctx))
  9537. {
  9538. ApplyStmtBuilder builder(*this);
  9539. builder.buildStmt(ctx, expr);
  9540. builder.flush(ctx);
  9541. return;
  9542. }
  9543. IHqlExpression * dataset = expr->queryChild(0);
  9544. if (expr->hasAttribute(groupedAtom) && (dataset->getOperator() != no_null))
  9545. throwError1(HQLERR_NotSupportedInsideNoThor, "Grouped OUTPUT");
  9546. LinkedHqlExpr seq = querySequence(expr);
  9547. LinkedHqlExpr name = queryResultName(expr);
  9548. assertex(seq != NULL);
  9549. int sequence = (int)getIntValue(seq, (int)ResultSequenceInternal);
  9550. if (!seq)
  9551. seq.setown(getSizetConstant(sequence));
  9552. if (!name)
  9553. name.setown(createQuoted("NULL", LINK(constUnknownVarStringType)));
  9554. Owned<IWUResult> result = createDatasetResultSchema(seq, name, dataset->queryRecord(), true, false);
  9555. CHqlBoundExpr bound;
  9556. buildDataset(ctx, dataset, bound, FormatNatural);
  9557. OwnedHqlExpr count = getBoundCount(bound);
  9558. HqlExprArray args;
  9559. args.append(*LINK(name));
  9560. args.append(*LINK(seq));
  9561. args.append(*bound.getTranslatedExpr());
  9562. args.append(*createTranslated(count));
  9563. args.append(*LINK(queryBoolExpr(expr->hasAttribute(extendAtom))));
  9564. buildFunctionCall(ctx, setResultDatasetId, args);
  9565. }
  9566. //-------------------------------------------------------------------------------------------------------------------
  9567. ABoundActivity * HqlCppTranslator::doBuildActivityDictionaryWorkunitWrite(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  9568. {
  9569. IHqlExpression * dictionary = expr->queryChild(0);
  9570. IHqlExpression * record = dictionary->queryRecord();
  9571. IHqlExpression * seq = querySequence(expr);
  9572. IHqlExpression * name = queryResultName(expr);
  9573. int sequence = (int)getIntValue(seq, ResultSequenceInternal);
  9574. assertex(dictionary->getOperator() == no_createdictionary);
  9575. IHqlExpression * dataset = dictionary->queryChild(0);
  9576. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9577. StringBuffer graphLabel;
  9578. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdictionaryworkunitwrite, expr, "DictionaryWorkUnitWrite");
  9579. graphLabel.append(getActivityText(instance->kind)).append("\n");
  9580. getStoredDescription(graphLabel, seq, name, true);
  9581. instance->graphLabel.set(graphLabel.str());
  9582. buildActivityFramework(instance, isRoot && !isInternalSeq(seq));
  9583. buildInstancePrefix(instance);
  9584. noteResultDefined(ctx, instance, seq, name, isRoot);
  9585. //virtual unsigned getFlags()
  9586. StringBuffer flags;
  9587. doBuildSequenceFunc(instance->classctx, seq, true);
  9588. if (name)
  9589. {
  9590. BuildCtx namectx(instance->startctx);
  9591. namectx.addQuotedCompound("virtual const char * queryName()");
  9592. buildReturn(namectx, name, constUnknownVarStringType);
  9593. }
  9594. //Owned<IWUResult> result = createDatasetResultSchema(seq, name, record, true, false);
  9595. buildDictionaryHashMember(instance->createctx, dictionary, "queryHashLookupInfo");
  9596. if (flags.length())
  9597. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  9598. buildInstanceSuffix(instance);
  9599. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9600. associateRemoteResult(*instance, seq, name);
  9601. return instance->getBoundActivity();
  9602. }
  9603. //---------------------------------------------------------------------------
  9604. ABoundActivity * HqlCppTranslator::doBuildActivityPipeThrough(BuildCtx & ctx, IHqlExpression * expr)
  9605. {
  9606. checkPipeAllowed();
  9607. IHqlExpression * dataset = expr->queryChild(0);
  9608. IHqlExpression * pipe = expr->queryChild(1);
  9609. IHqlExpression * output = expr->queryAttribute(outputAtom);
  9610. IHqlExpression * csvToPipe = output ? output->queryAttribute(csvAtom) : NULL;
  9611. IHqlExpression * xmlToPipe = output ? output->queryAttribute(xmlAtom) : NULL;
  9612. IHqlExpression * csvFromPipe = expr->queryAttribute(csvAtom);
  9613. IHqlExpression * xmlFromPipe = expr->queryAttribute(xmlAtom);
  9614. //MORE: Could optimize dataset to not use LCR rows - if it is coming from a disk file
  9615. //Some other activities could similarly benefit (e.g., SORT), but they might need two
  9616. //metas and more intelligence in the activities...
  9617. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  9618. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKpipethrough, expr, "PipeThrough");
  9619. if (csvToPipe)
  9620. instance->addBaseClass("IHThorCsvWriteExtra", true);
  9621. else if (xmlToPipe)
  9622. instance->addBaseClass("IHThorXmlWriteExtra", true);
  9623. buildActivityFramework(instance);
  9624. buildInstancePrefix(instance);
  9625. if (expr->hasAttribute(repeatAtom))
  9626. {
  9627. //virtual const char * getPipeProgram() { return "grep"; }
  9628. instance->startctx.addQuoted("virtual char * getPipeProgram() { return NULL; }");
  9629. BuildCtx pipeCtx(instance->startctx);
  9630. pipeCtx.addQuotedCompound("virtual char * getNameFromRow(const void * _self)");
  9631. pipeCtx.addQuoted("const unsigned char * self = (const unsigned char *) _self;");
  9632. bindTableCursor(pipeCtx, dataset, "self");
  9633. buildReturn(pipeCtx, pipe, unknownVarStringType);
  9634. }
  9635. else
  9636. {
  9637. //virtual const char * getPipeProgram() { return "grep"; }
  9638. BuildCtx pipeCtx(instance->startctx);
  9639. pipeCtx.addQuotedCompound("virtual const char * getPipeProgram()");
  9640. buildReturn(pipeCtx, pipe, unknownVarStringType);
  9641. }
  9642. if (csvToPipe)
  9643. {
  9644. buildCsvWriteMembers(instance, dataset, csvToPipe);
  9645. instance->classctx.addQuoted("virtual IHThorCsvWriteExtra * queryCsvOutput() { return this; }");
  9646. }
  9647. if (xmlToPipe)
  9648. {
  9649. buildXmlWriteMembers(instance, dataset, xmlToPipe);
  9650. instance->classctx.addQuoted("virtual IHThorXmlWriteExtra * queryXmlOutput() { return this; }");
  9651. }
  9652. bool usesContents = false;
  9653. if (csvFromPipe)
  9654. {
  9655. if (isValidCsvRecord(expr->queryRecord()))
  9656. {
  9657. StringBuffer csvInstanceName;
  9658. buildCsvReadTransformer(expr, csvInstanceName, csvFromPipe);
  9659. StringBuffer s;
  9660. s.append("virtual ICsvToRowTransformer * queryCsvTransformer() { return &").append(csvInstanceName).append("; }");
  9661. instance->classctx.addQuoted(s);
  9662. }
  9663. else
  9664. {
  9665. throwUnexpected(); // should be caught earlier
  9666. }
  9667. }
  9668. else if (xmlFromPipe)
  9669. {
  9670. doBuildXmlReadMember(*instance, expr, "queryXmlTransformer", usesContents);
  9671. doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", queryAttributeChild(xmlFromPipe, rowAtom, 0));
  9672. }
  9673. StringBuffer flags;
  9674. if (expr->hasAttribute(repeatAtom))
  9675. flags.append("|TPFrecreateeachrow");
  9676. if (expr->hasAttribute(groupAtom))
  9677. flags.append("|TPFgroupeachrow");
  9678. if (expr->hasAttribute(optAtom))
  9679. flags.append("|TPFnofail");
  9680. if (csvToPipe)
  9681. flags.append("|TPFwritecsvtopipe");
  9682. if (xmlToPipe)
  9683. flags.append("|TPFwritexmltopipe");
  9684. if (csvFromPipe)
  9685. flags.append("|TPFreadcsvfrompipe");
  9686. if (xmlFromPipe)
  9687. flags.append("|TPFreadxmlfrompipe");
  9688. if (usesContents)
  9689. flags.append("|TPFreadusexmlcontents");
  9690. if (xmlToPipe && xmlToPipe->hasAttribute(noRootAtom))
  9691. flags.append("|TPFwritenoroot");
  9692. if (xmlFromPipe && xmlFromPipe->hasAttribute(noRootAtom))
  9693. flags.append("|TPFreadnoroot");
  9694. if (flags.length())
  9695. doBuildUnsignedFunction(instance->classctx, "getPipeFlags", flags.str()+1);
  9696. buildInstanceSuffix(instance);
  9697. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  9698. return instance->getBoundActivity();
  9699. }
  9700. //---------------------------------------------------------------------------
  9701. //-- no_join [JOIN] --
  9702. /* in parms: NOT linked */
  9703. void HqlCppTranslator::doCompareLeftRight(BuildCtx & ctx, const char * funcname, const DatasetReference & datasetLeft, const DatasetReference & datasetRight, const HqlExprArray & left, const HqlExprArray & right)
  9704. {
  9705. OwnedHqlExpr selSeq = createDummySelectorSequence();
  9706. OwnedHqlExpr leftList = createValueSafe(no_sortlist, makeSortListType(NULL), left);
  9707. OwnedHqlExpr leftSelect = datasetLeft.getSelector(no_left, selSeq);
  9708. OwnedHqlExpr leftResolved = datasetLeft.mapCompound(leftList, leftSelect);
  9709. OwnedHqlExpr rightList = createValueSafe(no_sortlist, makeSortListType(NULL), right);
  9710. OwnedHqlExpr rightSelect = datasetRight.getSelector(no_right, selSeq);
  9711. OwnedHqlExpr rightResolved = datasetRight.mapCompound(rightList, rightSelect);
  9712. OwnedHqlExpr order = createValue(no_order, LINK(signedType), LINK(leftResolved), LINK(rightResolved));
  9713. buildCompareMemberLR(ctx, funcname, order, datasetLeft.queryDataset(), datasetRight.queryDataset(), selSeq);
  9714. }
  9715. 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)
  9716. {
  9717. HqlExprArray left, right;
  9718. unsigned numSimple = leftEq.ordinality() - slidingMatches.ordinality();
  9719. for (unsigned j=0; j<numSimple; j++)
  9720. {
  9721. left.append(OLINK(leftEq.item(j)));
  9722. right.append(OLINK(rightEq.item(j)));
  9723. }
  9724. ForEachItemIn(i, slidingMatches)
  9725. {
  9726. IHqlExpression & cur = slidingMatches.item(i);
  9727. left.append(*LINK(cur.queryChild(0)));
  9728. right.append(*LINK(cur.queryChild(childIndex)));
  9729. }
  9730. doCompareLeftRight(ctx, funcname, datasetL, datasetR, left, right);
  9731. }
  9732. void HqlCppTranslator::generateSortCompare(BuildCtx & nestedctx, BuildCtx & ctx, node_operator side, const DatasetReference & dataset, const HqlExprArray & sorts, bool canRemoveSort, IHqlExpression * noSortAttr, bool canReuseLeft, bool isLightweight, bool isLocal)
  9733. {
  9734. StringBuffer s, compareName;
  9735. const char * sideText = (side == no_left) ? "Left" : "Right";
  9736. compareName.append("compare").append(sideText);
  9737. assertex(dataset.querySide() == no_activetable);
  9738. bool noNeedToSort = canRemoveSort && isAlreadySorted(dataset.queryDataset(), sorts, isLocal, true);
  9739. if (userPreventsSort(noSortAttr, side))
  9740. noNeedToSort = true;
  9741. if (noNeedToSort || isLightweight)
  9742. {
  9743. if (!noNeedToSort)
  9744. {
  9745. DBGLOG("Lightweight true, but code generator didn't think sort was required");
  9746. ctx.addQuoted("//Forced by lightweight");
  9747. }
  9748. s.clear().append("virtual bool is").append(sideText).append("AlreadySorted() { return true; }");
  9749. ctx.addQuoted(s);
  9750. }
  9751. if (canReuseLeft)
  9752. {
  9753. s.clear().append("virtual ICompare * queryCompare").append(sideText).append("() { return &compareLeft; }");
  9754. ctx.addQuoted(s);
  9755. }
  9756. else
  9757. {
  9758. s.clear().append("virtual ICompare * queryCompare").append(sideText).append("() { return &").append(compareName).append("; }");
  9759. ctx.addQuoted(s);
  9760. BuildCtx classctx(nestedctx);
  9761. beginNestedClass(classctx, compareName.str(), "ICompare");
  9762. BuildCtx funcctx(classctx);
  9763. funcctx.addQuotedCompound("virtual int docompare(const void * _left, const void * _right) const");
  9764. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  9765. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  9766. funcctx.associateExpr(constantMemberMarkerExpr, constantMemberMarkerExpr);
  9767. OwnedHqlExpr groupOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  9768. buildReturnOrder(funcctx, groupOrder, dataset);
  9769. endNestedClass();
  9770. }
  9771. }
  9772. 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)
  9773. {
  9774. ForEachChild(i, record)
  9775. {
  9776. IHqlExpression * cur = record->queryChild(i);
  9777. switch (cur->getOperator())
  9778. {
  9779. case no_field:
  9780. {
  9781. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(cur));
  9782. unsigned matchIndex = tgtSelects.find(*selected);
  9783. if (matchIndex != NotFound)
  9784. {
  9785. Owned<IHqlExpression> self = tgtDataset.mapScalar(&tgtSelects.item(matchIndex), selfSelect);
  9786. Owned<IHqlExpression> left = srcDataset.mapScalar(&srcSelects.item(matchIndex), leftSelect);
  9787. if (self->queryType() != left->queryType())
  9788. {
  9789. HqlExprArray args;
  9790. args.append(*LINK(left));
  9791. if (serializeOp == no_deserialize)
  9792. args.append(*LINK(self->queryRecord()));
  9793. args.append(*createAttribute(serialForm));
  9794. left.setown(createWrapper(serializeOp, self->queryType(), args));
  9795. }
  9796. buildAssign(ctx, self, left);
  9797. //Note, we could stop here if needToClear and all fields have been assigned, and all the following fields are fixed width.
  9798. // but not really sure it is worth it.
  9799. }
  9800. else if (cur->isDatarow())
  9801. {
  9802. generateSerializeAssigns(ctx, cur->queryRecord(), selected, selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, needToClear, serializeOp, serialForm);
  9803. }
  9804. else if (needToClear || mustInitializeField(cur))
  9805. {
  9806. //MORE: Might want to recurse if a record
  9807. Owned<IHqlExpression> self = tgtDataset.mapScalar(selected, selfSelect);
  9808. buildClear(ctx, self);
  9809. }
  9810. break;
  9811. }
  9812. case no_record:
  9813. generateSerializeAssigns(ctx, cur, selector, selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, needToClear, serializeOp, serialForm);
  9814. break;
  9815. case no_ifblock:
  9816. //Filter on target...
  9817. UNIMPLEMENTED;
  9818. generateSerializeAssigns(ctx, cur->queryChild(1), selector, selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, needToClear, serializeOp, serialForm);
  9819. break;
  9820. }
  9821. }
  9822. }
  9823. void HqlCppTranslator::generateSerializeFunction(BuildCtx & ctx, const char * funcName, const DatasetReference & srcDataset, const DatasetReference & tgtDataset, HqlExprArray & srcSelects, HqlExprArray & tgtSelects, node_operator serializeOp, IAtom * serialForm)
  9824. {
  9825. StringBuffer s;
  9826. BuildCtx r2kctx(ctx);
  9827. s.append("virtual unsigned ").append(funcName).append("(ARowBuilder & crSelf, const void * _src, unsigned & thisRecordSize)");
  9828. r2kctx.addQuotedCompound(s);
  9829. ensureRowAllocated(r2kctx, "crSelf");
  9830. r2kctx.addQuoted("const unsigned char * src = (const unsigned char *) _src;");
  9831. OwnedHqlExpr selSeq = createDummySelectorSequence();
  9832. BoundRow * tgtCursor = bindSelf(ctx, tgtDataset.queryDataset(), "crSelf");
  9833. BoundRow * srcCursor = bindTableCursor(ctx, srcDataset.queryDataset(), "src", no_left, selSeq);
  9834. IHqlExpression * leftSelect = srcCursor->querySelector();
  9835. IHqlExpression * selfSelect = tgtCursor->querySelector();
  9836. IHqlExpression * record = tgtDataset.queryDataset()->queryRecord();
  9837. generateSerializeAssigns(r2kctx, record, tgtDataset.querySelector(), selfSelect, leftSelect, srcDataset, tgtDataset, srcSelects, tgtSelects, !isFixedRecordSize(record), serializeOp, serialForm);
  9838. const bool serialize = (serializeOp == no_serialize);
  9839. BoundRow * recordCursor = serialize ? srcCursor : tgtCursor;
  9840. OwnedHqlExpr recordSize = getRecordSize(recordCursor->querySelector());
  9841. OwnedHqlExpr recordSizeVar = createVariable("thisRecordSize", LINK(unsignedType));
  9842. buildAssignToTemp(r2kctx, recordSizeVar, recordSize);
  9843. buildReturnRecordSize(r2kctx, serialize ? tgtCursor : srcCursor);
  9844. }
  9845. void HqlCppTranslator::generateSerializeKey(BuildCtx & nestedctx, node_operator side, const DatasetReference & dataset, const HqlExprArray & sorts, bool isGlobal, bool generateCompares, bool canReuseLeft)
  9846. {
  9847. //check if there are any ifblocks, and if so don't allow it. Even more accurate would be no join fields used in ifblocks
  9848. IHqlExpression * record = dataset.queryDataset()->queryRecord();
  9849. bool canSerialize = targetThor() && isGlobal && !recordContainsIfBlock(record);
  9850. const char * sideText = (side == no_none) ? "" : (side == no_left) ? "Left" : "Right";
  9851. StringBuffer s, s2;
  9852. HqlExprArray keyFields;
  9853. HqlExprArray keySelects;
  9854. HqlExprArray datasetSelects;
  9855. HqlExprArray keyCompares;
  9856. if (canSerialize)
  9857. {
  9858. ForEachItemIn(idx, sorts)
  9859. {
  9860. //MORE: Nested - this won't serialize the key if sorting by a field in a nested record
  9861. // If this is a problem we will need to create new fields for each value.
  9862. IHqlExpression & cur = sorts.item(idx);
  9863. IHqlExpression * value = &cur;
  9864. if (value->getOperator() == no_negate)
  9865. value=value->queryChild(0);
  9866. if ((value->getOperator() == no_select) && (value->queryChild(0)->queryNormalizedSelector() == dataset.querySelector()))
  9867. {
  9868. if (value->queryType()->getTypeCode() == type_alien)
  9869. {
  9870. //MORE: Really should check if a self contained alien data type.
  9871. canSerialize = false;
  9872. break;
  9873. }
  9874. OwnedHqlExpr serializedField = getSerializedForm(value->queryChild(1), diskAtom); // Could be internal, but may require serialized compare
  9875. OwnedHqlExpr mappedSelect = dataset.mapScalar(value,queryActiveTableSelector());
  9876. keyFields.append(*LINK(serializedField));
  9877. keySelects.append(*createSelectExpr(LINK(mappedSelect->queryChild(0)), LINK(serializedField)));
  9878. datasetSelects.append(*LINK(value));
  9879. keyCompares.append(*dataset.mapScalar(&cur,queryActiveTableSelector()));
  9880. }
  9881. else if (!value->isConstant())
  9882. {
  9883. canSerialize = false;
  9884. break;
  9885. }
  9886. }
  9887. }
  9888. //The following test will need to change if we serialize when nested fields are used (see above)
  9889. if (sorts.ordinality() >= getFlatFieldCount(record))
  9890. canSerialize = false;
  9891. if (canSerialize)
  9892. {
  9893. if (canReuseLeft)
  9894. {
  9895. assertex(!generateCompares);
  9896. s.clear().append("virtual ISortKeySerializer * querySerialize").append(sideText).append("() { return &serializerLeft; }");
  9897. nestedctx.addQuoted(s);
  9898. }
  9899. else
  9900. {
  9901. StringBuffer memberName;
  9902. memberName.append("serializer").append(sideText);
  9903. BuildCtx classctx(nestedctx);
  9904. beginNestedClass(classctx, memberName, "ISortKeySerializer");
  9905. IHqlExpression * keyRecord = createRecord(keyFields);
  9906. Owned<IHqlExpression> keyDataset = createDataset(no_anon, keyRecord);
  9907. DatasetReference keyActiveRef(keyDataset, no_activetable, NULL);
  9908. generateSerializeFunction(classctx, "recordToKey", dataset, keyActiveRef, datasetSelects, keySelects, no_serialize, diskAtom);
  9909. generateSerializeFunction(classctx, "keyToRecord", keyActiveRef, dataset, keySelects, datasetSelects, no_deserialize, diskAtom);
  9910. buildMetaMember(classctx, keyRecord, false, "queryRecordSize");
  9911. endNestedClass();
  9912. s.clear().append("virtual ISortKeySerializer * querySerialize").append(sideText).append("() { return &serializer").append(sideText).append("; }");
  9913. nestedctx.addQuoted(s);
  9914. if (generateCompares)
  9915. {
  9916. OwnedHqlExpr keyOrder = createValueSafe(no_sortlist, makeSortListType(NULL), keyCompares);
  9917. buildCompareMember(nestedctx, "CompareKey", keyOrder, keyActiveRef);
  9918. doCompareLeftRight(nestedctx, "CompareRowKey", dataset, keyActiveRef, sorts, keyCompares);
  9919. }
  9920. }
  9921. }
  9922. }
  9923. IHqlExpression * HqlCppTranslator::createFailMessage(const char * prefix, IHqlExpression * limit, IHqlExpression * filename, unique_id_t id)
  9924. {
  9925. StringBuffer s;
  9926. HqlExprArray values;
  9927. values.append(*createConstant(s.clear().append(prefix)));
  9928. if (limit)
  9929. {
  9930. values.append(*createConstant("("));
  9931. values.append(*ensureExprType(limit, unknownStringType));
  9932. values.append(*createConstant(")"));
  9933. }
  9934. if (filename)
  9935. {
  9936. values.append(*createConstant(" file '"));
  9937. values.append(*ensureExprType(filename, unknownStringType));
  9938. values.append(*createConstant("'"));
  9939. }
  9940. if (id)
  9941. values.append(*createConstant(s.clear().append(" [id=").append(id).append("]")));
  9942. OwnedHqlExpr errorText = createBalanced(no_concat, unknownStringType, values);
  9943. return foldHqlExpression(errorText);
  9944. }
  9945. IHqlExpression * HqlCppTranslator::createFailAction(const char * prefix, IHqlExpression * limit, IHqlExpression * filename, unique_id_t id)
  9946. {
  9947. IHqlExpression * msg = createFailMessage(prefix, limit, filename, id);
  9948. return createValue(no_fail, makeVoidType(), msg, getDefaultAttr());
  9949. }
  9950. void HqlCppTranslator::doBuildJoinRowLimitHelper(ActivityInstance & instance, IHqlExpression * rowlimit, IHqlExpression * filename, bool generateImplicitLimit)
  9951. {
  9952. if (rowlimit)
  9953. {
  9954. doBuildUnsignedFunction(instance.startctx, "getMatchAbortLimit", rowlimit->queryChild(0));
  9955. if (!rowlimit->hasAttribute(skipAtom))
  9956. {
  9957. LinkedHqlExpr fail = queryChildOperator(no_fail, rowlimit);
  9958. if (!fail)
  9959. fail.setown(createFailAction("JOIN limit exceeded", rowlimit->queryChild(0), filename, instance.activityId));
  9960. BuildCtx ctx(instance.startctx);
  9961. ctx.addQuotedCompound("virtual void onMatchAbortLimitExceeded()");
  9962. buildStmt(ctx, fail);
  9963. }
  9964. }
  9965. else if (generateImplicitLimit)
  9966. {
  9967. OwnedHqlExpr implicitLimit = getSizetConstant(options.defaultImplicitKeyedJoinLimit);
  9968. doBuildUnsignedFunction(instance.startctx, "getMatchAbortLimit", implicitLimit);
  9969. if (options.warnOnImplicitJoinLimit)
  9970. {
  9971. StringBuffer fname;
  9972. if (filename)
  9973. getExprECL(filename, fname.append(" "));
  9974. WARNING2(HQLWRN_ImplicitJoinLimit, options.defaultImplicitKeyedJoinLimit, fname.str());
  9975. }
  9976. }
  9977. }
  9978. static size32_t getMaxSubstringLength(IHqlExpression * expr)
  9979. {
  9980. IHqlExpression * rawSelect = expr->queryChild(0);
  9981. IHqlExpression * range = expr->queryChild(1);
  9982. IHqlExpression * rangeLow = range->queryChild(0);
  9983. unsigned rawLength = rawSelect->queryType()->getStringLen();
  9984. if (matchesConstantValue(rangeLow, 1))
  9985. return rawLength;
  9986. __int64 lowValue = getIntValue(rangeLow, UNKNOWN_LENGTH);
  9987. size32_t resultLength = UNKNOWN_LENGTH;
  9988. if ((rawLength != UNKNOWN_LENGTH) && (lowValue >= 1) && (lowValue <= rawLength))
  9989. resultLength = rawLength - (size32_t)(lowValue - 1);
  9990. return resultLength;
  9991. }
  9992. static IHqlExpression * getSimplifiedCommonSubstringRange(IHqlExpression * expr)
  9993. {
  9994. IHqlExpression * rawSelect = expr->queryChild(0);
  9995. IHqlExpression * range = expr->queryChild(1);
  9996. IHqlExpression * rangeLow = range->queryChild(0);
  9997. if (matchesConstantValue(rangeLow, 1))
  9998. return LINK(rawSelect);
  9999. HqlExprArray args;
  10000. args.append(*LINK(rawSelect));
  10001. args.append(*createValue(no_rangefrom, makeNullType(), LINK(rangeLow)));
  10002. return expr->clone(args);
  10003. }
  10004. ABoundActivity * HqlCppTranslator::doBuildActivityJoinOrDenormalize(BuildCtx & ctx, IHqlExpression * expr)
  10005. {
  10006. node_operator op = expr->getOperator();
  10007. assertex(op==no_join || op==no_selfjoin || op==no_denormalize || op==no_denormalizegroup);
  10008. LinkedHqlExpr dataset1 = expr->queryChild(0);
  10009. LinkedHqlExpr dataset2 = queryJoinRhs(expr);
  10010. IHqlExpression * condition = expr->queryChild(2);
  10011. IHqlExpression * transform = expr->queryChild(3);
  10012. IHqlExpression * noSortAttr = expr->queryAttribute(noSortAtom);
  10013. IHqlExpression * rowlimit = expr->queryAttribute(rowLimitAtom);
  10014. IHqlExpression * selSeq = querySelSeq(expr);
  10015. bool isLeftOuter = false;
  10016. bool isRightOuter = false;
  10017. bool excludeMatches = false;
  10018. bool isAllJoin = false;
  10019. bool isLightweight = expr->hasAttribute(_lightweight_Atom);
  10020. bool isManyLookup = expr->hasAttribute(manyAtom);
  10021. if (expr->hasAttribute(leftouterAtom))
  10022. isLeftOuter = true;
  10023. if (expr->hasAttribute(rightouterAtom))
  10024. isRightOuter = true;
  10025. if (expr->hasAttribute(fullouterAtom))
  10026. {
  10027. isLeftOuter = true;
  10028. isRightOuter = true;
  10029. }
  10030. if (expr->hasAttribute(leftonlyAtom))
  10031. {
  10032. isLeftOuter = true;
  10033. excludeMatches = true;
  10034. }
  10035. if (expr->hasAttribute(rightonlyAtom))
  10036. {
  10037. isRightOuter = true;
  10038. excludeMatches = true;
  10039. }
  10040. if (expr->hasAttribute(fullonlyAtom))
  10041. {
  10042. isLeftOuter = true;
  10043. isRightOuter = true;
  10044. excludeMatches = true;
  10045. }
  10046. if (expr->hasAttribute(allAtom))
  10047. isAllJoin = true;
  10048. bool isLookupJoin = expr->hasAttribute(lookupAtom);
  10049. bool isSmartJoin = expr->hasAttribute(smartAtom);
  10050. bool isHashJoin = targetThor() && expr->hasAttribute(hashAtom);
  10051. bool isLocalJoin = !isHashJoin && expr->hasAttribute(localAtom);
  10052. bool joinToSelf = (op == no_selfjoin);
  10053. bool allowAllToLookupConvert = !options.noAllToLookupConversion;
  10054. IHqlExpression * atmostAttr = expr->queryAttribute(atmostAtom);
  10055. LinkedHqlExpr keepLimit = queryAttributeChild(expr, keepAtom, 0);
  10056. //Delay removing ungroups until this point because they can be useful for reducing the size of spill files.
  10057. if (isUngroup(dataset1) && !isLookupJoin)
  10058. dataset1.set(dataset1->queryChild(0));
  10059. if (isUngroup(dataset2))
  10060. dataset2.set(dataset2->queryChild(0));
  10061. if (expr->hasAttribute(groupedAtom) && targetThor())
  10062. WARNING(HQLWRN_GroupedJoinIsLookupJoin);
  10063. if ((op == no_denormalize || op == no_denormalizegroup) && targetThor() && options.checkThorRestrictions)
  10064. {
  10065. if (isHashJoin)
  10066. throwError1(HQLERR_ThorDenormNoFeatureX, "HASH");
  10067. if (expr->hasAttribute(firstAtom))
  10068. throwError1(HQLERR_ThorDenormNoFeatureX, "FIRST");
  10069. if (expr->hasAttribute(firstLeftAtom))
  10070. throwError1(HQLERR_ThorDenormNoFeatureX, "FIRST LEFT");
  10071. if (expr->hasAttribute(firstRightAtom))
  10072. throwError1(HQLERR_ThorDenormNoFeatureX, "FIRST RIGHT");
  10073. if (expr->hasAttribute(partitionRightAtom))
  10074. throwError1(HQLERR_ThorDenormNoFeatureX, "PARTITION RIGHT");
  10075. }
  10076. bool slidingAllowed = options.slidingJoins && canBeSlidingJoin(expr);
  10077. JoinSortInfo joinInfo;
  10078. joinInfo.findJoinSortOrders(expr, slidingAllowed);
  10079. if (atmostAttr && joinInfo.hasHardRightNonEquality())
  10080. {
  10081. if (isAllJoin)
  10082. allowAllToLookupConvert = false;
  10083. else
  10084. {
  10085. StringBuffer s;
  10086. throwError1(HQLERR_BadJoinConditionAtMost,getExprECL(joinInfo.extraMatch, s.append(" (")).append(")").str());
  10087. }
  10088. }
  10089. LinkedHqlExpr rhs = dataset2;
  10090. if (isAllJoin)
  10091. {
  10092. if (joinInfo.hasRequiredEqualities() && allowAllToLookupConvert)
  10093. {
  10094. //Convert an all join to a many lookup if it can be done that way - more efficient, and same resourcing/semantics ...
  10095. isManyLookup = true;
  10096. isAllJoin = false;
  10097. isLookupJoin = true;
  10098. }
  10099. }
  10100. else if (!joinInfo.hasRequiredEqualities() && !joinInfo.hasOptionalEqualities())
  10101. {
  10102. if (expr->hasAttribute(_conditionFolded_Atom))
  10103. {
  10104. //LIMIT on an ALL join is equivalent to applying a limit to the rhs of the join (since all will hard match).
  10105. //This could be transformed early, but uncommon enough to not be too concerned.
  10106. if (rowlimit)
  10107. {
  10108. HqlExprArray args;
  10109. args.append(*LINK(rhs));
  10110. //A LIMIT on a join means no limit, whilst a LIMIT(ds, 0) limits to no records.
  10111. //So avoid adding a zero limit (if constant), or ensure 0 is mapped to a maximal value.
  10112. LinkedHqlExpr count = rowlimit->queryChild(0);
  10113. if (count->queryValue())
  10114. {
  10115. if (isZero(count))
  10116. count.clear();
  10117. }
  10118. else
  10119. {
  10120. OwnedHqlExpr zero = createConstant(count->queryType()->castFrom(false, I64C(0)));
  10121. OwnedHqlExpr all = createConstant(count->queryType()->castFrom(false, I64C(-1)));
  10122. OwnedHqlExpr ne = createBoolExpr(no_ne, LINK(count), zero.getClear());
  10123. count.setown(createValue(no_if, count->getType(), LINK(ne), LINK(count), LINK(all)));
  10124. }
  10125. if (count)
  10126. {
  10127. args.append(*LINK(count));
  10128. unwindChildren(args, rowlimit, 1);
  10129. rhs.setown(createDataset(no_limit, args));
  10130. }
  10131. }
  10132. isAllJoin = true;
  10133. //A non-many LOOKUP join can't really be converted to an ALL join.
  10134. //Possibly if KEEP(1) was added, no limits, no skipping in transform etc.
  10135. if (isLookupJoin && !isManyLookup)
  10136. isAllJoin = false;
  10137. WARNING(HQLWRN_JoinConditionFoldedNowAll);
  10138. }
  10139. else
  10140. {
  10141. StringBuffer name;
  10142. if (expr->queryName())
  10143. name.append(" ").append(expr->queryName());
  10144. throwError1(HQLERR_JoinXTooComplex, name.str());
  10145. }
  10146. }
  10147. Owned<ABoundActivity> boundDataset1 = buildCachedActivity(ctx, dataset1);
  10148. Owned<ABoundActivity> boundDataset2;
  10149. if (!joinToSelf)
  10150. boundDataset2.setown(buildCachedActivity(ctx, rhs));
  10151. const char * argName;
  10152. ThorActivityKind kind;
  10153. if (op == no_selfjoin)
  10154. {
  10155. if (isLightweight)
  10156. kind = TAKselfjoinlight;
  10157. else
  10158. kind = TAKselfjoin;
  10159. argName = "Join";
  10160. }
  10161. else if (op == no_join)
  10162. {
  10163. if (isAllJoin)
  10164. {
  10165. kind = TAKalljoin;
  10166. argName = "AllJoin";
  10167. }
  10168. else if (isLookupJoin)
  10169. {
  10170. kind = TAKlookupjoin;
  10171. argName = "HashJoin";
  10172. }
  10173. else if (isSmartJoin)
  10174. {
  10175. kind = TAKsmartjoin;
  10176. argName = "HashJoin";
  10177. }
  10178. else if (isHashJoin)
  10179. {
  10180. kind = TAKhashjoin;
  10181. argName = "HashJoin";
  10182. }
  10183. else
  10184. {
  10185. kind = TAKjoin;
  10186. argName = "Join";
  10187. }
  10188. }
  10189. else if (op == no_denormalize)
  10190. {
  10191. if (isAllJoin)
  10192. {
  10193. kind = TAKalldenormalize;
  10194. argName = "AllDenormalize";
  10195. }
  10196. else if (isLookupJoin)
  10197. {
  10198. kind = TAKlookupdenormalize;
  10199. argName = "HashDenormalize";
  10200. }
  10201. else if (isSmartJoin)
  10202. {
  10203. kind = TAKsmartdenormalize;
  10204. argName = "HashDenormalize";
  10205. }
  10206. else if (isHashJoin)
  10207. {
  10208. kind = TAKhashdenormalize;
  10209. argName = "HashDenormalize";
  10210. }
  10211. else
  10212. {
  10213. kind = TAKdenormalize;
  10214. argName = "Denormalize";
  10215. }
  10216. }
  10217. else
  10218. {
  10219. if (isAllJoin)
  10220. {
  10221. kind = TAKalldenormalizegroup;
  10222. argName = "AllDenormalizeGroup";
  10223. }
  10224. else if (isLookupJoin)
  10225. {
  10226. kind = TAKlookupdenormalizegroup;
  10227. argName = "HashDenormalizeGroup";
  10228. }
  10229. else if (isSmartJoin)
  10230. {
  10231. kind = TAKsmartdenormalizegroup;
  10232. argName = "HashDenormalizeGroup";
  10233. }
  10234. else if (isHashJoin)
  10235. {
  10236. kind = TAKhashdenormalizegroup;
  10237. argName = "HashDenormalizeGroup";
  10238. }
  10239. else
  10240. {
  10241. kind = TAKdenormalizegroup;
  10242. argName = "DenormalizeGroup";
  10243. }
  10244. }
  10245. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, argName);
  10246. if (isLightweight)
  10247. {
  10248. StringBuffer graphLabel;
  10249. if (kind != TAKselfjoinlight)
  10250. graphLabel.append("Lightweight ");
  10251. graphLabel.append(getActivityText(kind));
  10252. instance->graphLabel.set(graphLabel.str());
  10253. }
  10254. instance->setLocal(isLocalJoin);
  10255. buildActivityFramework(instance);
  10256. buildInstancePrefix(instance);
  10257. StringBuffer s,temp;
  10258. DatasetReference lhsDsRef(dataset1, no_activetable, NULL);
  10259. DatasetReference rhsDsRef(dataset2, no_activetable, NULL);
  10260. bool couldBeKeepOne = keepLimit && (!keepLimit->queryValue() || (keepLimit->queryValue()->getIntValue() <= 1));
  10261. if (dataset1->queryRecord() == dataset2->queryRecord())
  10262. {
  10263. //more could use the compareLeftRight function instead of generating the same code
  10264. //several time....
  10265. }
  10266. bool canReuseLeftCompare = recordTypesMatch(dataset1, dataset2) && arraysMatch(joinInfo.queryLeftSort(), joinInfo.queryRightSort());
  10267. if (!isAllJoin)
  10268. {
  10269. bool isLocalSort = isLocalJoin || !targetThor();
  10270. //Lookup join doesn't need the left sort (unless it is reused elsewhere), or the right sort unless it is deduping.
  10271. if (canReuseLeftCompare || !isLookupJoin)
  10272. generateSortCompare(instance->nestedctx, instance->classctx, no_left, lhsDsRef, joinInfo.queryLeftSort(), true, noSortAttr, false, isLightweight, isLocalSort);
  10273. if (!(isLookupJoin && isManyLookup && !couldBeKeepOne && !targetThor())) // many lookup doesn't need to dedup the rhs
  10274. generateSortCompare(instance->nestedctx, instance->classctx, no_right, rhsDsRef, joinInfo.queryRightSort(), isLocalSort, noSortAttr, canReuseLeftCompare, isLightweight, isLocalSort);
  10275. bool isGlobal = !isLocalJoin && !instance->isChildActivity();
  10276. generateSerializeKey(instance->nestedctx, no_left, lhsDsRef, joinInfo.queryLeftSort(), isGlobal, false, false);
  10277. generateSerializeKey(instance->nestedctx, no_right, rhsDsRef, joinInfo.queryRightSort(), isGlobal, false, canReuseLeftCompare);
  10278. }
  10279. StringBuffer flags;
  10280. if (excludeMatches) flags.append("|JFexclude");
  10281. if (isLeftOuter) flags.append("|JFleftouter");
  10282. if (isRightOuter) flags.append("|JFrightouter");
  10283. if (expr->hasAttribute(firstAtom)) flags.append("|JFfirst");
  10284. if (expr->hasAttribute(firstLeftAtom)) flags.append("|JFfirstleft");
  10285. if (expr->hasAttribute(firstRightAtom)) flags.append("|JFfirstright");
  10286. if (expr->hasAttribute(partitionRightAtom)) flags.append("|JFpartitionright");
  10287. if (expr->hasAttribute(parallelAtom)) flags.append("|JFparallel");
  10288. if (expr->hasAttribute(sequentialAtom)) flags.append("|JFsequential");
  10289. if (transformContainsSkip(transform))
  10290. flags.append("|JFtransformMaySkip");
  10291. if (rowlimit && rowlimit->hasAttribute(skipAtom))
  10292. flags.append("|JFmatchAbortLimitSkips");
  10293. if (rowlimit && rowlimit->hasAttribute(countAtom))
  10294. flags.append("|JFcountmatchabortlimit");
  10295. if (joinInfo.slidingMatches.ordinality()) flags.append("|JFslidingmatch");
  10296. if (joinInfo.extraMatch) flags.append("|JFmatchrequired");
  10297. if (isLookupJoin && isManyLookup) flags.append("|JFmanylookup");
  10298. if (expr->hasAttribute(onFailAtom))
  10299. flags.append("|JFonfail");
  10300. if (expr->hasAttribute(unorderedAtom))
  10301. flags.append("|JFreorderable");
  10302. if (transformReturnsSide(expr, no_left, 0))
  10303. flags.append("|JFtransformmatchesleft");
  10304. if (joinInfo.hasOptionalEqualities())
  10305. flags.append("|JFlimitedprefixjoin");
  10306. if (isAlreadySorted(dataset1, joinInfo.queryLeftSort(), true, true) || userPreventsSort(noSortAttr, no_left))
  10307. flags.append("|JFleftSortedLocally");
  10308. if (isAlreadySorted(dataset2, joinInfo.queryRightSort(), true, true) || userPreventsSort(noSortAttr, no_right))
  10309. flags.append("|JFrightSortedLocally");
  10310. if (isSmartJoin) flags.append("|JFsmart|JFmanylookup");
  10311. if (isSmartJoin || expr->hasAttribute(unstableAtom))
  10312. flags.append("|JFunstable");
  10313. if (flags.length())
  10314. doBuildUnsignedFunction(instance->classctx, "getJoinFlags", flags.str()+1);
  10315. if (!isAllJoin)
  10316. {
  10317. buildSkewThresholdMembers(instance->classctx, expr);
  10318. if (!isZero(joinInfo.atmost.limit))
  10319. doBuildUnsignedFunction(instance->startctx, "getJoinLimit", joinInfo.atmost.limit);
  10320. }
  10321. if (keepLimit)
  10322. doBuildUnsignedFunction(instance->startctx, "getKeepLimit", keepLimit);
  10323. // The transform function is pretty standard - no need for copies here
  10324. BuildCtx transformctx(instance->startctx);
  10325. switch (op)
  10326. {
  10327. case no_denormalize:
  10328. {
  10329. transformctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned counter)");
  10330. ensureRowAllocated(transformctx, "crSelf");
  10331. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  10332. associateCounter(transformctx, counter, "counter");
  10333. buildTransformBody(transformctx, transform, dataset1, dataset2, instance->dataset, selSeq);
  10334. break;
  10335. }
  10336. case no_denormalizegroup:
  10337. {
  10338. transformctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned numRows, const void * * _rows)");
  10339. ensureRowAllocated(transformctx, "crSelf");
  10340. transformctx.addQuoted("unsigned char * * rows = (unsigned char * *) _rows;");
  10341. BoundRow * selfCursor = buildTransformCursors(transformctx, transform, dataset1, dataset2, instance->dataset, selSeq);
  10342. bindRows(transformctx, no_right, selSeq, expr->queryAttribute(_rowsid_Atom), dataset2, "numRows", "rows", options.mainRowsAreLinkCounted);
  10343. doBuildTransformBody(transformctx, transform, selfCursor);
  10344. break;
  10345. }
  10346. case no_join:
  10347. case no_selfjoin:
  10348. {
  10349. transformctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right)");
  10350. ensureRowAllocated(transformctx, "crSelf");
  10351. buildTransformBody(transformctx, transform, dataset1, dataset2, instance->dataset, selSeq);
  10352. break;
  10353. }
  10354. }
  10355. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  10356. if (onFail)
  10357. {
  10358. BuildCtx funcctx(instance->startctx);
  10359. funcctx.addQuotedCompound("virtual size32_t onFailTransform(ARowBuilder & crSelf, const void * _left, const void * _right, IException * except)");
  10360. ensureRowAllocated(funcctx, "crSelf");
  10361. associateLocalFailure(funcctx, "except");
  10362. buildTransformBody(funcctx, onFail->queryChild(0), dataset1, dataset2, instance->dataset, selSeq);
  10363. }
  10364. // The collate function is used to work out which side to read from or if we have a potentially matching record
  10365. if (!isAllJoin)
  10366. {
  10367. //if left and right match, then leftright compare function is also the same
  10368. if (canReuseLeftCompare && !joinInfo.hasOptionalEqualities())
  10369. instance->nestedctx.addQuoted("virtual ICompare * queryCompareLeftRight() { return &compareLeft; }");
  10370. else
  10371. doCompareLeftRight(instance->nestedctx, "CompareLeftRight", lhsDsRef, rhsDsRef, joinInfo.queryLeftReq(), joinInfo.queryRightReq());
  10372. }
  10373. doBuildJoinRowLimitHelper(*instance, rowlimit, NULL, false);
  10374. //--function to clear left, used for right outer join and vice-versa
  10375. bool createDefaultRight = onFail || isLeftOuter;
  10376. if (isRightOuter)
  10377. buildClearRecordMember(instance->createctx, "Left", dataset1);
  10378. if (createDefaultRight)
  10379. buildClearRecordMember(instance->createctx, "Right", dataset2);
  10380. buildJoinMatchFunction(instance->startctx, "match", dataset1, dataset2, joinInfo.extraMatch, selSeq);
  10381. if (joinInfo.slidingMatches.ordinality())
  10382. {
  10383. buildSlidingMatchFunction(instance->nestedctx, joinInfo.queryLeftSort(), joinInfo.queryRightSort(), joinInfo.slidingMatches, "CompareLeftRightLower", 1, lhsDsRef, rhsDsRef);
  10384. buildSlidingMatchFunction(instance->nestedctx, joinInfo.queryLeftSort(), joinInfo.queryRightSort(), joinInfo.slidingMatches, "CompareLeftRightUpper", 2, lhsDsRef, rhsDsRef);
  10385. }
  10386. if (isHashJoin||isLookupJoin|isSmartJoin)
  10387. {
  10388. OwnedHqlExpr leftList = createValueSafe(no_sortlist, makeSortListType(NULL), joinInfo.queryLeftReq());
  10389. buildHashOfExprsClass(instance->nestedctx, "HashLeft", leftList, lhsDsRef, false);
  10390. bool canReuseLeftHash = recordTypesMatch(dataset1, dataset2) && arraysMatch(joinInfo.queryLeftReq(), joinInfo.queryRightReq());
  10391. if (!canReuseLeftHash)
  10392. {
  10393. OwnedHqlExpr rightList = createValueSafe(no_sortlist, makeSortListType(NULL), joinInfo.queryRightReq());
  10394. buildHashOfExprsClass(instance->nestedctx, "HashRight", rightList, rhsDsRef, false);
  10395. }
  10396. else
  10397. instance->nestedctx.addQuoted("virtual IHash * queryHashRight() { return &HashLeft; }");
  10398. }
  10399. if (joinInfo.hasOptionalEqualities())
  10400. {
  10401. OwnedHqlExpr leftSelect = createSelector(no_left, dataset1, selSeq);
  10402. OwnedHqlExpr rightSelect = createSelector(no_right, dataset2, selSeq);
  10403. UnsignedArray origins;
  10404. unsigned origin = 0;
  10405. ForEachItemIn(i, joinInfo.queryLeftOpt())
  10406. {
  10407. IHqlExpression & left = joinInfo.queryLeftOpt().item(i);
  10408. IHqlExpression & right = joinInfo.queryRightOpt().item(i);
  10409. unsigned delta;
  10410. if (origin == UNKNOWN_LENGTH)
  10411. throwError(HQLERR_AtmostFollowUnknownSubstr);
  10412. if (isCommonSubstringRange(&left))
  10413. {
  10414. size32_t leftLen = getMaxSubstringLength(&left);
  10415. size32_t rightLen = getMaxSubstringLength(&right);
  10416. if (leftLen == rightLen)
  10417. delta = leftLen;
  10418. else
  10419. delta = UNKNOWN_LENGTH;
  10420. }
  10421. else
  10422. delta = 1;
  10423. origins.append(origin);
  10424. if (delta != UNKNOWN_LENGTH)
  10425. origin += delta;
  10426. else
  10427. origin = UNKNOWN_LENGTH;
  10428. }
  10429. OwnedHqlExpr compare;
  10430. OwnedITypeInfo retType = makeIntType(4, true);
  10431. OwnedHqlExpr zero = createConstant(retType->castFrom(true, 0));
  10432. ForEachItemInRev(i1, joinInfo.queryLeftOpt())
  10433. {
  10434. IHqlExpression & left = joinInfo.queryLeftOpt().item(i1);
  10435. IHqlExpression & right = joinInfo.queryRightOpt().item(i1);
  10436. unsigned origin = origins.item(i1);
  10437. if (isCommonSubstringRange(&left))
  10438. {
  10439. OwnedHqlExpr simpleLeft = getSimplifiedCommonSubstringRange(&left);
  10440. OwnedHqlExpr simpleRight = getSimplifiedCommonSubstringRange(&right);
  10441. HqlExprArray args;
  10442. args.append(*lhsDsRef.mapCompound(simpleLeft, leftSelect));
  10443. args.append(*rhsDsRef.mapCompound(simpleRight, rightSelect));
  10444. IIdAtom * func = prefixDiffStrId;
  10445. ITypeInfo * lhsType = args.item(0).queryType();
  10446. if (isUnicodeType(lhsType))
  10447. {
  10448. func = prefixDiffUnicodeId;
  10449. args.append(*createConstant(lhsType->queryLocale()->str()));
  10450. }
  10451. args.append(*getSizetConstant(origin));
  10452. OwnedHqlExpr diff = bindFunctionCall(func, args);
  10453. if (compare)
  10454. {
  10455. OwnedHqlExpr alias = createAlias(diff, NULL);
  10456. OwnedHqlExpr compareNe = createValue(no_ne, makeBoolType(), LINK(alias), LINK(zero));
  10457. compare.setown(createValue(no_if, LINK(retType), compareNe.getClear(), LINK(alias), compare.getClear()));
  10458. }
  10459. else
  10460. compare.set(diff);
  10461. }
  10462. else
  10463. {
  10464. OwnedHqlExpr leftExpr = lhsDsRef.mapCompound(&left, leftSelect);
  10465. OwnedHqlExpr rightExpr = lhsDsRef.mapCompound(&right, rightSelect);
  10466. OwnedHqlExpr compareGt = createValue(no_gt, makeBoolType(), LINK(leftExpr), LINK(rightExpr));
  10467. OwnedHqlExpr gtValue = createConstant(retType->castFrom(true, origin+1));
  10468. OwnedHqlExpr ltValue = createConstant(retType->castFrom(true, -(int)(origin+1)));
  10469. OwnedHqlExpr mismatch = createValue(no_if, LINK(retType), compareGt.getClear(), gtValue.getClear(), ltValue.getClear());
  10470. OwnedHqlExpr compareNe = createValue(no_ne, makeBoolType(), LINK(leftExpr), LINK(rightExpr));
  10471. OwnedHqlExpr eqValue = compare ? LINK(compare) : LINK(zero);
  10472. compare.setown(createValue(no_if, LINK(retType), compareNe.getClear(), mismatch.getClear(), eqValue.getClear()));
  10473. origin += 1;
  10474. }
  10475. }
  10476. buildCompareMemberLR(instance->nestedctx, "PrefixCompare", compare, dataset1, dataset2, selSeq);
  10477. }
  10478. buildInstanceSuffix(instance);
  10479. buildConnectInputOutput(ctx, instance, boundDataset1, 0, 0, boundDataset2 ? "LEFT" : NULL);
  10480. if (boundDataset2)
  10481. buildConnectInputOutput(ctx, instance, boundDataset2, 0, 1, "RIGHT");
  10482. return instance->getBoundActivity();
  10483. }
  10484. ABoundActivity * HqlCppTranslator::doBuildActivityJoin(BuildCtx & ctx, IHqlExpression * expr)
  10485. {
  10486. if (isKeyedJoin(expr))
  10487. return doBuildActivityKeyedJoinOrDenormalize(ctx, expr);
  10488. else
  10489. return doBuildActivityJoinOrDenormalize(ctx, expr);
  10490. }
  10491. //---------------------------------------------------------------------------
  10492. void HqlCppTranslator::doUserTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self)
  10493. {
  10494. node_operator transformOp = transform->getOperator();
  10495. assertex(transformOp == no_call || transformOp == no_externalcall);
  10496. //Ugly, but target selector is passed in as the target.expr. Should possibly have an extra parameter.
  10497. CHqlBoundTarget target;
  10498. target.expr.set(self->querySelector());
  10499. doBuildCall(ctx, &target, transform, NULL);
  10500. }
  10501. void HqlCppTranslator::doTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self)
  10502. {
  10503. HqlExprArray assigns;
  10504. IHqlExpression * record = self->queryRecord();
  10505. TransformBuilder builder(*this, ctx, record, self, assigns);
  10506. builder.doTransform(ctx, transform, self);
  10507. }
  10508. void HqlCppTranslator::doUpdateTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * self, BoundRow * previous, bool alwaysNextRow)
  10509. {
  10510. HqlExprArray assigns;
  10511. IHqlExpression * record = self->queryRecord();
  10512. UpdateTransformBuilder builder(*this, ctx, record, self, previous->querySelector(), assigns, alwaysNextRow);
  10513. builder.doTransform(ctx, transform, self);
  10514. }
  10515. void HqlCppTranslator::doInlineTransform(BuildCtx & ctx, IHqlExpression * transform, BoundRow * targetRow)
  10516. {
  10517. Owned<BoundRow> rowBuilder = createRowBuilder(ctx, targetRow);
  10518. doTransform(ctx, transform, rowBuilder);
  10519. finalizeTempRow(ctx, targetRow, rowBuilder);
  10520. }
  10521. void HqlCppTranslator::precalculateFieldOffsets(BuildCtx & ctx, IHqlExpression * expr, BoundRow * cursor)
  10522. {
  10523. if (!cursor)
  10524. return;
  10525. if (isFixedRecordSize(cursor->queryRecord()))
  10526. return;
  10527. IHqlExpression * lastField;
  10528. IHqlExpression * selector = cursor->querySelector();
  10529. {
  10530. FieldAccessAnalyser analyser(selector);
  10531. analyser.analyse(expr, 0);
  10532. lastField = analyser.queryLastFieldAccessed();
  10533. }
  10534. if (!lastField)
  10535. return;
  10536. OwnedHqlExpr selected = createSelectExpr(LINK(selector), LINK(lastField));
  10537. Owned<IReferenceSelector> ref = buildReference(ctx, selected);
  10538. CHqlBoundExpr boundOffset;
  10539. ref->buildAddress(ctx, boundOffset);
  10540. }
  10541. BoundRow * HqlCppTranslator::buildTransformCursors(BuildCtx & ctx, IHqlExpression * transform, IHqlExpression * left, IHqlExpression * right, IHqlExpression * self, IHqlExpression * selSeq)
  10542. {
  10543. if (transform->getOperator() == no_skip)
  10544. return NULL;
  10545. assertRecordTypesMatch(self->queryRecord(), transform->queryRecord());
  10546. if (left)
  10547. ctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  10548. if (right)
  10549. ctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  10550. // Bind left to "left" and right to RIGHT
  10551. BoundRow * leftRow = NULL;
  10552. BoundRow * rightRow = NULL;
  10553. if (left)
  10554. leftRow = bindTableCursor(ctx, left, "left", no_left, selSeq);
  10555. if (right)
  10556. rightRow = bindTableCursor(ctx, right, "right", no_right, selSeq);
  10557. if (options.precalculateFieldOffsets)
  10558. precalculateFieldOffsets(ctx, transform, leftRow);
  10559. return bindSelf(ctx, self, "crSelf");
  10560. }
  10561. void HqlCppTranslator::doBuildTransformBody(BuildCtx & ctx, IHqlExpression * transform, BoundRow * selfCursor)
  10562. {
  10563. if (transform->getOperator() == no_skip)
  10564. {
  10565. ctx.addReturn(queryZero());
  10566. return;
  10567. }
  10568. associateSkipReturnMarker(ctx, queryZero(), selfCursor);
  10569. doTransform(ctx, transform, selfCursor);
  10570. buildReturnRecordSize(ctx, selfCursor);
  10571. }
  10572. void HqlCppTranslator::buildTransformBody(BuildCtx & ctx, IHqlExpression * transform, IHqlExpression * left, IHqlExpression * right, IHqlExpression * self, IHqlExpression * selSeq)
  10573. {
  10574. BoundRow * selfCursor = buildTransformCursors(ctx, transform, left, right, self, selSeq);
  10575. doBuildTransformBody(ctx, transform, selfCursor);
  10576. }
  10577. void HqlCppTranslator::buildIterateTransformFunction(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * transform, IHqlExpression * counter, IHqlExpression * selSeq)
  10578. {
  10579. BuildCtx funcctx(ctx);
  10580. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned __int64 counter)");
  10581. ensureRowAllocated(funcctx, "crSelf");
  10582. associateCounter(funcctx, counter, "counter");
  10583. buildTransformBody(funcctx, transform, dataset, dataset, dataset, selSeq);
  10584. }
  10585. void HqlCppTranslator::buildRollupTransformFunction(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * transform, IHqlExpression * selSeq)
  10586. {
  10587. BuildCtx funcctx(ctx);
  10588. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right)");
  10589. ensureRowAllocated(funcctx, "crSelf");
  10590. buildTransformBody(funcctx, transform, dataset, dataset, dataset, selSeq);
  10591. }
  10592. ABoundActivity * HqlCppTranslator::doBuildActivityIterate(BuildCtx & ctx, IHqlExpression * expr)
  10593. {
  10594. IHqlExpression * dataset = expr->queryChild(0);
  10595. IHqlExpression * transform = expr->queryChild(1);
  10596. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  10597. IHqlExpression * selSeq = querySelSeq(expr);
  10598. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  10599. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKiterate, expr, "Iterate");
  10600. buildActivityFramework(instance);
  10601. buildInstancePrefix(instance);
  10602. buildIterateTransformFunction(instance->startctx, dataset, transform, counter, selSeq);
  10603. buildClearRecordMember(instance->createctx, "", dataset);
  10604. if (transformContainsSkip(transform))
  10605. doBuildBoolFunction(instance->classctx, "canFilter", true);
  10606. buildInstanceSuffix(instance);
  10607. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  10608. return instance->getBoundActivity();
  10609. }
  10610. //---------------------------------------------------------------------------
  10611. IHqlExpression * HqlCppTranslator::queryExpandAliasScope(BuildCtx & ctx, IHqlExpression * expr)
  10612. {
  10613. loop
  10614. {
  10615. switch (expr->getOperator())
  10616. {
  10617. case no_alias_scope:
  10618. expandAliasScope(ctx, expr);
  10619. expr = expr->queryChild(0);
  10620. break;
  10621. case no_compound:
  10622. buildStmt(ctx, expr->queryChild(0));
  10623. expr = expr->queryChild(1);
  10624. break;
  10625. default:
  10626. return expr;
  10627. }
  10628. }
  10629. }
  10630. void HqlCppTranslator::buildProcessTransformFunction(BuildCtx & ctx, IHqlExpression * expr)
  10631. {
  10632. IHqlExpression * dataset = expr->queryChild(0);
  10633. IHqlExpression * right = expr->queryChild(1);
  10634. IHqlExpression * transformRow = expr->queryChild(2);
  10635. IHqlExpression * transformRight = expr->queryChild(3);
  10636. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  10637. IHqlExpression * selSeq = querySelSeq(expr);
  10638. BuildCtx funcctx(ctx);
  10639. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, ARowBuilder & crSelfRight, const void * _left, const void * _right, unsigned __int64 counter)");
  10640. associateCounter(funcctx, counter, "counter");
  10641. if ((transformRow->getOperator() == no_skip) || (transformRight->getOperator() == no_skip))
  10642. {
  10643. funcctx.addReturn(queryZero());
  10644. return;
  10645. }
  10646. ensureRowAllocated(funcctx, "crSelf");
  10647. ensureRowAllocated(funcctx, "crSelfRight");
  10648. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  10649. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  10650. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  10651. bindTableCursor(funcctx, right, "right", no_right, selSeq);
  10652. LinkedHqlExpr skipReturnValue = queryZero();
  10653. associateSkipReturnMarker(funcctx, skipReturnValue, NULL);
  10654. if (!recordTypesMatch(dataset, right))
  10655. {
  10656. //self won't clash, so can generate efficient code.
  10657. //Perform cse on both transforms
  10658. OwnedHqlExpr comma = createComma(LINK(transformRow), LINK(transformRight));
  10659. comma.setown(spotScalarCSE(comma));
  10660. if (comma->getOperator() == no_alias_scope)
  10661. comma.set(comma->queryChild(0));
  10662. HqlExprArray unwound;
  10663. comma->unwindList(unwound, no_comma);
  10664. unsigned max = unwound.ordinality();
  10665. BoundRow * selfCursor = bindSelf(funcctx, dataset, "crSelf");
  10666. BoundRow * selfRowCursor = bindSelf(funcctx, right, "crSelfRight");
  10667. for (unsigned i=0; i<max-2; i++)
  10668. buildStmt(funcctx, &unwound.item(i));
  10669. IHqlExpression * newTransformRow = queryExpandAliasScope(funcctx, &unwound.item(max-2));
  10670. IHqlExpression * newTransformRight = queryExpandAliasScope(funcctx, &unwound.item(max-1));
  10671. assertex(newTransformRow->getOperator() == no_transform && newTransformRight->getOperator() == no_transform);
  10672. doTransform(funcctx, newTransformRow, selfCursor);
  10673. doTransform(funcctx, newTransformRight, selfRowCursor);
  10674. buildReturnRecordSize(funcctx, selfCursor);
  10675. }
  10676. else
  10677. {
  10678. BuildCtx ctx1(funcctx);
  10679. ctx1.addGroup();
  10680. BoundRow * selfRowCursor = bindSelf(ctx1, right, "crSelfRight");
  10681. doTransform(ctx1, transformRight, selfRowCursor);
  10682. BuildCtx ctx2(funcctx);
  10683. ctx2.addGroup();
  10684. BoundRow * selfCursor = bindSelf(ctx2, dataset, "crSelf");
  10685. doTransform(ctx2, transformRow, selfCursor);
  10686. buildReturnRecordSize(ctx2, selfCursor);
  10687. }
  10688. }
  10689. ABoundActivity * HqlCppTranslator::doBuildActivityProcess(BuildCtx & ctx, IHqlExpression * expr)
  10690. {
  10691. IHqlExpression * dataset = expr->queryChild(0);
  10692. IHqlExpression * right = expr->queryChild(1);
  10693. IHqlExpression * transformRow = expr->queryChild(2);
  10694. IHqlExpression * transformRight = expr->queryChild(3);
  10695. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  10696. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKprocess, expr, "Process");
  10697. buildActivityFramework(instance);
  10698. buildInstancePrefix(instance);
  10699. buildMetaMember(instance->classctx, right->queryRecord(), false, "queryRightRecordSize");
  10700. {
  10701. BuildCtx initialctx(instance->startctx);
  10702. initialctx.addQuotedCompound("virtual size32_t createInitialRight(ARowBuilder & crSelf)");
  10703. ensureRowAllocated(initialctx, "crSelf");
  10704. BoundRow * cursor = bindSelf(initialctx, right, "crSelf");
  10705. Owned<IReferenceSelector> createdRef = createReferenceSelector(cursor);
  10706. buildRowAssign(initialctx, createdRef, right);
  10707. buildReturnRecordSize(initialctx, cursor);
  10708. }
  10709. buildProcessTransformFunction(instance->startctx, expr);
  10710. if (transformContainsSkip(transformRow) || transformContainsSkip(transformRight))
  10711. doBuildBoolFunction(instance->classctx, "canFilter", true);
  10712. buildInstanceSuffix(instance);
  10713. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  10714. return instance->getBoundActivity();
  10715. }
  10716. //---------------------------------------------------------------------------
  10717. ABoundActivity * HqlCppTranslator::doBuildActivitySelectNth(BuildCtx & ctx, IHqlExpression * expr)
  10718. {
  10719. IHqlExpression * dataset = expr->queryChild(0);
  10720. IHqlExpression * index = expr->queryChild(1);
  10721. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  10722. //If selecting 1st element of a non-grouped aggregate (which can only produce one row) then don't need to
  10723. //add the selectNth operator.
  10724. IHqlExpression * search = dataset;
  10725. if (hasSingleRow(dataset))
  10726. {
  10727. IValue * indexValue = index->queryValue();
  10728. if (indexValue && (indexValue->getIntValue() == 1))
  10729. {
  10730. //index first element - don't need to do anything...
  10731. //if x[n] is ever used as a dataset this assumption is invalid....
  10732. return LINK(boundDataset);
  10733. }
  10734. }
  10735. #if 0
  10736. //MORE: Should optimize left.child[1] and probably others - e.g., localresult[n]
  10737. switch (dataset->getOperator())
  10738. {
  10739. case no_select:
  10740. if (!isNewSelector(dataset))
  10741. return doBuildActivityChildDataset(ctx, expr);
  10742. break;
  10743. //MORE: What other selects are worth special casing?
  10744. }
  10745. #endif
  10746. bool useImplementationClass = options.minimizeActivityClasses && (index->getOperator() == no_constant);
  10747. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKselectn, expr, "SelectN");
  10748. if (useImplementationClass)
  10749. instance->setImplementationClass(newSelectNArgId);
  10750. buildActivityFramework(instance);
  10751. if (matchesConstantValue(index, 1))
  10752. instance->graphLabel.set("Select 1st");
  10753. buildInstancePrefix(instance);
  10754. if (!useImplementationClass)
  10755. {
  10756. BuildCtx funcctx(instance->startctx);
  10757. funcctx.addQuotedCompound("virtual unsigned __int64 getRowToSelect()");
  10758. buildReturn(funcctx, index);
  10759. buildClearRecordMember(instance->createctx, "", dataset);
  10760. }
  10761. else
  10762. {
  10763. instance->addConstructorParameter(index);
  10764. OwnedHqlExpr func = getClearRecordFunction(dataset->queryRecord());
  10765. //This is a mess - pretend that the pointer to function parameter is a boolean
  10766. //The code generator really should have better support for classes etc.. One day...
  10767. OwnedHqlExpr fakeFunc = createValue(no_typetransfer, makeBoolType(), LINK(func));
  10768. OwnedHqlExpr translatedFakeFunc = createValue(no_translated, makeBoolType(), LINK(fakeFunc));
  10769. instance->addConstructorParameter(translatedFakeFunc);
  10770. }
  10771. buildInstanceSuffix(instance);
  10772. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  10773. return instance->getBoundActivity();
  10774. }
  10775. //---------------------------------------------------------------------------
  10776. void HqlCppTranslator::doBuildClearAggregateRecord(BuildCtx & ctx, IHqlExpression * record, IHqlExpression * self, IHqlExpression * transform)
  10777. {
  10778. ForEachChild(i, record)
  10779. {
  10780. IHqlExpression * cur = record->queryChild(i);
  10781. switch (cur->getOperator())
  10782. {
  10783. case no_record:
  10784. doBuildClearAggregateRecord(ctx, cur, self, transform);
  10785. break;
  10786. case no_field:
  10787. {
  10788. OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(cur));
  10789. IHqlExpression * value = queryTransformAssignValue(transform, cur);
  10790. assertex(value);
  10791. if (value->isConstant())
  10792. buildAssign(ctx, target, value);
  10793. else
  10794. buildClear(ctx, target);
  10795. break;
  10796. }
  10797. case no_ifblock:
  10798. throwUnexpected();
  10799. }
  10800. }
  10801. }
  10802. void HqlCppTranslator::doBuildAggregateClearFunc(BuildCtx & ctx, IHqlExpression * expr)
  10803. {
  10804. IHqlExpression * tgtRecord = expr->queryChild(1);
  10805. IHqlExpression * transform = expr->queryChild(2);
  10806. BuildCtx funcctx(ctx);
  10807. funcctx.addQuotedCompound("virtual size32_t clearAggregate(ARowBuilder & crSelf)");
  10808. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  10809. BoundRow * selfRow = bindSelf(funcctx, resultDataset, "crSelf");
  10810. if (!isKnownTransform(transform))
  10811. {
  10812. OwnedHqlExpr clearCall = createClearRowCall(funcctx, selfRow);
  10813. funcctx.addReturn(clearCall);
  10814. return;
  10815. }
  10816. ensureRowAllocated(funcctx, "crSelf");
  10817. doBuildClearAggregateRecord(funcctx, transform->queryRecord(), selfRow->querySelector(), transform);
  10818. buildReturnRecordSize(funcctx, selfRow);
  10819. }
  10820. void HqlCppTranslator::doBuildAggregateFirstFunc(BuildCtx & ctx, IHqlExpression * expr)
  10821. {
  10822. IHqlExpression * dataset = expr->queryChild(0);
  10823. IHqlExpression * tgtRecord = expr->queryChild(1);
  10824. IHqlExpression * transform = expr->queryChild(2);
  10825. BuildCtx funcctx(ctx);
  10826. funcctx.addQuotedCompound("virtual size32_t processFirst(ARowBuilder & crSelf, const void * _src)");
  10827. ensureRowAllocated(funcctx, "crSelf");
  10828. funcctx.addQuoted("unsigned char * src = (unsigned char *) _src;");
  10829. //NOTE: no_throughaggregate recordof(expr) != tgtRecord => we need to create a temporary dataset
  10830. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  10831. BoundRow * selfRow = bindSelf(funcctx, resultDataset, "crSelf");
  10832. bindTableCursor(funcctx, dataset, "src");
  10833. doBuildAggregateProcessTransform(funcctx, selfRow, expr, queryBoolExpr(false));
  10834. buildReturnRecordSize(funcctx, selfRow);
  10835. }
  10836. void HqlCppTranslator::doBuildAggregateNextFunc(BuildCtx & ctx, IHqlExpression * expr)
  10837. {
  10838. IHqlExpression * dataset = expr->queryChild(0);
  10839. IHqlExpression * tgtRecord = expr->queryChild(1);
  10840. BuildCtx funcctx(ctx);
  10841. funcctx.addQuotedCompound("virtual size32_t processNext(ARowBuilder & crSelf, const void * _src)");
  10842. //no need ensureRowAllocated(funcctx, "crSelf");
  10843. funcctx.addQuoted("unsigned char * src = (unsigned char *) _src;");
  10844. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  10845. BoundRow * selfRow = bindSelf(funcctx, resultDataset, "crSelf");
  10846. bindTableCursor(funcctx, dataset, "src");
  10847. doBuildAggregateProcessTransform(funcctx, selfRow, expr, queryBoolExpr(true));
  10848. buildReturnRecordSize(funcctx, selfRow);
  10849. }
  10850. void HqlCppTranslator::doBuildAggregateProcessTransform(BuildCtx & ctx, BoundRow * selfRow, IHqlExpression * expr, IHqlExpression * alreadyDoneExpr)
  10851. {
  10852. bool alwaysFirstRow = matchesBoolean(alreadyDoneExpr, false);
  10853. bool alwaysNextRow = matchesBoolean(alreadyDoneExpr, true);
  10854. OwnedHqlExpr notAlreadyDone = getInverse(alreadyDoneExpr);
  10855. IHqlExpression * transform = expr->queryChild(2);
  10856. unsigned numAggregates = transform->numChildren();
  10857. unsigned idx;
  10858. bool isVariableOffset = false;
  10859. OwnedHqlExpr self = getSelf(expr->queryChild(1));
  10860. for (idx = 0; idx < numAggregates; idx++)
  10861. {
  10862. IHqlExpression * cur = transform->queryChild(idx);
  10863. if (cur->isAttribute())
  10864. continue;
  10865. OwnedHqlExpr target = selfRow->bindToRow(cur->queryChild(0), self);
  10866. IHqlExpression * src = cur->queryChild(1);
  10867. IHqlExpression * arg = src->queryChild(0);
  10868. IHqlExpression * cond = queryRealChild(src, 1);
  10869. BuildCtx condctx(ctx);
  10870. node_operator srcOp = src->getOperator();
  10871. switch (srcOp)
  10872. {
  10873. case no_countgroup:
  10874. {
  10875. assertex(!(arg && isVariableOffset));
  10876. if (arg)
  10877. buildFilter(condctx, arg);
  10878. OwnedHqlExpr one = createConstant(createIntValue(1,8,true));
  10879. if (alwaysFirstRow)
  10880. {
  10881. buildAssign(condctx, target, one);
  10882. }
  10883. else
  10884. {
  10885. if (!alwaysNextRow && isVariableOffset)
  10886. {
  10887. IHqlStmt * ifStmt = condctx.addFilter(notAlreadyDone);
  10888. buildAssign(condctx, target, one);
  10889. condctx.selectElse(ifStmt);
  10890. }
  10891. buildIncrementAssign(condctx, target, one);
  10892. }
  10893. }
  10894. break;
  10895. case no_sumgroup:
  10896. {
  10897. assertex(!(cond && isVariableOffset));
  10898. if (cond)
  10899. buildFilter(condctx, cond);
  10900. if (alwaysFirstRow)
  10901. {
  10902. buildAssign(condctx, target, arg);
  10903. }
  10904. else
  10905. {
  10906. if (!alwaysNextRow && isVariableOffset)
  10907. {
  10908. IHqlStmt * ifStmt = condctx.addFilter(notAlreadyDone);
  10909. buildAssign(condctx, target, arg);
  10910. condctx.selectElse(ifStmt);
  10911. }
  10912. OwnedITypeInfo type = getPromotedECLType(target->queryType(), arg->queryType());
  10913. buildIncrementAssign(condctx, target, arg);
  10914. }
  10915. }
  10916. break;
  10917. case no_maxgroup:
  10918. case no_mingroup:
  10919. {
  10920. node_operator compareOp = (srcOp == no_maxgroup) ? no_gt : no_lt;
  10921. assertex(!cond);
  10922. OwnedHqlExpr castArg = ensureExprType(arg, target->queryType()); // cast to correct type, assume it can fit in the target type.
  10923. if (!alwaysFirstRow)
  10924. {
  10925. castArg.setown(buildSimplifyExpr(condctx, castArg));
  10926. OwnedHqlExpr compare = createBoolExpr (compareOp, LINK(castArg), LINK(target));
  10927. if (!alwaysNextRow)
  10928. compare.setown(createBoolExpr(no_or, LINK(notAlreadyDone), LINK(compare)));
  10929. buildFilter(condctx, compare);
  10930. }
  10931. buildAssign(condctx, target, castArg);
  10932. }
  10933. break;
  10934. case no_existsgroup:
  10935. assertex(!(arg && isVariableOffset));
  10936. cond = arg;
  10937. if (cond || !alwaysNextRow)
  10938. {
  10939. //The assign is conditional because unconditionally it is done in the AggregateFirst
  10940. if (cond)
  10941. buildFilter(condctx, cond);
  10942. buildAssign(condctx, target, queryBoolExpr(true));
  10943. }
  10944. break;
  10945. default:
  10946. if (!src->isConstant() || isVariableOffset)
  10947. {
  10948. if (!alwaysNextRow)
  10949. {
  10950. if (!alwaysFirstRow)
  10951. buildFilter(condctx, notAlreadyDone);
  10952. buildAssign(condctx, target, src);
  10953. }
  10954. }
  10955. break;
  10956. }
  10957. if (target->queryType()->getSize() == UNKNOWN_LENGTH)
  10958. isVariableOffset = true;
  10959. }
  10960. }
  10961. void HqlCppTranslator::doBuildAggregateMergeFunc(BuildCtx & ctx, IHqlExpression * expr, bool & requiresOrderedMerge)
  10962. {
  10963. if (expr->getOperator() == no_aggregate)
  10964. {
  10965. OwnedHqlExpr mergeTransform = getUserAggregateMergeTransform(expr, requiresOrderedMerge);
  10966. doBuildUserMergeAggregateFunc(ctx, expr, mergeTransform);
  10967. return;
  10968. }
  10969. IHqlExpression * tgtRecord = expr->queryChild(1);
  10970. IHqlExpression * transform = expr->queryChild(2);
  10971. requiresOrderedMerge = false;
  10972. OwnedHqlExpr selSeq = createDummySelectorSequence();
  10973. BuildCtx funcctx(ctx);
  10974. funcctx.addQuotedCompound("virtual size32_t mergeAggregate(ARowBuilder & crSelf, const void * _right)");
  10975. //ensureRowAllocated(funcctx, "crSelf"); must be non null
  10976. funcctx.addQuoted("unsigned char * right = (unsigned char *) _right;");
  10977. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(tgtRecord));
  10978. BoundRow * selfRow = bindSelf(funcctx, resultDataset, "crSelf");
  10979. BoundRow * leftCursor = bindTableCursor(funcctx, resultDataset, "left", no_left, selSeq);
  10980. BoundRow * rightCursor = bindTableCursor(funcctx, resultDataset, "right", no_right, selSeq);
  10981. unsigned numAggregates = transform->numChildren();
  10982. unsigned idx;
  10983. IHqlExpression * left = leftCursor->querySelector();
  10984. IHqlExpression * right = rightCursor->querySelector();
  10985. OwnedHqlExpr self = getSelf(tgtRecord);
  10986. for (idx = 0; idx < numAggregates; idx++)
  10987. {
  10988. IHqlExpression * cur = transform->queryChild(idx);
  10989. if (cur->isAttribute())
  10990. continue;
  10991. OwnedHqlExpr target = selfRow->bindToRow(cur->queryChild(0), self);
  10992. OwnedHqlExpr src = replaceSelector(cur->queryChild(0), self, right);
  10993. IHqlExpression * op = cur->queryChild(1);
  10994. //MORE: How bind cursors...
  10995. switch (op->getOperator())
  10996. {
  10997. case no_countgroup:
  10998. case no_sumgroup:
  10999. {
  11000. buildIncrementAssign(funcctx, target, src);
  11001. }
  11002. break;
  11003. case no_maxgroup:
  11004. {
  11005. OwnedHqlExpr compare = createBoolExpr (no_gt, LINK(src), LINK(target));
  11006. BuildCtx filteredctx(funcctx);
  11007. buildFilter(filteredctx, compare);
  11008. buildAssign(filteredctx, target, src);
  11009. }
  11010. break;
  11011. case no_mingroup:
  11012. {
  11013. OwnedHqlExpr compare = createBoolExpr (no_lt, LINK(src), LINK(target));
  11014. BuildCtx filteredctx(funcctx);
  11015. buildFilter(filteredctx, compare);
  11016. buildAssign(filteredctx, target, src);
  11017. }
  11018. break;
  11019. case no_existsgroup:
  11020. {
  11021. BuildCtx condctx(funcctx);
  11022. buildFilter(condctx, src);
  11023. buildAssign(condctx, target, queryBoolExpr(true));
  11024. break;
  11025. }
  11026. default:
  11027. //already filled in and wouldn't be legal to have an expression in this case anyway...
  11028. break;
  11029. }
  11030. }
  11031. buildReturnRecordSize(funcctx, selfRow);
  11032. }
  11033. //--------------------------------------------------------------------------------------
  11034. // User aggregate helpers
  11035. //--------------------------------------------------------------------------------------
  11036. void HqlCppTranslator::doBuildUserAggregateProcessTransform(BuildCtx & ctx, BoundRow * selfRow, IHqlExpression * expr, IHqlExpression * transform, IHqlExpression * alreadyDoneExpr)
  11037. {
  11038. bool alwaysFirstRow = matchesBoolean(alreadyDoneExpr, false);
  11039. bool alwaysNextRow = matchesBoolean(alreadyDoneExpr, true);
  11040. OwnedHqlExpr right = createSelector(no_right, expr, querySelSeq(expr));
  11041. bool usesRight = exprReferencesDataset(transform, right);
  11042. BuildCtx condctx(ctx);
  11043. if (!isKnownTransform(transform))
  11044. {
  11045. if (!alwaysNextRow)
  11046. {
  11047. IHqlStmt * ifStmt = NULL;
  11048. if (!alwaysFirstRow)
  11049. ifStmt = condctx.addFilter(alreadyDoneExpr);
  11050. if (usesRight)
  11051. {
  11052. CHqlBoundExpr boundNullRow;
  11053. buildDefaultRow(condctx, transform, boundNullRow);
  11054. bindTableCursor(condctx, transform->queryRecord(), boundNullRow.expr, no_right, querySelSeq(expr));
  11055. }
  11056. doUserTransform(condctx, transform, selfRow);
  11057. if (ifStmt)
  11058. condctx.selectElse(ifStmt);
  11059. }
  11060. if (!alwaysFirstRow)
  11061. {
  11062. if (usesRight)
  11063. bindTableCursor(condctx, transform->queryRecord(), selfRow->queryBound(), no_right, querySelSeq(expr));
  11064. doUserTransform(condctx, transform, selfRow);
  11065. }
  11066. }
  11067. else
  11068. {
  11069. if (usesRight)
  11070. {
  11071. BoundRow * rightCursor;
  11072. if (alwaysNextRow)
  11073. rightCursor = bindTableCursor(condctx, transform->queryRecord(), selfRow->queryBound(), no_right, querySelSeq(expr));
  11074. else
  11075. {
  11076. CHqlBoundExpr boundNullRow;
  11077. buildDefaultRow(condctx, transform, boundNullRow);
  11078. if (alwaysFirstRow)
  11079. {
  11080. //MORE: Only do this (and create default row) if transform refers to RIGHT...
  11081. rightCursor = bindTableCursor(condctx, transform->queryRecord(), boundNullRow.expr, no_right, querySelSeq(expr));
  11082. }
  11083. else
  11084. {
  11085. //create a temporary
  11086. Owned<ITypeInfo> rowType = makeReferenceModifier(expr->getType());
  11087. OwnedHqlExpr rowExpr = ctx.getTempDeclare(rowType, NULL);
  11088. OwnedHqlExpr defaultRowPtr = getPointer(boundNullRow.expr);
  11089. OwnedHqlExpr condRow = createValue(no_if, LINK(rowType), LINK(alreadyDoneExpr), LINK(selfRow->queryBound()), LINK(defaultRowPtr));
  11090. condctx.addAssign(rowExpr, condRow);
  11091. rightCursor = bindTableCursor(condctx, transform->queryRecord(), rowExpr, no_right, querySelSeq(expr));
  11092. }
  11093. }
  11094. if (alwaysFirstRow)
  11095. doTransform(condctx, transform, selfRow);
  11096. else
  11097. doUpdateTransform(condctx, transform, selfRow, rightCursor, alwaysNextRow);
  11098. }
  11099. else
  11100. doTransform(condctx, transform, selfRow);
  11101. }
  11102. }
  11103. //------------------------------------------------------------------------------------------------
  11104. static bool matchesSelect(IHqlExpression * expr, IHqlExpression * selector, IHqlExpression * field)
  11105. {
  11106. if (isCast(expr))
  11107. {
  11108. ITypeInfo * afterType = expr->queryType();
  11109. ITypeInfo * beforeType = expr->queryChild(0)->queryType();
  11110. if (preservesValue(afterType, beforeType))
  11111. expr = expr->queryChild(0);
  11112. else if (beforeType->isInteger() && afterType->isInteger() && beforeType->getSize() == afterType->getSize())
  11113. expr = expr->queryChild(0);
  11114. }
  11115. if (expr->getOperator() != no_select)
  11116. return false;
  11117. if (expr->queryChild(0) != selector)
  11118. return false;
  11119. if (expr->queryChild(1) != field)
  11120. return false;
  11121. return true;
  11122. }
  11123. //MORE: Derive a merge transform by walking and spotting self.x := self.x := right.x op a or a op right.x
  11124. class MergeTransformCreator
  11125. {
  11126. public:
  11127. MergeTransformCreator(IHqlExpression * expr)
  11128. {
  11129. IHqlExpression * dataset = expr->queryChild(0);
  11130. IHqlExpression * selSeq = querySelSeq(expr);
  11131. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  11132. self.setown(getSelf(expr));
  11133. left.setown(createSelector(no_left, dataset, selSeq));
  11134. right.setown(createSelector(no_right, expr, selSeq));
  11135. mergeLeft.set(right);
  11136. OwnedHqlExpr rows = createDataset(no_rows, LINK(right), LINK(rowsid));
  11137. mergeRight.setown(createRow(no_selectnth, LINK(rows), createConstant(2)));
  11138. requiresOrderedMerge = false;
  11139. }
  11140. IHqlExpression * transform(IHqlExpression * expr);
  11141. inline bool isOrdered() { return requiresOrderedMerge; }
  11142. protected:
  11143. IHqlExpression * transformAssign(IHqlExpression * expr);
  11144. protected:
  11145. OwnedHqlExpr self;
  11146. OwnedHqlExpr left;
  11147. OwnedHqlExpr right;
  11148. OwnedHqlExpr mergeLeft;
  11149. OwnedHqlExpr mergeRight;
  11150. bool requiresOrderedMerge;
  11151. };
  11152. //self.x := right.x append|concat f() -> self.x := right.x <op> rows(right)[2].x
  11153. //self.x := f() append|concat right.x -> self.x := rows(right)[2].x <op> right.x
  11154. //self.x := right.x [+|band|bor|max|min|xor] f() -> self.x := right.x <op> rows(right)[2].x
  11155. //self.x := f() [+|band|bor|max|min|xor] right.x -> self.x := right.x <op> rows(right)[2].x
  11156. IHqlExpression * MergeTransformCreator::transformAssign(IHqlExpression * expr)
  11157. {
  11158. IHqlExpression * lhs = expr->queryChild(0);
  11159. IHqlExpression * rhs = expr->queryChild(1);
  11160. IHqlExpression * field = lhs->queryChild(1);
  11161. bool commutative = true;
  11162. node_operator op = rhs->getOperator();
  11163. HqlExprArray args;
  11164. switch (op)
  11165. {
  11166. case no_concat:
  11167. case no_addfiles:
  11168. commutative = false;
  11169. rhs->unwindList(args, op);
  11170. break;
  11171. case no_add:
  11172. case no_band:
  11173. case no_bor:
  11174. case no_bxor:
  11175. case no_mul:
  11176. rhs->unwindList(args, op);
  11177. break;
  11178. case no_sumlist:
  11179. case no_maxlist:
  11180. case no_minlist:
  11181. {
  11182. IHqlExpression * list = rhs->queryChild(0);
  11183. if (list->getOperator() != no_list)
  11184. return NULL;
  11185. unwindChildren(args, list);
  11186. break;
  11187. }
  11188. default:
  11189. //ok, if it is only assigned once.
  11190. if (exprReferencesDataset(rhs, right))
  11191. return NULL;
  11192. //need to preserve the value if at a variable offset... Should be stripped if unnecessary
  11193. OwnedHqlExpr newRhs = createSelectExpr(LINK(mergeLeft), LINK(field));
  11194. return createAssign(LINK(lhs), newRhs.getClear());
  11195. }
  11196. unsigned matchPos = NotFound;
  11197. ForEachItemIn(i, args)
  11198. {
  11199. IHqlExpression & cur = args.item(i);
  11200. if (exprReferencesDataset(&cur, right))
  11201. {
  11202. if ((matchPos == NotFound) && matchesSelect(&cur, right, field))
  11203. matchPos = i;
  11204. else
  11205. return NULL;
  11206. }
  11207. }
  11208. if (matchPos == NotFound)
  11209. return NULL;
  11210. if (!commutative)
  11211. requiresOrderedMerge = true;
  11212. HqlExprArray newArgs;
  11213. if (commutative || (matchPos == 0))
  11214. {
  11215. newArgs.append(*createSelectExpr(LINK(mergeLeft), LINK(field)));
  11216. newArgs.append(*createSelectExpr(LINK(mergeRight), LINK(field)));
  11217. }
  11218. else if (matchPos == args.ordinality() - 1)
  11219. {
  11220. newArgs.append(*createSelectExpr(LINK(mergeRight), LINK(field)));
  11221. newArgs.append(*createSelectExpr(LINK(mergeLeft), LINK(field)));
  11222. }
  11223. if (newArgs.ordinality())
  11224. {
  11225. switch (op)
  11226. {
  11227. case no_sumlist:
  11228. case no_minlist:
  11229. case no_maxlist:
  11230. {
  11231. OwnedHqlExpr list = rhs->queryChild(0)->clone(newArgs);
  11232. newArgs.kill();
  11233. newArgs.append(*list.getClear());
  11234. break;
  11235. }
  11236. }
  11237. return createAssign(LINK(lhs), rhs->clone(newArgs));
  11238. }
  11239. return NULL;
  11240. }
  11241. IHqlExpression * MergeTransformCreator::transform(IHqlExpression * expr)
  11242. {
  11243. HqlExprArray children;
  11244. ForEachChild(i, expr)
  11245. {
  11246. IHqlExpression * cur = expr->queryChild(i);
  11247. OwnedHqlExpr mapped;
  11248. switch (cur->getOperator())
  11249. {
  11250. case no_assign:
  11251. mapped.setown(transformAssign(cur));
  11252. if (!mapped)
  11253. return NULL;
  11254. break;
  11255. case no_assignall:
  11256. mapped.setown(transform(cur));
  11257. if (!mapped)
  11258. return NULL;
  11259. break;
  11260. case no_alias_scope:
  11261. //Not so sure - there shouldn't be any at this point... Maybe we should allow...
  11262. return NULL;
  11263. case no_assert:
  11264. case no_skip:
  11265. return NULL;
  11266. case no_attr:
  11267. case no_attr_link:
  11268. case no_attr_expr:
  11269. break;
  11270. default:
  11271. UNIMPLEMENTED;
  11272. }
  11273. if (mapped)
  11274. children.append(*mapped.getClear());
  11275. }
  11276. return expr->clone(children);
  11277. }
  11278. //------------------------------------------------------------------------------------------------
  11279. // Replace SELF.x := F(LEFT) with SELF.x := RIGHT.x.
  11280. //i) To ensure the first value is always used and
  11281. //ii) to allow subsequent optimizations to remove the assignment
  11282. class NextTransformCreator
  11283. {
  11284. public:
  11285. NextTransformCreator(IHqlExpression * expr)
  11286. {
  11287. IHqlExpression * dataset = expr->queryChild(0);
  11288. IHqlExpression * selSeq = querySelSeq(expr);
  11289. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  11290. self.setown(getSelf(expr));
  11291. left.setown(createSelector(no_left, dataset, selSeq));
  11292. right.setown(createSelector(no_right, expr, selSeq));
  11293. }
  11294. IHqlExpression * transform(IHqlExpression * expr);
  11295. protected:
  11296. IHqlExpression * transformAssign(IHqlExpression * expr);
  11297. protected:
  11298. OwnedHqlExpr self;
  11299. OwnedHqlExpr left;
  11300. OwnedHqlExpr right;
  11301. };
  11302. IHqlExpression * NextTransformCreator::transformAssign(IHqlExpression * expr)
  11303. {
  11304. IHqlExpression * lhs = expr->queryChild(0);
  11305. IHqlExpression * rhs = expr->queryChild(1);
  11306. IHqlExpression * field = lhs->queryChild(1);
  11307. if (!rhs->isConstant() && !exprReferencesDataset(rhs, right))
  11308. {
  11309. OwnedHqlExpr newRhs = createSelectExpr(LINK(right), LINK(field));
  11310. return createAssign(LINK(lhs), newRhs.getClear());
  11311. }
  11312. return LINK(expr);
  11313. }
  11314. IHqlExpression * NextTransformCreator::transform(IHqlExpression * expr)
  11315. {
  11316. HqlExprArray children;
  11317. ForEachChild(i, expr)
  11318. {
  11319. IHqlExpression * cur = expr->queryChild(i);
  11320. OwnedHqlExpr mapped = LINK(cur);
  11321. switch (cur->getOperator())
  11322. {
  11323. case no_assign:
  11324. mapped.setown(transformAssign(cur));
  11325. break;
  11326. case no_assignall:
  11327. mapped.setown(transform(cur));
  11328. break;
  11329. }
  11330. children.append(*mapped.getClear());
  11331. }
  11332. return expr->clone(children);
  11333. }
  11334. //------------------------------------------------------------------------------------------------
  11335. void HqlCppTranslator::processUserAggregateTransform(IHqlExpression * expr, IHqlExpression * transform, SharedHqlExpr & firstTransform, SharedHqlExpr & nextTransform)
  11336. {
  11337. if (isKnownTransform(transform))
  11338. {
  11339. OwnedHqlExpr right = createSelector(no_right, expr, querySelSeq(expr));
  11340. OwnedHqlExpr nullRow = createRow(no_newrow, createRow(no_null, LINK(expr->queryRecord())));
  11341. firstTransform.setown(replaceSelector(transform, right, nullRow));
  11342. firstTransform.setown(foldHqlExpression(firstTransform));
  11343. }
  11344. else
  11345. firstTransform.set(transform);
  11346. if (isKnownTransform(transform))
  11347. {
  11348. {
  11349. NextTransformCreator builder(expr);
  11350. nextTransform.setown(builder.transform(transform));
  11351. }
  11352. }
  11353. else
  11354. nextTransform.set(transform);
  11355. }
  11356. IHqlExpression * HqlCppTranslator::getUserAggregateMergeTransform(IHqlExpression * expr, bool & requiresOrderedMerge)
  11357. {
  11358. IHqlExpression * mergeTransform = queryAttributeChild(expr, mergeTransformAtom, 0);
  11359. if (mergeTransform)
  11360. {
  11361. requiresOrderedMerge = true;
  11362. return LINK(mergeTransform);
  11363. }
  11364. IHqlExpression * transform = expr->queryChild(2);
  11365. if (!isKnownTransform(transform))
  11366. return NULL;
  11367. MergeTransformCreator builder(expr);
  11368. OwnedHqlExpr ret = builder.transform(transform);
  11369. requiresOrderedMerge = builder.isOrdered();
  11370. return ret.getClear();
  11371. }
  11372. void HqlCppTranslator::doBuildUserMergeAggregateFunc(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * mergeTransform)
  11373. {
  11374. IHqlExpression * dataset = expr->queryChild(0);
  11375. IHqlExpression * tgtRecord = expr->queryChild(1);
  11376. IHqlExpression * transform = expr->queryChild(2);
  11377. IHqlExpression * selSeq = querySelSeq(expr);
  11378. if (!mergeTransform)
  11379. throwError(HQLERR_AggregateNeedMergeTransform);
  11380. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  11381. BuildCtx funcctx(ctx);
  11382. funcctx.addQuotedCompound("virtual size32_t mergeAggregate(ARowBuilder & upRight1, const void * _right2)");
  11383. funcctx.addQuoted("unsigned char * right2 = (unsigned char *) _right2;");
  11384. BoundRow * rightCursor = bindTableCursor(funcctx, expr, "upRight1.row()", no_right, selSeq);
  11385. BoundRow * leftCursor = bindTableCursor(funcctx, expr, "right2", no_left, selSeq);
  11386. BoundRow * selfCursor = bindSelf(funcctx, expr, "upRight1");
  11387. //Ugly!! RIGHT:2 is represented as ROWS(RIGHT)[2]. Change it to no_left since it will make like cleaner
  11388. //If we fail to replace all references then fall back to the worse case generation
  11389. OwnedHqlExpr rows = createDataset(no_rows, LINK(rightCursor->querySelector()), LINK(rowsid));
  11390. OwnedHqlExpr complexRight1 = createRow(no_selectnth, LINK(rows), createConstant(1));
  11391. OwnedHqlExpr complexRight2 = createRow(no_selectnth, LINK(rows), createConstant(2));
  11392. OwnedHqlExpr mappedTransform1 = removeAnnotations(mergeTransform, rows);
  11393. OwnedHqlExpr mappedTransform2 = replaceExpression(mappedTransform1, complexRight1, rightCursor->querySelector());
  11394. OwnedHqlExpr mappedTransform3 = replaceExpression(mappedTransform2, complexRight2, leftCursor->querySelector());
  11395. if (containsExpression(mappedTransform3, rows))
  11396. {
  11397. //Worse case fallback behaviour. Shouldn't occur in practice.
  11398. //If ROWS() really is needed due to some weird expression then we need to clone the target/RIGHT1 row because
  11399. //any modification may cause it to relocate and so invalidate the pointer passed in.
  11400. IHqlExpression * leftBound = leftCursor->queryBound();
  11401. ITypeInfo * rowType = leftBound->queryType();
  11402. CHqlBoundExpr boundRow1;
  11403. buildTempExpr(funcctx, rightCursor->querySelector(), boundRow1);
  11404. OwnedHqlExpr rows = createVariable("rows", makeArrayType(LINK(rowType), 2));
  11405. OwnedHqlExpr initializer = createValue(no_list, makeSetType(LINK(rowType)), LINK(boundRow1.expr), LINK(leftBound));
  11406. funcctx.addDeclare(rows, initializer);
  11407. bindRows(funcctx, no_right, selSeq, rowsid, expr, "2", "rows", options.mainRowsAreLinkCounted);
  11408. }
  11409. doUpdateTransform(funcctx, mappedTransform3, selfCursor, rightCursor, true);
  11410. buildReturnRecordSize(funcctx, selfCursor);
  11411. }
  11412. void HqlCppTranslator::doBuildUserAggregateFuncs(BuildCtx & ctx, IHqlExpression * expr, bool & requiresOrderedMerge)
  11413. {
  11414. IHqlExpression * dataset = expr->queryChild(0);
  11415. IHqlExpression * tgtRecord = expr->queryChild(1);
  11416. IHqlExpression * transform = expr->queryChild(2);
  11417. IHqlExpression * selSeq = querySelSeq(expr);
  11418. LinkedHqlExpr firstTransform;
  11419. LinkedHqlExpr nextTransform;
  11420. processUserAggregateTransform(expr, transform, firstTransform, nextTransform);
  11421. {
  11422. BuildCtx funcctx(ctx);
  11423. funcctx.addQuotedCompound("virtual size32_t processFirst(ARowBuilder & crSelf, const void * _src)");
  11424. ensureRowAllocated(funcctx, "crSelf");
  11425. funcctx.addQuoted("unsigned char * src = (unsigned char *) _src;");
  11426. BoundRow * selfRow = bindSelf(funcctx, expr, "crSelf");
  11427. bindTableCursor(funcctx, dataset, "src", options.mainRowsAreLinkCounted, no_left, selSeq);
  11428. doBuildUserAggregateProcessTransform(funcctx, selfRow, expr, firstTransform, queryBoolExpr(false));
  11429. buildReturnRecordSize(funcctx, selfRow);
  11430. }
  11431. {
  11432. BuildCtx funcctx(ctx);
  11433. funcctx.addQuotedCompound("virtual size32_t processNext(ARowBuilder & crSelf, const void * _src)");
  11434. ensureRowAllocated(funcctx, "crSelf");
  11435. funcctx.addQuoted("unsigned char * src = (unsigned char *) _src;");
  11436. BoundRow * leftCursor = bindTableCursor(funcctx, dataset, "src", options.mainRowsAreLinkCounted, no_left, selSeq);
  11437. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  11438. BoundRow * rightCursor = bindTableCursor(funcctx, expr, "crSelf.row()", no_right, querySelSeq(expr));
  11439. doBuildUserAggregateProcessTransform(funcctx, selfCursor, expr, nextTransform, queryBoolExpr(true));
  11440. buildReturnRecordSize(funcctx, selfCursor);
  11441. }
  11442. if (targetThor() && !isGrouped(dataset) && !expr->hasAttribute(localAtom))
  11443. {
  11444. OwnedHqlExpr mergeTransform = getUserAggregateMergeTransform(expr, requiresOrderedMerge);
  11445. doBuildUserMergeAggregateFunc(ctx, expr, mergeTransform);
  11446. }
  11447. }
  11448. //--------------------------------------------------------------------------------------
  11449. void getMappedFields(HqlExprArray & aggregateFields, IHqlExpression * transform, HqlExprArray & recordFields, IHqlExpression * newSelector)
  11450. {
  11451. unsigned numFields = transform->numChildren();
  11452. OwnedHqlExpr self = getSelf(transform);
  11453. ForEachItemIn(idx, recordFields)
  11454. {
  11455. IHqlExpression & cur = recordFields.item(idx);
  11456. unsigned fieldIdx;
  11457. for (fieldIdx = 0; fieldIdx < numFields; fieldIdx++)
  11458. {
  11459. IHqlExpression * curAssign = transform->queryChild(fieldIdx);
  11460. IHqlExpression * rhs = curAssign->queryChild(1);
  11461. if (rhs->getOperator() == no_activerow)
  11462. rhs = rhs->queryChild(0);
  11463. if (rhs == &cur)
  11464. {
  11465. aggregateFields.append(*replaceSelector(curAssign->queryChild(0), self, newSelector));
  11466. break;
  11467. }
  11468. }
  11469. if (fieldIdx == numFields)
  11470. {
  11471. StringBuffer s;
  11472. getExprECL(&cur, s);
  11473. throwError1(HQLERR_AggregateMissingGroupingFields, s.str());
  11474. }
  11475. }
  11476. }
  11477. ABoundActivity * HqlCppTranslator::doBuildActivityAggregate(BuildCtx & ctx, IHqlExpression * expr)
  11478. {
  11479. IHqlExpression * dataset = expr->queryChild(0);
  11480. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  11481. node_operator op = expr->getOperator();
  11482. IHqlExpression * transform = expr->queryChild(2);
  11483. LinkedHqlExpr grouping = queryRealChild(expr, 3);
  11484. bool passThrough = (op == no_throughaggregate);
  11485. if (passThrough)
  11486. grouping.clear();
  11487. unsigned tableType = dataset->queryType()->getTypeCode();
  11488. const char *activity;
  11489. ThorActivityKind kind = TAKaggregate;
  11490. node_operator specialOp = no_none;
  11491. IIdAtom * implementationClassId = NULL;
  11492. if (passThrough)
  11493. {
  11494. activity = "ThroughAggregate";
  11495. kind = TAKthroughaggregate;
  11496. }
  11497. else if (grouping)
  11498. {
  11499. activity = "HashAggregate";
  11500. kind = TAKhashaggregate;
  11501. }
  11502. else if (targetThor() && (tableType == type_groupedtable))
  11503. activity = "GroupAggregate";
  11504. else
  11505. {
  11506. activity = "Aggregate";
  11507. specialOp = querySimpleAggregate(expr, false, false);
  11508. if (specialOp == no_existsgroup)
  11509. {
  11510. kind = TAKexistsaggregate;
  11511. activity = "ExistsAggregate";
  11512. if (options.minimizeActivityClasses)
  11513. implementationClassId = newExistsAggregateArgId;
  11514. }
  11515. else if (specialOp == no_countgroup)
  11516. {
  11517. kind = TAKcountaggregate;
  11518. activity = "CountAggregate";
  11519. if (options.minimizeActivityClasses)
  11520. implementationClassId = newCountAggregateArgId;
  11521. }
  11522. else
  11523. specialOp = no_none;
  11524. }
  11525. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, activity);
  11526. if (implementationClassId)
  11527. instance->setImplementationClass(implementationClassId);
  11528. if (passThrough)
  11529. {
  11530. StringBuffer graphLabel;
  11531. graphLabel.append("Through Aggregate");
  11532. ForEachChild(idx, expr)
  11533. {
  11534. IHqlExpression * cur = expr->queryChild(idx);
  11535. if (cur->getOperator() == no_setresult || cur->getOperator() == no_extractresult)
  11536. {
  11537. IHqlExpression * sequence = queryAttributeChild(cur, sequenceAtom, 0);
  11538. IHqlExpression * name = queryAttributeChild(cur, namedAtom, 0);
  11539. getStoredDescription(graphLabel.append("\n"), sequence, name, false);
  11540. }
  11541. }
  11542. instance->graphLabel.set(graphLabel.str());
  11543. }
  11544. if (isKeyedCountAggregate(expr))
  11545. throwError(HQLERR_KeyedCountNonKeyable);
  11546. buildActivityFramework(instance);
  11547. buildInstancePrefix(instance);
  11548. StringBuffer flags;
  11549. bool requiresOrderedMerge = false;
  11550. if (specialOp == no_none)
  11551. {
  11552. doBuildAggregateClearFunc(instance->startctx, expr);
  11553. if (op == no_aggregate)
  11554. {
  11555. doBuildUserAggregateFuncs(instance->startctx, expr, requiresOrderedMerge);
  11556. }
  11557. else
  11558. {
  11559. doBuildAggregateFirstFunc(instance->startctx, expr);
  11560. doBuildAggregateNextFunc(instance->startctx, expr);
  11561. if (targetThor() && !isGroupedActivity(expr) && !expr->hasAttribute(localAtom))
  11562. doBuildAggregateMergeFunc(instance->startctx, expr, requiresOrderedMerge);
  11563. }
  11564. }
  11565. if (requiresOrderedMerge)
  11566. flags.append("|TAForderedmerge");
  11567. if (flags.length())
  11568. doBuildUnsignedFunction(instance->classctx, "getAggregateFlags", flags.str()+1);
  11569. if (grouping)
  11570. {
  11571. HqlExprArray recordFields, aggregateFields;
  11572. grouping->unwindList(recordFields, no_sortlist);
  11573. getMappedFields(aggregateFields, transform, recordFields, queryActiveTableSelector());
  11574. DatasetReference inputRef(dataset, (op == no_aggregate) ? no_left : no_none, querySelSeq(expr));
  11575. DatasetReference outRef(expr, no_activetable, NULL);
  11576. OwnedHqlExpr allRecordFields = createValueSafe(no_sortlist, makeSortListType(NULL), recordFields);
  11577. OwnedHqlExpr allAggregateFields = createValueSafe(no_sortlist, makeSortListType(NULL), aggregateFields);
  11578. buildCompareMember(instance->nestedctx, "CompareElements", allAggregateFields, outRef); // compare transformed elements
  11579. doCompareLeftRight(instance->nestedctx, "CompareRowElement", inputRef, outRef, recordFields, aggregateFields);
  11580. buildHashOfExprsClass(instance->nestedctx, "Hash", allRecordFields, inputRef, true);
  11581. buildHashOfExprsClass(instance->nestedctx, "HashElement", allAggregateFields, outRef, true);
  11582. }
  11583. if (passThrough)
  11584. {
  11585. BuildCtx sendctx(instance->startctx);
  11586. sendctx.addQuotedCompound("virtual void sendResult(const void * _self)");
  11587. sendctx.addQuoted("const unsigned char * self = (const unsigned char *)_self;");
  11588. OwnedHqlExpr resultDataset = createDataset(no_anon, LINK(expr->queryChild(1)), NULL);
  11589. bindTableCursor(sendctx, resultDataset, "self");
  11590. bindTableCursor(sendctx, dataset, "self");
  11591. ForEachChild(idx, expr)
  11592. {
  11593. IHqlExpression * cur = expr->queryChild(idx);
  11594. if (cur->getOperator() == no_setresult)
  11595. {
  11596. IHqlExpression * value = cur->queryChild(0);
  11597. IHqlExpression * sequence = queryAttributeChild(cur, sequenceAtom, 0);
  11598. IHqlExpression * name = queryAttributeChild(cur, namedAtom, 0);
  11599. buildSetResultInfo(sendctx, cur, value, NULL, false, false);
  11600. associateRemoteResult(*instance, sequence, name);
  11601. }
  11602. else if (cur->getOperator() == no_extractresult)
  11603. {
  11604. IHqlExpression * value = cur->queryChild(1);
  11605. IHqlExpression * sequence = queryAttributeChild(cur, sequenceAtom, 0);
  11606. IHqlExpression * name = queryAttributeChild(cur, namedAtom, 0);
  11607. buildSetResultInfo(sendctx, cur, value, NULL, false, false);
  11608. associateRemoteResult(*instance, sequence, name);
  11609. }
  11610. }
  11611. buildMetaMember(instance->classctx, resultDataset, isGrouped(resultDataset), "queryAggregateRecordSize");
  11612. }
  11613. buildInstanceSuffix(instance);
  11614. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  11615. return instance->getBoundActivity();
  11616. }
  11617. //---------------------------------------------------------------------------
  11618. ABoundActivity * HqlCppTranslator::doBuildActivityChildDataset(BuildCtx & ctx, IHqlExpression * expr)
  11619. {
  11620. if (options.mainRowsAreLinkCounted || isGrouped(expr))
  11621. return doBuildActivityLinkedRawChildDataset(ctx, expr);
  11622. StringBuffer s;
  11623. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKchilditerator, expr, "ChildIterator");
  11624. buildActivityFramework(instance);
  11625. buildInstancePrefix(instance);
  11626. //Dummy implementation that just clears the record
  11627. OwnedHqlExpr value = LINK(expr);
  11628. switch (value->getOperator())
  11629. {
  11630. case no_alias:
  11631. case no_left:
  11632. case no_right:
  11633. case no_top:
  11634. case no_id2blob:
  11635. case no_rows:
  11636. case no_getgraphresult:
  11637. case no_activetable:
  11638. break;
  11639. case no_select:
  11640. if (!isNewSelector(expr))
  11641. break;
  11642. //fall through
  11643. default:
  11644. {
  11645. CHqlBoundExpr bound;
  11646. doBuildAliasValue(instance->onstartctx, value, bound);
  11647. value.setown(bound.getTranslatedExpr());
  11648. break;
  11649. }
  11650. }
  11651. Owned<IHqlCppDatasetCursor> iter = createDatasetSelector(instance->onstartctx, value);
  11652. iter->buildIterateMembers(instance->startctx, instance->onstartctx);
  11653. //virtual size32_t transform(ARowBuilder & crSelf) = 0;
  11654. BuildCtx transformCtx(instance->startctx);
  11655. transformCtx.addQuotedCompound("size32_t transform(ARowBuilder & crSelf)");
  11656. ensureRowAllocated(transformCtx, "crSelf");
  11657. BoundRow * selfCursor = bindSelf(transformCtx, expr, "crSelf");
  11658. OwnedHqlExpr active = ensureActiveRow(value);
  11659. buildAssign(transformCtx, selfCursor->querySelector(), active);
  11660. buildReturnRecordSize(transformCtx, selfCursor);
  11661. buildInstanceSuffix(instance);
  11662. return instance->getBoundActivity();
  11663. }
  11664. //---------------------------------------------------------------------------
  11665. ABoundActivity * HqlCppTranslator::doBuildActivityStreamedCall(BuildCtx & ctx, IHqlExpression * expr)
  11666. {
  11667. StringBuffer s;
  11668. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKstreamediterator, expr, "StreamedIterator");
  11669. buildActivityFramework(instance);
  11670. buildInstancePrefix(instance);
  11671. BuildCtx createctx(instance->startctx);
  11672. createctx.addQuotedCompound("virtual IRowStream * createInput()");
  11673. CHqlBoundExpr bound;
  11674. doBuildExprCall(createctx, expr, bound);
  11675. createctx.addReturn(bound.expr);
  11676. buildInstanceSuffix(instance);
  11677. return instance->getBoundActivity();
  11678. }
  11679. //---------------------------------------------------------------------------
  11680. ABoundActivity * HqlCppTranslator::doBuildActivityLinkedRawChildDataset(BuildCtx & ctx, IHqlExpression * expr)
  11681. {
  11682. StringBuffer s;
  11683. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKlinkedrawiterator, expr, "LinkedRawIterator");
  11684. buildActivityFramework(instance);
  11685. buildInstancePrefix(instance);
  11686. OwnedHqlExpr value = expr->isDatarow() ? createDatasetFromRow(LINK(expr)) : LINK(expr);
  11687. BuildCtx * declarectx;
  11688. BuildCtx * callctx;
  11689. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, &callctx, false, true); // possibly should sometimes generate in onCreate(), if can evaluate in parent
  11690. CHqlBoundTarget invariantDs;
  11691. buildTempExpr(*callctx, *declarectx, invariantDs, value, FormatLinkedDataset, false);
  11692. CHqlBoundExpr boundDs;
  11693. boundDs.setFromTarget(invariantDs);
  11694. CHqlBoundTarget boundActiveIndex;
  11695. OwnedHqlExpr zero = getSizetConstant(0);
  11696. buildTempExpr(*callctx, *declarectx, boundActiveIndex, zero, FormatNatural, false);
  11697. //virtual byte * next() = 0;
  11698. BuildCtx funcctx(instance->startctx);
  11699. funcctx.addQuotedCompound("virtual byte * next()");
  11700. OwnedHqlExpr count = getBoundCount(boundDs);
  11701. OwnedHqlExpr test = createValue(no_lt, makeBoolType(), LINK(boundActiveIndex.expr), LINK(count));
  11702. BuildCtx subctx(funcctx);
  11703. subctx.addFilter(test);
  11704. OwnedHqlExpr ret = createValue(no_index, expr->getType(), LINK(boundDs.expr), createValue(no_postinc, LINK(sizetType), LINK(boundActiveIndex.expr)));
  11705. subctx.addReturn(ret);
  11706. funcctx.addReturn(queryQuotedNullExpr());
  11707. buildInstanceSuffix(instance);
  11708. return instance->getBoundActivity();
  11709. }
  11710. //---------------------------------------------------------------------------
  11711. static void gatherDedupCompareExpr(HqlExprArray & equalities, HqlExprArray & comparisons, HqlExprArray & conds, IHqlExpression * left, IHqlExpression * right, IHqlExpression * dataset)
  11712. {
  11713. ForEachItemIn(idx, conds)
  11714. {
  11715. IHqlExpression * cond = &conds.item(idx);
  11716. if (cond->getOperator() == no_and)
  11717. {
  11718. HqlExprArray expanded;
  11719. cond->unwindList(expanded, no_and);
  11720. gatherDedupCompareExpr(equalities, comparisons, expanded, left, right, dataset);
  11721. }
  11722. else if (containsSelector(cond, left) || containsSelector(cond, right))
  11723. comparisons.append(*LINK(cond));
  11724. else if (!cond->isConstant())
  11725. equalities.append(*LINK(cond));
  11726. }
  11727. }
  11728. void optimizeGroupOrder(HqlExprArray & optimized, IHqlExpression * dataset, HqlExprArray & exprs)
  11729. {
  11730. RecordSelectIterator iter(dataset->queryRecord(), dataset->queryNormalizedSelector());
  11731. ForEach(iter)
  11732. {
  11733. IHqlExpression * select = iter.query();
  11734. unsigned match = exprs.find(*select);
  11735. if (match != NotFound)
  11736. {
  11737. optimized.append(*LINK(select));
  11738. //Remove this item, and all other matches (unusual, but if it does occur it is wasteful.)
  11739. do
  11740. {
  11741. exprs.remove(match);
  11742. match = exprs.find(*select);
  11743. } while (match != NotFound);
  11744. if (exprs.empty())
  11745. break;
  11746. }
  11747. }
  11748. }
  11749. IHqlExpression * createOrderFromCompareArray(HqlExprArray & exprs, IHqlExpression * dataset, IHqlExpression * left, IHqlExpression * right)
  11750. {
  11751. OwnedHqlExpr equalExpr = createSortList(exprs);
  11752. OwnedHqlExpr lhs = replaceSelector(equalExpr, dataset, left);
  11753. OwnedHqlExpr rhs = replaceSelector(equalExpr, dataset, right);
  11754. return createValue(no_order, LINK(signedType), lhs.getClear(), rhs.getClear());
  11755. }
  11756. void HqlCppTranslator::buildDedupFilterFunction(BuildCtx & ctx, HqlExprArray & equalities, HqlExprArray & conds, IHqlExpression * dataset, IHqlExpression * selSeq)
  11757. {
  11758. HqlExprArray comparisons;
  11759. HqlExprArray allEqualities;
  11760. //MORE: The equalities really shouldn't be here - the activities should do them via the primaryCompare
  11761. appendArray(allEqualities, equalities);
  11762. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  11763. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  11764. gatherDedupCompareExpr(allEqualities, comparisons, conds, left, right, dataset);
  11765. BuildCtx funcctx(ctx);
  11766. IHqlStmt * functionStmt = funcctx.addQuotedCompound("virtual bool matches(const void * _left, const void * _right)");
  11767. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  11768. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  11769. BuildCtx filterctx(funcctx);
  11770. BoundRow * lRow = bindTableCursor(filterctx, dataset, "left", no_left, selSeq);
  11771. BoundRow * rRow = bindTableCursor(filterctx, dataset, "right", no_right, selSeq);
  11772. //convert any LEFT.x = RIGHT.y to an equality
  11773. unsigned numComparisons = comparisons.ordinality();
  11774. for (unsigned i1=0; i1 < numComparisons; )
  11775. {
  11776. IHqlExpression * cur = &comparisons.item(i1);
  11777. if (cur->getOperator() == no_eq)
  11778. {
  11779. IHqlExpression * lhs = cur->queryChild(0);
  11780. OwnedHqlExpr newLhs = replaceSelector(lhs, lRow->querySelector(), rRow->querySelector());
  11781. if (newLhs == cur->queryChild(1))
  11782. {
  11783. allEqualities.append(*replaceSelector(lhs, lRow->querySelector(), dataset));
  11784. comparisons.remove(i1);
  11785. numComparisons--;
  11786. }
  11787. //could check for right.x = left.x, but pretty unlikely.
  11788. else
  11789. i1++;
  11790. }
  11791. else
  11792. i1++;
  11793. }
  11794. ForEachItemIn(i, comparisons)
  11795. {
  11796. IHqlExpression * cur = &comparisons.item(i);
  11797. //if no equalities to follow, generate a return for the last non-equality
  11798. if (allEqualities.empty() && (i+1 == numComparisons))
  11799. {
  11800. buildReturn(filterctx, cur);
  11801. }
  11802. else
  11803. {
  11804. OwnedHqlExpr inverse = getInverse(cur);
  11805. buildFilteredReturn(filterctx, inverse, queryBoolExpr(false));
  11806. }
  11807. }
  11808. if (allEqualities.ordinality())
  11809. {
  11810. HqlExprArray optimized;
  11811. //Even better... sort the equality list by the field order...
  11812. if (options.optimizeGrouping && (allEqualities.ordinality() > 1))
  11813. optimizeGroupOrder(optimized, dataset, allEqualities);
  11814. appendArray(optimized, allEqualities);
  11815. OwnedHqlExpr order = createOrderFromCompareArray(optimized, dataset, lRow->querySelector(), rRow->querySelector());
  11816. doBuildReturnCompare(filterctx, order, no_eq, true);
  11817. }
  11818. else if (comparisons.ordinality() == 0)
  11819. functionStmt->setIncluded(false); // Use the implementation in the base class
  11820. }
  11821. void HqlCppTranslator::buildDedupSerializeFunction(BuildCtx & ctx, const char * funcName, IHqlExpression * srcDataset, IHqlExpression * tgtDataset, HqlExprArray & srcValues, HqlExprArray & tgtValues, IHqlExpression * selSeq)
  11822. {
  11823. StringBuffer s;
  11824. BuildCtx r2kctx(ctx);
  11825. s.append("virtual unsigned ").append(funcName).append("(ARowBuilder & crSelf, const void * _src)");
  11826. r2kctx.addQuotedCompound(s);
  11827. ensureRowAllocated(r2kctx, "crSelf");
  11828. r2kctx.addQuoted("const unsigned char * src = (const unsigned char *) _src;");
  11829. BoundRow * tgtCursor = bindSelf(ctx, tgtDataset, "crSelf");
  11830. BoundRow * srcCursor = bindTableCursor(ctx, srcDataset, "src", no_left, selSeq);
  11831. ForEachItemIn(idx2, srcValues)
  11832. {
  11833. Owned<IHqlExpression> self = tgtCursor->bindToRow(&tgtValues.item(idx2), queryActiveTableSelector());
  11834. Owned<IHqlExpression> left = srcCursor->bindToRow(&srcValues.item(idx2), srcDataset);
  11835. buildAssign(r2kctx, self, left);
  11836. }
  11837. buildReturnRecordSize(r2kctx, tgtCursor);
  11838. }
  11839. ABoundActivity * HqlCppTranslator::doBuildActivityDedup(BuildCtx & ctx, IHqlExpression * expr)
  11840. {
  11841. StringBuffer s;
  11842. DedupInfoExtractor info(expr);
  11843. IHqlExpression * dataset = expr->queryChild(0);
  11844. IHqlExpression * selSeq = querySelSeq(expr);
  11845. bool isGrouped = ::isGrouped(dataset);
  11846. bool isLocal = isLocalActivity(expr);
  11847. bool useHash = expr->hasAttribute(hashAtom);
  11848. if (targetThor() && !isGrouped && !isLocal)
  11849. {
  11850. //Should really be done via an attribute on the dedup.
  11851. if (info.compareAllRows && !info.conds.ordinality())
  11852. useHash = true;
  11853. }
  11854. if (useHash && info.conds.ordinality())
  11855. throwError(HQLERR_GlobalDedupFuzzy);
  11856. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  11857. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, useHash ? TAKhashdedup : TAKdedup, expr, useHash ? "HashDedup" : "Dedup");
  11858. buildActivityFramework(instance);
  11859. buildInstancePrefix(instance);
  11860. if (!useHash)
  11861. {
  11862. if (info.compareAllRows)
  11863. doBuildBoolFunction(instance->classctx, "compareAll", info.compareAllRows);
  11864. if (!info.keepLeft)
  11865. doBuildBoolFunction(instance->classctx, "keepLeft", info.keepLeft);
  11866. if (!matchesConstantValue(info.numToKeep, 1))
  11867. doBuildUnsignedFunction(instance->startctx, "numToKeep", info.numToKeep);
  11868. //MORE: If input is grouped (pretty likely), then no need to include fields in the filter function that are already included.
  11869. if (instance->isGrouped)
  11870. {
  11871. HqlExprArray normalizedEqualities;
  11872. ForEachItemIn(i1, info.equalities)
  11873. normalizedEqualities.append(*replaceSelector(info.equalities.item(i1).queryBody(), dataset, queryActiveTableSelector()));
  11874. IHqlExpression * grouping = queryGrouping(dataset);
  11875. ForEachChild(i, grouping)
  11876. {
  11877. IHqlExpression * curGroup = grouping->queryChild(i);
  11878. unsigned match = normalizedEqualities.find(*curGroup);
  11879. if (match != NotFound)
  11880. {
  11881. normalizedEqualities.remove(match);
  11882. info.equalities.remove(match);
  11883. }
  11884. }
  11885. }
  11886. HqlExprArray noEqualities;
  11887. HqlExprArray * equalities = &info.equalities;
  11888. if (info.compareAllRows)
  11889. {
  11890. if (info.equalities.ordinality() && !instance->isGrouped)
  11891. {
  11892. OwnedHqlExpr order = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  11893. buildCompareMember(instance->nestedctx, "ComparePrimary", order, DatasetReference(dataset));
  11894. if (!targetThor())
  11895. equalities = &noEqualities;
  11896. }
  11897. }
  11898. buildDedupFilterFunction(instance->startctx, *equalities, info.conds, dataset, selSeq);
  11899. }
  11900. else
  11901. {
  11902. if (info.equalities.ordinality() == 0)
  11903. throwError(HQLERR_GlobalDedupNoEquality);
  11904. if (!matchesConstantValue(info.numToKeep, 1))
  11905. throwError1(HQLERR_HashDedupNotSupportX, "KEEP");
  11906. if (!info.keepLeft)
  11907. throwError1(HQLERR_HashDedupNotSupportX, "RIGHT");
  11908. OwnedHqlExpr order = createValueSafe(no_sortlist, makeSortListType(NULL), info.equalities);
  11909. buildCompareMember(instance->nestedctx, "Compare", order, DatasetReference(dataset));
  11910. buildHashOfExprsClass(instance->nestedctx, "Hash", order, DatasetReference(dataset), true);
  11911. HqlExprArray fields, selects;
  11912. ForEachItemIn(idx, info.equalities)
  11913. {
  11914. IHqlExpression & cur = info.equalities.item(idx);
  11915. IHqlExpression * field;
  11916. if ((cur.getOperator() == no_select) && (cur.queryChild(0) == dataset->queryNormalizedSelector()))
  11917. field = LINK(cur.queryChild(1));
  11918. else
  11919. {
  11920. StringBuffer name;
  11921. name.append("_expression_").append(idx);
  11922. field = createField(createIdAtom(name.str()), cur.getType(), NULL);
  11923. }
  11924. fields.append(*field);
  11925. selects.append(*createSelectExpr(getActiveTableSelector(), LINK(field)));
  11926. }
  11927. OwnedHqlExpr keyDataset = createDataset(no_anon, createRecord(fields));
  11928. //virtual IOutputMetaData * queryKeySize()
  11929. buildMetaMember(instance->classctx, keyDataset, false, "queryKeySize");
  11930. //virtual unsigned recordToKey(void * _key, const void * _record)
  11931. buildDedupSerializeFunction(instance->startctx, "recordToKey", dataset, keyDataset, info.equalities, selects, selSeq);
  11932. //virtual ICompare * queryKeyCompare()
  11933. bool reuseCompare = false;
  11934. OwnedHqlExpr keyOrder = createValueSafe(no_sortlist, makeSortListType(NULL), selects);
  11935. if (recordTypesMatch(dataset, keyDataset))
  11936. {
  11937. OwnedHqlExpr globalOrder = replaceSelector(order, dataset, queryActiveTableSelector());
  11938. if (keyOrder == globalOrder)
  11939. reuseCompare = true;
  11940. }
  11941. if (!reuseCompare)
  11942. buildCompareMember(instance->nestedctx, "KeyCompare", keyOrder, DatasetReference(keyDataset, no_activetable, NULL));
  11943. else
  11944. instance->nestedctx.addQuoted("virtual ICompare * queryKeyCompare() { return &Compare; }");
  11945. //virtual unsigned getFlags() = 0;
  11946. {
  11947. StringBuffer flags;
  11948. if (recordTypesMatch(dataset, keyDataset)) flags.append("|HFDwholerecord");
  11949. if (flags.length())
  11950. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  11951. }
  11952. //virtual IHash * queryKeyHash()=0;
  11953. if (reuseCompare)
  11954. instance->nestedctx.addQuoted("virtual IHash * queryKeyHash() { return &Hash; }");
  11955. else
  11956. buildHashOfExprsClass(instance->nestedctx, "KeyHash", keyOrder, DatasetReference(keyDataset, no_activetable, NULL), true);
  11957. //virtual ICompare * queryRowKeyCompare()=0; // lhs is a row, rhs is a key
  11958. if (!reuseCompare)
  11959. {
  11960. doCompareLeftRight(instance->nestedctx, "RowKeyCompare", DatasetReference(dataset), DatasetReference(keyDataset, no_activetable, NULL), info.equalities, selects);
  11961. }
  11962. else
  11963. instance->nestedctx.addQuoted("virtual ICompare * queryRowKeyCompare() { return &Compare; }");
  11964. }
  11965. buildInstanceSuffix(instance);
  11966. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  11967. return instance->getBoundActivity();
  11968. }
  11969. //---------------------------------------------------------------------------
  11970. // no_distribute
  11971. ABoundActivity * HqlCppTranslator::doBuildActivityDistribute(BuildCtx & ctx, IHqlExpression * expr)
  11972. {
  11973. if (!targetThor() || insideChildQuery(ctx))
  11974. return buildCachedActivity(ctx, expr->queryChild(0));
  11975. StringBuffer s;
  11976. IHqlExpression * dataset = expr->queryChild(0);
  11977. if (isUngroup(dataset))
  11978. dataset = dataset->queryChild(0);
  11979. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  11980. IHqlExpression * cond = expr->queryChild(1);
  11981. IHqlExpression * mergeOrder = queryAttributeChild(expr, mergeAtom, 0);
  11982. if (cond->getOperator() == no_sortpartition)
  11983. {
  11984. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKpartition, expr, "Merge");
  11985. buildActivityFramework(instance);
  11986. buildInstancePrefix(instance);
  11987. HqlExprArray sorts;
  11988. unwindChildren(sorts, cond);
  11989. OwnedHqlExpr sortOrder = createValueSafe(no_sortlist, makeSortListType(NULL), sorts);
  11990. instance->startctx.addQuoted("virtual ICompare * queryCompare() { return &compare; }");
  11991. DatasetReference dsRef(dataset);
  11992. buildCompareClass(instance->nestedctx, "compare", sortOrder, dsRef);
  11993. if (!instance->isLocal)
  11994. generateSerializeKey(instance->nestedctx, no_none, dsRef, sorts, true, true, false);
  11995. buildInstanceSuffix(instance);
  11996. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  11997. return instance->getBoundActivity();
  11998. }
  11999. else
  12000. {
  12001. //Now generate the instance definition...
  12002. ThorActivityKind tak = (expr->getOperator() == no_distribute) ?
  12003. (mergeOrder ? TAKhashdistributemerge : TAKhashdistribute) : TAKdistributed;
  12004. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "HashDistribute");
  12005. if (expr->hasAttribute(skewAtom))
  12006. instance->graphLabel.set("Skew Distribute");
  12007. buildActivityFramework(instance);
  12008. buildInstancePrefix(instance);
  12009. if (!expr->hasAttribute(skewAtom))
  12010. buildHashClass(instance->nestedctx, "Hash", cond, DatasetReference(dataset));
  12011. doBuildBoolFunction(instance->classctx, "isPulled", expr->hasAttribute(pulledAtom));
  12012. buildSkewThresholdMembers(instance->classctx, expr);
  12013. if (mergeOrder)
  12014. buildCompareMember(instance->nestedctx, "MergeCompare", mergeOrder, DatasetReference(dataset));
  12015. buildInstanceSuffix(instance);
  12016. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12017. return instance->getBoundActivity();
  12018. }
  12019. }
  12020. //---------------------------------------------------------------------------
  12021. // no_rollup
  12022. void HqlCppTranslator::checkAmbiguousRollupCondition(IHqlExpression * expr)
  12023. {
  12024. IHqlExpression * select = queryAmbiguousRollupCondition(expr, false);
  12025. if (select)
  12026. {
  12027. IHqlExpression * dataset = expr->queryChild(0);
  12028. OwnedHqlExpr newSelect = replaceSelector(select, dataset->queryNormalizedSelector(), queryActiveTableSelector());
  12029. StringBuffer selectText;
  12030. getExprECL(newSelect, selectText);
  12031. reportWarning(queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupCondition), selectText.str());
  12032. }
  12033. }
  12034. ABoundActivity * HqlCppTranslator::doBuildActivityRollup(BuildCtx & ctx, IHqlExpression * expr)
  12035. {
  12036. StringBuffer s;
  12037. IHqlExpression * dataset = expr->queryChild(0);
  12038. IHqlExpression * cond = expr->queryChild(1);
  12039. IHqlExpression * transform = expr->queryChild(2);
  12040. IHqlExpression * selSeq = querySelSeq(expr);
  12041. HqlExprArray equalities;
  12042. HqlExprArray conds;
  12043. if (cond->getOperator() == no_sortlist)
  12044. unwindChildren(conds, cond);
  12045. else
  12046. conds.append(*LINK(cond));
  12047. //build child table....
  12048. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12049. //Now generate the instance definition...
  12050. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKrollup, expr, "Rollup");
  12051. buildActivityFramework(instance);
  12052. buildInstancePrefix(instance);
  12053. if (options.checkAmbiguousRollupCondition)
  12054. checkAmbiguousRollupCondition(expr);
  12055. buildDedupFilterFunction(instance->startctx, equalities, conds, dataset, selSeq);
  12056. buildRollupTransformFunction(instance->startctx, dataset, transform, selSeq);
  12057. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  12058. OwnedHqlExpr right = createSelector(no_right, dataset, selSeq);
  12059. StringBuffer flags;
  12060. if (cond->usesSelector(left) || cond->usesSelector(right))
  12061. flags.append("|RFrolledismatchleft");
  12062. if (flags.length())
  12063. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  12064. buildInstanceSuffix(instance);
  12065. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12066. return instance->getBoundActivity();
  12067. }
  12068. //---------------------------------------------------------------------------
  12069. // no_denormalize
  12070. ABoundActivity * HqlCppTranslator::doBuildActivityDenormalize(BuildCtx & ctx, IHqlExpression * expr)
  12071. {
  12072. if (isKeyedJoin(expr))
  12073. return doBuildActivityKeyedJoinOrDenormalize(ctx, expr);
  12074. return doBuildActivityJoinOrDenormalize(ctx, expr);
  12075. }
  12076. //---------------------------------------------------------------------------
  12077. ABoundActivity * HqlCppTranslator::doBuildActivityFirstN(BuildCtx & ctx, IHqlExpression * expr)
  12078. {
  12079. IHqlExpression * dataset = expr->queryChild(0);
  12080. IHqlExpression * limit = expr->queryChild(1);
  12081. //choosen(x,ALL) does nothing, but is a way of getting round the implicit limitation.
  12082. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12083. if (isChooseNAllLimit(limit) && !expr->queryChild(2))
  12084. return boundDataset.getClear();
  12085. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfirstn, expr, "FirstN");
  12086. buildActivityFramework(instance);
  12087. buildInstancePrefix(instance);
  12088. BuildCtx funcctx(instance->startctx);
  12089. funcctx.addQuotedCompound("virtual __int64 getLimit()");
  12090. OwnedHqlExpr newLimit = ensurePositiveOrZeroInt64(limit);
  12091. if (options.spotCSE)
  12092. newLimit.setown(spotScalarCSE(newLimit));
  12093. buildReturn(funcctx, newLimit);
  12094. if (queryRealChild(expr, 2))
  12095. {
  12096. OwnedHqlExpr adjusted = adjustValue(expr->queryChild(2), -1);
  12097. OwnedHqlExpr newAdjusted = ensurePositiveOrZeroInt64(adjusted);
  12098. BuildCtx funcctx(instance->startctx);
  12099. funcctx.addQuotedCompound("virtual __int64 numToSkip()");
  12100. buildReturn(funcctx, newAdjusted);
  12101. }
  12102. if (expr->hasAttribute(groupedAtom))
  12103. doBuildBoolFunction(instance->classctx, "preserveGrouping", true);
  12104. buildInstanceSuffix(instance);
  12105. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12106. return instance->getBoundActivity();
  12107. }
  12108. //---------------------------------------------------------------------------
  12109. ABoundActivity * HqlCppTranslator::doBuildActivityChooseSetsEx(BuildCtx & ctx, IHqlExpression * expr)
  12110. {
  12111. IHqlExpression * dataset = expr->queryChild(0);
  12112. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12113. bool isEnth = expr->hasAttribute(enthAtom);
  12114. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, isEnth ? TAKchoosesetsenth : TAKchoosesetslast, expr, "ChooseSetsEx");
  12115. buildActivityFramework(instance);
  12116. buildInstancePrefix(instance);
  12117. unsigned numArgs = expr->numChildren();
  12118. bool keepExtras = false;
  12119. unsigned numConditions = 0;
  12120. for (unsigned idx1 = 1; idx1 < numArgs; idx1++)
  12121. {
  12122. switch (expr->queryChild(idx1)->getOperator())
  12123. {
  12124. case no_mapto:
  12125. numConditions++;
  12126. break;
  12127. case no_attr:
  12128. break;
  12129. default:
  12130. keepExtras = true;
  12131. }
  12132. }
  12133. unsigned numCategories = numConditions + (keepExtras ? 1 : 0);
  12134. //virtual unsigned getNumSets()
  12135. BuildCtx funcctx(instance->classctx);
  12136. funcctx.addQuotedCompound("virtual unsigned getNumSets()");
  12137. OwnedHqlExpr numExpr = createConstant((int)numCategories);
  12138. buildReturn(funcctx, numExpr, unsignedType);
  12139. //virtual unsigned getRecordCategory(const void * _self) = 0;
  12140. BuildCtx categoryctx(instance->startctx);
  12141. categoryctx.addQuotedCompound("virtual unsigned getCategory(const void * _self)");
  12142. categoryctx.addQuoted("const unsigned char * self = (const unsigned char *)_self;");
  12143. bindTableCursor(categoryctx, dataset, "self");
  12144. HqlExprArray args;
  12145. for (unsigned idx3 = 1; idx3 <= numConditions; idx3++)
  12146. {
  12147. IHqlExpression * cur = expr->queryChild(idx3);
  12148. args.append(*createValue(no_mapto, makeVoidType(), LINK(cur->queryChild(0)), createConstant(unsignedType->castFrom(false, (__int64)idx3))));
  12149. }
  12150. if (keepExtras)
  12151. args.append(*createConstant((__int64)numConditions+1));
  12152. else
  12153. args.append(*createConstant((__int64)0));
  12154. OwnedHqlExpr map = createValue(no_map, LINK(unsignedType), args);
  12155. buildReturn(categoryctx, map);
  12156. //virtual void getLimits(unsigned * counts) = 0;
  12157. BuildCtx limitctx(instance->startctx);
  12158. StringBuffer s;
  12159. limitctx.addQuotedCompound("virtual void getLimits(__int64 * counts)");
  12160. for (unsigned idx2 = 1; idx2 <= numCategories; idx2++)
  12161. {
  12162. IHqlExpression * cur = expr->queryChild(idx2);
  12163. s.clear().append("counts[").append(idx2-1).append("]");
  12164. OwnedHqlExpr target = createVariable(s.str(), LINK(defaultIntegralType));
  12165. switch (cur->getOperator())
  12166. {
  12167. case no_mapto:
  12168. buildAssignToTemp(limitctx, target, cur->queryChild(1));
  12169. break;
  12170. default:
  12171. buildAssignToTemp(limitctx, target, cur);
  12172. break;
  12173. }
  12174. }
  12175. buildInstanceSuffix(instance);
  12176. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12177. return instance->getBoundActivity();
  12178. }
  12179. ABoundActivity * HqlCppTranslator::doBuildActivityChooseSets(BuildCtx & ctx, IHqlExpression * expr)
  12180. {
  12181. if (expr->hasAttribute(enthAtom) || expr->hasAttribute(lastAtom))
  12182. return doBuildActivityChooseSetsEx(ctx, expr);
  12183. IHqlExpression * dataset = expr->queryChild(0);
  12184. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12185. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKchoosesets, expr, "ChooseSets");
  12186. buildActivityFramework(instance);
  12187. buildInstancePrefix(instance);
  12188. unsigned numArgs = expr->numChildren();
  12189. bool allowSpill = !expr->hasAttribute(exclusiveAtom);
  12190. bool keepExtras = false;
  12191. unsigned numConditions = 0;
  12192. for (unsigned idx1 = 1; idx1 < numArgs; idx1++)
  12193. {
  12194. switch (expr->queryChild(idx1)->getOperator())
  12195. {
  12196. case no_mapto:
  12197. numConditions++;
  12198. break;
  12199. case no_attr:
  12200. case no_attr_expr:
  12201. case no_attr_link:
  12202. break;
  12203. default:
  12204. keepExtras = true;
  12205. }
  12206. }
  12207. unsigned numCategories = numConditions + (keepExtras ? 1 : 0);
  12208. BuildCtx funcctx(instance->classctx);
  12209. funcctx.addQuotedCompound("virtual unsigned getNumSets()");
  12210. OwnedHqlExpr numExpr = createConstant((int)numCategories);
  12211. buildReturn(funcctx, numExpr, unsignedType);
  12212. StringBuffer s;
  12213. BuildCtx limitctx(instance->classctx);
  12214. instance->startctx.addQuoted("unsigned * counts;");
  12215. instance->startctx.addQuoted("unsigned numFull;");
  12216. limitctx.addQuotedCompound("virtual bool setCounts(unsigned * data)");
  12217. limitctx.addQuoted("counts = data;");
  12218. limitctx.addQuoted("numFull = 0;");
  12219. OwnedHqlExpr tally = createVariable("counts", makeIntType(4, false));
  12220. BuildCtx validctx(instance->startctx);
  12221. validctx.addQuotedCompound("virtual unsigned getRecordAction(const void * _self)");
  12222. validctx.addQuoted("const unsigned char * self = (const unsigned char *)_self;");
  12223. bindTableCursor(validctx, dataset, "self");
  12224. OwnedHqlExpr one = createConstant((int)1);
  12225. for (unsigned idx = 0; idx < numCategories; idx++)
  12226. {
  12227. OwnedHqlExpr indexExpr = getSizetConstant(idx);
  12228. OwnedHqlExpr bucketExpr = createValue(no_index, LINK(unsignedType), tally.getLink(), indexExpr.getLink());
  12229. OwnedHqlExpr transBucketExpr = createTranslated(bucketExpr);
  12230. IHqlExpression * arg = expr->queryChild(idx+1);
  12231. IHqlExpression * count = (arg->getOperator() == no_mapto ? arg->queryChild(1) : arg);
  12232. OwnedHqlExpr cond2 = createBoolExpr(no_lt, transBucketExpr.getLink(), ensureExprType(count, unsignedType));
  12233. OwnedHqlExpr condDone = createBoolExpr(no_eq, transBucketExpr.getLink(), ensureExprType(count, unsignedType));
  12234. BuildCtx condctx(validctx);
  12235. if (arg->getOperator() == no_mapto)
  12236. {
  12237. IHqlExpression * filter = arg->queryChild(0);
  12238. if (allowSpill)
  12239. {
  12240. OwnedHqlExpr cond = createBoolExpr(no_and, LINK(filter), cond2.getLink());
  12241. CHqlBoundExpr bound;
  12242. buildExpr(condctx, cond, bound);
  12243. condctx.addFilter(bound.expr);
  12244. }
  12245. else
  12246. {
  12247. buildFilter(condctx, filter);
  12248. BuildCtx failctx(condctx);
  12249. buildFilter(condctx, cond2);
  12250. buildReturn(failctx, queryZero());
  12251. }
  12252. }
  12253. else
  12254. {
  12255. buildFilter(condctx, cond2);
  12256. }
  12257. OwnedHqlExpr inc = createValue(no_postinc, bucketExpr.getLink());
  12258. condctx.addExpr(inc);
  12259. BuildCtx doneCtx(condctx);
  12260. buildFilter(doneCtx, condDone);
  12261. doneCtx.addQuoted(s.clear().append("if (++numFull == ").append(numCategories).append(") return 2;"));
  12262. buildReturn(condctx, one, unsignedType);
  12263. BuildCtx limitCondCtx(limitctx);
  12264. buildFilter(limitCondCtx, condDone);
  12265. limitCondCtx.addQuoted("numFull++;");
  12266. }
  12267. buildReturn(validctx, queryZero());
  12268. limitctx.addQuoted(s.clear().append("return numFull == ").append(numCategories).append(";"));
  12269. buildInstanceSuffix(instance);
  12270. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12271. return instance->getBoundActivity();
  12272. }
  12273. //---------------------------------------------------------------------------
  12274. ABoundActivity * HqlCppTranslator::doBuildActivityNormalizeGroup(BuildCtx & ctx, IHqlExpression * expr)
  12275. {
  12276. throwUnexpected();
  12277. IHqlExpression * dataset = expr->queryChild(0);
  12278. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12279. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalize, expr,"Normalize");
  12280. buildActivityFramework(instance);
  12281. buildInstancePrefix(instance);
  12282. buildInstanceSuffix(instance);
  12283. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12284. return instance->getBoundActivity();
  12285. }
  12286. //---------------------------------------------------------------------------
  12287. ABoundActivity * HqlCppTranslator::doBuildActivityNormalize(BuildCtx & ctx, IHqlExpression * expr)
  12288. {
  12289. IHqlExpression * numRows = expr->queryChild(1);
  12290. if (!numRows->queryType()->isScalar())
  12291. return doBuildActivityNormalizeChild(ctx, expr);
  12292. IHqlExpression * dataset = expr->queryChild(0);
  12293. IHqlExpression * transform = expr->queryChild(2);
  12294. IHqlExpression * selSeq = querySelSeq(expr);
  12295. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12296. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalize, expr,"Normalize");
  12297. buildActivityFramework(instance);
  12298. buildInstancePrefix(instance);
  12299. BuildCtx funcctx(instance->startctx);
  12300. funcctx.addQuotedCompound("virtual unsigned numExpandedRows(const void * _left)");
  12301. funcctx.addQuoted("unsigned char * left = (unsigned char *) _left;");
  12302. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  12303. bindTableCursor(funcctx, dataset, "left");
  12304. buildReturn(funcctx, numRows);
  12305. BuildCtx transformctx(instance->startctx);
  12306. transformctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned counter)");
  12307. ensureRowAllocated(transformctx, "crSelf");
  12308. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12309. associateCounter(transformctx, counter, "counter");
  12310. buildTransformBody(transformctx, transform, dataset, NULL, instance->dataset, selSeq);
  12311. buildInstanceSuffix(instance);
  12312. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12313. return instance->getBoundActivity();
  12314. }
  12315. //---------------------------------------------------------------------------
  12316. ABoundActivity * HqlCppTranslator::doBuildActivityNormalizeChild(BuildCtx & ctx, IHqlExpression * expr)
  12317. {
  12318. IHqlExpression * dataset = expr->queryChild(0);
  12319. LinkedHqlExpr childDataset = expr->queryChild(1);
  12320. IHqlExpression * transform = expr->queryChild(2);
  12321. IHqlExpression * selSeq = querySelSeq(expr);
  12322. if (transformReturnsSide(expr, no_right, 1))
  12323. return doBuildActivityNormalizeLinkedChild(ctx, expr);
  12324. StringBuffer s;
  12325. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12326. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalizechild, expr,"NormalizeChild");
  12327. buildActivityFramework(instance);
  12328. buildInstancePrefix(instance);
  12329. //Generate queryChildRecordSize();
  12330. buildMetaMember(instance->classctx, childDataset, isGrouped(childDataset), "queryChildRecordSize");
  12331. // INormalizeChildIterator * queryIterator();
  12332. {
  12333. bool outOfLine = true;
  12334. if (childDataset->isDatarow())
  12335. childDataset.setown(createDatasetFromRow(childDataset.getClear()));
  12336. if (childDataset->getOperator() == no_select)
  12337. outOfLine = isArrayRowset(childDataset->queryType());
  12338. if (hasLinkCountedModifier(childDataset))
  12339. outOfLine = true;
  12340. BuildCtx iterclassctx(instance->nestedctx);
  12341. StringBuffer memberName, className;
  12342. getUniqueId(memberName.append("m"));
  12343. getMemberClassName(className, memberName.str());
  12344. ExpressionFormat format;
  12345. if (outOfLine)
  12346. {
  12347. beginNestedClass(iterclassctx, memberName, "CNormalizeLinkedChildIterator");
  12348. format = FormatLinkedDataset;
  12349. }
  12350. else
  12351. {
  12352. beginNestedClass(iterclassctx, memberName, "CNormalizeChildIterator");
  12353. format = FormatBlockedDataset;
  12354. MetaInstance childmeta(*this, childDataset->queryRecord(), isGrouped(childDataset));
  12355. buildMetaInfo(childmeta);
  12356. s.clear().append(className).append("() : CNormalizeChildIterator(").append(childmeta.queryInstanceObject()).append(") {}");
  12357. iterclassctx.addQuoted(s);
  12358. }
  12359. bool callFromActivity = false;
  12360. BuildCtx activityinitctx(instance->startctx);
  12361. BuildCtx funcctx(iterclassctx);
  12362. funcctx.addQuotedCompound("virtual void init(const void * _left)");
  12363. funcctx.addQuoted("const byte * left = (const byte *)_left;");
  12364. CHqlBoundExpr bound;
  12365. if (childDataset->getOperator() != no_select)
  12366. {
  12367. //Ugly......
  12368. //If this is a complex expression, then ensure the temporary variable is a member of the activity class, and
  12369. //evaluate it in the function defined inside the activity (so the member variables don't need mangling)
  12370. funcctx.addQuoted("activity->init(left);");
  12371. BuildCtx * declarectx = NULL;
  12372. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, NULL, false, true);
  12373. queryEvalContext(iterclassctx)->ensureHelpersExist();
  12374. assertex(declarectx);
  12375. activityinitctx.addQuotedCompound("void init(const byte * left)");
  12376. bindTableCursor(activityinitctx, dataset, "left", no_left, selSeq);
  12377. CHqlBoundTarget tempTarget;
  12378. buildTempExpr(activityinitctx, *declarectx, tempTarget, childDataset, format, false);
  12379. bound.setFromTarget(tempTarget);
  12380. callFromActivity = true;
  12381. }
  12382. else
  12383. {
  12384. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  12385. buildDataset(funcctx, childDataset, bound, format);
  12386. }
  12387. s.clear();
  12388. if (callFromActivity)
  12389. s.append(memberName).append(".");
  12390. s.append("setDataset(");
  12391. if (outOfLine)
  12392. {
  12393. generateExprCpp(s, bound.count).append(",");
  12394. generateExprCpp(s, bound.expr).append(");");
  12395. }
  12396. else
  12397. {
  12398. OwnedHqlExpr length = getBoundLength(bound);
  12399. generateExprCpp(s, length).append(",");
  12400. generateExprCpp(s, bound.expr).append(");");
  12401. }
  12402. if (callFromActivity)
  12403. activityinitctx.addQuoted(s);
  12404. else
  12405. funcctx.addQuoted(s);
  12406. endNestedClass();
  12407. s.clear().append("INormalizeChildIterator * queryIterator() { return &").append(memberName).append("; }");
  12408. instance->startctx.addQuoted(s);
  12409. }
  12410. BuildCtx transformctx(instance->startctx);
  12411. transformctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned counter)");
  12412. ensureRowAllocated(transformctx, "crSelf");
  12413. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12414. associateCounter(transformctx, counter, "counter");
  12415. buildTransformBody(transformctx, transform, dataset, childDataset, instance->dataset, selSeq);
  12416. buildInstanceSuffix(instance);
  12417. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12418. return instance->getBoundActivity();
  12419. }
  12420. //---------------------------------------------------------------------------
  12421. ABoundActivity * HqlCppTranslator::doBuildActivityNormalizeLinkedChild(BuildCtx & ctx, IHqlExpression * expr)
  12422. {
  12423. OwnedHqlExpr dataset;
  12424. OwnedHqlExpr childDataset;
  12425. node_operator selectorOp = no_none;
  12426. IHqlExpression * selSeq = NULL;
  12427. switch (expr->getOperator())
  12428. {
  12429. case no_select:
  12430. {
  12431. bool isNew;
  12432. dataset.set(querySelectorDataset(expr, isNew));
  12433. //Ensure input is a dataset so cleanly bound as a cursor later
  12434. if (dataset->isDatarow())
  12435. dataset.setown(createDatasetFromRow(dataset.getClear()));
  12436. assertex(isNew);
  12437. OwnedHqlExpr active = ensureActiveRow(dataset);
  12438. childDataset.setown(replaceSelectorDataset(expr, active));
  12439. break;
  12440. }
  12441. case no_normalize:
  12442. {
  12443. dataset.set(expr->queryChild(0));
  12444. childDataset.set(expr->queryChild(1));
  12445. selectorOp = no_left;
  12446. selSeq = querySelSeq(expr);
  12447. break;
  12448. }
  12449. default:
  12450. throwUnexpectedOp(expr->getOperator());
  12451. }
  12452. StringBuffer s;
  12453. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12454. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKnormalizelinkedchild, expr,"NormalizeLinkedChild");
  12455. buildActivityFramework(instance);
  12456. buildInstancePrefix(instance);
  12457. OwnedHqlExpr value = childDataset->isDatarow() ? createDatasetFromRow(LINK(childDataset)) : LINK(childDataset);
  12458. BuildCtx * declarectx = NULL;
  12459. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, NULL, false, true);
  12460. assertex(declarectx);
  12461. CHqlBoundTarget childTarget;
  12462. CHqlBoundExpr boundChild;
  12463. CHqlBoundTarget boundActive;
  12464. createTempFor(*declarectx, value->queryType(), childTarget, typemod_none, FormatLinkedDataset);
  12465. boundChild.setFromTarget(childTarget);
  12466. assertex(boundChild.count != NULL);
  12467. OwnedHqlExpr test;
  12468. OwnedHqlExpr ret;
  12469. //virtual byte * first(const void * parentRecord) = 0;
  12470. {
  12471. BuildCtx firstctx(instance->startctx);
  12472. firstctx.addQuotedCompound("virtual byte * first(const void * parentRecord)");
  12473. firstctx.addQuoted("const byte * left = (const byte *)parentRecord;");
  12474. bindTableCursor(firstctx, dataset, "left", selectorOp, selSeq);
  12475. buildDatasetAssign(firstctx, childTarget, value);
  12476. OwnedHqlExpr zero = getSizetConstant(0);
  12477. buildTempExpr(firstctx, *declarectx, boundActive, zero, FormatNatural, false);
  12478. test.setown(createValue(no_lt, makeBoolType(), LINK(boundActive.expr), LINK(boundChild.count)));
  12479. ret.setown(createValue(no_index, expr->getType(), LINK(boundChild.expr), LINK(boundActive.expr)));
  12480. BuildCtx subctx(firstctx);
  12481. subctx.addFilter(test);
  12482. subctx.addReturn(ret);
  12483. firstctx.addReturn(queryQuotedNullExpr());
  12484. }
  12485. {
  12486. //virtual byte * next() = 0;
  12487. BuildCtx nextctx(instance->startctx);
  12488. nextctx.addQuotedCompound("virtual byte * next()");
  12489. OwnedHqlExpr inc = createValue(no_postinc, LINK(sizetType), LINK(boundActive.expr));
  12490. nextctx.addExpr(inc);
  12491. BuildCtx subctx(nextctx);
  12492. subctx.addFilter(test);
  12493. subctx.addReturn(ret);
  12494. nextctx.addReturn(queryQuotedNullExpr());
  12495. }
  12496. buildInstanceSuffix(instance);
  12497. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12498. return instance->getBoundActivity();
  12499. }
  12500. //---------------------------------------------------------------------------
  12501. ABoundActivity * HqlCppTranslator::doBuildActivitySelectNew(BuildCtx & ctx, IHqlExpression * expr)
  12502. {
  12503. if (!expr->isDatarow())
  12504. return doBuildActivityNormalizeLinkedChild(ctx, expr);
  12505. bool isNew = false;
  12506. IHqlExpression * dataset = querySelectorDataset(expr, isNew);
  12507. assertex(isNew);
  12508. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12509. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKproject, expr, "Project");
  12510. buildActivityFramework(instance);
  12511. buildInstancePrefix(instance);
  12512. {
  12513. //Need to create a dataset to replace the parent selector - since it might be a row
  12514. OwnedHqlExpr anon = createDataset(no_anon, LINK(dataset->queryRecord()));
  12515. BuildCtx funcctx(instance->startctx);
  12516. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  12517. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  12518. ensureRowAllocated(funcctx, "crSelf");
  12519. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  12520. bindTableCursor(funcctx, anon->queryNormalizedSelector(), "left");
  12521. OwnedHqlExpr activeAnon = ensureActiveRow(anon);
  12522. OwnedHqlExpr value = replaceSelectorDataset(expr, activeAnon);
  12523. buildAssign(funcctx, selfCursor->querySelector(), value);
  12524. buildReturnRecordSize(funcctx, selfCursor);
  12525. }
  12526. buildInstanceSuffix(instance);
  12527. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12528. return instance->getBoundActivity();
  12529. }
  12530. //---------------------------------------------------------------------------
  12531. ABoundActivity * HqlCppTranslator::doBuildActivityPrefetchProject(BuildCtx & ctx, IHqlExpression * expr)
  12532. {
  12533. IHqlExpression * dataset = expr->queryChild(0);
  12534. IHqlExpression * transform = queryNewColumnProvider(expr);
  12535. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12536. IHqlExpression * selSeq = querySelSeq(expr);
  12537. IHqlExpression * prefetch = expr->queryAttribute(prefetchAtom);
  12538. IHqlExpression * lookahead = queryAttributeChild(expr, prefetchAtom, 0);
  12539. IHqlExpression * record = expr->queryRecord();
  12540. #ifdef _DEBUG
  12541. assertex((counter != NULL) == transformContainsCounter(transform, counter));
  12542. #endif
  12543. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12544. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, counter ? TAKprefetchcountproject : TAKprefetchproject, expr, "PrefetchProject");
  12545. buildActivityFramework(instance);
  12546. buildInstancePrefix(instance);
  12547. StringBuffer flags;
  12548. if (prefetch && prefetch->hasAttribute(parallelAtom)) flags.append("|PPFparallel");
  12549. if (flags.length())
  12550. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  12551. if (transformContainsSkip(transform))
  12552. doBuildBoolFunction(instance->classctx, "canFilter", true);
  12553. if (lookahead)
  12554. doBuildUnsignedFunction(instance->startctx, "getLookahead", lookahead);
  12555. //Similar code to project below. First generate the post processing function (which all aliases etc. will get generated into)
  12556. BuildCtx postctx(instance->startctx);
  12557. postctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IEclGraphResults * results, unsigned __int64 _counter)");
  12558. ensureRowAllocated(postctx, "crSelf");
  12559. postctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  12560. if (expr->getOperator() == no_hqlproject)
  12561. bindTableCursor(postctx, dataset, "left", no_left, selSeq);
  12562. else
  12563. bindTableCursor(postctx, dataset, "left");
  12564. BoundRow * selfCursor = bindSelf(postctx, expr, "crSelf");
  12565. associateSkipReturnMarker(postctx, queryZero(), selfCursor);
  12566. if (counter)
  12567. associateCounter(postctx, counter, "counter");
  12568. //Now process the transform
  12569. HqlExprArray assigns;
  12570. //Introduce a scope to ensure that mapper and builder have the minimum lifetime.
  12571. {
  12572. //Possibly cleaner if this was implemented inside a class derived from TransformBuilder
  12573. TransformBuilder builder(*this, postctx, record, selfCursor, assigns);
  12574. filterExpandAssignments(postctx, &builder, assigns, transform);
  12575. builder.buildTransformChildren(postctx, record, selfCursor->querySelector());
  12576. OwnedHqlExpr subgraph = builder.getPrefetchGraph();
  12577. if (subgraph)
  12578. {
  12579. //Generate the extract preparation function
  12580. BuildCtx prectx(instance->startctx);
  12581. IHqlStmt * preStmt = prectx.addQuotedCompound("virtual bool preTransform(rtlRowBuilder & builder, const void * _left, unsigned __int64 _counter)");
  12582. associateSkipReturnMarker(prectx, queryBoolExpr(false), NULL);
  12583. prectx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  12584. if (expr->getOperator() == no_hqlproject)
  12585. bindTableCursor(prectx, dataset, "left", no_left, selSeq);
  12586. else
  12587. bindTableCursor(prectx, dataset, "left");
  12588. if (counter)
  12589. associateCounter(prectx, counter, "counter");
  12590. OwnedHqlExpr graphInstance;
  12591. ChildGraphBuilder graphBuilder(*this, subgraph);
  12592. graphBuilder.generatePrefetchGraph(prectx, &graphInstance);
  12593. prectx.addReturn(queryBoolExpr(true));
  12594. BuildCtx childctx(instance->startctx);
  12595. childctx.addQuotedCompound("virtual IThorChildGraph *queryChild()");
  12596. childctx.addReturn(graphInstance);
  12597. //Add an association for the results into the transform function.
  12598. IHqlExpression * graph = subgraph->queryChild(0);
  12599. OwnedHqlExpr results = createAttribute(resultsAtom, LINK(graph));
  12600. OwnedHqlExpr resultsInstanceExpr = createQuoted("results", makeBoolType());
  12601. postctx.associateExpr(results, resultsInstanceExpr);
  12602. }
  12603. builder.flush(postctx);
  12604. }
  12605. buildReturnRecordSize(postctx, selfCursor);
  12606. buildInstanceSuffix(instance);
  12607. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12608. return instance->getBoundActivity();
  12609. }
  12610. ABoundActivity * HqlCppTranslator::doBuildActivityProject(BuildCtx & ctx, IHqlExpression * expr)
  12611. {
  12612. if (expr->hasAttribute(prefetchAtom) || options.usePrefetchForAllProjects)
  12613. return doBuildActivityPrefetchProject(ctx, expr);
  12614. const node_operator op = expr->getOperator();
  12615. IHqlExpression * dataset = expr->queryChild(0);
  12616. IHqlExpression * normalized = dataset->queryNormalizedSelector();
  12617. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  12618. IHqlExpression * selSeq = querySelSeq(expr);
  12619. LinkedHqlExpr transform = queryNewColumnProvider(expr);
  12620. LinkedHqlExpr invariantCondition;
  12621. HqlExprArray filterConditions;
  12622. OwnedHqlExpr leftSelector = (op != no_newusertable) ? createSelector(no_left, normalized, selSeq) : NULL;
  12623. //Spot any filters preceding this project/user table, and fold them into the project
  12624. //It doesn't work with count projects though - because it would alter the counter passed to the transform.
  12625. //MORE: It would be possible to spot a skip condition for a count project which was input invariant, but thor
  12626. //would need a new implementation if the input wasn't grouped because the count would need to be global.
  12627. if (!counter)
  12628. {
  12629. bool done = false;
  12630. do
  12631. {
  12632. switch (dataset->getOperator())
  12633. {
  12634. case no_filter:
  12635. {
  12636. LinkedHqlExpr invariant;
  12637. OwnedHqlExpr cond = extractFilterConditions(invariant, dataset, normalized, false);
  12638. //A dataset invariant filter is only worth combining if the engine supports a filtered project operation.
  12639. if (!options.supportFilterProject && invariant)
  12640. {
  12641. done = true;
  12642. break;
  12643. }
  12644. //Don't merge the condition if it would create an ambiguity on LEFT - highly unlikely to occur in practice
  12645. if (leftSelector && cond)
  12646. {
  12647. if (containsSelectorAnywhere(cond, leftSelector))
  12648. {
  12649. done = true;
  12650. break;
  12651. }
  12652. cond.setown(replaceSelector(cond, normalized, leftSelector));
  12653. }
  12654. extendConditionOwn(invariantCondition, no_and, invariant.getClear());
  12655. if (cond)
  12656. cond->unwindList(filterConditions, no_and);
  12657. dataset = dataset->queryChild(0);
  12658. break;
  12659. }
  12660. case no_sorted:
  12661. dataset = dataset->queryChild(0);
  12662. break;
  12663. default:
  12664. done = true;
  12665. break;
  12666. }
  12667. } while (!done);
  12668. }
  12669. bool isFilterProject = invariantCondition != NULL;
  12670. bool containsCounter = expr->hasAttribute(_countProject_Atom);
  12671. #ifdef _DEBUG
  12672. assertex(containsCounter == transformContainsCounter(transform, counter));
  12673. #endif
  12674. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12675. Owned<ActivityInstance> instance = isFilterProject ? new ActivityInstance(*this, ctx, TAKfilterproject, expr, "FilterProject") :
  12676. containsCounter ? new ActivityInstance(*this, ctx, TAKcountproject, expr, "CountProject")
  12677. : new ActivityInstance(*this, ctx, TAKproject, expr, "Project");
  12678. if (filterConditions.ordinality())
  12679. {
  12680. if (isGroupedActivity(expr))
  12681. instance->graphLabel.set("Grouped Filtered Project");
  12682. else
  12683. instance->graphLabel.set("Filtered Project");
  12684. }
  12685. buildActivityFramework(instance);
  12686. buildInstancePrefix(instance);
  12687. BuildCtx funcctx(instance->startctx);
  12688. if (isFilterProject || containsCounter)
  12689. {
  12690. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned __int64 counter)");
  12691. if (containsCounter)
  12692. associateCounter(funcctx, counter, "counter");
  12693. }
  12694. else
  12695. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  12696. ensureRowAllocated(funcctx, "crSelf");
  12697. if (filterConditions.ordinality())
  12698. {
  12699. HqlExprArray args;
  12700. ForEachItemIn(i, filterConditions)
  12701. {
  12702. OwnedHqlExpr test = createValue(no_skip, makeVoidType(), getInverse(&filterConditions.item(i)));
  12703. args.append(*LINK(test));
  12704. }
  12705. unwindChildren(args, transform);
  12706. transform.setown(transform->clone(args));
  12707. }
  12708. if (op == no_newusertable)
  12709. {
  12710. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  12711. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  12712. associateSkipReturnMarker(funcctx, queryZero(), selfCursor);
  12713. bindTableCursor(funcctx, dataset, "left");
  12714. doTransform(funcctx, transform, selfCursor);
  12715. buildReturnRecordSize(funcctx, selfCursor);
  12716. }
  12717. else
  12718. buildTransformBody(funcctx, transform, dataset, NULL, instance->dataset, selSeq);
  12719. if (filterConditions.ordinality() || transformContainsSkip(transform))
  12720. doBuildBoolFunction(instance->classctx, "canFilter", true);
  12721. if (invariantCondition)
  12722. doBuildBoolFunction(instance->startctx, "canMatchAny", invariantCondition);
  12723. buildInstanceSuffix(instance);
  12724. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12725. return instance->getBoundActivity();
  12726. }
  12727. //---------------------------------------------------------------------------
  12728. ABoundActivity * HqlCppTranslator::doBuildActivitySerialize(BuildCtx & ctx, IHqlExpression * expr)
  12729. {
  12730. IHqlExpression * dataset = expr->queryChild(0);
  12731. bool serialize = (expr->getOperator() == no_serialize);
  12732. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12733. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKproject, expr, "Project");
  12734. buildActivityFramework(instance);
  12735. buildInstancePrefix(instance);
  12736. BuildCtx funcctx(instance->startctx);
  12737. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left)");
  12738. // Bind left to "left" and right to RIGHT
  12739. BoundRow * leftCursor = bindTableCursor(funcctx, dataset, "_left");
  12740. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  12741. //MORE: I don't have any examples that trigger this code as far as I know...
  12742. IIdAtom * func = serialize ? rtlSerializeToBuilderId : rtlDeserializeToBuilderId;
  12743. IAtom * kind = serialize ? serializerAtom : deserializerAtom;
  12744. IAtom * serializeForm = serialize ? expr->queryChild(1)->queryName() : expr->queryChild(2)->queryName();
  12745. IHqlExpression * record = expr->queryRecord();
  12746. HqlExprArray args;
  12747. args.append(*createSerializer(ctx, record, serializeForm, kind));
  12748. args.append(*ensureActiveRow(dataset));
  12749. Owned<ITypeInfo> type = makeTransformType(record->getType());
  12750. OwnedHqlExpr call = bindFunctionCall(func, args, type);
  12751. doTransform(funcctx, call, selfCursor);
  12752. buildReturnRecordSize(funcctx, selfCursor);
  12753. buildInstanceSuffix(instance);
  12754. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12755. return instance->getBoundActivity();
  12756. }
  12757. //---------------------------------------------------------------------------
  12758. ABoundActivity * HqlCppTranslator::doBuildActivityDefineSideEffect(BuildCtx & ctx, IHqlExpression * expr)
  12759. {
  12760. Owned<ABoundActivity> parentActivity = buildCachedActivity(ctx, expr->queryChild(0));
  12761. OwnedHqlExpr attr = createAttribute(_sideEffect_Atom, LINK(expr->queryAttribute(_uid_Atom)));
  12762. OwnedHqlExpr unknown = createUnknown(no_attr, NULL, NULL, LINK(parentActivity));
  12763. activeGraphCtx->associateExpr(attr, unknown);
  12764. return parentActivity.getClear();
  12765. }
  12766. //---------------------------------------------------------------------------
  12767. ABoundActivity * HqlCppTranslator::doBuildActivityCallSideEffect(BuildCtx & ctx, IHqlExpression * expr)
  12768. {
  12769. OwnedHqlExpr attr = createAttribute(_sideEffect_Atom, LINK(expr->queryAttribute(_uid_Atom)));
  12770. HqlExprAssociation * match = activeGraphCtx->queryMatchExpr(attr);
  12771. if (!match)
  12772. throwUnexpected();
  12773. ABoundActivity * activity = static_cast<ABoundActivity *>(match->queryExpr()->queryUnknownExtra());
  12774. return LINK(activity);
  12775. }
  12776. //---------------------------------------------------------------------------
  12777. ABoundActivity * HqlCppTranslator::doBuildActivityExecuteWhen(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  12778. {
  12779. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  12780. Owned<ABoundActivity> associatedActivity = buildCachedActivity(ctx, expr->queryChild(1));
  12781. if (!associatedActivity)
  12782. return boundDataset.getClear();
  12783. const char * label;
  12784. int when;
  12785. if (expr->hasAttribute(successAtom))
  12786. {
  12787. label = "Success";
  12788. when = WhenSuccessId;
  12789. }
  12790. else if (expr->hasAttribute(failureAtom))
  12791. {
  12792. label = "Failure";
  12793. when = WhenFailureId;
  12794. }
  12795. else if (expr->hasAttribute(parallelAtom))
  12796. {
  12797. label = "Parallel";
  12798. when = WhenParallelId;
  12799. }
  12800. else
  12801. {
  12802. label = "Before";
  12803. when = WhenDefaultId;
  12804. }
  12805. bool useImplementationClass = options.minimizeActivityClasses;
  12806. ThorActivityKind kind = (expr->isAction() ? TAKwhen_action : TAKwhen_dataset);
  12807. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, "WhenAction");
  12808. if (useImplementationClass)
  12809. instance->setImplementationClass(newWhenActionArgId);
  12810. buildActivityFramework(instance, isRoot);
  12811. buildInstancePrefix(instance);
  12812. buildInstanceSuffix(instance);
  12813. if (expr->isAction())
  12814. addActionConnection(ctx, boundDataset, instance, dependencyAtom, NULL, 0, 1);
  12815. else
  12816. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12817. addActionConnection(ctx, associatedActivity, instance, dependencyAtom, label, 0, when);
  12818. return instance->getBoundActivity();
  12819. }
  12820. //---------------------------------------------------------------------------
  12821. IHqlExpression * extractFilterConditions(HqlExprAttr & invariant, IHqlExpression * expr, IHqlExpression * dataset, bool spotCSE)
  12822. {
  12823. unsigned num = expr->numChildren();
  12824. assertex(num > 1);
  12825. HqlExprAttr cond = queryRealChild(expr, 1);
  12826. bool changed = false;
  12827. unsigned idx;
  12828. for (idx = 2; idx < num; idx++)
  12829. {
  12830. IHqlExpression * cur = expr->queryChild(idx);
  12831. if (!cur->isAttribute())
  12832. extendConditionOwn(cond, no_and, LINK(cur));
  12833. }
  12834. if (!cond)
  12835. return NULL;
  12836. if (spotCSE)
  12837. cond.setown(spotScalarCSE(cond));
  12838. HqlExprArray tests;
  12839. cond->unwindList(tests, no_and);
  12840. ForEachItemInRev(i, tests)
  12841. {
  12842. IHqlExpression & cur = tests.item(i);
  12843. if (!exprReferencesDataset(&cur, dataset))
  12844. {
  12845. changed = true;
  12846. if (!matchesBoolean(&cur, true))
  12847. invariant.setown(extendConditionOwn(no_and, LINK(&cur), invariant.getClear()));
  12848. tests.remove(i);
  12849. }
  12850. }
  12851. if (changed)
  12852. cond.setown(createBalanced(no_and, queryBoolType(), tests));
  12853. return cond.getClear();
  12854. }
  12855. ABoundActivity * HqlCppTranslator::doBuildActivityFilter(BuildCtx & ctx, IHqlExpression * expr)
  12856. {
  12857. IHqlExpression * dataset = expr->queryChild(0);
  12858. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12859. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfilter, expr,"Filter");
  12860. buildActivityFramework(instance);
  12861. buildInstancePrefix(instance);
  12862. HqlExprAttr invariant;
  12863. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, dataset, options.spotCSE);
  12864. //Base class returns true, so only generate if no non-invariant conditions
  12865. if (cond)
  12866. {
  12867. BuildCtx funcctx(instance->startctx);
  12868. funcctx.addQuotedCompound("virtual bool isValid(const void * _self)");
  12869. funcctx.addQuoted("unsigned char * self = (unsigned char *) _self;");
  12870. bindTableCursor(funcctx, dataset, "self");
  12871. buildReturn(funcctx, cond);
  12872. }
  12873. if (invariant)
  12874. doBuildBoolFunction(instance->startctx, "canMatchAny", invariant);
  12875. buildInstanceSuffix(instance);
  12876. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12877. return instance->getBoundActivity();
  12878. }
  12879. ABoundActivity * HqlCppTranslator::doBuildActivityFilterGroup(BuildCtx & ctx, IHqlExpression * expr)
  12880. {
  12881. IHqlExpression * dataset = expr->queryChild(0);
  12882. IHqlExpression * selSeq = querySelSeq(expr);
  12883. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  12884. if (targetThor() && !isGrouped(dataset))
  12885. throwError(HQLERR_ThorHavingMustBeGrouped);
  12886. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  12887. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfiltergroup, expr,"FilterGroup");
  12888. buildActivityFramework(instance);
  12889. buildInstancePrefix(instance);
  12890. HqlExprAttr invariant;
  12891. OwnedHqlExpr left = createSelector(no_left, dataset, selSeq);
  12892. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, left, options.spotCSE);
  12893. //Base class returns true, so only generate if no non-invariant conditions
  12894. if (cond)
  12895. {
  12896. BuildCtx funcctx(instance->startctx);
  12897. funcctx.addQuotedCompound("virtual bool isValid(unsigned numRows, const void * * _rows)");
  12898. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _rows[0];");
  12899. funcctx.addQuoted("unsigned char * * rows = (unsigned char * *) _rows;");
  12900. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  12901. bindRows(funcctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  12902. buildReturn(funcctx, cond);
  12903. }
  12904. if (invariant)
  12905. doBuildBoolFunction(instance->startctx, "canMatchAny", invariant);
  12906. buildInstanceSuffix(instance);
  12907. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  12908. return instance->getBoundActivity();
  12909. }
  12910. //---------------------------------------------------------------------------
  12911. ABoundActivity * HqlCppTranslator::doBuildActivityCombine(BuildCtx & ctx, IHqlExpression * expr)
  12912. {
  12913. //MORE: Need to expand nested combines so they have multiple inputs.
  12914. //But will need to assign aliases to the inputs + do a reasonable amount of processing.
  12915. IHqlExpression * left = expr->queryChild(0);
  12916. IHqlExpression * right = expr->queryChild(1);
  12917. IHqlExpression * transform = expr->queryChild(2);
  12918. IHqlExpression * selSeq = querySelSeq(expr);
  12919. if (targetThor() && !expr->hasAttribute(localAtom))
  12920. ERRORAT(queryLocation(expr), HQLERR_ThorCombineOnlyLocal);
  12921. CIArray bound;
  12922. bound.append(*buildCachedActivity(ctx, left));
  12923. bound.append(*buildCachedActivity(ctx, right));
  12924. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKcombine, expr, "Combine");
  12925. buildActivityFramework(instance);
  12926. buildInstancePrefix(instance);
  12927. BuildCtx funcctx(instance->startctx);
  12928. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, unsigned _num, const void * * _rows)");
  12929. if (transform->getOperator() != no_skip)
  12930. {
  12931. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _rows[0];");
  12932. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _rows[1];");
  12933. ensureRowAllocated(funcctx, "crSelf");
  12934. bindTableCursor(funcctx, left, "left", no_left, selSeq);
  12935. bindTableCursor(funcctx, right, "right", no_right, selSeq);
  12936. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  12937. associateSkipReturnMarker(funcctx, queryZero(), selfCursor);
  12938. doTransform(funcctx, transform, selfCursor);
  12939. buildReturnRecordSize(funcctx, selfCursor);
  12940. }
  12941. else
  12942. funcctx.addReturn(queryZero());
  12943. if (transformContainsSkip(transform))
  12944. doBuildBoolFunction(instance->classctx, "canFilter", true);
  12945. buildInstanceSuffix(instance);
  12946. ForEachItemIn(idx2, bound)
  12947. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  12948. return instance->getBoundActivity();
  12949. }
  12950. //---------------------------------------------------------------------------
  12951. void HqlCppTranslator::bindRows(BuildCtx & ctx, node_operator side, IHqlExpression * selSeq, IHqlExpression * rowsid, IHqlExpression * dataset, const char * numText, const char * rowsText, bool rowsAreLinkCounted)
  12952. {
  12953. OwnedHqlExpr selector = createSelector(side, dataset, selSeq);
  12954. OwnedHqlExpr rowsExpr = createDataset(no_rows, LINK(selector), LINK(rowsid));
  12955. Owned<ITypeInfo> rowType = makeReferenceModifier(LINK(rowsExpr->queryType()->queryChildType()));
  12956. if (rowsAreLinkCounted)
  12957. rowType.setown(setLinkCountedAttr(rowType, true));
  12958. //Rows may be link counted, but rows() is not a linkable rowset
  12959. OwnedITypeInfo rowsType = makeReferenceModifier(makeTableType(rowType.getClear()));
  12960. rowsType.setown(makeOutOfLineModifier(LINK(rowsType)));
  12961. CHqlBoundExpr boundRows;
  12962. boundRows.count.setown(createQuoted(numText, LINK(unsignedType)));
  12963. boundRows.expr.setown(createQuoted(rowsText, LINK(rowsType)));
  12964. ctx.associateExpr(rowsExpr, boundRows);
  12965. }
  12966. //---------------------------------------------------------------------------
  12967. ABoundActivity * HqlCppTranslator::doBuildActivityCombineGroup(BuildCtx & ctx, IHqlExpression * expr)
  12968. {
  12969. //MORE: Need to expand nested combines so they have multiple inputs.
  12970. //But will need to assign aliases to the inputs + do a reasonable amount of processing.
  12971. IHqlExpression * left = expr->queryChild(0);
  12972. IHqlExpression * right = expr->queryChild(1);
  12973. IHqlExpression * selSeq = querySelSeq(expr);
  12974. IHqlExpression * transform = expr->queryChild(2);
  12975. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  12976. CIArray bound;
  12977. bound.append(*buildCachedActivity(ctx, left));
  12978. bound.append(*buildCachedActivity(ctx, right));
  12979. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKcombinegroup, expr, "CombineGroup");
  12980. buildActivityFramework(instance);
  12981. buildInstancePrefix(instance);
  12982. BuildCtx funcctx(instance->startctx);
  12983. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, unsigned numRows, const void * * _rows)");
  12984. if (transform->getOperator() != no_skip)
  12985. {
  12986. funcctx.addQuoted("const unsigned char * left = (const unsigned char *)_left;");
  12987. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _rows[0];");
  12988. funcctx.addQuoted("unsigned char * * rows = (unsigned char * *) _rows;");
  12989. ensureRowAllocated(funcctx, "crSelf");
  12990. bindTableCursor(funcctx, left, "left", no_left, selSeq);
  12991. bindTableCursor(funcctx, right, "right", no_right, selSeq);
  12992. bindRows(funcctx, no_right, selSeq, rowsid, right, "numRows", "rows", options.mainRowsAreLinkCounted);
  12993. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  12994. associateSkipReturnMarker(funcctx, queryZero(), selfCursor);
  12995. doTransform(funcctx, transform, selfCursor);
  12996. buildReturnRecordSize(funcctx, selfCursor);
  12997. }
  12998. else
  12999. funcctx.addReturn(queryZero());
  13000. if (transformContainsSkip(transform))
  13001. doBuildBoolFunction(instance->classctx, "canFilter", true);
  13002. buildInstanceSuffix(instance);
  13003. ForEachItemIn(idx2, bound)
  13004. buildConnectInputOutput(ctx, instance, (ABoundActivity *)&bound.item(idx2), 0, idx2);
  13005. return instance->getBoundActivity();
  13006. }
  13007. //---------------------------------------------------------------------------
  13008. ABoundActivity * HqlCppTranslator::doBuildActivityRollupGroup(BuildCtx & ctx, IHqlExpression * expr)
  13009. {
  13010. //MORE: Need to expand nested combines so they have multiple inputs.
  13011. IHqlExpression * dataset = expr->queryChild(0);
  13012. IHqlExpression * transform = expr->queryChild(1);
  13013. IHqlExpression * selSeq = querySelSeq(expr);
  13014. IHqlExpression * rowsid = expr->queryAttribute(_rowsid_Atom);
  13015. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13016. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKrollupgroup, expr, "RollupGroup");
  13017. instance->graphLabel.set("Rollup Group"); // Grouped Rollup Group looks silly
  13018. buildActivityFramework(instance);
  13019. buildInstancePrefix(instance);
  13020. BuildCtx funcctx(instance->startctx);
  13021. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, unsigned numRows, const void * * _rows)");
  13022. if (transform->getOperator() != no_skip)
  13023. {
  13024. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _rows[0];");
  13025. funcctx.addQuoted("unsigned char * * rows = (unsigned char * *) _rows;");
  13026. ensureRowAllocated(funcctx, "crSelf");
  13027. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  13028. bindRows(funcctx, no_left, selSeq, rowsid, dataset, "numRows", "rows", options.mainRowsAreLinkCounted);
  13029. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  13030. associateSkipReturnMarker(funcctx, queryZero(), selfCursor);
  13031. doTransform(funcctx, transform, selfCursor);
  13032. buildReturnRecordSize(funcctx, selfCursor);
  13033. }
  13034. else
  13035. funcctx.addReturn(queryZero());
  13036. if (transformContainsSkip(transform))
  13037. doBuildBoolFunction(instance->classctx, "canFilter", true);
  13038. buildInstanceSuffix(instance);
  13039. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13040. return instance->getBoundActivity();
  13041. }
  13042. //---------------------------------------------------------------------------
  13043. ABoundActivity * HqlCppTranslator::doBuildActivityAssert(BuildCtx & ctx, IHqlExpression * expr)
  13044. {
  13045. HqlExprArray args;
  13046. expr->unwindList(args, expr->getOperator());
  13047. IHqlExpression * dataset = &args.item(0);
  13048. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13049. //MORE: Change this when ThroughApply activities are supported in engines.
  13050. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKfilter, expr,"Filter");
  13051. instance->graphLabel.set("Assert");
  13052. buildActivityFramework(instance);
  13053. buildInstancePrefix(instance);
  13054. unsigned num = args.ordinality();
  13055. BuildCtx funcctx(instance->startctx);
  13056. funcctx.addQuotedCompound("virtual bool isValid(const void * _self)");
  13057. funcctx.addQuoted("unsigned char * self = (unsigned char *) _self;");
  13058. bindTableCursor(funcctx, dataset, "self");
  13059. for (unsigned i=1; i < num; i++)
  13060. {
  13061. IHqlExpression & cur = args.item(i);
  13062. if (!cur.isAttribute())
  13063. buildStmt(funcctx, &cur);
  13064. }
  13065. funcctx.addReturn(queryBoolExpr(true));
  13066. buildInstanceSuffix(instance);
  13067. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13068. return instance->getBoundActivity();
  13069. }
  13070. //---------------------------------------------------------------------------
  13071. void HqlCppTranslator::buildLimitHelpers(BuildCtx & ctx, IHqlExpression * rowLimit, IHqlExpression * failAction, bool isSkip, IHqlExpression * filename, unique_id_t id)
  13072. {
  13073. doBuildUnsigned64Function(ctx, "getRowLimit", rowLimit);
  13074. if (isZero(rowLimit))
  13075. WARNING(HQLWRN_LimitIsZero);
  13076. if (!isSkip)
  13077. {
  13078. LinkedHqlExpr fail = failAction;
  13079. if (!fail || fail->isAttribute())
  13080. {
  13081. if (!id)
  13082. id = queryCurrentActivityId(ctx);
  13083. fail.setown(createFailAction("Limit exceeded", rowLimit, filename, id));
  13084. }
  13085. BuildCtx ctx2(ctx);
  13086. ctx2.addQuotedCompound("virtual void onLimitExceeded()");
  13087. buildStmt(ctx2, fail);
  13088. }
  13089. }
  13090. void HqlCppTranslator::buildLimitHelpers(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * filename, unique_id_t id)
  13091. {
  13092. buildLimitHelpers(ctx, expr->queryChild(1), queryRealChild(expr, 2), expr->hasAttribute(skipAtom), filename, id);
  13093. IHqlExpression * transform = queryAttributeChild(expr, onFailAtom, 0);
  13094. if (transform)
  13095. {
  13096. BuildCtx transformctx(ctx);
  13097. transformctx.addQuotedCompound("virtual size32_t transformOnLimitExceeded(ARowBuilder & crSelf)");
  13098. ensureRowAllocated(transformctx, "crSelf");
  13099. buildTransformBody(transformctx, transform, NULL, NULL, expr, NULL);
  13100. }
  13101. }
  13102. ABoundActivity * HqlCppTranslator::doBuildActivityLimit(BuildCtx & ctx, IHqlExpression * expr)
  13103. {
  13104. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13105. IHqlExpression * transform = queryAttributeChild(expr, onFailAtom, 0);
  13106. ThorActivityKind kind = TAKlimit;
  13107. const char * helper = "Limit";
  13108. if (transform)
  13109. {
  13110. kind = TAKcreaterowlimit;
  13111. helper = "CreateRowLimit";
  13112. }
  13113. else if (expr->hasAttribute(skipAtom))
  13114. kind = TAKskiplimit;
  13115. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  13116. buildActivityFramework(instance);
  13117. buildInstancePrefix(instance);
  13118. buildLimitHelpers(instance->startctx, expr, NULL, instance->activityId);
  13119. buildInstanceSuffix(instance);
  13120. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13121. return instance->getBoundActivity();
  13122. }
  13123. ABoundActivity * HqlCppTranslator::doBuildActivityCatch(BuildCtx & ctx, IHqlExpression * expr)
  13124. {
  13125. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13126. IHqlExpression * arg1 = queryRealChild(expr, 1);
  13127. IHqlExpression * filter = NULL;
  13128. IHqlExpression * action = NULL;
  13129. if (arg1 && arg1->isBoolean())
  13130. {
  13131. filter = arg1;
  13132. action = queryRealChild(expr, 2);
  13133. }
  13134. else
  13135. action = arg1;
  13136. IHqlExpression * transform = queryAttributeChild(expr, onFailAtom, 0);
  13137. bool isSkip = expr->hasAttribute(skipAtom);
  13138. ThorActivityKind kind = TAKcatch;
  13139. const char * helper = "Catch";
  13140. if (transform)
  13141. kind = TAKcreaterowcatch;
  13142. else if (isSkip)
  13143. kind = TAKskipcatch;
  13144. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  13145. buildActivityFramework(instance);
  13146. buildInstancePrefix(instance);
  13147. if (filter)
  13148. {
  13149. BuildCtx isMatchCtx(instance->startctx);
  13150. isMatchCtx.addQuotedCompound("virtual bool isMatch(IException * except)");
  13151. associateLocalFailure(isMatchCtx, "except");
  13152. OwnedHqlExpr cseFilter = spotScalarCSE(filter);
  13153. buildReturn(isMatchCtx, cseFilter, queryBoolType());
  13154. }
  13155. if (transform)
  13156. {
  13157. BuildCtx onFailCtx(instance->startctx);
  13158. onFailCtx.addQuotedCompound("virtual unsigned transformOnExceptionCaught(ARowBuilder & crSelf, IException * except)");
  13159. ensureRowAllocated(onFailCtx, "crSelf");
  13160. associateLocalFailure(onFailCtx, "except");
  13161. buildTransformBody(onFailCtx, transform, NULL, NULL, expr, NULL);
  13162. }
  13163. else if (!isSkip)
  13164. {
  13165. LinkedHqlExpr fail = action;
  13166. if (!fail)
  13167. fail.setown(createFailAction("Missing failure", NULL, NULL, instance->activityId));
  13168. BuildCtx throwctx(instance->startctx);
  13169. throwctx.addQuotedCompound("virtual void onExceptionCaught()");
  13170. buildStmt(throwctx, fail);
  13171. }
  13172. buildInstanceSuffix(instance);
  13173. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13174. return instance->getBoundActivity();
  13175. }
  13176. ABoundActivity * HqlCppTranslator::doBuildActivitySection(BuildCtx & ctx, IHqlExpression * expr)
  13177. {
  13178. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13179. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsection, expr, "Section");
  13180. StringBuffer label;
  13181. getStringValue(label, expr->queryChild(1));
  13182. instance->graphLabel.set(label.str());
  13183. buildActivityFramework(instance);
  13184. buildInstancePrefix(instance);
  13185. StringBuffer flags;
  13186. IHqlExpression * description = NULL;
  13187. ForEachChildFrom(i, expr, 2)
  13188. {
  13189. IHqlExpression * cur = expr->queryChild(i);
  13190. if (cur->isAttribute())
  13191. {
  13192. IAtom * name= cur->queryName();
  13193. if (name == privateAtom)
  13194. flags.append("|TSFprivate");
  13195. }
  13196. else if (isStringType(cur->queryType()))
  13197. {
  13198. description = cur;
  13199. flags.append("|TSFdynamicDescription");
  13200. }
  13201. }
  13202. if (description)
  13203. doBuildStringFunction(instance->startctx, "getDescription", description);
  13204. if (flags.length())
  13205. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  13206. buildInstanceSuffix(instance);
  13207. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13208. return instance->getBoundActivity();
  13209. }
  13210. ABoundActivity * HqlCppTranslator::doBuildActivitySectionInput(BuildCtx & ctx, IHqlExpression * expr)
  13211. {
  13212. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13213. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsectioninput, expr, "SectionInput");
  13214. StringBuffer label;
  13215. expr->queryChild(1)->queryValue()->getStringValue(label);
  13216. instance->graphLabel.set(label.str());
  13217. instance->graphEclText.append("<>");
  13218. buildActivityFramework(instance);
  13219. buildInstancePrefix(instance);
  13220. StringBuffer flags;
  13221. if (expr->hasAttribute(privateAtom))
  13222. flags.append("|TSFprivate");
  13223. if (flags.length())
  13224. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  13225. buildInstanceSuffix(instance);
  13226. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13227. return instance->getBoundActivity();
  13228. }
  13229. //---------------------------------------------------------------------------
  13230. ABoundActivity * HqlCppTranslator::doBuildActivityMetaActivity(BuildCtx & ctx, IHqlExpression * expr)
  13231. {
  13232. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, expr->queryChild(0));
  13233. if (!targetThor())
  13234. return boundDataset.getClear();
  13235. assertex(expr->hasAttribute(pullAtom));
  13236. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKpull, expr, "Pull");
  13237. buildActivityFramework(instance);
  13238. buildInstancePrefix(instance);
  13239. buildInstanceSuffix(instance);
  13240. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13241. return instance->getBoundActivity();
  13242. }
  13243. //---------------------------------------------------------------------------
  13244. //-- no_sub --
  13245. ABoundActivity * HqlCppTranslator::doBuildActivitySub(BuildCtx & ctx, IHqlExpression * expr)
  13246. {
  13247. assertex(!"MORE!");
  13248. return NULL;
  13249. }
  13250. //---------------------------------------------------------------------------
  13251. //-- no_sample [GROUP] --
  13252. ABoundActivity * HqlCppTranslator::doBuildActivityEnth(BuildCtx & ctx, IHqlExpression * expr)
  13253. {
  13254. IHqlExpression * dataset = expr->queryChild(0);
  13255. IHqlExpression * numerator = expr->queryChild(1);
  13256. IHqlExpression * denominator = expr->queryChild(2);
  13257. IHqlExpression * sample = expr->queryChild(3);
  13258. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13259. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKenth, expr, "Enth");
  13260. buildActivityFramework(instance);
  13261. buildInstancePrefix(instance);
  13262. BuildCtx funcctx(instance->startctx);
  13263. funcctx.addQuotedCompound("virtual unsigned __int64 getProportionNumerator()");
  13264. buildReturn(funcctx, numerator);
  13265. BuildCtx funcctx2(instance->startctx);
  13266. funcctx2.addQuotedCompound("virtual unsigned __int64 getProportionDenominator()");
  13267. if (denominator && !denominator->isAttribute())
  13268. buildReturn(funcctx2, denominator);
  13269. else
  13270. {
  13271. OwnedHqlExpr notProvided = createConstant(counterType->castFrom(true, I64C(-1)));
  13272. buildReturn(funcctx2, notProvided);
  13273. }
  13274. BuildCtx funcctx3(instance->startctx);
  13275. funcctx3.addQuotedCompound("virtual unsigned getSampleNumber()");
  13276. if (sample && !sample->isAttribute())
  13277. buildReturn(funcctx3, sample);
  13278. else
  13279. funcctx3.addQuoted("return 1;");
  13280. buildInstanceSuffix(instance);
  13281. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13282. return instance->getBoundActivity();
  13283. }
  13284. //---------------------------------------------------------------------------
  13285. //-- no_sample [GROUP] --
  13286. ABoundActivity * HqlCppTranslator::doBuildActivitySample(BuildCtx & ctx, IHqlExpression * expr)
  13287. {
  13288. StringBuffer s;
  13289. IHqlExpression * dataset = expr->queryChild(0);
  13290. IHqlExpression * sampleExpr = queryRealChild(expr, 2);
  13291. unsigned sample = (unsigned)getIntValue(sampleExpr, 1);
  13292. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13293. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsample, expr,"Sample");
  13294. buildActivityFramework(instance);
  13295. buildInstancePrefix(instance);
  13296. doBuildUnsignedFunction(instance->startctx, "getProportion", expr->queryChild(1));
  13297. BuildCtx funcctx2(instance->startctx);
  13298. funcctx2.addQuotedCompound("virtual unsigned getSampleNumber()");
  13299. s.clear().append("return ").append(sample).append(";");
  13300. funcctx2.addQuoted(s);
  13301. buildInstanceSuffix(instance);
  13302. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13303. return instance->getBoundActivity();
  13304. }
  13305. //---------------------------------------------------------------------------
  13306. //-- no_group [GROUP] --
  13307. /* In parms: NOT linked. Return: linked */
  13308. IHqlExpression * HqlCppTranslator::createOrderFromSortList(const DatasetReference & dataset, IHqlExpression * sortList, IHqlExpression * leftSelect, IHqlExpression * rightSelect)
  13309. {
  13310. HqlExprArray leftList, rightList;
  13311. unsigned max = sortList->numChildren();
  13312. unsigned idx;
  13313. for (idx = 0; idx < max; idx++)
  13314. {
  13315. IHqlExpression * next = sortList->queryChild(idx);
  13316. //optimize order on (string)qstring to order on qstring for example. Can make quite a difference.
  13317. if (isCast(next))
  13318. {
  13319. IHqlExpression * uncast = next->queryChild(0);
  13320. ITypeInfo * castType = next->queryType();
  13321. ITypeInfo * uncastType = uncast->queryType();
  13322. if (preservesValue(castType, uncastType) && preservesOrder(castType, uncastType))
  13323. next = uncast;
  13324. }
  13325. bool invert = false;
  13326. if (next->getOperator() == no_negate)
  13327. {
  13328. invert = true;
  13329. next = next->queryChild(0);
  13330. }
  13331. IHqlExpression * leftResolved = dataset.mapScalar(next, leftSelect);
  13332. IHqlExpression * rightResolved = dataset.mapScalar(next, rightSelect);
  13333. if (invert)
  13334. {
  13335. leftList.append(*rightResolved);
  13336. rightList.append(*leftResolved);
  13337. }
  13338. else
  13339. {
  13340. leftList.append(*leftResolved);
  13341. rightList.append(*rightResolved);
  13342. }
  13343. }
  13344. return createValue(no_order, LINK(signedType), createSortList(leftList), createSortList(rightList));
  13345. }
  13346. void HqlCppTranslator::buildReturnOrder(BuildCtx & ctx, IHqlExpression *sortList, const DatasetReference & dataset)
  13347. {
  13348. OwnedHqlExpr selSeq = createDummySelectorSequence();
  13349. OwnedHqlExpr leftSelect = dataset.getSelector(no_left, selSeq);
  13350. OwnedHqlExpr rightSelect = dataset.getSelector(no_right, selSeq);
  13351. OwnedHqlExpr order = createOrderFromSortList(dataset, sortList, leftSelect, rightSelect);
  13352. bindTableCursor(ctx, dataset.queryDataset(), "left", no_left, selSeq);
  13353. bindTableCursor(ctx, dataset.queryDataset(), "right", no_right, selSeq);
  13354. doBuildReturnCompare(ctx, order, no_order, false);
  13355. }
  13356. void HqlCppTranslator::doBuildFuncIsSameGroup(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * sortlist)
  13357. {
  13358. BuildCtx funcctx(ctx);
  13359. funcctx.addQuotedCompound("virtual bool isSameGroup(const void * _left, const void * _right)");
  13360. if (sortlist->getOperator() == no_activetable)
  13361. buildReturn(funcctx, queryBoolExpr(false));
  13362. else
  13363. {
  13364. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  13365. funcctx.addQuoted("const unsigned char * right = (const unsigned char *) _right;");
  13366. OwnedHqlExpr selSeq = createSelectorSequence();
  13367. OwnedHqlExpr leftSelect = createSelector(no_left, dataset, selSeq);
  13368. OwnedHqlExpr rightSelect = createSelector(no_right, dataset, selSeq);
  13369. HqlExprArray args;
  13370. HqlExprArray leftValues, rightValues;
  13371. HqlExprArray compares;
  13372. unwindChildren(compares, sortlist);
  13373. //Optimize the grouping conditions by ordering them by the fields in the record (so the
  13374. //doBuildReturnCompare() can combine as many as possible), and remove duplicates
  13375. if (options.optimizeGrouping && (compares.ordinality() > 1))
  13376. {
  13377. HqlExprArray equalities;
  13378. optimizeGroupOrder(equalities, dataset, compares);
  13379. ForEachItemIn(i, equalities)
  13380. {
  13381. IHqlExpression * test = &equalities.item(i);
  13382. leftValues.append(*replaceSelector(test, dataset, leftSelect));
  13383. rightValues.append(*replaceSelector(test, dataset, rightSelect));
  13384. }
  13385. }
  13386. ForEachItemIn(idx, compares)
  13387. {
  13388. IHqlExpression * test = &compares.item(idx);
  13389. if (containsSelector(test, leftSelect) || containsSelector(test, rightSelect))
  13390. args.append(*LINK(test));
  13391. else
  13392. {
  13393. OwnedHqlExpr lhs = replaceSelector(test, dataset, leftSelect);
  13394. OwnedHqlExpr rhs = replaceSelector(test, dataset, rightSelect);
  13395. if (lhs != rhs)
  13396. {
  13397. leftValues.append(*lhs.getClear());
  13398. rightValues.append(*rhs.getClear());
  13399. }
  13400. }
  13401. }
  13402. OwnedHqlExpr result;
  13403. OwnedHqlExpr orderResult;
  13404. //Use the optimized equality code for more than one element - which often combines the comparisons.
  13405. if (leftValues.ordinality() != 0)
  13406. {
  13407. if (leftValues.ordinality() == 1)
  13408. args.append(*createValue(no_eq, makeBoolType(), LINK(&leftValues.item(0)), LINK(&rightValues.item(0))));
  13409. else
  13410. orderResult.setown(createValue(no_order, LINK(signedType), createSortList(leftValues), createSortList(rightValues)));
  13411. }
  13412. if (args.ordinality() == 1)
  13413. result.set(&args.item(0));
  13414. else if (args.ordinality() != 0)
  13415. result.setown(createValue(no_and, makeBoolType(), args));
  13416. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  13417. bindTableCursor(funcctx, dataset, "right", no_right, selSeq);
  13418. IHqlExpression * trueExpr = queryBoolExpr(true);
  13419. if (result)
  13420. {
  13421. if (orderResult)
  13422. {
  13423. buildFilteredReturn(funcctx, result, trueExpr);
  13424. doBuildReturnCompare(funcctx, orderResult, no_eq, true);
  13425. }
  13426. else
  13427. {
  13428. buildReturn(funcctx, result);
  13429. }
  13430. }
  13431. else
  13432. {
  13433. if (orderResult)
  13434. doBuildReturnCompare(funcctx, orderResult, no_eq, true);
  13435. else
  13436. buildReturn(funcctx, trueExpr);
  13437. }
  13438. }
  13439. }
  13440. ABoundActivity * HqlCppTranslator::doBuildActivityGroup(BuildCtx & ctx, IHqlExpression * expr)
  13441. {
  13442. IHqlExpression * dataset = expr->queryChild(0);
  13443. IHqlExpression * child = dataset;
  13444. while (child->getOperator() == no_group)
  13445. child = child->queryChild(0);
  13446. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, child);
  13447. if (queryGrouping(expr) == queryGrouping(child))
  13448. return boundDataset.getClear();
  13449. IHqlExpression * sortlist = queryRealChild(expr, 1);
  13450. if (!sortlist || ((sortlist->numChildren() == 0) && (sortlist->getOperator() != no_activetable)))
  13451. {
  13452. bool useImplementationClass = options.minimizeActivityClasses;
  13453. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdegroup, expr,"Degroup");
  13454. if (useImplementationClass)
  13455. instance->setImplementationClass(newDegroupArgId);
  13456. buildActivityFramework(instance);
  13457. buildInstancePrefix(instance);
  13458. buildInstanceSuffix(instance);
  13459. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13460. return instance->getBoundActivity();
  13461. }
  13462. else
  13463. {
  13464. ThorActivityKind tak = (expr->getOperator() == no_group) ? TAKgroup: TAKgrouped;
  13465. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "Group");
  13466. buildActivityFramework(instance);
  13467. buildInstancePrefix(instance);
  13468. //virtual bool isSameGroup(const void *left, const void *right);
  13469. doBuildFuncIsSameGroup(instance->startctx, dataset, sortlist);
  13470. buildInstanceSuffix(instance);
  13471. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13472. return instance->getBoundActivity();
  13473. }
  13474. }
  13475. //---------------------------------------------------------------------------
  13476. //-- no_if (dataset) --
  13477. ABoundActivity * queryAssociatedActivity(BuildCtx & ctx, IHqlExpression * expr)
  13478. {
  13479. ActivityAssociation * match = static_cast<ActivityAssociation *>(ctx.queryAssociation(expr, AssocActivity, NULL));
  13480. if (match)
  13481. return match->activity;
  13482. return NULL;
  13483. }
  13484. ABoundActivity * HqlCppTranslator::getConditionalActivity(BuildCtx & ctx, IHqlExpression * expr, bool isChild)
  13485. {
  13486. if (!expr)
  13487. return NULL;
  13488. return buildCachedActivity(ctx, expr);
  13489. }
  13490. ABoundActivity * HqlCppTranslator::doBuildActivityIf(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13491. {
  13492. LinkedHqlExpr cond = expr->queryChild(0);
  13493. IHqlExpression * trueBranch = expr->queryChild(1);
  13494. IHqlExpression * falseBranch = queryRealChild(expr, 2);
  13495. const char * firstLabel = "True";
  13496. if (!expr->isDatarow())
  13497. {
  13498. if (falseBranch && (falseBranch->getOperator() == no_null))
  13499. falseBranch = NULL;
  13500. else if (trueBranch->getOperator() == no_null)
  13501. {
  13502. trueBranch = falseBranch;
  13503. falseBranch = NULL;
  13504. cond.setown(getInverse(cond));
  13505. firstLabel = "False";
  13506. }
  13507. }
  13508. OwnedHqlExpr cseCond = options.spotCSE ? spotScalarCSE(cond) : LINK(cond);
  13509. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx) || insideLibrary());
  13510. IHqlExpression * activeGraph = queryActiveSubGraph(ctx)->graphTag;
  13511. if (isChild)
  13512. {
  13513. Owned<ABoundActivity> boundTrue = buildCachedActivity(ctx, trueBranch);
  13514. Owned<ABoundActivity> boundFalse = falseBranch ? buildCachedActivity(ctx, falseBranch) : NULL;
  13515. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKchildif, expr, "If");
  13516. buildActivityFramework(instance, isRoot);
  13517. buildInstancePrefix(instance);
  13518. {
  13519. MemberFunction getcond(*this, instance->startctx, "virtual bool getCondition()", MFsingle);
  13520. buildReturn(getcond.ctx, cseCond);
  13521. }
  13522. if (isGraphIndependent(cseCond, activeGraph) && !instance->hasChildActivity)
  13523. instance->addAttributeBool("_graphIndependent", true);
  13524. buildConnectInputOutput(ctx, instance, boundTrue, 0, 0, firstLabel);
  13525. if (boundFalse)
  13526. buildConnectInputOutput(ctx, instance, boundFalse, 0, 1, "False");
  13527. buildInstanceSuffix(instance);
  13528. return instance->getBoundActivity();
  13529. }
  13530. else
  13531. {
  13532. Owned<ABoundActivity> boundTrue = getConditionalActivity(ctx, trueBranch, isChild);
  13533. Owned<ABoundActivity> boundFalse = getConditionalActivity(ctx, falseBranch, isChild);
  13534. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, expr->isAction() ? TAKifaction : TAKif, expr,"If");
  13535. buildActivityFramework(instance, isRoot);
  13536. buildInstancePrefix(instance);
  13537. {
  13538. MemberFunction getcond(*this, instance->startctx, "virtual bool getCondition()", MFsingle);
  13539. buildReturn(getcond.ctx, cseCond);
  13540. }
  13541. if (isGraphIndependent(cseCond, activeGraph) && !instance->hasChildActivity)
  13542. instance->addAttributeBool("_graphIndependent", true);
  13543. if (expr->isAction())
  13544. {
  13545. if (boundTrue)
  13546. addActionConnection(ctx, boundTrue, instance, dependencyAtom, firstLabel, 0, 1);
  13547. if (boundFalse)
  13548. addActionConnection(ctx, boundFalse, instance, dependencyAtom, "False", 1, 2);
  13549. }
  13550. else
  13551. {
  13552. if (boundTrue)
  13553. buildConnectInputOutput(ctx, instance, boundTrue, 0, 0, firstLabel);
  13554. if (boundFalse)
  13555. buildConnectInputOutput(ctx, instance, boundFalse, 0, 1, "False");
  13556. }
  13557. buildInstanceSuffix(instance);
  13558. return instance->getBoundActivity();
  13559. }
  13560. }
  13561. //---------------------------------------------------------------------------
  13562. ABoundActivity * HqlCppTranslator::doBuildActivitySequentialParallel(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13563. {
  13564. Array boundActivities;
  13565. ForEachChild(i, expr)
  13566. {
  13567. IHqlExpression * cur = expr->queryChild(i);
  13568. if (!cur->isAttribute() && (cur->getOperator() != no_null))
  13569. {
  13570. ABoundActivity * activity = buildCachedActivity(ctx, cur);
  13571. if (activity)
  13572. boundActivities.append(*activity);
  13573. }
  13574. }
  13575. ThorActivityKind kind = (expr->getOperator() != no_parallel) ? TAKsequential : TAKparallel;
  13576. const char * helper = (expr->getOperator() != no_parallel) ? "Sequential" : "Parallel";
  13577. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, helper);
  13578. buildActivityFramework(instance, isRoot);
  13579. buildInstancePrefix(instance);
  13580. doBuildUnsignedFunction(instance->createctx, "numBranches", boundActivities.ordinality());
  13581. ForEachItemIn(j, boundActivities)
  13582. {
  13583. ABoundActivity & cur = (ABoundActivity&)boundActivities.item(j);
  13584. StringBuffer temp;
  13585. temp.append("Action #").append(j+1);
  13586. addActionConnection(ctx, &cur, instance, dependencyAtom, temp.str(), j, j+1);
  13587. }
  13588. buildInstanceSuffix(instance);
  13589. return instance->getBoundActivity();
  13590. }
  13591. ABoundActivity * HqlCppTranslator::doBuildActivityChoose(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * cond, CIArrayOf<ABoundActivity> & inputs, bool isRoot)
  13592. {
  13593. Owned<ABoundActivity> boundDefault = &inputs.popGet();
  13594. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx));
  13595. assertex(!expr->isAction());
  13596. ThorActivityKind tak = isChild ? TAKchildcase : TAKcase;
  13597. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "Case");
  13598. buildActivityFramework(instance, isRoot);
  13599. buildInstancePrefix(instance);
  13600. BuildCtx funcctx(instance->startctx);
  13601. funcctx.addQuotedCompound("virtual unsigned getBranch()");
  13602. OwnedHqlExpr fullCond(foldHqlExpression(cond));
  13603. if (options.spotCSE)
  13604. fullCond.setown(spotScalarCSE(fullCond));
  13605. buildReturn(funcctx, fullCond);
  13606. StringBuffer label;
  13607. ForEachItemIn(branchIdx, inputs)
  13608. {
  13609. ABoundActivity * boundBranch = &inputs.item(branchIdx);
  13610. label.clear().append("Branch ").append(branchIdx+1);
  13611. if (expr->isAction())
  13612. addActionConnection(ctx, boundBranch, instance, dependencyAtom, label.str(), branchIdx, branchIdx+1);
  13613. else
  13614. buildConnectInputOutput(ctx, instance, boundBranch, 0, branchIdx, label.str());
  13615. }
  13616. IHqlExpression * activeGraph = queryActiveSubGraph(ctx)->graphTag;
  13617. bool graphIndependent = isGraphIndependent(fullCond, activeGraph);
  13618. if (graphIndependent && !instance->hasChildActivity)
  13619. instance->addAttributeBool("_graphIndependent", true);
  13620. buildConnectInputOutput(ctx, instance, boundDefault, 0, inputs.ordinality(), "default");
  13621. buildInstanceSuffix(instance);
  13622. return instance->getBoundActivity();
  13623. }
  13624. ABoundActivity * HqlCppTranslator::doBuildActivityChoose(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13625. {
  13626. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx));
  13627. CIArrayOf<ABoundActivity> inputs;
  13628. ForEachChildFrom(i, expr, 1)
  13629. inputs.append(*getConditionalActivity(ctx, expr->queryChild(i), isChild));
  13630. OwnedHqlExpr branch = adjustValue(expr->queryChild(0), -1);
  13631. return doBuildActivityChoose(ctx, expr, branch, inputs, isRoot);
  13632. }
  13633. ABoundActivity * HqlCppTranslator::doBuildActivityCase(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  13634. {
  13635. node_operator op = expr->getOperator();
  13636. bool isChild = (insideChildOrLoopGraph(ctx) || insideRemoteGraph(ctx));
  13637. unsigned first = 0;
  13638. unsigned max = expr->numChildren();
  13639. if (op == no_case)
  13640. first++;
  13641. CIArrayOf<ABoundActivity> inputs;
  13642. for (unsigned iinput = first; iinput < max-1; iinput++)
  13643. inputs.append(*getConditionalActivity(ctx, expr->queryChild(iinput)->queryChild(1), isChild));
  13644. Owned<ABoundActivity> boundDefault = getConditionalActivity(ctx, expr->queryChild(max-1), isChild);
  13645. ThorActivityKind tak = isChild ? TAKchildcase : TAKcase;
  13646. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, "Case");
  13647. buildActivityFramework(instance, isRoot);
  13648. buildInstancePrefix(instance);
  13649. BuildCtx funcctx(instance->startctx);
  13650. funcctx.addQuotedCompound("virtual unsigned getBranch()");
  13651. //MORE: If we created a map/case expression and then called buildReturn it would potentially generate better code.
  13652. // code is below, but not enabled because it doesn't necessarily improve things at the moment (see jholt39.xhql)
  13653. IHqlExpression * activeGraph = queryActiveSubGraph(ctx)->graphTag;
  13654. HqlExprArray args;
  13655. if (op == no_case)
  13656. args.append(*LINK(expr->queryChild(0)));
  13657. StringBuffer label;
  13658. for (unsigned idx = first; idx < max-1; idx++)
  13659. {
  13660. unsigned branchIdx = idx-first;
  13661. IHqlExpression * branch = expr->queryChild(idx);
  13662. IHqlExpression * branchCond = branch->queryChild(0);
  13663. OwnedHqlExpr ret = getSizetConstant(branchIdx);
  13664. args.append(*createValue(no_mapto, ret->getType(), LINK(branchCond), LINK(ret)));
  13665. ABoundActivity * boundBranch = &inputs.item(branchIdx);
  13666. getExprECL(branchCond, label.clear(), false, true);
  13667. if (label.length() > 20)
  13668. label.clear().append("Branch ").append(branchIdx+1);
  13669. if (expr->isAction())
  13670. addActionConnection(ctx, boundBranch, instance, dependencyAtom, label.str(), branchIdx, branchIdx+1);
  13671. else
  13672. buildConnectInputOutput(ctx, instance, boundBranch, 0, branchIdx, label.str());
  13673. }
  13674. args.append(*createConstant(unsignedType->castFrom(false, (__int64)max-1)));
  13675. OwnedHqlExpr fullCond = createValue(op, LINK(unsignedType), args);
  13676. fullCond.setown(foldHqlExpression(fullCond));
  13677. if (options.spotCSE)
  13678. fullCond.setown(spotScalarCSE(fullCond));
  13679. buildReturn(funcctx, fullCond);
  13680. bool graphIndependent = isGraphIndependent(fullCond, activeGraph);
  13681. if (graphIndependent && !instance->hasChildActivity)
  13682. instance->addAttributeBool("_graphIndependent", true);
  13683. buildConnectInputOutput(ctx, instance, boundDefault, 0, max-1-first, "default");
  13684. buildInstanceSuffix(instance);
  13685. return instance->getBoundActivity();
  13686. }
  13687. //---------------------------------------------------------------------------
  13688. //-- no_sort [SORT] --
  13689. void HqlCppTranslator::buildSkewThresholdMembers(BuildCtx & ctx, IHqlExpression * expr)
  13690. {
  13691. StringBuffer s, temp;
  13692. if (getAttribute(expr, thresholdAtom, temp.clear()))
  13693. {
  13694. s.clear().append("virtual unsigned __int64 getThreshold() { return ").append(temp).append("; }");
  13695. ctx.addQuoted(s);
  13696. }
  13697. IHqlExpression * skew = expr->queryAttribute(skewAtom);
  13698. if (skew)
  13699. {
  13700. Owned<ITypeInfo> doubleType = makeRealType(8);
  13701. IHqlExpression * skewMax = skew->queryChild(0);
  13702. if (skewMax->getOperator() != no_null)
  13703. doBuildFunction(ctx, doubleType, "getSkew", skewMax);
  13704. IHqlExpression * skewTarget = queryRealChild(skew, 1);
  13705. doBuildFunction(ctx, doubleType, "getTargetSkew", skewTarget);
  13706. }
  13707. }
  13708. ABoundActivity * HqlCppTranslator::doBuildActivitySort(BuildCtx & ctx, IHqlExpression * expr)
  13709. {
  13710. IHqlExpression * dataset = expr->queryChild(0);
  13711. LinkedHqlExpr sortlist = expr->queryChild(1);
  13712. IHqlExpression * limit = NULL;
  13713. IHqlExpression * cosort = NULL;
  13714. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13715. const char *helper;
  13716. ThorActivityKind actKind = TAKsort;
  13717. switch (expr->getOperator())
  13718. {
  13719. case no_topn:
  13720. {
  13721. actKind = TAKtopn;
  13722. limit = expr->queryChild(2);
  13723. helper = "TopN";
  13724. break;
  13725. }
  13726. case no_assertsorted:
  13727. {
  13728. actKind = TAKsorted;
  13729. helper = "Sort";
  13730. break;
  13731. }
  13732. case no_subsort:
  13733. actKind = TAKsubsort;
  13734. helper = "SubSort";
  13735. break;
  13736. default:
  13737. {
  13738. cosort = expr->queryChild(2);
  13739. if (cosort && cosort->isAttribute())
  13740. cosort = NULL;
  13741. helper = "Sort";
  13742. break;
  13743. }
  13744. }
  13745. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, actKind, expr, helper);
  13746. buildActivityFramework(instance);
  13747. StringBuffer s;
  13748. buildInstancePrefix(instance);
  13749. instance->classctx.addQuoted("virtual ICompare * queryCompare() { return &compare; }");
  13750. // sortlist.setown(spotScalarCSE(sortlist));
  13751. buildCompareClass(instance->nestedctx, "compare", sortlist, DatasetReference(dataset));
  13752. IHqlExpression * record = dataset->queryRecord();
  13753. IAtom * serializeType = diskAtom; //MORE: Does this place a dependency on the implementation?
  13754. OwnedHqlExpr serializedRecord = getSerializedForm(record, serializeType);
  13755. if (!targetRoxie())
  13756. {
  13757. if (record != serializedRecord)
  13758. {
  13759. instance->classctx.addQuoted("virtual ICompare * queryCompareSerializedRow() { return &compareSR; }");
  13760. OwnedHqlExpr selSeq = createSelectorSequence();
  13761. OwnedHqlExpr leftSelector = createSelector(no_left, dataset, selSeq);
  13762. OwnedHqlExpr mappedSortlist = replaceSelector(sortlist, dataset, leftSelector);
  13763. OwnedHqlExpr serializedSortlist = replaceMemorySelectorWithSerializedSelector(mappedSortlist, record, no_left, selSeq, serializeType);
  13764. OwnedHqlExpr serializedDataset = createDataset(no_null, LINK(serializedRecord));
  13765. DatasetReference serializedRef(serializedDataset, no_left, selSeq);
  13766. try
  13767. {
  13768. buildCompareClass(instance->nestedctx, "compareSR", serializedSortlist, serializedRef);
  13769. }
  13770. catch (IException * e)
  13771. {
  13772. e->Release();
  13773. ERRORAT(queryLocation(expr), HQLERR_CannotGenerateSerializedCompare);
  13774. }
  13775. }
  13776. }
  13777. HqlExprArray sorts;
  13778. sortlist->unwindList(sorts, no_sortlist);
  13779. bool tryToSerializeKey = (actKind == TAKsort) && !isGroupedActivity(expr) && !isLocalActivity(expr) && !instance->isChildActivity();
  13780. generateSerializeKey(instance->nestedctx, no_none, DatasetReference(dataset), sorts, tryToSerializeKey, false, false);
  13781. buildSkewThresholdMembers(instance->classctx, expr);
  13782. if (expr->getOperator() == no_subsort)
  13783. doBuildFuncIsSameGroup(instance->startctx, dataset, expr->queryChild(2));
  13784. if (limit)
  13785. {
  13786. OwnedHqlExpr newLimit = ensurePositiveOrZeroInt64(limit);
  13787. BuildCtx funcctx(instance->startctx);
  13788. funcctx.addQuotedCompound("virtual __int64 getLimit()");
  13789. buildReturn(funcctx, newLimit, defaultIntegralType);
  13790. }
  13791. IHqlExpression * best = expr->queryAttribute(bestAtom);
  13792. if (best)
  13793. {
  13794. doBuildBoolFunction(instance->classctx, "hasBest", true);
  13795. HqlExprArray sortValues, maxValues;
  13796. sortlist->unwindList(sortValues, no_sortlist);
  13797. unwindChildren(maxValues, best);
  13798. ForEachItemIn(i, sortValues)
  13799. {
  13800. IHqlExpression & cur = sortValues.item(i);
  13801. if (cur.getOperator() == no_negate)
  13802. {
  13803. sortValues.replace(OLINK(maxValues.item(i)), i);
  13804. maxValues.replace(*LINK(cur.queryChild(0)), i);
  13805. }
  13806. }
  13807. OwnedHqlExpr order = createValue(no_order, LINK(signedType), createSortList(sortValues), createSortList(maxValues));
  13808. BuildCtx funcctx(instance->startctx);
  13809. funcctx.addQuotedCompound("virtual int compareBest(const void * _self)");
  13810. funcctx.addQuoted("unsigned char * self = (unsigned char *) _self;");
  13811. bindTableCursor(funcctx, dataset, "self");
  13812. buildReturn(funcctx, order);
  13813. }
  13814. if (cosort)
  13815. {
  13816. //cosort has form joined(dataset),
  13817. IHqlExpression * cosortDataset = cosort->queryChild(0);
  13818. if (cosortDataset->getOperator() == no_compound_diskread)
  13819. cosortDataset = cosortDataset->queryChild(0);
  13820. if (cosortDataset->getOperator() == no_sorted)
  13821. {
  13822. IHqlExpression * source = cosortDataset->queryChild(0);
  13823. if (source->getOperator() != no_table)
  13824. throwError(HQLERR_JoinSortedMustBeDataset);
  13825. IHqlExpression * sourceType = source->queryChild(2);
  13826. if (!sourceType || sourceType->getOperator() != no_thor)
  13827. throwError(HQLERR_JoinSortedMustBeThor);
  13828. s.clear().append("virtual const char * getSortedFilename() { return ");
  13829. generateExprCpp(s, source->queryChild(0)).append("; }");
  13830. instance->startctx.addQuoted(s);
  13831. buildMetaMember(instance->classctx, cosortDataset, false, "querySortedRecordSize");
  13832. }
  13833. else
  13834. {
  13835. instance->startctx.addQuoted("virtual const char * getSortedFilename() { return NULL; }");
  13836. instance->classctx.addQuoted("virtual IOutputMetaData * querySortedRecordSize() { return NULL; }");
  13837. ABoundActivity * masterSort = queryAssociatedActivity(ctx, cosortDataset);
  13838. if (!masterSort)
  13839. throwError(HQLERR_SortAndCoSortConcurrent);
  13840. Owned<ABoundActivity> slave = instance->getBoundActivity();
  13841. buildConnectOrders(ctx, slave, masterSort);
  13842. }
  13843. HqlExprArray left, right;
  13844. cosortDataset->queryChild(1)->unwindList(left, no_sortlist);
  13845. sortlist->unwindList(right, no_sortlist);
  13846. doCompareLeftRight(instance->nestedctx, "CompareLeftRight", DatasetReference(cosortDataset), DatasetReference(dataset), left, right);
  13847. }
  13848. if (expr->hasAttribute(manyAtom))
  13849. instance->classctx.addQuoted("virtual bool hasManyRecords() { return true; }");
  13850. IHqlExpression * stable = expr->queryAttribute(stableAtom);
  13851. IHqlExpression * unstable = expr->queryAttribute(unstableAtom);
  13852. IHqlExpression * method = NULL;
  13853. StringBuffer flags;
  13854. if (stable)
  13855. {
  13856. flags.append("|TAFstable");
  13857. method = stable->queryChild(0);
  13858. }
  13859. else if (unstable)
  13860. {
  13861. flags.append("|TAFunstable");
  13862. method = unstable->queryChild(0);
  13863. }
  13864. if (!method || method->isConstant())
  13865. flags.append("|TAFconstant");
  13866. if (method)
  13867. doBuildVarStringFunction(instance->startctx, "getAlgorithm", method);
  13868. if (!streq(flags.str(), "|TAFconstant"))
  13869. instance->classctx.addQuotedF("virtual unsigned getAlgorithmFlags() { return %s; }", flags.str()+1);
  13870. buildInstanceSuffix(instance);
  13871. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13872. return instance->getBoundActivity();
  13873. }
  13874. //---------------------------------------------------------------------------
  13875. void HqlCppTranslator::doBuildXmlReadMember(ActivityInstance & instance, IHqlExpression * expr, const char * functionName, bool & usesContents)
  13876. {
  13877. StringBuffer s, xmlInstanceName;
  13878. usesContents = false;
  13879. if (isValidXmlRecord(expr->queryRecord()))
  13880. {
  13881. StringBuffer xmlFactoryName;
  13882. getUniqueId(xmlInstanceName.append("xml"));
  13883. buildXmlReadTransform(expr, xmlFactoryName, usesContents);
  13884. instance.classctx.addQuoted(s.clear().append("Owned<IXmlToRowTransformer> ").append(xmlInstanceName).append(";"));
  13885. BuildCtx * callctx = NULL;
  13886. instance.evalContext->getInvariantMemberContext(NULL, NULL, &callctx, true, false);
  13887. callctx->addQuoted(s.clear().append(xmlInstanceName).append(".setown(").append(xmlFactoryName).append("(ctx,").append(instance.activityId).append("));"));
  13888. }
  13889. else
  13890. xmlInstanceName.append("NULL");
  13891. s.clear().append("virtual IXmlToRowTransformer * ").append(functionName).append("() { return ").append(xmlInstanceName).append("; }");
  13892. instance.classctx.addQuoted(s);
  13893. }
  13894. ABoundActivity * HqlCppTranslator::doBuildActivityWorkunitRead(BuildCtx & ctx, IHqlExpression * expr)
  13895. {
  13896. IHqlExpression * wuid = expr->queryAttribute(wuidAtom);
  13897. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  13898. IHqlExpression * name = queryAttributeChild(expr, nameAtom, 0);
  13899. __int64 sequenceValue = sequence->queryValue()->getIntValue();
  13900. bool isStored = (sequenceValue == ResultSequenceStored);
  13901. bool useImplementationClass = options.minimizeActivityClasses && !wuid && (sequenceValue == ResultSequenceInternal);
  13902. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKworkunitread, expr,"WorkunitRead");
  13903. if (useImplementationClass)
  13904. instance->setImplementationClass(newWorkUnitReadArgId);
  13905. noteResultAccessed(ctx, sequence, name);
  13906. StringBuffer graphLabel;
  13907. graphLabel.append(getActivityText(instance->kind)).append("\n");
  13908. getStoredDescription(graphLabel, sequence, name, true);
  13909. instance->graphLabel.set(graphLabel.str());
  13910. buildActivityFramework(instance);
  13911. buildInstancePrefix(instance);
  13912. if (!useImplementationClass)
  13913. {
  13914. doBuildVarStringFunction(instance->classctx, "queryName", name);
  13915. if (sequenceValue != ResultSequenceInternal)
  13916. {
  13917. BuildCtx func2ctx(instance->classctx);
  13918. func2ctx.addQuotedCompound("virtual int querySequence()");
  13919. buildReturn(func2ctx, sequence, signedType);
  13920. }
  13921. if (wuid)
  13922. doBuildVarStringFunction(instance->startctx, "getWUID", wuid->queryChild(0));
  13923. bool usesContents = false;
  13924. if (isStored || (targetRoxie() && (sequenceValue >= 0)))
  13925. doBuildXmlReadMember(*instance, expr, "queryXmlTransformer", usesContents);
  13926. StringBuffer csvInstanceName;
  13927. if (isValidCsvRecord(expr->queryRecord()) && isStored && options.allowCsvWorkunitRead)
  13928. {
  13929. buildCsvReadTransformer(expr, csvInstanceName, NULL);
  13930. StringBuffer s;
  13931. s.append("virtual ICsvToRowTransformer * queryCsvTransformer() { return &").append(csvInstanceName).append("; }");
  13932. instance->classctx.addQuoted(s);
  13933. }
  13934. }
  13935. else
  13936. {
  13937. instance->addConstructorParameter(name);
  13938. }
  13939. queryAddResultDependancy(*instance->queryBoundActivity(), sequence, name);
  13940. buildInstanceSuffix(instance);
  13941. return instance->getBoundActivity();
  13942. }
  13943. //---------------------------------------------------------------------------
  13944. //-- xmlparse
  13945. void HqlCppTranslator::noteXpathUsed(const char * xpath)
  13946. {
  13947. if (strstr(xpath, XPATH_CONTENTS_TEXT))
  13948. xmlUsesContents = true;
  13949. }
  13950. void HqlCppTranslator::noteXpathUsed(IHqlExpression * expr)
  13951. {
  13952. IValue * value = expr->queryValue();
  13953. if (value)
  13954. {
  13955. StringBuffer temp;
  13956. value->getStringValue(temp);
  13957. noteXpathUsed(temp);
  13958. }
  13959. else
  13960. xmlUsesContents = true;
  13961. }
  13962. ABoundActivity * HqlCppTranslator::doBuildActivityXmlParse(BuildCtx & ctx, IHqlExpression * expr)
  13963. {
  13964. IHqlExpression * dataset = expr->queryChild(0);
  13965. IHqlExpression * selSeq = querySelSeq(expr);
  13966. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  13967. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKxmlparse, expr, "XmlParse");
  13968. buildActivityFramework(instance);
  13969. buildInstancePrefix(instance);
  13970. IHqlExpression * xmlAttr = expr->queryAttribute(xmlAtom);
  13971. //MORE: What encoding is the search text in???
  13972. doBuildParseSearchText(instance->startctx, dataset, expr->queryChild(1), type_utf8, unknownStringType);
  13973. doBuildVarStringFunction(instance->classctx, "getXmlIteratorPath", xmlAttr ? queryRealChild(xmlAttr, 0) : NULL);
  13974. BuildCtx funcctx(instance->startctx);
  13975. funcctx.addQuotedCompound("virtual size32_t transform(ARowBuilder & crSelf, const void * _left, IColumnProvider * parsed)");
  13976. ensureRowAllocated(funcctx, "crSelf");
  13977. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  13978. // Both left and the dataset are bound to left because it might be a new transform or a transform
  13979. IHqlExpression * transform = expr->queryChild(3);
  13980. BoundRow * selfCursor = bindSelf(funcctx, expr, "crSelf");
  13981. if (transform->getOperator() == no_newtransform)
  13982. bindTableCursor(funcctx, dataset, "left");
  13983. else
  13984. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  13985. associateSkipReturnMarker(funcctx, queryZero(), selfCursor);
  13986. OwnedHqlExpr helperName = createQuoted("parsed", makeBoolType());
  13987. funcctx.associateExpr(xmlColumnProviderMarkerExpr, helperName);
  13988. bindTableCursor(funcctx, queryXmlParsePseudoTable(), queryXmlParsePseudoTable());
  13989. xmlUsesContents = false;
  13990. doTransform(funcctx, transform, selfCursor);
  13991. buildReturnRecordSize(funcctx, selfCursor);
  13992. if (xmlUsesContents)
  13993. instance->classctx.addQuoted("virtual bool requiresContents() { return true; }");
  13994. buildInstanceSuffix(instance);
  13995. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  13996. return instance->getBoundActivity();
  13997. }
  13998. void HqlCppTranslator::doBuildExprXmlText(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  13999. {
  14000. HqlExprAssociation * match = ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  14001. if (!match)
  14002. throwError(HQLERR_XmlTextNotValid);
  14003. IHqlExpression * xpath = expr->queryChild(0);
  14004. noteXpathUsed(xpath);
  14005. HqlExprArray args;
  14006. args.append(*LINK(match->queryExpr()));
  14007. args.append(*LINK(xpath));
  14008. OwnedHqlExpr call = bindFunctionCall(columnGetStringXId, args);
  14009. buildCachedExpr(ctx, call, tgt);
  14010. }
  14011. void HqlCppTranslator::doBuildExprXmlUnicode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  14012. {
  14013. HqlExprAssociation * match = ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  14014. if (!match)
  14015. throwError(HQLERR_XmlUnicodeNotValid);
  14016. IHqlExpression * xpath = expr->queryChild(0);
  14017. noteXpathUsed(xpath);
  14018. HqlExprArray args;
  14019. args.append(*LINK(match->queryExpr()));
  14020. args.append(*LINK(xpath));
  14021. OwnedHqlExpr call = bindFunctionCall(columnGetUnicodeXId, args);
  14022. buildCachedExpr(ctx, call, tgt);
  14023. }
  14024. void HqlCppTranslator::buildDatasetAssignXmlProject(BuildCtx & ctx, IHqlCppDatasetBuilder * target, IHqlExpression * expr)
  14025. {
  14026. HqlExprAssociation * match = ctx.queryMatchExpr(xmlColumnProviderMarkerExpr);
  14027. if (!match)
  14028. throwError(HQLERR_XmlTextNotValid);
  14029. StringBuffer iterTag;
  14030. IHqlExpression * xpath = expr->queryChild(0);
  14031. if (xpath->queryValue())
  14032. xpath->queryValue()->getStringValue(iterTag);
  14033. noteXpathUsed(xpath);
  14034. //Generate the code to process a child iterator
  14035. OwnedHqlExpr subRowExpr;
  14036. BuildCtx loopctx(ctx);
  14037. buildXmlReadChildrenIterator(loopctx, iterTag.str(), match->queryExpr(), subRowExpr);
  14038. loopctx.associateExpr(xmlColumnProviderMarkerExpr, subRowExpr);
  14039. BoundRow * targetRow = target->buildCreateRow(loopctx);
  14040. Owned<IReferenceSelector> targetRef = buildActiveRow(loopctx, targetRow->querySelector());
  14041. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(expr->queryChild(1)));
  14042. buildRowAssign(loopctx, targetRef, rowValue);
  14043. target->finishRow(loopctx, targetRow);
  14044. }
  14045. //---------------------------------------------------------------------------
  14046. //-- no_temptable [DATASET] --
  14047. void HqlCppTranslator::doBuildTempTableFlags(BuildCtx & ctx, IHqlExpression * expr, bool isConstant)
  14048. {
  14049. StringBuffer flags;
  14050. if (expr->hasAttribute(distributedAtom))
  14051. flags.append("|TTFdistributed");
  14052. if (!isConstant)
  14053. flags.append("|TTFnoconstant");
  14054. if (flags.length())
  14055. doBuildUnsignedFunction(ctx, "getFlags", flags.str()+1);
  14056. }
  14057. ABoundActivity * HqlCppTranslator::doBuildActivityTempTable(BuildCtx & ctx, IHqlExpression * expr)
  14058. {
  14059. StringBuffer s;
  14060. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineTable");
  14061. OwnedHqlExpr values = normalizeListCasts(expr->queryChild(0));
  14062. IHqlExpression * record = expr->queryChild(1);
  14063. IHqlExpression * defaults = expr->queryChild(2);
  14064. assertex(values->getOperator() != no_recordlist); // should have been transformed by now.
  14065. //-----------------
  14066. buildActivityFramework(instance);
  14067. buildInstancePrefix(instance);
  14068. BuildCtx funcctx(instance->startctx);
  14069. funcctx.addQuotedCompound("virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14070. ensureRowAllocated(funcctx, "crSelf");
  14071. BoundRow * selfCursor = bindSelf(funcctx, instance->dataset, "crSelf");
  14072. IHqlExpression * self = selfCursor->querySelector();
  14073. OwnedHqlExpr clearAction;
  14074. OwnedHqlExpr rowsExpr;
  14075. OwnedHqlExpr rowVar = createVariable("row", makeIntType(8, false));
  14076. if (expr->getOperator() == no_datasetfromrow)
  14077. {
  14078. BuildCtx subctx(funcctx);
  14079. subctx.addFilter(rowVar);
  14080. if (clearAction)
  14081. subctx.addExpr(clearAction);
  14082. subctx.addReturn(queryZero());
  14083. buildAssign(funcctx, self, values);
  14084. buildReturnRecordSize(funcctx, selfCursor);
  14085. rowsExpr.setown(getSizetConstant(1));
  14086. }
  14087. else if ((values->getOperator() == no_list) || (values->getOperator() == no_null))
  14088. // else if (((values->getOperator() == no_list) &&
  14089. // (!values->isConstant() || (values->queryType()->queryChildType()->getSize() == UNKNOWN_LENGTH))) || (values->getOperator() == no_null))
  14090. {
  14091. //
  14092. unsigned maxRows = values->numChildren();
  14093. if (maxRows)
  14094. {
  14095. unsigned dummyIdx = 0;
  14096. OwnedHqlExpr tgt = createSelectExpr(LINK(self), LINK(queryNextRecordField(record, dummyIdx)));
  14097. BuildCtx switchctx(funcctx);
  14098. switchctx.addQuotedCompound("switch (row)");
  14099. unsigned row;
  14100. for (row = 0; row < maxRows; row++)
  14101. {
  14102. BuildCtx casectx(switchctx);
  14103. casectx.addQuotedCompound(s.clear().append("case ").append(row).append(":"));
  14104. buildAssign(casectx, tgt, values->queryChild(row));
  14105. //casectx.setNextDestructor();
  14106. buildReturnRecordSize(casectx, selfCursor);
  14107. }
  14108. }
  14109. if (clearAction)
  14110. funcctx.addExpr(clearAction);
  14111. funcctx.addReturn(queryZero());
  14112. rowsExpr.setown(getSizetConstant(maxRows));
  14113. }
  14114. else
  14115. {
  14116. CHqlBoundExpr bound;
  14117. //MORE: This shouldn't be done this way...
  14118. OwnedHqlExpr normalized = normalizeListCasts(values);
  14119. if (normalized->getOperator() == no_alias)
  14120. buildExpr(instance->startctx, normalized, bound);
  14121. else
  14122. {
  14123. BuildCtx * declarectx;
  14124. BuildCtx * callctx;
  14125. instance->evalContext->getInvariantMemberContext(NULL, &declarectx, &callctx, false, isContextDependent(normalized, false, false) || !isIndependentOfScope(normalized));
  14126. // if (isContextDependent(normalized, false, false))
  14127. // buildTempExpr(instance->onstartctx, *declarectx, normalized, bound, FormatNatural);
  14128. // else
  14129. CHqlBoundTarget tempTarget;
  14130. buildTempExpr(*callctx, *declarectx, tempTarget, normalized, FormatNatural, !canSetBeAll(normalized));
  14131. bound.setFromTarget(tempTarget);
  14132. }
  14133. rowsExpr.setown(getBoundCount(bound));
  14134. rowsExpr.setown(createTranslated(rowsExpr));
  14135. OwnedHqlExpr compare = createValue(no_ge, makeBoolType(), LINK(rowVar), ensureExprType(rowsExpr, rowVar->queryType()));
  14136. BuildCtx condctx(funcctx);
  14137. buildFilter(condctx, compare);
  14138. if (clearAction)
  14139. condctx.addExpr(clearAction);
  14140. buildReturn(condctx, queryZero());
  14141. HqlExprArray args;
  14142. args.append(*bound.getTranslatedExpr());
  14143. args.append(*adjustValue(rowVar, 1));
  14144. args.append(*createAttribute(noBoundCheckAtom));
  14145. args.append(*createAttribute(forceAllCheckAtom));
  14146. OwnedHqlExpr src = createValue(no_index, LINK(values->queryType()->queryChildType()), args);
  14147. OwnedHqlExpr tgt = createSelectExpr(LINK(self), LINK(queryOnlyField(record)));
  14148. buildAssign(funcctx, tgt, src);
  14149. buildReturnRecordSize(funcctx, selfCursor);
  14150. }
  14151. doBuildUnsigned64Function(instance->startctx, "numRows", rowsExpr);
  14152. doBuildTempTableFlags(instance->startctx, expr, values->isConstant());
  14153. buildInstanceSuffix(instance);
  14154. return instance->getBoundActivity();
  14155. }
  14156. //NB: Also used to create row no_null as an activity.
  14157. ABoundActivity * HqlCppTranslator::doBuildActivityCreateRow(BuildCtx & ctx, IHqlExpression * expr, bool isDataset)
  14158. {
  14159. bool valuesAreConstant = false;
  14160. StringBuffer valueText;
  14161. IValue * singleValue = NULL;
  14162. node_operator op = expr->getOperator();
  14163. if (op == no_createrow)
  14164. {
  14165. IHqlExpression * transform = expr->queryChild(0);
  14166. if (transform->isConstant())
  14167. {
  14168. IHqlExpression * assign = queryTransformSingleAssign(transform);
  14169. if (assign)
  14170. {
  14171. singleValue = assign->queryChild(1)->queryValue();
  14172. if (singleValue)
  14173. singleValue->generateECL(valueText);
  14174. }
  14175. valuesAreConstant = true;
  14176. }
  14177. if (!isDataset && containsSkip(transform))
  14178. reportError(queryLocation(transform), ECODETEXT(HQLERR_SkipInsideCreateRow));
  14179. }
  14180. else if (op == no_null)
  14181. {
  14182. valueText.append("Blank");
  14183. valuesAreConstant = true;
  14184. }
  14185. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineRow");
  14186. if (valueText.length())
  14187. {
  14188. StringBuffer graphLabel;
  14189. elideString(valueText, MAX_ROW_VALUE_TEXT_LEN);
  14190. graphLabel.append("Inline Row\n{").append(valueText).append("}");
  14191. instance->graphLabel.set(graphLabel.str());
  14192. }
  14193. else
  14194. instance->graphLabel.set("Inline Row");
  14195. //-----------------
  14196. buildActivityFramework(instance);
  14197. buildInstancePrefix(instance);
  14198. BuildCtx funcctx(instance->startctx);
  14199. // Ignoring row argument, since engines will stop at numRows(), which is 1
  14200. funcctx.addQuotedCompound("virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14201. ensureRowAllocated(funcctx, "crSelf");
  14202. BoundRow * selfCursor = bindSelf(funcctx, instance->dataset, "crSelf");
  14203. IHqlExpression * self = selfCursor->querySelector();
  14204. if (isDataset)
  14205. associateSkipReturnMarker(funcctx, queryBoolExpr(false), selfCursor);
  14206. buildAssign(funcctx, self, expr);
  14207. buildReturnRecordSize(funcctx, selfCursor);
  14208. doBuildTempTableFlags(instance->startctx, expr, valuesAreConstant);
  14209. buildInstanceSuffix(instance);
  14210. return instance->getBoundActivity();
  14211. }
  14212. ABoundActivity * HqlCppTranslator::doBuildActivityInlineTable(BuildCtx & ctx, IHqlExpression * expr)
  14213. {
  14214. IHqlExpression * values = expr->queryChild(0);
  14215. if (values->numChildren() == 1)
  14216. {
  14217. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(values->queryChild(0)));
  14218. OwnedHqlExpr row = expr->cloneAllAnnotations(rowValue);
  14219. return doBuildActivityCreateRow(ctx, row, true);
  14220. }
  14221. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineTable");
  14222. //-----------------
  14223. buildActivityFramework(instance);
  14224. buildInstancePrefix(instance);
  14225. BuildCtx funcctx(instance->startctx);
  14226. funcctx.addQuotedCompound("virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14227. ensureRowAllocated(funcctx, "crSelf");
  14228. BoundRow * selfCursor = bindSelf(funcctx, instance->dataset, "crSelf");
  14229. IHqlExpression * self = selfCursor->querySelector();
  14230. unsigned maxRows = values->numChildren();
  14231. bool done = false;
  14232. if (values->isConstant())
  14233. {
  14234. CHqlBoundExpr bound;
  14235. if (doBuildDatasetInlineTable(funcctx, expr, bound, FormatNatural))
  14236. {
  14237. OwnedHqlExpr whichRow = createVariable("row", LINK(unsignedType));
  14238. BuildCtx subctx(funcctx);
  14239. OwnedHqlExpr test = createValue(no_ge, makeBoolType(), LINK(whichRow), getSizetConstant(maxRows));
  14240. subctx.addFilter(test);
  14241. buildReturn(subctx, queryZero());
  14242. OwnedHqlExpr ds = bound.getTranslatedExpr();
  14243. OwnedHqlExpr thisRow = createRowF(no_selectnth, LINK(ds), adjustValue(whichRow, 1), createAttribute(noBoundCheckAtom), NULL);
  14244. buildAssign(funcctx, self, thisRow);
  14245. buildReturnRecordSize(funcctx, selfCursor);
  14246. done = true;
  14247. }
  14248. }
  14249. if (!done)
  14250. {
  14251. if (maxRows)
  14252. {
  14253. StringBuffer s;
  14254. BuildCtx switchctx(funcctx);
  14255. switchctx.addQuotedCompound("switch (row)");
  14256. unsigned row;
  14257. for (row = 0; row < maxRows; row++)
  14258. {
  14259. BuildCtx casectx(switchctx);
  14260. casectx.addQuotedCompound(s.clear().append("case ").append(row).append(":"));
  14261. IHqlExpression * cur = values->queryChild(row);
  14262. OwnedHqlExpr rowValue = createRow(no_createrow, LINK(cur));
  14263. buildAssign(casectx, self, rowValue);
  14264. buildReturnRecordSize(casectx, selfCursor);
  14265. }
  14266. }
  14267. funcctx.addReturn(queryZero());
  14268. }
  14269. OwnedHqlExpr rowsExpr = getSizetConstant(maxRows);
  14270. doBuildUnsigned64Function(instance->startctx, "numRows", rowsExpr);
  14271. doBuildTempTableFlags(instance->startctx, expr, values->isConstant());
  14272. buildInstanceSuffix(instance);
  14273. return instance->getBoundActivity();
  14274. }
  14275. //---------------------------------------------------------------------------
  14276. ABoundActivity * HqlCppTranslator::doBuildActivityCountTransform(BuildCtx & ctx, IHqlExpression * expr)
  14277. {
  14278. IHqlExpression * count = expr->queryChild(0);
  14279. IHqlExpression * transform = queryNewColumnProvider(expr);
  14280. IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
  14281. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKinlinetable, expr, "InlineTable");
  14282. buildActivityFramework(instance);
  14283. buildInstancePrefix(instance);
  14284. // size32_t getRow()
  14285. BuildCtx funcctx(instance->startctx);
  14286. funcctx.addQuotedCompound("virtual size32_t getRow(ARowBuilder & crSelf, __uint64 row)");
  14287. ensureRowAllocated(funcctx, "crSelf");
  14288. BoundRow * selfCursor = bindSelf(funcctx, instance->dataset, "crSelf");
  14289. IHqlExpression * self = selfCursor->querySelector();
  14290. associateCounter(funcctx, counter, "(row+1)");
  14291. buildTransformBody(funcctx, transform, NULL, NULL, instance->dataset, self);
  14292. // unsigned numRows() - count is guaranteed by lexer
  14293. doBuildUnsigned64Function(instance->startctx, "numRows", count);
  14294. // unsigned getFlags()
  14295. doBuildTempTableFlags(instance->startctx, expr, isConstantTransform(transform));
  14296. buildInstanceSuffix(instance);
  14297. return instance->getBoundActivity();
  14298. }
  14299. //---------------------------------------------------------------------------
  14300. void HqlCppTranslator::buildHTTPtoXml(BuildCtx & ctx)
  14301. {
  14302. BuildCtx funcctx(ctx);
  14303. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  14304. funcctx.addQuotedCompound("virtual void toXML(const byte *, IXmlWriter & out)");
  14305. }
  14306. //---------------------------------------------------------------------------
  14307. void HqlCppTranslator::buildSOAPtoXml(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * transform, IHqlExpression * selSeq)
  14308. {
  14309. BuildCtx funcctx(ctx);
  14310. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  14311. if (dataset)
  14312. {
  14313. funcctx.addQuotedCompound("virtual void toXML(const byte * left, IXmlWriter & out)");
  14314. if (transform->getOperator() == no_newtransform)
  14315. bindTableCursor(funcctx, dataset, "left");
  14316. else
  14317. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  14318. }
  14319. else
  14320. funcctx.addQuotedCompound("virtual void toXML(const byte *, IXmlWriter & out)");
  14321. // Bind left to "left" and right to RIGHT
  14322. HqlExprArray assigns;
  14323. filterExpandAssignments(funcctx, NULL, assigns, transform);
  14324. OwnedHqlExpr self = getSelf(transform);
  14325. buildXmlSerialize(funcctx, transform->queryRecord(), self, &assigns);
  14326. }
  14327. IHqlExpression * HqlCppTranslator::associateLocalFailure(BuildCtx & ctx, const char * exceptionName)
  14328. {
  14329. OwnedHqlExpr activeFailMarker = createAttribute(activeFailureAtom);
  14330. OwnedHqlExpr activeFailVariable = createVariable(exceptionName, makeBoolType());
  14331. ctx.associateExpr(activeFailMarker, activeFailVariable);
  14332. return activeFailVariable;
  14333. }
  14334. void HqlCppTranslator::validateExprScope(BuildCtx & ctx, IHqlExpression * dataset, IHqlExpression * expr, const char * opName, const char * argName)
  14335. {
  14336. if (dataset && exprReferencesDataset(expr, dataset) && !resolveSelectorDataset(ctx, dataset))
  14337. throwError2(HQLERR_OpArgDependsDataset, opName, argName);
  14338. }
  14339. ABoundActivity * HqlCppTranslator::doBuildActivitySOAP(BuildCtx & ctx, IHqlExpression * expr, bool isSink, bool isRoot)
  14340. {
  14341. ThorActivityKind tak;
  14342. const char * helper;
  14343. unsigned firstArg = 0;
  14344. IHqlExpression * dataset = NULL;
  14345. Owned<ABoundActivity> boundDataset;
  14346. IHqlExpression * selSeq = querySelSeq(expr);
  14347. if (expr->getOperator() == no_newsoapcall)
  14348. {
  14349. if (isSink)
  14350. {
  14351. tak = TAKsoap_rowaction;
  14352. helper = "SoapAction";
  14353. }
  14354. else
  14355. {
  14356. tak = TAKsoap_rowdataset;
  14357. helper = "SoapCall";
  14358. }
  14359. }
  14360. else
  14361. {
  14362. if (isSink)
  14363. {
  14364. tak = TAKsoap_datasetaction;
  14365. helper = "SoapAction";
  14366. }
  14367. else
  14368. {
  14369. tak = TAKsoap_datasetdataset;
  14370. helper = "SoapCall";
  14371. }
  14372. dataset = expr->queryChild(0);
  14373. boundDataset.setown(buildCachedActivity(ctx, dataset));
  14374. firstArg = 1;
  14375. }
  14376. StringBuffer s;
  14377. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, helper);
  14378. //-----------------
  14379. buildActivityFramework(instance, isRoot);
  14380. buildInstancePrefix(instance);
  14381. IHqlExpression * hosts = expr->queryChild(firstArg);
  14382. IHqlExpression * service = expr->queryChild(firstArg+1);
  14383. //Because of scope handling in parser it is possible for these expressions to be unexpectedly dependent on the dataset
  14384. const char * opText = getOpString(expr->getOperator());
  14385. validateExprScope(instance->startctx, dataset, hosts, opText, "host url");
  14386. validateExprScope(instance->startctx, dataset, service, opText, "service");
  14387. //virtual const char * getHosts() = 0;
  14388. doBuildVarStringFunction(instance->startctx, "getHosts", hosts);
  14389. //virtual const char * getService() = 0;
  14390. doBuildVarStringFunction(instance->startctx, "getService", service);
  14391. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  14392. buildSOAPtoXml(instance->startctx, dataset, expr->queryChild(firstArg+3), selSeq);
  14393. //virtual const char * queryOutputIteratorPath()
  14394. IHqlExpression * separator = expr->queryAttribute(separatorAtom);
  14395. if (separator)
  14396. doBuildVarStringFunction(instance->startctx, "queryOutputIteratorPath", separator->queryChild(0));
  14397. //virtual const char * getHeader()
  14398. //virtual const char * getFooter()
  14399. IHqlExpression * header = expr->queryAttribute(headingAtom);
  14400. if (header)
  14401. {
  14402. doBuildVarStringFunction(instance->startctx, "getHeader", header->queryChild(0));
  14403. doBuildVarStringFunction(instance->startctx, "getFooter", header->queryChild(1));
  14404. }
  14405. IHqlExpression * action = expr->queryAttribute(soapActionAtom);
  14406. if (action)
  14407. doBuildVarStringFunction(instance->startctx, "getSoapAction", action->queryChild(0));
  14408. IHqlExpression * httpHeader = expr->queryAttribute(httpHeaderAtom);
  14409. if (httpHeader)
  14410. {
  14411. doBuildVarStringFunction(instance->startctx, "getHttpHeaderName", httpHeader->queryChild(0));
  14412. doBuildVarStringFunction(instance->startctx, "getHttpHeaderValue", httpHeader->queryChild(1));
  14413. }
  14414. IHqlExpression * proxyAddress = expr->queryAttribute(proxyAddressAtom);
  14415. if (proxyAddress)
  14416. {
  14417. doBuildVarStringFunction(instance->startctx, "getProxyAddress", proxyAddress->queryChild(0));
  14418. }
  14419. IHqlExpression * namespaceAttr = expr->queryAttribute(namespaceAtom);
  14420. IHqlExpression * responseAttr = expr->queryAttribute(responseAtom);
  14421. IHqlExpression * logText = NULL;
  14422. bool logMin = false;
  14423. bool logXml = false;
  14424. ForEachChildFrom(i, expr, 1)
  14425. {
  14426. IHqlExpression * cur = expr->queryChild(i);
  14427. if (cur->isAttribute() && cur->queryName()==logAtom)
  14428. {
  14429. IHqlExpression * opt = cur->queryChild(0);
  14430. if (!opt)
  14431. logXml = true;
  14432. else if (!opt->isAttribute())
  14433. logText = opt;
  14434. else if (opt->queryName() == minAtom)
  14435. logMin = true;
  14436. }
  14437. }
  14438. //virtual unsigned getFlags()
  14439. {
  14440. StringBuffer flags;
  14441. if (expr->hasAttribute(groupAtom))
  14442. flags.append("|SOAPFgroup");
  14443. if (expr->hasAttribute(onFailAtom))
  14444. flags.append("|SOAPFonfail");
  14445. if (logXml)
  14446. flags.append("|SOAPFlog");
  14447. if (expr->hasAttribute(trimAtom))
  14448. flags.append("|SOAPFtrim");
  14449. if (expr->hasAttribute(literalAtom))
  14450. flags.append("|SOAPFliteral");
  14451. if (namespaceAttr)
  14452. flags.append("|SOAPFnamespace");
  14453. if (expr->hasAttribute(encodingAtom))
  14454. flags.append("|SOAPFencoding");
  14455. if (responseAttr && responseAttr->hasAttribute(noTrimAtom))
  14456. flags.append("|SOAPFpreserveSpace");
  14457. if (logMin)
  14458. flags.append("|SOAPFlogmin");
  14459. if (logText)
  14460. flags.append("|SOAPFlogusermsg");
  14461. if (flags.length())
  14462. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  14463. }
  14464. //virtual unsigned numParallelThreads()
  14465. doBuildUnsignedFunction(instance->classctx, "numParallelThreads", queryAttributeChild(expr, parallelAtom, 0));
  14466. //virtual unsigned numRecordsPerBatch()
  14467. doBuildUnsignedFunction(instance->classctx, "numRecordsPerBatch", queryAttributeChild(expr, mergeAtom, 0));
  14468. //virtual int numRetries()
  14469. doBuildSignedFunction(instance->classctx, "numRetries", queryAttributeChild(expr, retryAtom, 0));
  14470. //virtual double getTimeout()
  14471. doBuildDoubleFunction(instance->classctx, "getTimeout", queryAttributeChild(expr, timeoutAtom, 0));
  14472. //virtual double getTimeLimit()
  14473. doBuildDoubleFunction(instance->classctx, "getTimeLimit", queryAttributeChild(expr, timeLimitAtom, 0));
  14474. if (namespaceAttr)
  14475. {
  14476. doBuildVarStringFunction(instance->startctx, "getNamespaceName", namespaceAttr->queryChild(0));
  14477. if (namespaceAttr->queryChild(1))
  14478. doBuildVarStringFunction(instance->startctx, "getNamespaceVar", namespaceAttr->queryChild(1));
  14479. }
  14480. if (logText)
  14481. {
  14482. BuildCtx funcctx(instance->startctx);
  14483. funcctx.addQuotedCompound("virtual void getLogText(size32_t & __lenResult, char * & __result, const void * _left)");
  14484. if (dataset)
  14485. {
  14486. funcctx.addQuoted("const unsigned char * left = (const unsigned char *) _left;");
  14487. bindTableCursor(funcctx, dataset, "left");
  14488. bindTableCursor(funcctx, dataset, "left", no_left, selSeq);
  14489. }
  14490. doBuildFunctionReturn(funcctx, unknownStringType, logText);
  14491. }
  14492. if (!isSink)
  14493. {
  14494. //virtual IXmlToRowTransformer * queryTransformer()
  14495. bool usesContents = false;
  14496. doBuildXmlReadMember(*instance, expr, "queryInputTransformer", usesContents);
  14497. if (usesContents)
  14498. throwError(HQLERR_ContentsInSoapCall);
  14499. //virtual const char * getInputIteratorPath()
  14500. IHqlExpression * xpath = expr->queryAttribute(xpathAtom);
  14501. if (xpath)
  14502. doBuildVarStringFunction(instance->classctx, "getInputIteratorPath", xpath->queryChild(0));
  14503. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  14504. if (onFail)
  14505. {
  14506. IHqlExpression * onFailTransform = onFail->queryChild(0);
  14507. if (onFailTransform->isTransform())
  14508. assertex(recordTypesMatch(expr, onFailTransform));
  14509. //virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * e)
  14510. BuildCtx onFailCtx(instance->startctx);
  14511. onFailCtx.addQuotedCompound("virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * except)");
  14512. ensureRowAllocated(onFailCtx, "crSelf");
  14513. associateLocalFailure(onFailCtx, "except");
  14514. buildTransformBody(onFailCtx, onFailTransform, dataset, NULL, expr, selSeq);
  14515. }
  14516. }
  14517. buildInstanceSuffix(instance);
  14518. if (boundDataset)
  14519. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  14520. if (isSink)
  14521. return NULL;
  14522. return instance->getBoundActivity();
  14523. }
  14524. //---------------------------------------------------------------------------
  14525. ABoundActivity * HqlCppTranslator::doBuildActivityHTTP(BuildCtx & ctx, IHqlExpression * expr, bool isSink, bool isRoot)
  14526. {
  14527. ThorActivityKind tak;
  14528. const char * helper = "HttpCall";
  14529. unsigned firstArg = 0;
  14530. IHqlExpression * dataset = NULL;
  14531. Owned<ABoundActivity> boundDataset;
  14532. IHqlExpression * selSeq = querySelSeq(expr);
  14533. assertex(!isSink);
  14534. tak = TAKhttp_rowdataset;
  14535. StringBuffer s;
  14536. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, tak, expr, helper);
  14537. //-----------------
  14538. buildActivityFramework(instance, isRoot);
  14539. buildInstancePrefix(instance);
  14540. //virtual const char * getHosts() = 0;
  14541. doBuildVarStringFunction(instance->startctx, "getHosts", expr->queryChild(firstArg));
  14542. //virtual const char * getService() = 0;
  14543. doBuildVarStringFunction(instance->startctx, "getService", expr->queryChild(firstArg+1));
  14544. //virtual const char * getAcceptType() = 0;
  14545. doBuildVarStringFunction(instance->startctx, "getAcceptType", expr->queryChild(firstArg+2));
  14546. //virtual void toXML(const byte * self, StringBuffer & out) = 0;
  14547. buildHTTPtoXml(instance->startctx);
  14548. //virtual const char * queryOutputIteratorPath()
  14549. IHqlExpression * separator = expr->queryAttribute(separatorAtom);
  14550. if (separator)
  14551. doBuildVarStringFunction(instance->startctx, "queryOutputIteratorPath", separator->queryChild(0));
  14552. IHqlExpression * namespaceAttr = expr->queryAttribute(namespaceAtom);
  14553. IHqlExpression * logText = NULL;
  14554. bool logMin = false;
  14555. bool logXml = false;
  14556. ForEachChildFrom(i, expr, 1)
  14557. {
  14558. IHqlExpression * cur = expr->queryChild(i);
  14559. if (cur->isAttribute() && cur->queryName()==logAtom)
  14560. {
  14561. IHqlExpression * opt = cur->queryChild(0);
  14562. if (!opt)
  14563. logXml = true;
  14564. else if (!opt->isAttribute())
  14565. logText = opt;
  14566. else if (opt->queryName() == minAtom)
  14567. logMin = true;
  14568. }
  14569. }
  14570. //virtual unsigned getFlags()
  14571. {
  14572. StringBuffer flags;
  14573. if (expr->hasAttribute(groupAtom))
  14574. flags.append("|SOAPFgroup");
  14575. if (expr->hasAttribute(onFailAtom))
  14576. flags.append("|SOAPFonfail");
  14577. if (logXml)
  14578. flags.append("|SOAPFlog");
  14579. if (expr->hasAttribute(trimAtom))
  14580. flags.append("|SOAPFtrim");
  14581. if (expr->hasAttribute(literalAtom))
  14582. flags.append("|SOAPFliteral");
  14583. if (namespaceAttr)
  14584. flags.append("|SOAPFnamespace");
  14585. if (logMin)
  14586. flags.append("|SOAPFlogmin");
  14587. if (logText)
  14588. flags.append("|SOAPFlogusermsg");
  14589. if (flags.length())
  14590. doBuildUnsignedFunction(instance->classctx, "getFlags", flags.str()+1);
  14591. }
  14592. //virtual unsigned numParallelThreads()
  14593. doBuildUnsignedFunction(instance->classctx, "numParallelThreads", queryAttributeChild(expr, parallelAtom, 0));
  14594. //virtual unsigned numRecordsPerBatch()
  14595. doBuildUnsignedFunction(instance->classctx, "numRecordsPerBatch", queryAttributeChild(expr, mergeAtom, 0));
  14596. //virtual int numRetries()
  14597. doBuildSignedFunction(instance->classctx, "numRetries", queryAttributeChild(expr, retryAtom, 0));
  14598. //virtual double getTimeout()
  14599. doBuildDoubleFunction(instance->classctx, "getTimeout", queryAttributeChild(expr, timeoutAtom, 0));
  14600. //virtual double getTimeLimit()
  14601. doBuildDoubleFunction(instance->classctx, "getTimeLimit", queryAttributeChild(expr, timeLimitAtom, 0));
  14602. if (namespaceAttr)
  14603. {
  14604. doBuildVarStringFunction(instance->startctx, "getNamespaceName", namespaceAttr->queryChild(0));
  14605. if (namespaceAttr->queryChild(1))
  14606. doBuildVarStringFunction(instance->startctx, "getNamespaceVar", namespaceAttr->queryChild(1));
  14607. }
  14608. if (logText)
  14609. {
  14610. BuildCtx funcctx(instance->startctx);
  14611. funcctx.addQuotedCompound("virtual void getLogText(size32_t & __lenResult, char * & __result, const void * _left)");
  14612. doBuildFunctionReturn(funcctx, unknownStringType, logText);
  14613. }
  14614. if (!isSink)
  14615. {
  14616. //virtual IXmlToRowTransformer * queryTransformer()
  14617. bool usesContents = false;
  14618. doBuildXmlReadMember(*instance, expr, "queryInputTransformer", usesContents);
  14619. if (usesContents)
  14620. throwError(HQLERR_ContentsInSoapCall);
  14621. //virtual const char * getInputIteratorPath()
  14622. IHqlExpression * xpath = expr->queryAttribute(xpathAtom);
  14623. if (xpath)
  14624. doBuildVarStringFunction(instance->classctx, "getInputIteratorPath", xpath->queryChild(0));
  14625. IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
  14626. if (onFail)
  14627. {
  14628. //virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * e)
  14629. BuildCtx onFailCtx(instance->startctx);
  14630. onFailCtx.addQuotedCompound("virtual unsigned onFailTransform(ARowBuilder & crSelf, const void * _left, IException * except)");
  14631. ensureRowAllocated(onFailCtx, "crSelf");
  14632. associateLocalFailure(onFailCtx, "except");
  14633. buildTransformBody(onFailCtx, onFail->queryChild(0), dataset, NULL, expr, selSeq);
  14634. }
  14635. }
  14636. buildInstanceSuffix(instance);
  14637. if (boundDataset)
  14638. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  14639. if (isSink)
  14640. return NULL;
  14641. return instance->getBoundActivity();
  14642. }
  14643. //---------------------------------------------------------------------------
  14644. IHqlExpression * HqlCppTranslator::doBuildRegexCompileInstance(BuildCtx & ctx, IHqlExpression * pattern, bool isUnicode, bool isCaseSensitive)
  14645. {
  14646. OwnedHqlExpr searchKey = createAttribute(_regexInstance_Atom, LINK(pattern), createConstant(isUnicode), createConstant(isCaseSensitive));
  14647. HqlExprAssociation * match = ctx.queryMatchExpr(searchKey);
  14648. if (match)
  14649. return match->queryExpr();
  14650. BuildCtx * initCtx = &ctx;
  14651. BuildCtx * declareCtx = &ctx;
  14652. if (pattern->isConstant())
  14653. getInvariantMemberContext(ctx, &declareCtx, &initCtx, true, false);
  14654. StringBuffer tempName;
  14655. getUniqueId(tempName.append("regex"));
  14656. ITypeInfo * type = makeClassType(isUnicode ? "rtlCompiledUStrRegex" : "rtlCompiledStrRegex");
  14657. OwnedHqlExpr regexInstance = createVariable(tempName.str(), type);
  14658. declareCtx->addDeclare(regexInstance);
  14659. HqlExprArray args;
  14660. args.append(*LINK(regexInstance));
  14661. args.append(*LINK(pattern));
  14662. args.append(*createConstant(isCaseSensitive));
  14663. IIdAtom * func = isUnicode ? regexNewSetUStrPatternId : regexNewSetStrPatternId;
  14664. buildFunctionCall(*initCtx, func, args);
  14665. declareCtx->associateExpr(searchKey, regexInstance);
  14666. return regexInstance;
  14667. }
  14668. IHqlExpression * HqlCppTranslator::doBuildRegexFindInstance(BuildCtx & ctx, IHqlExpression * compiled, IHqlExpression * search, bool cloneSearch)
  14669. {
  14670. OwnedHqlExpr searchKey = createAttribute(_regexFindInstance_Atom, LINK(compiled), LINK(search), createConstant(cloneSearch));
  14671. HqlExprAssociation * match = ctx.queryMatchExpr(searchKey);
  14672. if (match)
  14673. return match->queryExpr();
  14674. bool isUnicode = isUnicodeType(search->queryType());
  14675. StringBuffer tempName;
  14676. getUniqueId(tempName.append("fi"));
  14677. ITypeInfo * type = makeClassType(isUnicode ? "rtlUStrRegexFindInstance" : "rtlStrRegexFindInstance");
  14678. OwnedHqlExpr regexInstance = createVariable(tempName.str(), type);
  14679. ctx.addDeclare(regexInstance);
  14680. //Would be better if I allowed classes in my external functions instead of faking booleans
  14681. OwnedHqlExpr castCompiled = createValue(no_typetransfer, makeBoolType(), LINK(compiled));
  14682. HqlExprArray args;
  14683. args.append(*LINK(regexInstance));
  14684. args.append(*createTranslated(castCompiled));
  14685. args.append(*LINK(search));
  14686. if (!isUnicode)
  14687. args.append(*createConstant(cloneSearch));
  14688. IIdAtom * func = isUnicode ? regexNewUStrFindId : regexNewStrFindId;
  14689. buildFunctionCall(ctx, func, args);
  14690. ctx.associateExpr(searchKey, regexInstance);
  14691. return regexInstance;
  14692. }
  14693. void HqlCppTranslator::doBuildNewRegexFindReplace(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * bound)
  14694. {
  14695. CHqlBoundExpr boundMatch;
  14696. if (ctx.getMatchExpr(expr, boundMatch))
  14697. {
  14698. if (bound)
  14699. bound->set(boundMatch);
  14700. else
  14701. assign(ctx, *target, boundMatch);
  14702. return;
  14703. }
  14704. IHqlExpression * pattern = expr->queryChild(0);
  14705. IHqlExpression * search = expr->queryChild(1);
  14706. bool isUnicode = isUnicodeType(search->queryType());
  14707. IHqlExpression * compiled = doBuildRegexCompileInstance(ctx, pattern, isUnicode, !expr->hasAttribute(noCaseAtom));
  14708. if (expr->getOperator() == no_regex_replace)
  14709. {
  14710. HqlExprArray args;
  14711. args.append(*LINK(compiled));
  14712. args.append(*LINK(search));
  14713. args.append(*LINK(expr->queryChild(2)));
  14714. IIdAtom * func = isUnicode ? regexNewUStrReplaceXId : regexNewStrReplaceXId;
  14715. OwnedHqlExpr call = bindFunctionCall(func, args);
  14716. //Need to associate???
  14717. buildExprOrAssign(ctx, target, call, bound);
  14718. return;
  14719. }
  14720. // Because the search instance is created locally, the search parameter is always going to be valid
  14721. // as long as the find instance. Only exception could be if call created a temporary class instance.
  14722. bool cloneSearch = false;
  14723. IHqlExpression * findInstance = doBuildRegexFindInstance(ctx, compiled, search, cloneSearch);
  14724. if(expr->queryType() == queryBoolType())
  14725. {
  14726. HqlExprArray args;
  14727. args.append(*LINK(findInstance));
  14728. IIdAtom * func= isUnicode ? regexNewUStrFoundId : regexNewStrFoundId;
  14729. OwnedHqlExpr call = bindFunctionCall(func, args);
  14730. buildExprOrAssign(ctx, target, call, bound);
  14731. }
  14732. else
  14733. {
  14734. HqlExprArray args;
  14735. args.append(*LINK(findInstance));
  14736. args.append(*LINK(expr->queryChild(2)));
  14737. IIdAtom * func= isUnicode ? regexNewUStrFoundXId : regexNewStrFoundXId;
  14738. OwnedHqlExpr call = bindFunctionCall(func, args);
  14739. buildExprOrAssign(ctx, target, call, bound);
  14740. }
  14741. }
  14742. void HqlCppTranslator::doBuildExprRegexFindReplace(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & bound)
  14743. {
  14744. doBuildNewRegexFindReplace(ctx, NULL, expr, &bound);
  14745. }
  14746. void HqlCppTranslator::doBuildAssignRegexFindReplace(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  14747. {
  14748. doBuildNewRegexFindReplace(ctx, &target, expr, NULL);
  14749. }
  14750. //---------------------------------------------------------------------------
  14751. //-- no_null [DATASET] --
  14752. ABoundActivity * HqlCppTranslator::doBuildActivityNull(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  14753. {
  14754. StringBuffer s;
  14755. ThorActivityKind kind = expr->isAction() ? TAKemptyaction : TAKnull;
  14756. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr,"Null");
  14757. if (options.minimizeActivityClasses)
  14758. instance->setImplementationClass(newNullArgId);
  14759. //-----------------
  14760. buildActivityFramework(instance, isRoot);
  14761. buildInstancePrefix(instance);
  14762. buildInstanceSuffix(instance);
  14763. return instance->getBoundActivity();
  14764. }
  14765. //---------------------------------------------------------------------------
  14766. ABoundActivity * HqlCppTranslator::doBuildActivitySideEffect(BuildCtx & ctx, IHqlExpression * expr, bool isRoot, bool expandChildren)
  14767. {
  14768. //Something that is treated like an input, but causes something else to happen - e.g., a failure
  14769. StringBuffer s;
  14770. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsideeffect, expr,"Action");
  14771. //-----------------
  14772. instance->graphLabel.set(getOpString(expr->getOperator())); // label node as "fail"
  14773. buildActivityFramework(instance, isRoot);
  14774. buildInstancePrefix(instance);
  14775. BuildCtx funcctx(instance->startctx);
  14776. funcctx.addQuotedCompoundOpt("virtual void action()");
  14777. if (expandChildren)
  14778. {
  14779. unsigned numChildren = expr->numChildren();
  14780. for (unsigned idx=1; idx < numChildren; idx++)
  14781. {
  14782. IHqlExpression * cur = expr->queryChild(idx);
  14783. if (!cur->isAttribute())
  14784. buildStmt(funcctx, cur);
  14785. }
  14786. }
  14787. else
  14788. {
  14789. buildStmt(funcctx, expr);
  14790. }
  14791. buildInstanceSuffix(instance);
  14792. return instance->getBoundActivity();
  14793. }
  14794. ABoundActivity * HqlCppTranslator::doBuildActivityAction(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  14795. {
  14796. StringBuffer s;
  14797. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKsimpleaction, expr, "Action");
  14798. //-----------------
  14799. instance->graphLabel.set(getOpString(expr->getOperator())); // label node as "fail"
  14800. buildActivityFramework(instance, isRoot);
  14801. buildInstancePrefix(instance);
  14802. BuildCtx funcctx(instance->startctx);
  14803. funcctx.addQuotedCompoundOpt("virtual void action()");
  14804. buildStmt(funcctx, expr);
  14805. buildInstanceSuffix(instance);
  14806. return instance->getBoundActivity();
  14807. }
  14808. //---------------------------------------------------------------------------
  14809. // if (ctx->currentWorkflowId() == number)
  14810. // doCode();
  14811. void HqlCppTranslator::buildWorkflowItem(BuildCtx & ctx, IHqlStmt * switchStmt, unsigned wfid, IHqlExpression * expr)
  14812. {
  14813. OwnedHqlExpr value = getSizetConstant(wfid);
  14814. BuildCtx condctx(ctx);
  14815. IHqlStmt * caseStmt = condctx.addCase(switchStmt, value);
  14816. //Unwind the statement list to prevent very deep recursion.
  14817. HqlExprArray exprs;
  14818. unwindCommaCompound(exprs, expr);
  14819. ForEachItemIn(i, exprs)
  14820. buildStmt(condctx, &exprs.item(i));
  14821. if (caseStmt->numChildren() == 0)
  14822. condctx.addGroup(); // ensure a break statement is generated...
  14823. }
  14824. void HqlCppTranslator::buildWorkflowPersistCheck(BuildCtx & ctx, IHqlExpression * expr)
  14825. {
  14826. OwnedHqlExpr resultName = ::createResultName(queryAttributeChild(expr, namedAtom, 0));
  14827. resultName.setown(ensureExprType(resultName, unknownVarStringType));
  14828. IHqlExpression * filesRead = expr->queryAttribute(_files_Atom);
  14829. DependenciesUsed dependencies(true);
  14830. if (filesRead)
  14831. {
  14832. ForEachChild(i, filesRead)
  14833. dependencies.tablesRead.append(*getNormalizedFilename(filesRead->queryChild(i)));
  14834. }
  14835. IHqlExpression * resultsRead = expr->queryAttribute(_results_Atom);
  14836. if (resultsRead)
  14837. unwindChildren(dependencies.resultsRead, resultsRead);
  14838. IHqlExpression * crcVal = queryAttributeChild(expr, _codehash_Atom, 0);
  14839. OwnedHqlExpr crcExpr = calculatePersistInputCrc(ctx, dependencies);
  14840. HqlExprArray args;
  14841. args.append(*LINK(resultName));
  14842. args.append(*LINK(crcVal));
  14843. args.append(*LINK(crcExpr));
  14844. args.append(*createConstant(expr->hasAttribute(fileAtom)));
  14845. buildFunctionCall(ctx, returnPersistVersionId, args);
  14846. }
  14847. void HqlCppTranslator::buildWorkflow(WorkflowArray & workflow)
  14848. {
  14849. BuildCtx classctx(*code, goAtom);
  14850. classctx.addQuotedCompound("struct MyEclProcess : public EclProcess", ";");
  14851. classctx.addQuoted("virtual unsigned getActivityVersion() const { return ACTIVITY_INTERFACE_VERSION; }");
  14852. BuildCtx performctx(classctx);
  14853. performctx.addQuotedCompound("virtual int perform(IGlobalCodeContext * gctx, unsigned wfid)");
  14854. performctx.addQuoted("ICodeContext * ctx;");
  14855. performctx.addQuoted("ctx = gctx->queryCodeContext();");
  14856. performctx.associateExpr(globalContextMarkerExpr, globalContextMarkerExpr);
  14857. performctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  14858. OwnedHqlExpr function = createQuoted("wfid", LINK(unsignedType));
  14859. BuildCtx switchctx(performctx);
  14860. IHqlStmt * switchStmt = switchctx.addSwitch(function);
  14861. ForEachItemIn(idx, workflow)
  14862. {
  14863. WorkflowItem & action = workflow.item(idx);
  14864. HqlExprArray & exprs = action.queryExprs();
  14865. unsigned wfid = action.queryWfid();
  14866. optimizePersists(exprs);
  14867. bool isEmpty = exprs.ordinality() == 0;
  14868. if (exprs.ordinality() == 1 && (exprs.item(0).getOperator() == no_workflow_action))
  14869. isEmpty = true;
  14870. if (!isEmpty)
  14871. {
  14872. if (action.isFunction())
  14873. {
  14874. OwnedHqlExpr function = action.getFunction();
  14875. buildFunctionDefinition(function);
  14876. }
  14877. else
  14878. {
  14879. OwnedHqlExpr expr = createActionList(action.queryExprs());
  14880. IHqlExpression * persistAttr = expr->queryAttribute(_workflowPersist_Atom);
  14881. if (persistAttr)
  14882. {
  14883. if (!options.freezePersists)
  14884. {
  14885. HqlExprArray args2;
  14886. unwindChildren(args2, expr);
  14887. OwnedHqlExpr setResult = createSetResult(args2);
  14888. buildWorkflowItem(switchctx, switchStmt, wfid, setResult);
  14889. }
  14890. }
  14891. else
  14892. buildWorkflowItem(switchctx, switchStmt, wfid, expr);
  14893. }
  14894. }
  14895. }
  14896. OwnedHqlExpr returnExpr = getSizetConstant(maxSequence);
  14897. performctx.addReturn(returnExpr);
  14898. }
  14899. //---------------------------------------------------------------------------
  14900. void HqlCppTranslator::doBuildStmtWait(BuildCtx & ctx, IHqlExpression * expr)
  14901. {
  14902. throwError(HQLERR_WaitNotSupported);
  14903. }
  14904. void HqlCppTranslator::doBuildStmtNotify(BuildCtx & ctx, IHqlExpression * expr)
  14905. {
  14906. IHqlExpression * event = expr->queryChild(0);
  14907. IHqlExpression * target = queryRealChild(expr, 1);
  14908. HqlExprArray args;
  14909. args.append(*LINK(event->queryChild(0)));
  14910. args.append(*LINK(event->queryChild(1)));
  14911. if (target)
  14912. {
  14913. args.append(*LINK(target));
  14914. buildFunctionCall(ctx, doNotifyTargetId, args);
  14915. }
  14916. else
  14917. buildFunctionCall(ctx, doNotifyId, args);
  14918. }
  14919. //---------------------------------------------------------------------------
  14920. // no_thorresult
  14921. // no_thorremoteresult
  14922. ABoundActivity * HqlCppTranslator::doBuildActivitySetResult(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  14923. {
  14924. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  14925. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  14926. IHqlExpression * persist = expr->queryAttribute(_workflowPersist_Atom);
  14927. HqlExprAttr dataset, row, attribute;
  14928. if (expr->getOperator() == no_extractresult)
  14929. {
  14930. row.set(expr->queryChild(0));
  14931. dataset.set(row->queryNormalizedSelector(true));
  14932. attribute.set(expr->queryChild(1));
  14933. }
  14934. else
  14935. {
  14936. if (!options.canGenerateSimpleAction)
  14937. {
  14938. row.setown(createDataset(no_null, LINK(queryNullRecord()), NULL));
  14939. dataset.set(row);
  14940. }
  14941. attribute.set(expr->queryChild(0));
  14942. }
  14943. // splitSetResultValue(dataset, row, attribute, value);
  14944. if (attribute->isAction())
  14945. {
  14946. //This code is decidedly strange - as far as I can see there is no explicit link between this activity and
  14947. //the child root activity, it works because they happen to be generated in the same graph
  14948. switch (attribute->getOperator())
  14949. {
  14950. case no_output:
  14951. buildRootActivity(ctx, attribute);
  14952. break;
  14953. default:
  14954. buildStmt(ctx, attribute);
  14955. break;
  14956. }
  14957. attribute.set(queryBoolExpr(true));
  14958. }
  14959. Owned<ABoundActivity> boundDataset;
  14960. ThorActivityKind kind = row ? TAKremoteresult : TAKsimpleaction;
  14961. if (row)
  14962. boundDataset.setown(buildCachedActivity(ctx, row));
  14963. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, kind, expr, kind == TAKremoteresult ? "RemoteResult" : "Action");
  14964. if (sequence)
  14965. {
  14966. StringBuffer graphLabel;
  14967. graphLabel.append("Store\n");
  14968. getStoredDescription(graphLabel, sequence, name, true);
  14969. instance->graphLabel.set(graphLabel.str());
  14970. }
  14971. buildActivityFramework(instance, isRoot && !isInternalSeq(sequence));
  14972. buildInstancePrefix(instance);
  14973. noteResultDefined(ctx, instance, sequence, name, isRoot);
  14974. if (attribute->isDatarow())
  14975. attribute.setown(::ensureSerialized(attribute, diskAtom));
  14976. if (kind == TAKremoteresult)
  14977. {
  14978. doBuildSequenceFunc(instance->classctx, sequence, true);
  14979. BuildCtx sendctx(instance->startctx);
  14980. sendctx.addQuotedCompound("virtual void sendResult(const void * _self)");
  14981. sendctx.addQuoted("const unsigned char * self = (const unsigned char *)_self;");
  14982. if (dataset->isDatarow())
  14983. {
  14984. OwnedHqlExpr bound = createVariable("self", makeRowReferenceType(dataset));
  14985. bindRow(sendctx, dataset, bound);
  14986. }
  14987. else
  14988. bindTableCursor(sendctx, dataset, "self");
  14989. buildSetResultInfo(sendctx, expr, attribute, NULL, (persist != NULL), false);
  14990. }
  14991. else
  14992. {
  14993. BuildCtx sendctx(instance->startctx);
  14994. sendctx.addQuotedCompound("virtual void action()");
  14995. buildSetResultInfo(sendctx, expr, attribute, NULL, (persist != NULL), false);
  14996. }
  14997. buildInstanceSuffix(instance);
  14998. if (boundDataset)
  14999. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  15000. associateRemoteResult(*instance, sequence, name);
  15001. return instance->getBoundActivity();
  15002. }
  15003. //---------------------------------------------------------------------------
  15004. //-- no_distribution
  15005. static void getInterfaceName(StringBuffer & name, ITypeInfo * type)
  15006. {
  15007. switch (type->getTypeCode())
  15008. {
  15009. case type_boolean:
  15010. name.append("IBoolDistributionTable");
  15011. break;
  15012. case type_real:
  15013. name.append("IRealDistributionTable");
  15014. break;
  15015. case type_string:
  15016. case type_data:
  15017. case type_qstring:
  15018. assertex(type->getSize() != UNKNOWN_LENGTH);
  15019. name.append("IStringDistributionTable");
  15020. break;
  15021. case type_int:
  15022. case type_swapint:
  15023. case type_packedint:
  15024. if (type->isSigned())
  15025. {
  15026. if (type->getSize() == 8)
  15027. name.append("IInt64DistributionTable");
  15028. else
  15029. name.append("IIntDistributionTable");
  15030. }
  15031. else
  15032. {
  15033. if (type->getSize() == 8)
  15034. name.append("IUInt64DistributionTable");
  15035. else
  15036. name.append("IUIntDistributionTable");
  15037. }
  15038. break;
  15039. default:
  15040. UNIMPLEMENTED;
  15041. }
  15042. }
  15043. static bool expandFieldName(StringBuffer & s, IHqlExpression * e)
  15044. {
  15045. if (e->getOperator() == no_select)
  15046. {
  15047. if (expandFieldName(s, e->queryChild(0)))
  15048. s.append('.');
  15049. const char * name = e->queryChild(1)->queryName()->str();
  15050. s.appendLower(strlen(name), name);
  15051. return true;
  15052. }
  15053. return false;
  15054. }
  15055. void HqlCppTranslator::doBuildDistributionClearFunc(BuildCtx & ctx, IHqlExpression * dataset, HqlExprArray & selects)
  15056. {
  15057. StringBuffer s, func;
  15058. BuildCtx funcctx(ctx);
  15059. funcctx.addQuotedCompound("virtual void clearAggregate(IDistributionTable * * tables)");
  15060. ForEachItemIn(idx, selects)
  15061. {
  15062. IHqlExpression * original = &selects.item(idx);
  15063. ITypeInfo * type = original->queryType();
  15064. getInterfaceName(func.clear().append("create"), type);
  15065. s.clear().append("tables[").append(idx).append("] = ").append(func).append("(\"");
  15066. expandFieldName(s, original);
  15067. s.append("\", ").append(type->getSize()).append(");");
  15068. funcctx.addQuoted(s);
  15069. }
  15070. }
  15071. void HqlCppTranslator::doBuildDistributionNextFunc(BuildCtx & ctx, IHqlExpression * dataset, HqlExprArray & selects)
  15072. {
  15073. StringBuffer s;
  15074. BuildCtx funcctx(ctx);
  15075. funcctx.addQuotedCompound("virtual void process(IDistributionTable * * tables, const void * _src)");
  15076. funcctx.addQuoted("unsigned char * src = (unsigned char *) _src;");
  15077. bindTableCursor(funcctx, dataset, "src");
  15078. ForEachItemIn(idx, selects)
  15079. {
  15080. IHqlExpression * original = &selects.item(idx);
  15081. ITypeInfo * type = original->queryType();
  15082. CHqlBoundExpr bound;
  15083. buildExpr(funcctx, original, bound);
  15084. s.clear().append("((");
  15085. getInterfaceName(s, type);
  15086. s.append(" *)tables[").append(idx).append("])->noteValue(");
  15087. switch (type->getTypeCode())
  15088. {
  15089. case type_string:
  15090. case type_data:
  15091. case type_qstring:
  15092. {
  15093. if (bound.length)
  15094. generateExprCpp(s, bound.length);
  15095. else
  15096. s.append(type->getSize());
  15097. s.append(",");
  15098. OwnedHqlExpr addr = getElementPointer(bound.expr);
  15099. generateExprCpp(s, addr);
  15100. }
  15101. break;
  15102. default:
  15103. generateExprCpp(s, bound.expr);
  15104. break;
  15105. }
  15106. s.append(");");
  15107. funcctx.addQuoted(s);
  15108. }
  15109. }
  15110. void HqlCppTranslator::doBuildDistributionFunc(BuildCtx & funcctx, unsigned numFields, const char * action)
  15111. {
  15112. StringBuffer s;
  15113. s.clear().append("for (unsigned i=0;i<").append(numFields).append(";i++)");
  15114. funcctx.addQuotedCompound(s);
  15115. s.clear().append("tables[i]->").append(action).append(";");
  15116. funcctx.addQuoted(s);
  15117. }
  15118. void HqlCppTranslator::doBuildDistributionDestructFunc(BuildCtx & ctx, unsigned numFields)
  15119. {
  15120. BuildCtx funcctx(ctx);
  15121. funcctx.addQuotedCompound("virtual void destruct(IDistributionTable * * tables)");
  15122. doBuildDistributionFunc(funcctx, numFields, "Release()");
  15123. }
  15124. void HqlCppTranslator::doBuildDistributionSerializeFunc(BuildCtx & ctx, unsigned numFields)
  15125. {
  15126. BuildCtx funcctx(ctx);
  15127. funcctx.addQuotedCompound("virtual void serialize(IDistributionTable * * tables, MemoryBuffer & out)");
  15128. doBuildDistributionFunc(funcctx, numFields, "serialize(out)");
  15129. }
  15130. void HqlCppTranslator::doBuildDistributionMergeFunc(BuildCtx & ctx, unsigned numFields)
  15131. {
  15132. BuildCtx funcctx(ctx);
  15133. funcctx.addQuotedCompound("virtual void merge(IDistributionTable * * tables, MemoryBuffer & in)");
  15134. doBuildDistributionFunc(funcctx, numFields, "merge(in)");
  15135. }
  15136. void HqlCppTranslator::doBuildDistributionGatherFunc(BuildCtx & ctx, unsigned numFields)
  15137. {
  15138. BuildCtx funcctx(ctx);
  15139. funcctx.addQuotedCompound("virtual void gatherResult(IDistributionTable * * tables, StringBuffer & out)");
  15140. doBuildDistributionFunc(funcctx, numFields, "report(out)");
  15141. }
  15142. static void expandDistributionFields(IHqlExpression * record, HqlExprArray & selects, IHqlExpression * selector)
  15143. {
  15144. ForEachChild(idx, record)
  15145. {
  15146. IHqlExpression * cur = record->queryChild(idx);
  15147. switch (cur->getOperator())
  15148. {
  15149. case no_ifblock:
  15150. expandDistributionFields(cur->queryChild(1), selects, selector);
  15151. break;
  15152. case no_record:
  15153. expandDistributionFields(cur, selects, selector);
  15154. break;
  15155. case no_field:
  15156. {
  15157. OwnedHqlExpr selected = selector ? createSelectExpr(LINK(selector), LINK(cur)) : LINK(cur);
  15158. IAtom * name = cur->queryName();
  15159. if (cur->queryType()->getTypeCode() == type_row)
  15160. {
  15161. expandDistributionFields(cur->queryRecord(), selects, selected);
  15162. return;
  15163. }
  15164. selects.append(*selected.getClear());
  15165. break;
  15166. }
  15167. case no_attr:
  15168. case no_attr_expr:
  15169. case no_attr_link:
  15170. break;
  15171. default:
  15172. UNIMPLEMENTED;
  15173. break;
  15174. }
  15175. }
  15176. }
  15177. ABoundActivity * HqlCppTranslator::doBuildActivityDistribution(BuildCtx & ctx, IHqlExpression * expr, bool isRoot)
  15178. {
  15179. IHqlExpression * dataset = expr->queryChild(0);
  15180. IHqlExpression * fields = queryRealChild(expr, 1);
  15181. IHqlExpression * sequence = expr->queryAttribute(sequenceAtom);
  15182. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  15183. if (!sequence)
  15184. throwError(HQLERR_DistributionNoSequence);
  15185. useInclude("rtldistr.hpp");
  15186. Owned<ABoundActivity> boundDataset = buildCachedActivity(ctx, dataset);
  15187. Owned<ActivityInstance> instance = new ActivityInstance(*this, ctx, TAKdistribution, expr, "Distribution");
  15188. buildActivityFramework(instance, isRoot);
  15189. buildInstancePrefix(instance);
  15190. HqlExprArray selects;
  15191. if (fields)
  15192. unwindChildren(selects, fields);
  15193. else
  15194. expandDistributionFields(dataset->queryRecord(), selects, dataset);
  15195. unsigned numFields = selects.ordinality();
  15196. doBuildDistributionClearFunc(instance->startctx, dataset, selects);
  15197. doBuildDistributionNextFunc(instance->startctx, dataset, selects);
  15198. doBuildDistributionDestructFunc(instance->startctx, numFields);
  15199. doBuildDistributionGatherFunc(instance->startctx, numFields);
  15200. doBuildDistributionMergeFunc(instance->startctx, numFields);
  15201. doBuildDistributionSerializeFunc(instance->startctx, numFields);
  15202. //Need an extra meta information for the internal aggregate record
  15203. {
  15204. HqlExprArray fields;
  15205. fields.append(*createField(unnamedId, makeDataType(numFields*sizeof(void*)), NULL, NULL));
  15206. OwnedHqlExpr tempRecord = createRecord(fields);
  15207. buildMetaMember(instance->classctx, tempRecord, false, "queryInternalRecordSize");
  15208. }
  15209. //Generate the send Result method().
  15210. {
  15211. BuildCtx funcctx(instance->startctx);
  15212. funcctx.addQuotedCompound("virtual void sendResult(size32_t length, const char * text)");
  15213. CHqlBoundExpr bound;
  15214. HqlExprAttr translated;
  15215. bound.length.setown(createVariable("length", makeIntType(sizeof(size32_t), false)));
  15216. bound.expr.setown(createVariable("text", makeStringType(UNKNOWN_LENGTH, NULL, NULL)));
  15217. translated.setown(bound.getTranslatedExpr());
  15218. buildSetResultInfo(funcctx, expr, translated, NULL, false, false);
  15219. }
  15220. buildInstanceSuffix(instance);
  15221. buildConnectInputOutput(ctx, instance, boundDataset, 0, 0);
  15222. return instance->getBoundActivity();
  15223. }
  15224. //---------------------------------------------------------------------------
  15225. //-- pure hole table --
  15226. void HqlCppTranslator::addFileDependency(IHqlExpression * name, ABoundActivity * whoAmI)
  15227. {
  15228. if (name && activeGraphCtx)
  15229. {
  15230. OwnedHqlExpr search = createAttribute(fileAtom, getNormalizedFilename(name));
  15231. HqlExprAssociation * match = activeGraphCtx->queryMatchExpr(search);
  15232. if (match)
  15233. addDependency(*activeGraphCtx, ((ABoundActivity *)match->queryExpr()->queryUnknownExtra()), whoAmI, sourceAtom);
  15234. }
  15235. }
  15236. //---------------------------------------------------------------------------
  15237. StringBuffer &expandDotLiteral(StringBuffer &s, const char *f)
  15238. {
  15239. unsigned lines = 0;
  15240. unsigned chars = 0;
  15241. char c;
  15242. while ((c = *f++) != 0)
  15243. {
  15244. switch (c)
  15245. {
  15246. case '\t':
  15247. s.append(" ");
  15248. break;
  15249. case '\r':
  15250. break;
  15251. case '\n':
  15252. s.append("\\l"); // Means left justify.
  15253. if (lines++ > 10)
  15254. return s;
  15255. break;
  15256. case '}':
  15257. case '{':
  15258. case '<':
  15259. case '>': // Special chars in dot graphs
  15260. case '\\':
  15261. case '\"':
  15262. case '\'':
  15263. s.append('\\');
  15264. // fall into...
  15265. default:
  15266. if (chars++ > 1000)
  15267. return s;
  15268. s.append(c);
  15269. break;
  15270. }
  15271. }
  15272. return s;
  15273. }
  15274. void HqlCppTranslator::logGraphEdge(IPropertyTree * subGraph, unsigned __int64 source, unsigned __int64 target, unsigned outputIndex, unsigned inputIndex, const char * label, bool nWay)
  15275. {
  15276. addSimpleGraphEdge(subGraph, source, target, outputIndex, inputIndex, NULL, label, nWay);
  15277. }
  15278. void HqlCppTranslator::buildActivityFramework(ActivityInstance * instance)
  15279. {
  15280. assertex(!instance->isAction()); // All actions should be calling the 2 parameter version below instead
  15281. buildActivityFramework(instance, false);
  15282. }
  15283. void HqlCppTranslator::buildActivityFramework(ActivityInstance * instance, bool alwaysExecuted)
  15284. {
  15285. instance->createGraphNode(activeGraph->xgmml, alwaysExecuted);
  15286. if (options.trackDuplicateActivities)
  15287. {
  15288. IHqlExpression * search = instance->dataset;
  15289. node_operator op = search->getOperator();
  15290. if ((op != no_select) && (op != no_workunit_dataset))
  15291. {
  15292. IHqlExpression * searchNorm = queryLocationIndependent(search);
  15293. unsigned crc = getExpressionCRC(search);
  15294. ForEachItemIn(i, tracking.activityExprs)
  15295. {
  15296. if (search == &tracking.activityExprs.item(i))
  15297. instance->addAttributeInt("_duplicateActivity_", tracking.activityIds.item(i));
  15298. else if (crc == tracking.activityCrcs.item(i))
  15299. instance->addAttributeInt("_duplicateCrcActivity_", tracking.activityIds.item(i));
  15300. else if (searchNorm == &tracking.activityNorms.item(i))
  15301. instance->addAttributeInt("_duplicateNormActivity_", tracking.activityIds.item(i));
  15302. }
  15303. tracking.activityExprs.append(*LINK(search));
  15304. tracking.activityNorms.append(*LINK(searchNorm));
  15305. tracking.activityIds.append(instance->activityId);
  15306. tracking.activityCrcs.append(crc);
  15307. }
  15308. }
  15309. }
  15310. void HqlCppTranslator::buildConnectOrders(BuildCtx & ctx, ABoundActivity * slaveActivity, ABoundActivity * masterActivity)
  15311. {
  15312. //I'm not sure we even use this information, but at least it's there if needed.
  15313. if (targetThor())
  15314. {
  15315. IPropertyTree *edge = createPTree();
  15316. edge->setPropInt64("@target", slaveActivity->queryActivityId());
  15317. edge->setPropInt64("@source", masterActivity->queryActivityId());
  15318. addGraphAttributeBool(edge, "cosort", true);
  15319. SubGraphInfo * activeSubgraph = queryActiveSubGraph(ctx);
  15320. assertex(activeSubgraph);
  15321. activeSubgraph->tree->addPropTree("edge", edge);
  15322. }
  15323. }
  15324. ColumnToOffsetMap * HqlCppTranslator::queryRecordOffsetMap(IHqlExpression * record)
  15325. {
  15326. if (record)
  15327. return recordMap.queryMapping(record, options.maxRecordSize);
  15328. return NULL;
  15329. }
  15330. unsigned HqlCppTranslator::getFixedRecordSize(IHqlExpression * record)
  15331. {
  15332. return queryRecordOffsetMap(record)->getFixedRecordSize();
  15333. }
  15334. bool HqlCppTranslator::isFixedRecordSize(IHqlExpression * record)
  15335. {
  15336. return queryRecordOffsetMap(record)->isFixedWidth();
  15337. }
  15338. void HqlCppTranslator::buildReturnRecordSize(BuildCtx & ctx, BoundRow * cursor)
  15339. {
  15340. OwnedHqlExpr size = getRecordSize(cursor->querySelector());
  15341. buildReturn(ctx, size);
  15342. }
  15343. bool HqlCppTranslator::recordContainsIfBlock(IHqlExpression * record)
  15344. {
  15345. return queryRecordOffsetMap(record)->queryContainsIfBlock();
  15346. }
  15347. //-- Code to transform the expressions ready for generating source code.
  15348. static void logECL(const LogMsgCategory & category, size32_t len, const char * ecl)
  15349. {
  15350. const size32_t chunkSize = 31000;
  15351. while (len > chunkSize)
  15352. {
  15353. const char * next = strchr(ecl+chunkSize, '\n');
  15354. if (!next || !next[1])
  15355. break;
  15356. unsigned size = next-ecl;
  15357. if (ecl[size-1] == '\r')
  15358. size--;
  15359. LOG(category, unknownJob, "%.*s", size, ecl);
  15360. len -= (next+1-ecl);
  15361. ecl = next+1;
  15362. }
  15363. LOG(category, unknownJob, "%s", ecl);
  15364. }
  15365. void HqlCppTranslator::traceExpression(const char * title, IHqlExpression * expr, unsigned level)
  15366. {
  15367. if (!expr)
  15368. return;
  15369. checkAbort();
  15370. LOG(MCdebugInfo(200), unknownJob, "Tracing expressions: %s", title);
  15371. LogMsgCategory debug500 = MCdebugInfo(level);
  15372. if(REJECTLOG(debug500))
  15373. return;
  15374. if (options.traceIR)
  15375. {
  15376. EclIR::dbglogIR(expr);
  15377. }
  15378. else
  15379. {
  15380. StringBuffer s;
  15381. processedTreeToECL(expr, s);
  15382. logECL(debug500, s.length(), s.str());
  15383. }
  15384. }
  15385. void HqlCppTranslator::traceExpressions(const char * title, HqlExprArray & exprs, unsigned level)
  15386. {
  15387. OwnedHqlExpr compound = createComma(exprs);
  15388. traceExpression(title, compound, level);
  15389. }
  15390. void HqlCppTranslator::traceExpressions(const char * title, WorkflowArray & workflow)
  15391. {
  15392. checkAbort();
  15393. // PrintLog(title);
  15394. LOG(MCdebugInfo(200), unknownJob, "Tracing expressions: %s", title);
  15395. static LogMsgCategory debug500 = MCdebugInfo(500);
  15396. static LogMsgCategory debug5000 = MCdebugInfo(5000);
  15397. if(REJECTLOG(debug500))
  15398. return;
  15399. ForEachItemIn(idx1, workflow)
  15400. {
  15401. WorkflowItem & cur = workflow.item(idx1);
  15402. OwnedHqlExpr compound = createComma(cur.queryExprs());
  15403. if (compound)
  15404. {
  15405. LOG(debug500, unknownJob, "%s: #%d: id[%d]", title, idx1, cur.queryWfid());
  15406. if (options.traceIR)
  15407. {
  15408. EclIR::dbglogIR(compound);
  15409. }
  15410. else
  15411. {
  15412. StringBuffer s;
  15413. processedTreeToECL(compound, s);
  15414. logECL(debug500, s.length(), s.str());
  15415. }
  15416. }
  15417. }
  15418. }
  15419. void HqlCppTranslator::checkNormalized(WorkflowArray & workflow)
  15420. {
  15421. ForEachItemIn(i, workflow)
  15422. {
  15423. checkNormalized(workflow.item(i).queryExprs());
  15424. }
  15425. }
  15426. void HqlCppTranslator::checkNormalized(IHqlExpression * expr)
  15427. {
  15428. if (options.paranoidCheckDependencies)
  15429. checkDependencyConsistency(expr);
  15430. if (options.paranoidCheckNormalized)
  15431. {
  15432. ::checkNormalized(expr);
  15433. }
  15434. if (options.paranoidCheckSelects)
  15435. checkSelectConsistency(expr);
  15436. }
  15437. void HqlCppTranslator::checkNormalized(HqlExprArray & exprs)
  15438. {
  15439. if (options.paranoidCheckDependencies)
  15440. checkDependencyConsistency(exprs);
  15441. ForEachItemIn(i, exprs)
  15442. {
  15443. if (options.paranoidCheckNormalized)
  15444. ::checkNormalized(&exprs.item(i));
  15445. if (options.paranoidCheckSelects)
  15446. checkSelectConsistency(&exprs.item(i));
  15447. }
  15448. }
  15449. void HqlCppTranslator::checkNormalized(BuildCtx & ctx, IHqlExpression * expr)
  15450. {
  15451. if (options.paranoidCheckDependencies)
  15452. checkDependencyConsistency(expr);
  15453. if (options.paranoidCheckNormalized)
  15454. {
  15455. HqlExprArray activeTables;
  15456. //Added in reverse order, but normalize checker doesn't care
  15457. RowAssociationIterator iter(ctx);
  15458. ForEach(iter)
  15459. {
  15460. BoundRow & cur = iter.get();
  15461. if ((cur.querySide() != no_self) && !cur.isBuilder())
  15462. activeTables.append(*LINK(cur.querySelector()));
  15463. }
  15464. ::checkNormalized(expr, activeTables);
  15465. }
  15466. if (options.paranoidCheckSelects)
  15467. checkSelectConsistency(expr);
  15468. }
  15469. void createCompoundEnsure(HqlExprArray & exprs, unsigned first, unsigned last)
  15470. {
  15471. if (first >= last || last == NotFound)
  15472. return;
  15473. IHqlExpression * action = &exprs.item(last);
  15474. OwnedHqlExpr actionExpr = createActionList(exprs, first, last);
  15475. OwnedHqlExpr compound = createCompound(actionExpr.getClear(), LINK(action->queryChild(0)));
  15476. OwnedHqlExpr newAction = replaceChild(action, 0, compound);
  15477. exprs.replace(*newAction.getClear(), first);
  15478. exprs.removen(first+1, (last-first));
  15479. }
  15480. //move any set results inside a no_ensureresult so they don't get evaluated unless necessary.
  15481. void HqlCppTranslator::optimizePersists(HqlExprArray & exprs)
  15482. {
  15483. //If there is a single ensure result, and no set results created from other workflow items
  15484. //then move all previous actions inside the ensure result
  15485. unsigned max = exprs.ordinality();
  15486. if (max == 0)
  15487. return;
  15488. if (exprs.item(max-1).getOperator() != no_ensureresult)
  15489. return;
  15490. for (unsigned i=0; i < max-1; i++)
  15491. {
  15492. IHqlExpression & cur = exprs.item(i);
  15493. if ((cur.getOperator() == no_ensureresult) || cur.hasAttribute(_workflow_Atom))
  15494. return;
  15495. }
  15496. createCompoundEnsure(exprs, 0, max-1);
  15497. }
  15498. IHqlExpression * HqlCppTranslator::extractGlobalCSE(IHqlExpression * expr)
  15499. {
  15500. AutoScopeMigrateTransformer transformer(wu(), *this);
  15501. HqlExprArray exprs;
  15502. unwindCommaCompound(exprs, expr);
  15503. transformer.analyseArray(exprs, 0);
  15504. if (!transformer.worthTransforming())
  15505. return LINK(expr);
  15506. HqlExprArray results;
  15507. transformer.transformRoot(exprs, results);
  15508. return createActionList(results);
  15509. }
  15510. IHqlExpression * HqlCppTranslator::spotGlobalCSE(IHqlExpression * _expr)
  15511. {
  15512. if (!_expr->isAction())
  15513. return LINK(_expr);
  15514. LinkedHqlExpr expr = _expr;
  15515. switch (expr->getOperator())
  15516. {
  15517. case no_if:
  15518. {
  15519. IHqlExpression * left = expr->queryChild(1);
  15520. IHqlExpression * right = expr->queryChild(2);
  15521. HqlExprArray args;
  15522. args.append(*LINK(expr->queryChild(0)));
  15523. args.append(*extractGlobalCSE(left));
  15524. if (right)
  15525. args.append(*extractGlobalCSE(right));
  15526. if ((left != &args.item(1)) || (right && right != &args.item(2)))
  15527. {
  15528. unwindChildren(args, expr, 3);
  15529. expr.setown(_expr->clone(args));
  15530. }
  15531. break;
  15532. }
  15533. case no_sequential:
  15534. {
  15535. HqlExprArray args;
  15536. ForEachChild(i, expr)
  15537. args.append(*extractGlobalCSE(expr->queryChild(i)));
  15538. expr.setown(_expr->clone(args));
  15539. break;
  15540. }
  15541. case no_nothor:
  15542. return LINK(expr);
  15543. }
  15544. bool same = true;
  15545. HqlExprArray args;
  15546. ForEachChild(i, expr)
  15547. {
  15548. IHqlExpression * cur = expr->queryChild(i);
  15549. IHqlExpression * next = spotGlobalCSE(cur);
  15550. args.append(*next);
  15551. if (cur != next)
  15552. same = false;
  15553. }
  15554. if (same)
  15555. return expr.getClear();
  15556. return expr->clone(args);
  15557. }
  15558. void HqlCppTranslator::spotGlobalCSE(HqlExprArray & exprs)
  15559. {
  15560. HqlExprArray results;
  15561. AutoScopeMigrateTransformer transformer(wu(), *this);
  15562. transformer.analyseArray(exprs, 0);
  15563. if (transformer.worthTransforming())
  15564. {
  15565. transformer.transformRoot(exprs, results);
  15566. replaceArray(exprs, results);
  15567. }
  15568. if (!options.resourceConditionalActions)
  15569. {
  15570. //Now need to recursively walk actions, and if any conditional actions could do with things being hoisted within them
  15571. ForEachItemIn(i, exprs)
  15572. exprs.replace(*spotGlobalCSE(&exprs.item(i)), i);
  15573. }
  15574. }
  15575. void HqlCppTranslator::spotGlobalCSE(WorkflowItem & curWorkflow)
  15576. {
  15577. if (!insideLibrary() && options.globalAutoHoist)
  15578. {
  15579. unsigned startTime = msTick();
  15580. spotGlobalCSE(curWorkflow.queryExprs());
  15581. updateTimer("workunit;tree transform: spot global cse", msTick()-startTime);
  15582. }
  15583. }
  15584. void HqlCppTranslator::flattenDatasets(WorkflowArray & array)
  15585. {
  15586. //MORE: Should project fields needed outside <ds>.<ds> so that they are available.
  15587. }
  15588. // Code to check whether thor is required for a query. It should err towards true.
  15589. // The idea is to prevent some very simple queries going to thor, mainly when users are examining data. The main examples are:
  15590. // 1. Unfiltered table count
  15591. // 2. Filtered index count.
  15592. // 3. Restricted set of records from an index/table.
  15593. enum { NRTfiltered = 0x0001, NRTcount = 0x0002, NRTlimited = 0x0004 };
  15594. static bool needsRealThor(IHqlExpression *expr, unsigned flags)
  15595. {
  15596. unsigned numChildrenToCheck = (unsigned)-1;
  15597. switch (expr->getOperator())
  15598. {
  15599. case no_table:
  15600. //only allow non filtered limited outputs, and non filtered counts
  15601. return !((flags == NRTlimited) || (flags == NRTcount));
  15602. case no_newkeyindex:
  15603. case no_keyindex:
  15604. case no_compound_indexread:
  15605. //Don't allow count(choosen(...)) otherwise likely to be better in hthor
  15606. if (flags & NRTcount)
  15607. return (flags & NRTlimited) != 0;
  15608. //unfiltered index read should go via thor
  15609. if (flags == 0)
  15610. return true;
  15611. //filtered index reads likely to be much better in hthor.
  15612. return false;
  15613. case no_attr:
  15614. case no_attr_expr:
  15615. case no_attr_link:
  15616. case no_datasetfromrow:
  15617. case no_rows:
  15618. case no_libraryinput:
  15619. case no_fail:
  15620. case no_persist_check:
  15621. return false;
  15622. case no_distribution:
  15623. case no_buildindex:
  15624. case no_keydiff:
  15625. case no_keypatch:
  15626. case no_forcelocal:
  15627. case no_forcenolocal:
  15628. case no_allnodes:
  15629. case no_thisnode:
  15630. return true;
  15631. case no_hqlproject:
  15632. //If count project, a count will not be done as a compound operation
  15633. if (expr->hasAttribute(_countProject_Atom) && (flags & NRTcount))
  15634. return true;
  15635. break;
  15636. case no_compound_indexcount:
  15637. case no_transformascii:
  15638. case no_transformebcdic:
  15639. case no_selectfields:
  15640. case no_thor:
  15641. case no_apply:
  15642. case no_distributed:
  15643. case no_preservemeta:
  15644. case no_sorted:
  15645. case no_limit:
  15646. case no_catchds:
  15647. case no_keyedlimit:
  15648. case no_assertsorted:
  15649. case no_assertgrouped:
  15650. case no_assertdistributed:
  15651. case no_section:
  15652. case no_sectioninput:
  15653. case no_forcegraph:
  15654. case no_nofold:
  15655. case no_nohoist:
  15656. case no_actionlist:
  15657. case no_orderedactionlist:
  15658. case no_externalcall:
  15659. case no_call:
  15660. case no_compound_fetch:
  15661. case no_addfiles:
  15662. case no_nonempty:
  15663. case no_dataset_alias:
  15664. //i.e. go through children...
  15665. break;
  15666. case no_compound:
  15667. case no_comma:
  15668. case no_executewhen:
  15669. numChildrenToCheck = expr->numChildren();
  15670. break;
  15671. case no_choosen:
  15672. case no_selectnth:
  15673. flags |= NRTlimited;
  15674. break;
  15675. case no_filter:
  15676. flags |= NRTfiltered;
  15677. break;
  15678. case no_newaggregate:
  15679. case no_newusertable:
  15680. if (isAggregateDataset(expr))
  15681. {
  15682. //Only allow aggregates we can do on an index directly
  15683. if (datasetHasGroupBy(expr))
  15684. return true;
  15685. node_operator aggOp = querySingleAggregate(expr, false, false, true);
  15686. if ((aggOp != no_exists) && (aggOp != no_count))
  15687. return true;
  15688. flags |= NRTcount;
  15689. }
  15690. break;
  15691. case no_if:
  15692. case no_choose:
  15693. case no_chooseds:
  15694. {
  15695. if (needsRealThor(expr->queryChild(0), 0))
  15696. return true;
  15697. ForEachChildFrom(i, expr, 1)
  15698. {
  15699. if (needsRealThor(expr->queryChild(i), flags))
  15700. return true;
  15701. }
  15702. return false;
  15703. }
  15704. case no_colon:
  15705. case no_globalscope:
  15706. case no_extractresult:
  15707. return needsRealThor(expr->queryChild(0), flags);
  15708. case no_fetch:
  15709. return needsRealThor(expr->queryChild(1), flags);
  15710. case no_output:
  15711. {
  15712. //Assume any output to files needs to stay where it is.
  15713. IHqlExpression *child0 = expr->queryChild(0);
  15714. IHqlExpression *filename = queryRealChild(expr, 1);
  15715. if (filename)
  15716. return true;
  15717. return needsRealThor(child0, flags);
  15718. }
  15719. case no_ensureresult:
  15720. case no_setresult:
  15721. case no_evaluate_stmt:
  15722. case no_return_stmt:
  15723. {
  15724. IHqlExpression * child0 = expr->queryChild(0);
  15725. if (!child0->queryType()->isScalar())
  15726. return needsRealThor(child0, flags);
  15727. if (child0->getOperator() == no_evalonce)
  15728. child0 = child0->queryChild(0);
  15729. switch (child0->getOperator())
  15730. {
  15731. case no_externalcall:
  15732. case no_constant:
  15733. case no_all:
  15734. return false;
  15735. case no_select:
  15736. return needsRealThor(child0->queryChild(0), flags);
  15737. }
  15738. if (!containsAnyDataset(child0))
  15739. return false;
  15740. // return needsRealThor(child0, isFiltered);
  15741. //fallthrough...
  15742. }
  15743. default:
  15744. if (expr->isDataset())
  15745. return true;
  15746. ITypeInfo * type = expr->queryType();
  15747. if (!type || (type->getTypeCode() != type_void))
  15748. return false; //MORE Doesn't cope with scalar expressions that require thor e.g., counts of sorts of ....
  15749. //MORE: This means that lots of scalar expressions go to thor instead of hthor.
  15750. return true;
  15751. }
  15752. if (numChildrenToCheck == (unsigned)-1)
  15753. numChildrenToCheck = expr->isDataset() ? getNumChildTables(expr) : expr->numChildren();
  15754. for (unsigned idx=0; idx < numChildrenToCheck; idx++)
  15755. {
  15756. if (needsRealThor(expr->queryChild(idx), flags))
  15757. return true;
  15758. }
  15759. return false;
  15760. }
  15761. bool needsRealThor(IHqlExpression *expr)
  15762. {
  15763. return needsRealThor(expr, 0);
  15764. }
  15765. IHqlExpression * HqlCppTranslator::getDefaultOutputAttr(IHqlExpression * expr)
  15766. {
  15767. return createAttribute(workunitAtom); // backwards compatibility!
  15768. IHqlExpression * dataset = expr->queryChild(0);
  15769. if (dataset->getOperator() == no_selectfields)
  15770. dataset = dataset->queryChild(0);
  15771. if (dataset->getOperator()==no_choosen)
  15772. {
  15773. //If choosen() is specified, then output to SDS if small enough, else a temporary file.
  15774. IHqlExpression * count = dataset->queryChild(1);
  15775. if (count->queryValue())
  15776. {
  15777. unsigned __int64 value = count->queryValue()->getIntValue();
  15778. if (value <= MAX_ROWS_OUTPUT_TO_SDS)
  15779. return createAttribute(workunitAtom);
  15780. }
  15781. return createAttribute(diskAtom);
  15782. }
  15783. //No support yet in IFileView for delayed browsing - so output to disk.
  15784. return createAttribute(diskAtom);
  15785. }
  15786. void HqlCppTranslator::modifyOutputLocations(HqlExprArray & exprs)
  15787. {
  15788. ForEachItemIn(idx, exprs)
  15789. {
  15790. IHqlExpression &expr = exprs.item(idx);
  15791. IHqlExpression * filename = queryRealChild(&expr, 1);
  15792. //Deduce whether OUTPUT(x) should goes to SDS or a disk
  15793. if (expr.getOperator()==no_output && !filename)
  15794. {
  15795. if (!expr.hasAttribute(workunitAtom) && !expr.hasAttribute(firstAtom) && !expr.hasAttribute(diskAtom))
  15796. {
  15797. IHqlExpression * attr = getDefaultOutputAttr(&expr);
  15798. HqlExprArray args;
  15799. expr.unwindList(args, no_output);
  15800. args.append(*attr);
  15801. IHqlExpression * transformed = expr.clone(args);
  15802. exprs.replace(*transformed, idx);
  15803. }
  15804. }
  15805. }
  15806. }
  15807. void HqlCppTranslator::pickBestEngine(HqlExprArray & exprs)
  15808. {
  15809. // At this point it is not too late to decide whether real thor is needed.
  15810. // Basically, we will use real thor if available, unless it matches a very minimal set of patterns:
  15811. // 1. output(holequery)
  15812. // 2. output(choosen(holequery))
  15813. // 3. output([filtered/projected/firstn] thordiskfile); (not sure about the filtered)
  15814. // These correspond closely to the things that can eventually get turned into lazy remote views
  15815. //It would be more sensible to do this much earlier.....or not at all.
  15816. if (targetThor())
  15817. {
  15818. unsigned time = msTick();
  15819. ForEachItemIn(idx, exprs)
  15820. {
  15821. if (needsRealThor(&exprs.item(idx)))
  15822. return;
  15823. }
  15824. // if we got this far, thor not required
  15825. setTargetClusterType(HThorCluster);
  15826. DBGLOG("Thor query redirected to hthor instead");
  15827. updateTimer("workunit;tree transform: pick engine", msTick()-time);
  15828. }
  15829. }
  15830. void HqlCppTranslator::pickBestEngine(WorkflowArray & workflow)
  15831. {
  15832. if (targetThor())
  15833. {
  15834. unsigned time = msTick();
  15835. ForEachItemIn(idx2, workflow)
  15836. {
  15837. HqlExprArray & exprs = workflow.item(idx2).queryExprs();
  15838. ForEachItemIn(idx, exprs)
  15839. {
  15840. if (needsRealThor(&exprs.item(idx)))
  15841. return;
  15842. }
  15843. // if we got this far, thor not required
  15844. }
  15845. setTargetClusterType(HThorCluster);
  15846. DBGLOG("Thor query redirected to hthor instead");
  15847. updateTimer("workunit;tree transform: pick engine", msTick()-time);
  15848. }
  15849. }
  15850. unsigned getVirtualFieldSize(IHqlExpression * record)
  15851. {
  15852. unsigned size = 0;
  15853. ForEachChild(idx, record)
  15854. {
  15855. IHqlExpression * cur = record->queryChild(idx);
  15856. switch (cur->getOperator())
  15857. {
  15858. case no_field:
  15859. {
  15860. ITypeInfo * type = cur->queryType();
  15861. if (type->isScalar())
  15862. {
  15863. if (cur->hasAttribute(virtualAtom))
  15864. size += type->getSize();
  15865. }
  15866. else
  15867. size += getVirtualFieldSize(cur->queryRecord());
  15868. break;
  15869. }
  15870. case no_ifblock:
  15871. size += getVirtualFieldSize(cur->queryChild(1));
  15872. break;
  15873. case no_record:
  15874. size += getVirtualFieldSize(cur);
  15875. break;
  15876. }
  15877. }
  15878. return size;
  15879. }
  15880. //---------------------------------------------------------------------------
  15881. /*
  15882. The following transforms are applied to the graphs before the code is generated:
  15883. o replaceStoredValues(exprs, foldStored);
  15884. - Replaces any #stored values in the graph. Done first so everything remains consistent.
  15885. o normalizeHqlTree(exprs);
  15886. - Converts expressions to their normal form. Main change is to remove default values from fields, so the graph can be
  15887. transformed without having to remap fields its value (e.g., dataset on a select) changes. Impossible to do anything without
  15888. this stage.
  15889. - Also converts x : global to global(x) and normalizes a few simple constructs e.g., trim,right->trim
  15890. o allocateSequenceNumbers(exprs);
  15891. - Adds sequence numbers to all outputs
  15892. o foldHqlExpression
  15893. - does a global constant fold to simplify the graph before it gets broken up at all.
  15894. o optimizeHqlExpression
  15895. - 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...
  15896. o extractWorkflow(exprs)
  15897. - Converts a list of expressions into a list of workflow items. Once this is done each workflow item can be treated independently.
  15898. --- 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
  15899. --- together so increase likely hood for cses and reduce connections to the query engines.
  15900. o migrateExprToNaturalLevel [NewScopeMigrateTransformer]
  15901. - Ensure expressions are evaluated at the best level - e.g., counts moved to most appropriate level.
  15902. * global(x) is extracted to a global set/get result pair.
  15903. - This includes datasets, and specifically ignores any conditional context
  15904. * SET(dataset, field) is converted to a workunit output, workunit read pair
  15905. !!Needs revisiting for child queries
  15906. * global count(), max() on global tables used inside an activity are always hoisted
  15907. !!regardless of whether they are conditional or not.
  15908. * local(x) and global() interactions are processed
  15909. !!Once aggregate sources are implemented, this may not be so useful, or even needed.
  15910. o markThorBoundaries
  15911. - work out which engine is going to perform which operation.
  15912. o normalizeResultFormat
  15913. * convert thor(scalar|row) into compound(setresult,getresult) or global setresult, local getresult
  15914. !!It should common up conditional expressions with non conditional
  15915. * IF(count(x)...) inside thor, hoist the count(x) so it is global
  15916. * IF(ds[n]...) inside thor, hoist it so it is global.
  15917. !!Conditionals should be handled differently I am sure...
  15918. o flattenDatasets(array);
  15919. - Currently does nothing. It should add projects to hole to ensure fields are available.
  15920. o mergeThorGraphs
  15921. - Make sure thor graphs are together as much as possible to save transfers to thor, and maximise the cse chances.
  15922. - Combine results of above. Should probably just be a single transformation.
  15923. o spotGlobalCSE
  15924. - Spot CSEs between different graphs. E.g., f(a), if(x, g(a), h(a)) Should ensure a is spilled.
  15925. !!Current problem is that global can create a implicit dependency which isn't spotted.
  15926. !!also doesn't handle commoning up scalars very well.
  15927. o removeTrivialGraphs
  15928. - don't implement setresult(getresult) in thor - a waste of time....
  15929. o convertLogicalToActivities
  15930. - change representation from logical to actual implementation. E.g., dedup(a, b) becomes group(dedup(group(a,b,all)))
  15931. */