hqlcpp.cpp 440 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include <algorithm>
  15. #include "jliball.hpp"
  16. #include "jlib.hpp"
  17. #include "jexcept.hpp"
  18. #include "jmisc.hpp"
  19. #include "javahash.hpp"
  20. #include "jmd5.hpp"
  21. #include "jfile.hpp"
  22. #include "eclhelper.hpp"
  23. #include "hql.hpp"
  24. #include "hqlfunc.hpp"
  25. #include "hqlattr.hpp"
  26. #include "hqlcpp.ipp"
  27. #include "hqlwcpp.hpp"
  28. #include "hqlcpputil.hpp"
  29. #include "hqlres.hpp"
  30. #include "hqlerror.hpp"
  31. #include "hqlcerrors.hpp"
  32. #include "hqlcatom.hpp"
  33. #include "hqlpmap.hpp"
  34. #include "hqlthql.hpp"
  35. #include "hqlfold.hpp"
  36. #include "eclrtl.hpp"
  37. #include "hqllib.ipp"
  38. #include "hqlnlp.ipp"
  39. #include "hqlutil.hpp"
  40. #include "hqltcppc.ipp"
  41. #include "hqlttcpp.ipp"
  42. #include "hqlccommon.hpp"
  43. #include "hqlopt.hpp"
  44. #include "hqlpopt.hpp"
  45. #include "hqlcse.ipp"
  46. #include "thorplugin.hpp"
  47. #include "hqlinline.hpp"
  48. #include "hqlusage.hpp"
  49. #ifdef _DEBUG
  50. //#define ADD_ASSIGNMENT_COMMENTS
  51. //#define ADD_RESOURCE_AS_CPP_COMMENT
  52. #endif
  53. //Defaults for various options.
  54. #define COMPLEXITY_TO_HOIST 2
  55. #define INLINE_COMPARE_THRESHOLD 2 //7 // above this, a loop is generated
  56. #define MAX_NESTED_CASES 8
  57. #define MAX_SIMPLE_VAR_SIZE 99999
  58. #define MAX_STATIC_ROW_SIZE 10000
  59. #define MAX_LOCAL_ROW_SIZE 32
  60. #define DEFAULT_NLP_DETAIL 0
  61. #define DEFAULT_EXPIRY_PERIOD 7
  62. #define DEFAULT_PERSIST_EXPIRY_PERIOD 0 // Persists that expire by default have a period defined in sasha
  63. #ifdef _WIN32
  64. #define DEFAULT_ACTIVITIES_PER_CPP 800 // windows compiler is fast, linker is slow, but compiler also has quite a small compile limit
  65. #else
  66. #define DEFAULT_ACTIVITIES_PER_CPP 500 // gcc assembler is v.slow
  67. #endif
  68. //MORE: Simple vars don't work if they are made class members...
  69. //#define SEARCH_VARIABLE "v211"
  70. //===========================================================================
  71. static CriticalSection * systemCS;
  72. static IHqlScope * cppSystemScope;
  73. //===========================================================================
  74. MODULE_INIT(INIT_PRIORITY_STANDARD)
  75. {
  76. systemCS = new CriticalSection;
  77. return true;
  78. }
  79. MODULE_EXIT()
  80. {
  81. ::Release(cppSystemScope);
  82. cppSystemScope = NULL;
  83. delete systemCS;
  84. }
  85. //---------------------------------------------------------------------------
  86. class SubStringInfo : public SubStringHelper
  87. {
  88. public:
  89. SubStringInfo(IHqlExpression * _expr) : SubStringHelper(_expr) { expr = _expr; }
  90. void bindToFrom(HqlCppTranslator & translator, BuildCtx & ctx);
  91. public:
  92. IHqlExpression * expr;
  93. CHqlBoundExpr boundFrom;
  94. CHqlBoundExpr boundTo;
  95. };
  96. void SubStringInfo::bindToFrom(HqlCppTranslator & translator, BuildCtx & ctx)
  97. {
  98. if (to && to->isAttribute())
  99. throwError(HQLERR_StarRangeOnlyInJoinCondition);
  100. if (from == to)
  101. {
  102. if (from)
  103. {
  104. translator.buildSimpleExpr(ctx, from, boundFrom);
  105. boundTo.expr.set(boundFrom.expr);
  106. }
  107. }
  108. else
  109. {
  110. if (from)
  111. translator.buildCachedExpr(ctx, from, boundFrom);
  112. if (to)
  113. translator.buildCachedExpr(ctx, to, boundTo);
  114. }
  115. }
  116. //---------------------------------------------------------------------------
  117. WorkflowItem::WorkflowItem(IHqlExpression * _function) : wfid(999999999), workflowOp(no_funcdef), function(_function)
  118. {
  119. IHqlExpression * body = function->queryChild(0);
  120. assertex(body->getOperator() == no_outofline);
  121. IHqlExpression * ecl = body->queryChild(0);
  122. exprs.append(*createValue(no_return_stmt, makeVoidType(), LINK(ecl)));
  123. label.append(function->queryId()->queryStr());
  124. }
  125. IHqlExpression * WorkflowItem::getFunction() const
  126. {
  127. IHqlExpression * body = function->queryChild(0);
  128. unsigned max = exprs.ordinality();
  129. assertex(max);
  130. LinkedHqlExpr newecl = exprs.item(max-1).queryChild(0);
  131. for (unsigned i=max-1; i--; )
  132. {
  133. IHqlExpression * cur = &exprs.item(i);
  134. newecl.setown(createCompound(LINK(cur), newecl.getClear()));
  135. }
  136. OwnedHqlExpr newBody = replaceChild(body, 0, newecl);
  137. return replaceChild(function, 0, newBody);
  138. }
  139. //---------------------------------------------------------------------------
  140. IHqlExpression * DatasetReference::querySelector() const
  141. {
  142. if (side == no_none)
  143. return ds->queryNormalizedSelector();
  144. return selector;
  145. }
  146. IHqlExpression * DatasetReference::querySelSeq() const
  147. {
  148. if (side == no_none)
  149. return NULL;
  150. return selector->queryChild(1);
  151. }
  152. IHqlExpression * DatasetReference::mapCompound(IHqlExpression * expr, IHqlExpression * to) const
  153. {
  154. return replaceSelector(expr, querySelector(), to);
  155. }
  156. IHqlExpression * DatasetReference::mapScalar(IHqlExpression * expr, IHqlExpression * to) const
  157. {
  158. return replaceSelector(expr, querySelector(), to);
  159. }
  160. //---------------------------------------------------------------------------
  161. IHqlExpression * createVariable(ITypeInfo * type)
  162. {
  163. StringBuffer tempName;
  164. getUniqueId(tempName.append('v'));
  165. #ifdef _DEBUG
  166. #ifdef SEARCH_VARIABLE
  167. if (stricmp(tempName.str(), SEARCH_VARIABLE)==0)
  168. type = type;
  169. #endif
  170. #endif
  171. return ::createVariable(tempName.str(), type);
  172. }
  173. IHqlExpression * convertWrapperToPointer(IHqlExpression * expr)
  174. {
  175. ITypeInfo * type = expr->queryType();
  176. if (hasWrapperModifier(type))
  177. return createValue(no_implicitcast, makeReferenceModifier(removeModifier(type, typemod_wrapper)), LINK(expr));
  178. return LINK(expr);
  179. }
  180. IHqlExpression * ensureIndexable(IHqlExpression * expr)
  181. {
  182. ITypeInfo * type = expr->queryType();
  183. if (type->getTypeCode() == type_data)
  184. {
  185. IHqlExpression * base = queryStripCasts(expr);
  186. return createValue(no_implicitcast, makeReferenceModifier(makeStringType(type->getSize(), NULL, NULL)), LINK(base));
  187. }
  188. return convertWrapperToPointer(expr);
  189. }
  190. void extendConjunctionOwn(HqlExprAttr & cond, IHqlExpression * next)
  191. {
  192. if (cond)
  193. next = createBoolExpr(no_and, cond.getClear(), next);
  194. cond.setown(next);
  195. }
  196. inline bool isPushed(const IHqlExpression * expr)
  197. {
  198. return (expr->getOperator() == no_decimalstack);
  199. }
  200. inline bool isPushed(const CHqlBoundExpr & bound)
  201. {
  202. return isPushed(bound.expr);
  203. }
  204. bool isSimpleTranslatedStringExpr(IHqlExpression * expr)
  205. {
  206. for (;;)
  207. {
  208. node_operator op = expr->getOperator();
  209. switch (op)
  210. {
  211. case no_constant:
  212. case no_variable:
  213. case no_callback:
  214. case no_select:
  215. return true;
  216. case no_cast:
  217. case no_implicitcast:
  218. case no_typetransfer:
  219. case no_deref:
  220. case no_address:
  221. expr = expr->queryChild(0);
  222. break;
  223. case no_add:
  224. case no_sub:
  225. if (!isSimpleTranslatedStringExpr(expr->queryChild(1)))
  226. return false;
  227. expr = expr->queryChild(0);
  228. break;
  229. default:
  230. return false;
  231. }
  232. }
  233. }
  234. bool isSimpleTranslatedExpr(IHqlExpression * expr)
  235. {
  236. switch (expr->queryType()->getTypeCode())
  237. {
  238. case type_data:
  239. case type_string:
  240. case type_qstring:
  241. case type_varstring:
  242. case type_decimal:
  243. case type_unicode:
  244. case type_varunicode:
  245. //Less strict rules for strings (and decimal), because string temporaries are more expensive.
  246. return isSimpleTranslatedStringExpr(expr);
  247. case type_set:
  248. //for the moment assume set expressions are always simple once translated.
  249. return true;
  250. }
  251. for (;;)
  252. {
  253. node_operator op = expr->getOperator();
  254. switch (op)
  255. {
  256. case no_constant:
  257. case no_variable:
  258. case no_callback:
  259. case no_nullptr:
  260. return true;
  261. case no_typetransfer:
  262. expr = expr->queryChild(0);
  263. break;
  264. default:
  265. return false;
  266. }
  267. }
  268. }
  269. bool isFixedLengthList(IHqlExpression * expr)
  270. {
  271. switch (expr->getOperator())
  272. {
  273. case no_list:
  274. case no_datasetlist:
  275. case no_sortlist:
  276. return true;
  277. }
  278. return false;
  279. }
  280. bool needVarStringCompare(ITypeInfo * leftType, ITypeInfo * rightType)
  281. {
  282. unsigned lSize = leftType->getSize();
  283. unsigned rSize = rightType->getSize();
  284. return (lSize != rSize) || (lSize == UNKNOWN_LENGTH);
  285. }
  286. IIdAtom * queryStrCompareFunc(ITypeInfo * realType)
  287. {
  288. switch (realType->getTypeCode())
  289. {
  290. case type_data:
  291. return compareDataDataId;
  292. case type_qstring:
  293. return compareQStrQStrId;
  294. }
  295. ICharsetInfo * charset = realType->queryCharset();
  296. IAtom * charsetName = charset->queryName();
  297. if (charsetName == dataAtom)
  298. return compareDataDataId;
  299. if (charsetName == asciiAtom)
  300. return compareStrStrId;
  301. if (charsetName == ebcdicAtom)
  302. return compareEStrEStrId;
  303. assertex(!"Unknown string comparison");
  304. return compareStrStrId;
  305. }
  306. IHqlExpression * getAddress(IHqlExpression * expr)
  307. {
  308. if (expr->getOperator() == no_deref)
  309. {
  310. IHqlExpression * address = expr->queryChild(0);
  311. return LINK(address);
  312. }
  313. return createValue(no_address, makePointerType(expr->getType()), LINK(expr));
  314. }
  315. IHqlExpression * getRawAddress(IHqlExpression * expr)
  316. {
  317. OwnedHqlExpr raw = getAddress(expr);
  318. for (;;)
  319. {
  320. switch (raw->getOperator())
  321. {
  322. case no_cast:
  323. case no_implicitcast:
  324. break;
  325. default:
  326. return raw.getClear();
  327. }
  328. raw.set(raw->queryChild(0));
  329. }
  330. }
  331. IHqlExpression * getPointer(IHqlExpression * source)
  332. {
  333. if (source->getOperator() == no_constant)
  334. return LINK(source);
  335. ITypeInfo * type = source->queryType();
  336. Owned<ITypeInfo> newType;
  337. switch (type->getTypeCode())
  338. {
  339. case type_set:
  340. if (type->isReference())
  341. return LINK(source);
  342. newType.setown(makeReferenceModifier(LINK(queryUnqualifiedType(type))));
  343. if (hasWrapperModifier(type))
  344. {
  345. OwnedHqlExpr cast = createValue(no_implicitcast, LINK(newType), LINK(source));
  346. return createValue(no_typetransfer, LINK(newType), LINK(cast));
  347. }
  348. break;
  349. case type_dictionary:
  350. case type_table:
  351. case type_groupedtable:
  352. case type_row:
  353. case type_decimal:
  354. case type_string:
  355. case type_data:
  356. case type_qstring:
  357. case type_varstring:
  358. case type_unicode:
  359. case type_varunicode:
  360. case type_utf8:
  361. if (isTypePassedByAddress(type))
  362. {
  363. if (type->isReference())
  364. return LINK(source);
  365. newType.setown(makeReferenceModifier(LINK(queryUnqualifiedType(type))));
  366. if (hasLinkCountedModifier(type))
  367. newType.setown(makeAttributeModifier(newType.getClear(), getLinkCountedAttr()));
  368. if (hasWrapperModifier(type))
  369. return createValue(no_implicitcast, LINK(newType), LINK(source));
  370. //An array of X is implicitly converted to pointer to X so no need to do &a[0]
  371. return createValue(no_typetransfer, LINK(newType), LINK(source));
  372. }
  373. else
  374. {
  375. newType.setown(removeModifier(type, typemod_wrapper));
  376. if (hasWrapperModifier(type))
  377. return createValue(no_implicitcast, LINK(newType), LINK(source));
  378. return LINK(source);
  379. }
  380. break;
  381. case type_pointer:
  382. return LINK(source);
  383. default:
  384. newType.setown(makePointerType(LINK(type)));
  385. break;
  386. }
  387. IHqlExpression * cur = source;
  388. while (cur->getOperator() == no_typetransfer)
  389. cur = cur->queryChild(0);
  390. if (cur->getOperator() == no_deref)
  391. {
  392. IHqlExpression * address = cur->queryChild(0);
  393. if (address->queryType() == newType)
  394. return LINK(address);
  395. return createValue(no_implicitcast, newType.getClear(), LINK(address));
  396. }
  397. else
  398. return createValue(no_address, newType.getClear(), LINK(source));
  399. }
  400. bool isChildOf(IHqlExpression * parent, IHqlExpression * child)
  401. {
  402. unsigned max = parent->numChildren();
  403. unsigned idx;
  404. for (idx = 0; idx < max; idx++)
  405. {
  406. IHqlExpression * cur = parent->queryChild(idx);
  407. if (cur == child)
  408. return true;
  409. }
  410. return false;
  411. }
  412. bool canRemoveStringCast(ITypeInfo * to, ITypeInfo * from)
  413. {
  414. unsigned fromSize = from->getSize();
  415. unsigned toSize = to->getSize();
  416. //Special case string conversions that don't require us to copy any data.
  417. if ((toSize == UNKNOWN_LENGTH) || ((fromSize != UNKNOWN_LENGTH) && (toSize <= fromSize)))
  418. {
  419. switch (from->getTypeCode())
  420. {
  421. case type_varstring:
  422. if (toSize != UNKNOWN_LENGTH)
  423. break;
  424. //fall through
  425. case type_data:
  426. case type_string:
  427. {
  428. ICharsetInfo * srcset = from->queryCharset();
  429. ICharsetInfo * tgtset = to->queryCharset();
  430. //Data never calls a conversion function...
  431. if ((srcset == tgtset) || (to->getTypeCode() == type_data) || (from->getTypeCode() == type_data))
  432. return true;
  433. return false;
  434. }
  435. case type_qstring:
  436. return false;
  437. }
  438. }
  439. return false;
  440. }
  441. bool isProjectedInRecord(IHqlExpression * record, IHqlExpression * expr)
  442. {
  443. unsigned max = record->numChildren();
  444. unsigned idx;
  445. for (idx = 0; idx < max; idx++)
  446. {
  447. IHqlExpression * cur = record->queryChild(idx);
  448. if (cur->queryChild(0) == expr)
  449. return true;
  450. }
  451. return false;
  452. }
  453. // Format the list is stored in doesn't matter, so allow constant strings to be stored by reference
  454. IHqlExpression * getOptimialListFormat(IHqlExpression * table)
  455. {
  456. if (table->isConstant() && table->getOperator() == no_list)
  457. {
  458. ITypeInfo * elemType = table->queryType()->queryChildType();
  459. if (!elemType->isReference())
  460. {
  461. switch (elemType->getTypeCode())
  462. {
  463. case type_string:
  464. case type_data:
  465. {
  466. HqlExprArray args;
  467. table->unwindList(args, no_list);
  468. return createValue(no_list, makeSetType(makeReferenceModifier(LINK(elemType))), args);
  469. }
  470. }
  471. }
  472. }
  473. return LINK(table);
  474. }
  475. bool canOptimizeAdjust(IHqlExpression * value)
  476. {
  477. switch (value->getOperator())
  478. {
  479. case no_constant:
  480. return true;
  481. case no_add:
  482. case no_sub:
  483. return value->queryChild(1)->queryValue() != NULL;
  484. }
  485. return false;
  486. }
  487. IHqlExpression * adjustValue(IHqlExpression * value, __int64 delta)
  488. {
  489. if (delta == 0)
  490. return LINK(value);
  491. ITypeInfo * type = value->queryType();
  492. switch (value->getOperator())
  493. {
  494. case no_constant:
  495. {
  496. __int64 newValue = value->queryValue()->getIntValue()+delta;
  497. if (type == sizetType)
  498. return getSizetConstant((size32_t)newValue);
  499. return createConstant(type->castFrom(true, newValue));
  500. }
  501. case no_add:
  502. {
  503. IHqlExpression * lhs = value->queryChild(0);
  504. IHqlExpression * rhs = value->queryChild(1);
  505. IValue * rhsValue = rhs->queryValue();
  506. IValue * lhsValue = lhs->queryValue();
  507. if (rhsValue)
  508. {
  509. delta += rhsValue->getIntValue();
  510. if (delta == 0)
  511. return LINK(lhs);
  512. value = lhs;
  513. }
  514. else if (lhsValue)
  515. {
  516. delta += lhsValue->getIntValue();
  517. if (delta == 0)
  518. return LINK(rhs);
  519. value = rhs;
  520. }
  521. else if (canOptimizeAdjust(rhs))
  522. return createValue(no_add, value->getType(), LINK(lhs), adjustValue(rhs, delta));
  523. break;
  524. }
  525. case no_sub:
  526. {
  527. IValue * rhsValue = value->queryChild(1)->queryValue();
  528. if (rhsValue)
  529. {
  530. IHqlExpression * lhs = value->queryChild(0);
  531. delta -= rhsValue->getIntValue();
  532. if (delta == 0)
  533. return LINK(lhs);
  534. value = lhs;
  535. }
  536. break;
  537. }
  538. case no_translated:
  539. {
  540. IHqlExpression * arg = value->queryChild(0);
  541. if (arg->queryValue())
  542. {
  543. OwnedHqlExpr newValue = adjustValue(arg, delta);
  544. return createTranslated(newValue);
  545. }
  546. break;
  547. }
  548. //optimize no_case because it is generated by a transformation of the dataset no_case
  549. case no_case:
  550. case no_mapto:
  551. {
  552. HqlExprArray args;
  553. args.append(*LINK(value->queryChild(0)));
  554. ForEachChildFrom(i, value, 1)
  555. {
  556. IHqlExpression * cur = value->queryChild(i);
  557. args.append(*adjustValue(cur, delta));
  558. }
  559. return value->clone(args);
  560. }
  561. }
  562. IHqlExpression * deltaExpr;
  563. node_operator op = no_add;
  564. if (delta < 0)
  565. {
  566. op = no_sub;
  567. delta = -delta;
  568. }
  569. if (type == sizetType || !type->isInteger())
  570. deltaExpr = getSizetConstant((size32_t)delta);
  571. else
  572. deltaExpr = createConstant(type->castFrom(true, delta));
  573. return createValue(op, LINK(type), LINK(value), deltaExpr);
  574. }
  575. IHqlExpression * adjustIndexBaseToZero(IHqlExpression * index)
  576. {
  577. return adjustValue(index, -1);
  578. }
  579. IHqlExpression * adjustIndexBaseToOne(IHqlExpression * index)
  580. {
  581. return adjustValue(index, +1);
  582. }
  583. IHqlExpression * adjustBoundIntegerValues(IHqlExpression * left, IHqlExpression * right, bool subtract)
  584. {
  585. if (!left)
  586. {
  587. if (!subtract)
  588. return LINK(right);
  589. else
  590. return getNegative(right);
  591. }
  592. assertex(queryUnqualifiedType(left->queryType()) == queryUnqualifiedType(right->queryType()));
  593. if (canOptimizeAdjust(left))
  594. {
  595. node_operator op = right->getOperator();
  596. switch (op)
  597. {
  598. case no_constant:
  599. {
  600. __int64 rhsValue = right->queryValue()->getIntValue();
  601. if (subtract)
  602. rhsValue = -rhsValue;
  603. return adjustValue(left, rhsValue);
  604. }
  605. case no_add:
  606. case no_sub:
  607. {
  608. IHqlExpression * rl = right->queryChild(0);
  609. IHqlExpression * rr = right->queryChild(1);
  610. if (rr->getOperator() == no_constant)
  611. {
  612. if (queryUnqualifiedType(rl->queryType()) == queryUnqualifiedType(rr->queryType()))
  613. {
  614. __int64 delta = rr->queryValue()->getIntValue();
  615. if (op == no_sub)
  616. delta = -delta;
  617. if (subtract)
  618. delta = -delta;
  619. OwnedHqlExpr newLeft = adjustValue(left, delta);
  620. return adjustBoundIntegerValues(newLeft, rl, subtract);
  621. }
  622. }
  623. break;
  624. }
  625. }
  626. }
  627. switch (left->getOperator())
  628. {
  629. case no_constant:
  630. if (!subtract)
  631. return adjustBoundIntegerValues(right, left, false);
  632. break;
  633. case no_add:
  634. {
  635. IHqlExpression * lr = left->queryChild(1);
  636. if (lr->getOperator() == no_constant)
  637. {
  638. OwnedHqlExpr newLeft = adjustBoundIntegerValues(left->queryChild(0), right, subtract);
  639. return adjustBoundIntegerValues(newLeft, lr, false);
  640. }
  641. break;
  642. }
  643. case no_variable:
  644. if (!subtract && (right->getOperator() == no_add) && (right->queryChild(1)->getOperator() == no_constant))
  645. {
  646. OwnedHqlExpr temp = adjustBoundIntegerValues(left, right->queryChild(0), false);
  647. return adjustBoundIntegerValues(temp, right->queryChild(1), false);
  648. }
  649. break;
  650. }
  651. return createValue(subtract ? no_sub : no_add, left->getType(), LINK(left), LINK(right));
  652. }
  653. IHqlExpression * multiplyValue(IHqlExpression * expr, unsigned __int64 value)
  654. {
  655. if (isZero(expr))
  656. return LINK(expr);
  657. ITypeInfo * type = expr->queryType();
  658. IValue * exprValue = expr->queryValue();
  659. if (exprValue && type->isInteger())
  660. return createConstant(type->castFrom(false, exprValue->getIntValue() * value));
  661. if (expr->getOperator() == no_translated)
  662. {
  663. IHqlExpression * translated = expr->queryChild(0);
  664. if (translated->queryValue())
  665. {
  666. OwnedHqlExpr newValue = multiplyValue(translated, value);
  667. return createTranslated(newValue);
  668. }
  669. }
  670. return createValue(no_mul, LINK(type), LINK(expr), createConstant(type->castFrom(false, value)));
  671. }
  672. bool matchesConstValue(IHqlExpression * expr, __int64 matchValue)
  673. {
  674. IValue * value = expr->queryValue();
  675. if (value)
  676. return value->getIntValue() == matchValue;
  677. if (expr->getOperator() == no_translated)
  678. return matchesConstValue(expr->queryChild(0), matchValue);
  679. return false;
  680. }
  681. IHqlExpression * createTranslated(IHqlExpression * expr)
  682. {
  683. return createValue(no_translated, expr->getType(), LINK(expr));
  684. }
  685. IHqlExpression * createTranslatedOwned(IHqlExpression * expr)
  686. {
  687. return createValue(no_translated, expr->getType(), expr);
  688. }
  689. IHqlExpression * createTranslated(IHqlExpression * expr, IHqlExpression * length)
  690. {
  691. ITypeInfo * type = expr->queryType();
  692. switch (type->getTypeCode())
  693. {
  694. case type_dictionary:
  695. return createDictionary(no_translated, LINK(expr), LINK(length));
  696. case type_table:
  697. case type_groupedtable:
  698. return createDataset(no_translated, LINK(expr), LINK(length));
  699. }
  700. return createValue(no_translated, expr->getType(), LINK(expr), LINK(length));
  701. }
  702. static IHqlExpression * querySimplifyCompareArgCast(IHqlExpression * expr)
  703. {
  704. if (expr->isConstant())
  705. return expr;
  706. while ((expr->getOperator() == no_implicitcast) || (expr->getOperator() == no_cast))
  707. {
  708. ITypeInfo * type = expr->queryType()->queryPromotedType();
  709. switch (type->getTypeCode())
  710. {
  711. case type_string:
  712. case type_data:
  713. case type_unicode:
  714. case type_qstring:
  715. case type_utf8:
  716. break;
  717. default:
  718. return expr;
  719. }
  720. IHqlExpression * child = expr->queryChild(0);
  721. ITypeInfo * childType = child->queryType()->queryPromotedType();
  722. if (type->getStringLen() < childType->getStringLen())
  723. break;
  724. type_t tc = type->getTypeCode();
  725. if (tc != childType->getTypeCode())
  726. {
  727. if (tc == type_string)
  728. {
  729. if (childType->getTypeCode() != type_varstring)
  730. break;
  731. if (type->queryCharset() != childType->queryCharset())
  732. break;
  733. }
  734. else if (tc == type_unicode)
  735. {
  736. if (childType->getTypeCode() != type_varunicode)
  737. break;
  738. if (type->queryLocale() != childType->queryLocale())
  739. break;
  740. }
  741. else
  742. break;
  743. }
  744. else
  745. {
  746. Owned<ITypeInfo> stretched = getStretchedType(type->getStringLen(), childType);
  747. if (stretched != type)
  748. break;
  749. }
  750. expr = child;
  751. }
  752. return expr;
  753. }
  754. IHqlExpression * getSimplifyCompareArg(IHqlExpression * expr)
  755. {
  756. IHqlExpression * cast = querySimplifyCompareArgCast(expr);
  757. if (cast->getOperator() != no_substring)
  758. return LINK(cast);
  759. if (cast->queryChild(0)->queryType()->getTypeCode() == type_qstring)
  760. return LINK(cast);
  761. HqlExprArray args;
  762. unwindChildren(args, cast);
  763. args.append(*createAttribute(quickAtom));
  764. return cast->clone(args);
  765. }
  766. bool isNullAssign(const CHqlBoundTarget & target, IHqlExpression * expr)
  767. {
  768. ITypeInfo * targetType = target.expr->queryType();
  769. //if an assignment to a local variable size temporary object, then it is ok to omit an assignment of null
  770. //since it won't change its value, and it isn't going to be assigned more than once.
  771. if ((targetType->getSize() == UNKNOWN_LENGTH) && target.length && hasWrapperModifier(targetType) && !hasModifier(targetType, typemod_member))
  772. {
  773. ITypeInfo * exprType = expr->queryType();
  774. switch (exprType->getTypeCode())
  775. {
  776. case type_data:
  777. case type_string:
  778. case type_qstring:
  779. return exprType->getSize() == 0;
  780. case type_dictionary:
  781. case type_table:
  782. return expr->getOperator() == no_null;
  783. }
  784. }
  785. return false;
  786. }
  787. ExpressionFormat queryNaturalFormat(ITypeInfo * type)
  788. {
  789. if (hasStreamedModifier(type))
  790. return FormatStreamedDataset;
  791. if (hasOutOfLineModifier(type))
  792. return FormatArrayDataset;
  793. if (hasLinkCountedModifier(type))
  794. return FormatLinkedDataset;
  795. return FormatBlockedDataset;
  796. }
  797. //===========================================================================
  798. SubGraphInfo::SubGraphInfo(IPropertyTree * _tree, unsigned _id, unsigned _graphId, IHqlExpression * _graphTag, SubGraphType _type)
  799. : HqlExprAssociation(subGraphMarker), tree(_tree)
  800. {
  801. id = _id;
  802. graphId = _graphId;
  803. type = _type;
  804. graphTag.set(_graphTag);
  805. }
  806. //===========================================================================
  807. IHqlExpression * CHqlBoundExpr::getTranslatedExpr() const
  808. {
  809. HqlExprArray args;
  810. args.append(*LINK(expr));
  811. if (length) args.append(*LINK(length));
  812. if (count) args.append(*createAttribute(countAtom, LINK(count)));
  813. if (isAll) args.append(*createAttribute(allAtom, LINK(isAll)));
  814. ITypeInfo * type = expr->queryType();
  815. switch (type->getTypeCode())
  816. {
  817. case type_dictionary:
  818. return createDictionary(no_translated, args);
  819. case type_table:
  820. case type_groupedtable:
  821. return createDataset(no_translated, args);
  822. }
  823. return createValue(no_translated, LINK(type), args);
  824. }
  825. IHqlExpression * CHqlBoundExpr::getComplexExpr() const
  826. {
  827. assertex(count && expr);
  828. return createValue(no_complex, expr->getType(), LINK(count), LINK(expr));
  829. }
  830. IHqlExpression * CHqlBoundExpr::getIsAll() const
  831. {
  832. if (isAll)
  833. return LINK(isAll);
  834. return LINK(queryBoolExpr(false));
  835. }
  836. void CHqlBoundExpr::setFromTarget(const CHqlBoundTarget & target)
  837. {
  838. isAll.set(target.isAll);
  839. count.set(target.count);
  840. length.set(target.length);
  841. expr.setown(convertWrapperToPointer(target.expr));
  842. }
  843. void CHqlBoundExpr::setFromTranslated(IHqlExpression * translatedExpr)
  844. {
  845. expr.set(translatedExpr->queryChild(0));
  846. IHqlExpression * arg = translatedExpr->queryChild(1);
  847. if (arg)
  848. {
  849. unsigned i = 2;
  850. if (arg->getOperator() != no_attr)
  851. {
  852. length.set(arg);
  853. arg = translatedExpr->queryChild(i++);
  854. }
  855. while (arg)
  856. {
  857. IAtom * name = arg->queryName();
  858. if (name == countAtom)
  859. count.set(arg->queryChild(0));
  860. else if (name == allAtom)
  861. isAll.set(arg->queryChild(0));
  862. else
  863. UNIMPLEMENTED;
  864. arg = translatedExpr->queryChild(i++);
  865. }
  866. }
  867. }
  868. bool CHqlBoundTarget::extractFrom(const CHqlBoundExpr & bound)
  869. {
  870. ITypeInfo * boundType = bound.queryType();
  871. if (bound.count)
  872. {
  873. if (bound.count->getOperator() != no_variable)
  874. return false;
  875. if (!hasLinkCountedModifier(boundType))
  876. return false;
  877. }
  878. if (bound.isAll)
  879. {
  880. assertex(bound.isAll->getOperator() == no_variable);
  881. }
  882. else if (boundType->getTypeCode() == type_set)
  883. return false;
  884. if (bound.length)
  885. {
  886. if (bound.length->getOperator() != no_variable)
  887. return false;
  888. }
  889. else if (boundType->getSize() == UNKNOWN_LENGTH)
  890. {
  891. type_t btc = boundType->getTypeCode();
  892. if ((btc != type_varstring) && (btc != type_varunicode) && !hasLinkCountedModifier(boundType))
  893. return false;
  894. }
  895. IHqlExpression * boundExpr = bound.expr;
  896. if (boundExpr->getOperator() == no_implicitcast)
  897. {
  898. IHqlExpression * uncast = boundExpr->queryChild(0);
  899. if (hasModifier(uncast->queryType(), typemod_member) &&
  900. (queryUnqualifiedType(boundExpr->queryType()) == queryUnqualifiedType(uncast->queryType())))
  901. boundExpr = uncast;
  902. }
  903. expr.set(boundExpr);
  904. isAll.set(bound.isAll);
  905. length.set(bound.length);
  906. count.set(bound.count);
  907. return true;
  908. }
  909. bool CHqlBoundTarget::isFixedSize() const
  910. {
  911. validate();
  912. return queryType()->getSize() != UNKNOWN_LENGTH;
  913. }
  914. void CHqlBoundTarget::validate() const
  915. {
  916. if (expr)
  917. {
  918. ITypeInfo * type = queryType();
  919. type_t tc = type->getTypeCode();
  920. if (tc == type_row || type->isReference())
  921. {
  922. //No checks to apply in these cases.
  923. }
  924. else if (type->getSize() != UNKNOWN_LENGTH)
  925. {
  926. assertex(!length);
  927. }
  928. else if (isArrayRowset(type))
  929. {
  930. if (!hasStreamedModifier(type))
  931. assertex(count != NULL);
  932. }
  933. else
  934. {
  935. assertex(length || tc == type_varstring || tc == type_varunicode || hasStreamedModifier(queryType()));
  936. }
  937. }
  938. }
  939. ITypeInfo * CHqlBoundTarget::queryType() const
  940. {
  941. return expr->queryType();
  942. }
  943. IHqlExpression * CHqlBoundTarget::getTranslatedExpr() const
  944. {
  945. CHqlBoundExpr temp;
  946. temp.setFromTarget(*this);
  947. return temp.getTranslatedExpr();
  948. }
  949. //===========================================================================
  950. CompoundBuilder::CompoundBuilder(node_operator _op)
  951. {
  952. op = _op;
  953. }
  954. void CompoundBuilder::addOperand(IHqlExpression * arg)
  955. {
  956. if (first.get())
  957. {
  958. compound.setown(createOpenValue(op, makeBoolType()));
  959. compound->addOperand(first.getClear());
  960. }
  961. if (compound)
  962. compound->addOperand(arg);
  963. else
  964. first.setown(arg);
  965. }
  966. IHqlExpression * CompoundBuilder::getCompound()
  967. {
  968. if (compound)
  969. return compound.getClear()->closeExpr();
  970. return first.getClear();
  971. }
  972. //===========================================================================
  973. void buildClearPointer(BuildCtx & ctx, IHqlExpression * expr, CompilerType compiler)
  974. {
  975. StringBuffer s;
  976. generateExprCpp(s, expr, compiler).append("=NULL;");
  977. ctx.addQuoted(s);
  978. }
  979. void insertUniqueString(StringAttrArray & array, const char * text)
  980. {
  981. ForEachItemIn(idx, array)
  982. {
  983. StringAttrItem & cur = array.item(idx);
  984. if (stricmp(cur.text, text) == 0)
  985. return;
  986. }
  987. array.append(* new StringAttrItem(text));
  988. }
  989. HqlCppInstance::HqlCppInstance(IWorkUnit *_wu, const char * _wupathname) : resources(*this)
  990. {
  991. workunit.set(_wu);
  992. wupathname.set(_wupathname);
  993. }
  994. HqlStmts * HqlCppInstance::ensureSection(IAtom * section)
  995. {
  996. HqlStmts * match = querySection(section);
  997. if (match)
  998. return match;
  999. HqlCppSection * cur = new HqlCppSection;
  1000. cur->section = section;
  1001. sections.append(*cur);
  1002. return &cur->stmts;
  1003. }
  1004. void HqlCppInstance::processIncludes()
  1005. {
  1006. BuildCtx ctx(*this, includeAtom);
  1007. StringBuffer s;
  1008. ForEachItemIn(idx, includes)
  1009. {
  1010. s.clear().append("#include \"").append(includes.item(idx).text).append("\"");
  1011. ctx.addQuoted(s);
  1012. }
  1013. }
  1014. const char * HqlCppInstance::queryLibrary(unsigned idx)
  1015. {
  1016. if (modules.isItem(idx))
  1017. return modules.item(idx).text;
  1018. return NULL;
  1019. }
  1020. const char * HqlCppInstance::queryObjectFile(unsigned idx)
  1021. {
  1022. if (objectFiles.isItem(idx))
  1023. return objectFiles.item(idx).text;
  1024. return NULL;
  1025. }
  1026. const char * HqlCppInstance::querySourceFile(unsigned idx)
  1027. {
  1028. if (sourceFiles.isItem(idx))
  1029. return sourceFiles.item(idx).text;
  1030. return NULL;
  1031. }
  1032. const char * HqlCppInstance::querySourceFlags(unsigned idx)
  1033. {
  1034. if (sourceFlags.isItem(idx))
  1035. return sourceFlags.item(idx).text;
  1036. return NULL;
  1037. }
  1038. bool HqlCppInstance::querySourceIsTemp(unsigned idx)
  1039. {
  1040. if (sourceIsTemp.isItem(idx))
  1041. return sourceIsTemp.item(idx);
  1042. return false;
  1043. }
  1044. const char * HqlCppInstance::queryTempDirectory(unsigned idx)
  1045. {
  1046. if (tempDirs.isItem(idx))
  1047. return tempDirs.item(idx).text;
  1048. return NULL;
  1049. }
  1050. HqlStmts * HqlCppInstance::querySection(IAtom * section)
  1051. {
  1052. ForEachItemIn(idx, sections)
  1053. {
  1054. HqlCppSection & cur = (HqlCppSection &)sections.item(idx);
  1055. if (cur.section == section)
  1056. return &cur.stmts;
  1057. }
  1058. return NULL;
  1059. }
  1060. void HqlCppInstance::addPlugin(const char *plugin, const char *version)
  1061. {
  1062. if (!plugin || !*plugin)
  1063. return;
  1064. StringBuffer dllname(plugin);
  1065. getFileNameOnly(dllname, false); // MORE - shouldn't really need to do this here....
  1066. if (workunit)
  1067. {
  1068. Owned<IWUPlugin> p = workunit->updatePluginByName(dllname.str());
  1069. if (version && *version)
  1070. p->setPluginVersion(version);
  1071. }
  1072. if (!plugins)
  1073. plugins.setown(createPTree("Plugins"));
  1074. StringBuffer xpath;
  1075. xpath.append("Plugin[@dll='").append(dllname).append("']");
  1076. if (!plugins->hasProp(xpath.str()))
  1077. {
  1078. IPropertyTree * pluginNode = createPTree("Plugin");
  1079. pluginNode->setProp("@dll", dllname.str());
  1080. if (version && *version)
  1081. pluginNode->setProp("@version", version);
  1082. plugins->addPropTree("Plugin", pluginNode);
  1083. }
  1084. }
  1085. void HqlCppInstance::addPluginsAsResource()
  1086. {
  1087. if (!plugins)
  1088. return;
  1089. StringBuffer pluginXML;
  1090. toXML(plugins, pluginXML);
  1091. addResource("PLUGINS", pluginXML.length(), pluginXML.str(), NULL, 1);
  1092. }
  1093. void HqlCppInstance::getActivityRange(unsigned cppIndex, unsigned & minActivityId, unsigned & maxActivityId)
  1094. {
  1095. if (cppInfo.isItem(cppIndex))
  1096. {
  1097. minActivityId = cppInfo.item(cppIndex).minActivityId;
  1098. maxActivityId = cppInfo.item(cppIndex).maxActivityId;
  1099. }
  1100. else
  1101. {
  1102. minActivityId = 0;
  1103. maxActivityId = 0;
  1104. }
  1105. }
  1106. bool HqlCppInstance::useFunction(IHqlExpression * func)
  1107. {
  1108. assertex(func);
  1109. func = func->queryBody();
  1110. if (helpers.contains(*func))
  1111. return false;
  1112. helpers.append(*LINK(func));
  1113. IHqlExpression * funcDef = func->queryChild(0);
  1114. StringBuffer libname, init, include, source;
  1115. getAttribute(funcDef, libraryAtom, libname);
  1116. getAttribute(funcDef, initfunctionAtom, init);
  1117. getAttribute(funcDef, includeAtom, include);
  1118. getAttribute(funcDef, sourceAtom, source);
  1119. if (init.length())
  1120. {
  1121. BuildCtx ctx(*this, initAtom);
  1122. ctx.addQuoted(init.append("(wuid);"));
  1123. }
  1124. IHqlExpression *pluginAttr = funcDef->queryAttribute(pluginAtom);
  1125. if (pluginAttr)
  1126. {
  1127. StringBuffer plugin, version;
  1128. getStringValue(plugin, pluginAttr->queryChild(0));
  1129. getStringValue(version, pluginAttr->queryChild(1));
  1130. addPlugin(plugin.str(), version.str());
  1131. if (!libname.length())
  1132. {
  1133. getStringValue(libname, pluginAttr->queryChild(0));
  1134. getFullFileName(libname, true);
  1135. }
  1136. }
  1137. if (!funcDef->hasAttribute(ctxmethodAtom) && !funcDef->hasAttribute(gctxmethodAtom) && !funcDef->hasAttribute(methodAtom))
  1138. {
  1139. if (libname.length())
  1140. useLibrary(libname.str());
  1141. }
  1142. if (include.length())
  1143. useInclude(include.str());
  1144. if (source.length())
  1145. useSourceFile(source, nullptr, false);
  1146. return true;
  1147. }
  1148. void HqlCppInstance::useInclude(const char * include)
  1149. {
  1150. insertUniqueString(includes, include);
  1151. }
  1152. void HqlCppInstance::useLibrary(const char * libname)
  1153. {
  1154. insertUniqueString(modules, libname);
  1155. }
  1156. void HqlCppInstance::useObjectFile(const char * objname)
  1157. {
  1158. insertUniqueString(objectFiles, objname);
  1159. }
  1160. void HqlCppInstance::useSourceFile(const char * srcname, const char *flags, bool isTemp)
  1161. {
  1162. ForEachItemIn(idx, sourceFiles)
  1163. {
  1164. StringAttrItem & cur = sourceFiles.item(idx);
  1165. if (strcmp(cur.text, srcname) == 0)
  1166. {
  1167. assertex(!flags);
  1168. assertex(sourceIsTemp.item(idx)==isTemp);
  1169. return;
  1170. }
  1171. }
  1172. sourceFiles.append(* new StringAttrItem(srcname));
  1173. sourceFlags.append(* new StringAttrItem(flags));
  1174. sourceIsTemp.append(isTemp);
  1175. }
  1176. void HqlCppInstance::addTemporaryDir(const char * path)
  1177. {
  1178. insertUniqueString(tempDirs, path);
  1179. }
  1180. void HqlCppInstance::addHint(const char * hintXml, ICodegenContextCallback * ctxCallback)
  1181. {
  1182. if (!hintFile)
  1183. {
  1184. StringBuffer hintFilename;
  1185. if (wupathname)
  1186. hintFilename.append(wupathname);
  1187. else
  1188. hintFilename.append("wu");
  1189. hintFilename.append("_hints.xml");
  1190. Owned<IFile> file = createIFile(hintFilename);
  1191. Owned<IFileIO> io = file->open(IFOcreate);
  1192. if (!io)
  1193. return;
  1194. hintFile.setown(createIOStream(io));
  1195. appendHintText("<Hints>\n");
  1196. Owned<IWUQuery> query = workunit->updateQuery();
  1197. associateLocalFile(query, FileTypeCpp, hintFilename.str(), "Hints", 0);
  1198. }
  1199. appendHintText(hintXml);
  1200. }
  1201. void HqlCppInstance::appendHintText(const char * xml)
  1202. {
  1203. hintFile->write(strlen(xml), xml);
  1204. }
  1205. unsigned HqlCppInstance::addStringResource(unsigned len, const char * body)
  1206. {
  1207. return resources.addString(len, body);
  1208. }
  1209. void HqlCppInstance::addResource(const char * type, unsigned len, const void * body, IPropertyTree *manifestEntry, unsigned id)
  1210. {
  1211. resources.addNamed(type, len, body, manifestEntry, id);
  1212. }
  1213. void HqlCppInstance::addCompressResource(const char * type, unsigned len, const void * body, IPropertyTree *manifestEntry, unsigned id)
  1214. {
  1215. #ifdef ADD_RESOURCE_AS_CPP_COMMENT
  1216. BuildCtx ctx(*this, includeAtom);
  1217. StringBuffer s;
  1218. s.append("/* ").append(type).append(".").append(id).append(":\n").append(len,(const char *)data).newline().append("*/");
  1219. ctx.addQuoted(s);
  1220. #endif
  1221. resources.addCompress(type, len, body, manifestEntry, id);
  1222. }
  1223. void HqlCppInstance::flushHints()
  1224. {
  1225. if (hintFile)
  1226. {
  1227. appendHintText("</Hints>\n");
  1228. hintFile.clear();
  1229. }
  1230. }
  1231. void HqlCppInstance::flushResources(const char *filename, ICodegenContextCallback * ctxCallback)
  1232. {
  1233. addPluginsAsResource();
  1234. if (resources.count())
  1235. {
  1236. bool flushText = workunit->getDebugValueBool("flushResourceAsText", false);
  1237. #ifdef __64BIT__
  1238. bool target64bit = workunit->getDebugValueBool("target64bit", true);
  1239. #else
  1240. bool target64bit = workunit->getDebugValueBool("target64bit", false);
  1241. #endif
  1242. StringBuffer resname;
  1243. bool isObjectFile = resources.flush(resname, filename, flushText, target64bit);
  1244. StringBuffer resTextName;
  1245. if (flushText && resources.queryWriteText(resTextName, resname))
  1246. {
  1247. Owned<IWUQuery> query = workunit->updateQuery();
  1248. associateLocalFile(query, FileTypeHintXml, resTextName, "Workunit resource text", 0);
  1249. }
  1250. if (isObjectFile)
  1251. useObjectFile(resname);
  1252. else
  1253. useSourceFile(resname, nullptr, true);
  1254. }
  1255. }
  1256. IHqlCppInstance * createCppInstance(IWorkUnit *wu, const char * wupathname)
  1257. {
  1258. return new HqlCppInstance(wu, wupathname);
  1259. }
  1260. //===========================================================================
  1261. #include "hqlcppsys.ecl"
  1262. HqlCppTranslator::HqlCppTranslator(IErrorReceiver * _errors, const char * _soName, IHqlCppInstance * _code, ClusterType _targetClusterType, ICodegenContextCallback *_ctxCallback) : ctxCallback(_ctxCallback)
  1263. {
  1264. //Insert a couple of warning mapping layers - one for global #onwarnings, and another for local : onwarning
  1265. globalOnWarnings.setown(new ErrorSeverityMapper(*_errors));
  1266. localOnWarnings.setown(new ErrorSeverityMapper((IErrorReceiver &)*globalOnWarnings)); // horrible: cast required, otherwise copy constructor is called!
  1267. //Ensure that any errors reported within the code generator automatically abort compiling immediately
  1268. errorProcessor.setown(createAbortingErrorReceiver(*localOnWarnings));
  1269. targetClusterType = _targetClusterType;
  1270. {
  1271. CriticalBlock block(*systemCS);
  1272. if (!cppSystemScope)
  1273. {
  1274. StringBuffer systemText;
  1275. unsigned size = 0;
  1276. for (unsigned i1=0; cppSystemText[i1]; i1++)
  1277. size += strlen(cppSystemText[i1]) + 2;
  1278. systemText.ensureCapacity(size);
  1279. for (unsigned i2=0; cppSystemText[i2]; i2++)
  1280. systemText.append(cppSystemText[i2]).newline();
  1281. MultiErrorReceiver errs;
  1282. HqlDummyLookupContext ctx(&errs);
  1283. cppSystemScope = createScope();
  1284. Owned<ISourcePath> sysPath = createSourcePath("<system-definitions>");
  1285. Owned<IFileContents> systemContents = createFileContentsFromText(systemText.str(), sysPath, true, NULL, 0);
  1286. OwnedHqlExpr query = parseQuery(cppSystemScope, systemContents, ctx, NULL, NULL, false, false);
  1287. if (errs.errCount())
  1288. {
  1289. StringBuffer errtext;
  1290. IError *first = errs.firstError();
  1291. first->toString(errtext);
  1292. throw MakeStringException(HQLERR_FailedToLoadSystemModule, "%s @ %d:%d", errtext.str(), first->getColumn(), first->getLine());
  1293. }
  1294. #if 0
  1295. else if (errs.warnCount())
  1296. {
  1297. StringBuffer s;
  1298. errs.toString(s);
  1299. DBGLOG("Parsing system scope: %s", s.str());
  1300. }
  1301. #endif
  1302. }
  1303. }
  1304. litno = 0;
  1305. soName.set(_soName);
  1306. HqlDummyLookupContext dummyctx(NULL);
  1307. OwnedHqlExpr internalScopeLookup = cppSystemScope->lookupSymbol(createIdAtom("InternalCppService"), LSFsharedOK, dummyctx);
  1308. internalScope = internalScopeLookup->queryScope();
  1309. _clear(options); // init options is called later, but depends on the workunit.
  1310. startCursorSet = 0;
  1311. requireTable = true;
  1312. activeGraphCtx = NULL;
  1313. maxSequence = 0;
  1314. contextAvailable = true;
  1315. graphSeqNumber = 0;
  1316. nlpParse = NULL;
  1317. outputLibrary = NULL;
  1318. activitiesThisCpp = 0;
  1319. curCppFile = 0;
  1320. timeReporter.setown(createStdTimeReporter());
  1321. curActivityId = 0;
  1322. holeUniqueSequence = 0;
  1323. nextUid = 0;
  1324. nextTypeId = 0;
  1325. nextFieldId = 0;
  1326. curWfid = 0;
  1327. code = (HqlCppInstance*)_code;
  1328. xmlUsesContents = false;
  1329. }
  1330. HqlCppTranslator::~HqlCppTranslator()
  1331. {
  1332. ::Release(nlpParse);
  1333. ::Release(outputLibrary);
  1334. }
  1335. void HqlCppTranslator::setTargetClusterType(ClusterType clusterType)
  1336. {
  1337. targetClusterType = clusterType;
  1338. }
  1339. void HqlCppTranslator::ensureDiskAccessAllowed(IHqlExpression * expr)
  1340. {
  1341. bool isSigned = expr->hasAttribute(_signed_Atom);
  1342. if (!queryCallback()->allowAccess("datafile", isSigned))
  1343. reportErrorNoAbort(expr, HQLERR_DatafileRequiresSigned, "You do not have permission to directly access datafiles");
  1344. }
  1345. void HqlCppTranslator::checkAbort()
  1346. {
  1347. if (wu() && wu()->aborting())
  1348. throw MakeStringException(HQLERR_ErrorAlreadyReported, "Aborting");
  1349. }
  1350. // Option: (Name, value, ?overridden, default())
  1351. // problems:
  1352. // default value can depend on another option (e.g., cluster type/supports lcr).
  1353. // don't want code in multiple places - e.g., the values initialized and defaulted, and dependencies calculations duplicated separately.
  1354. // don't want lots of start up costs each time the translator is created -> lightweight classes if any.
  1355. // don't really want two structures, one for the definitions, and another for the values.
  1356. //RESOLVED? want to walk the debug options provided, instead of checking for each possibility in turn.
  1357. // Without this restriction it becomes much easier.
  1358. void HqlCppTranslator::cacheOptions()
  1359. {
  1360. size32_t outputLimit = wu()->getDebugValueInt("outputLimitMb", 0);
  1361. if (outputLimit > daliResultOutputMax)
  1362. throwError2(HQLERR_OutputLimitMaxExceeded, daliResultOutputMax, outputLimit);
  1363. if (outputLimit > futureResultOutputMax)
  1364. WARNING2(CategoryDeprecated, HQLERR_OutputLimitFutureMaxExceeded, futureResultOutputMax, outputLimit);
  1365. SCMStringBuffer targetText;
  1366. wu()->getDebugValue("targetClusterType", targetText);
  1367. ClusterType clusterType = getClusterType(targetText.s.str());
  1368. if (clusterType != NoCluster)
  1369. setTargetClusterType(clusterType);
  1370. //Some compound flags, which provide defaults for various other options.
  1371. bool paranoid = getDebugFlag("paranoid", false);
  1372. struct DebugOption
  1373. {
  1374. typedef enum { typeByte, typeUnsigned, typeSigned, typeBool } OptionType;
  1375. DebugOption (bool & _option, const char * name, bool defaultValue) : option(&_option), optName(name)
  1376. {
  1377. _option = defaultValue;
  1378. type = typeBool;
  1379. }
  1380. DebugOption (byte & _option, const char * name, byte defaultValue) : option(&_option), optName(name)
  1381. {
  1382. _option = defaultValue;
  1383. type = typeByte;
  1384. }
  1385. DebugOption (unsigned & _option, const char * name, unsigned defaultValue) : option(&_option), optName(name)
  1386. {
  1387. _option = defaultValue;
  1388. type = typeUnsigned;
  1389. }
  1390. DebugOption (int & _option, const char * name, unsigned defaultValue) : option(&_option), optName(name)
  1391. {
  1392. _option = defaultValue;
  1393. type = typeSigned;
  1394. }
  1395. void setValue(const char * val)
  1396. {
  1397. switch (type)
  1398. {
  1399. case typeBool:
  1400. {
  1401. bool * b = (bool*)option;
  1402. *b = strToBool(val);
  1403. break;
  1404. }
  1405. case typeUnsigned:
  1406. {
  1407. unsigned * u = (unsigned*)option;
  1408. *u = (unsigned)atoi(val);
  1409. break;
  1410. }
  1411. case typeSigned:
  1412. {
  1413. signed * u = (signed*)option;
  1414. *u = (signed)atoi(val);
  1415. break;
  1416. }
  1417. case typeByte:
  1418. {
  1419. byte * b = (byte*)option;
  1420. *b = (byte)atoi(val);
  1421. break;
  1422. }
  1423. }
  1424. }
  1425. void * option;
  1426. const char * optName;
  1427. OptionType type;
  1428. };
  1429. //Note this list cannot have any initial values which are dependent on other options.
  1430. DebugOption debugOptions[] =
  1431. {
  1432. DebugOption(options.peephole,"peephole", true),
  1433. DebugOption(options.foldConstantCast,"foldConstantCast", true),
  1434. DebugOption(options.optimizeBoolReturn,"optimizeBoolReturn", true),
  1435. DebugOption(options.freezePersists,"freezePersists", false),
  1436. DebugOption(options.maxRecordSize, "defaultMaxLengthRecord", MAX_RECORD_SIZE),
  1437. DebugOption(options.subgraphToRegenerate, "subgraphToRegenerate", 0),
  1438. DebugOption(options.checkRoxieRestrictions,"checkRoxieRestrictions", true), // a debug aid for running regression suite
  1439. DebugOption(options.checkThorRestrictions,"checkThorRestrictions", true), // a debug aid for running regression suite
  1440. DebugOption(options.allowCsvWorkunitRead,"allowStoredCsvFormat", false),
  1441. DebugOption(options.evaluateCoLocalRowInvariantInExtract,"evaluateCoLocalRowInvariantInExtract", false),
  1442. DebugOption(options.spanMultipleCpp,"spanMultipleCpp", true),
  1443. DebugOption(options.activitiesPerCpp, "<exception>", 0x7fffffff),
  1444. DebugOption(options.allowInlineSpill,"allowInlineSpill", true),
  1445. DebugOption(options.optimizeGlobalProjects,"optimizeGlobalProjects", false),
  1446. DebugOption(options.optimizeResourcedProjects,"optimizeResourcedProjects", false),
  1447. DebugOption(options.reduceNetworkTraffic,"aggressiveOptimizeProjects", false),
  1448. DebugOption(options.notifyOptimizedProjects, "notifyOptimizedProjects", 0),
  1449. DebugOption(options.optimizeProjectsPreservePersists,"optimizeProjectsPreservePersists", false),
  1450. DebugOption(options.expirePersists, "expirePersists", true),
  1451. DebugOption(options.defaultPersistExpiry, "defaultPersistExpiry", DEFAULT_PERSIST_EXPIRY_PERIOD),
  1452. DebugOption(options.defaultExpiry, "defaultExpiry", DEFAULT_EXPIRY_PERIOD),
  1453. DebugOption(options.searchDistanceThreshold, "searchDistanceThreshold", 1000000),
  1454. DebugOption(options.generateActivityThreshold, "generateActivityThreshold", 0), // most users are not interested so disable by default
  1455. DebugOption(options.checkAsserts,"checkAsserts", true),
  1456. DebugOption(options.assertSortedDistributed,"assertSortedDistributed", false),
  1457. DebugOption(options.optimizeLoopInvariant,"optimizeLoopInvariant", false), // doesn't fully work yet! and has little effect, and messes up the alias dependencies
  1458. DebugOption(options.defaultImplicitKeyedJoinLimit, "defaultImplicitKeyedJoinLimit", 10000),
  1459. DebugOption(options.defaultImplicitIndexReadLimit, "defaultImplicitIndexReadLimit", 0),
  1460. DebugOption(options.commonUpChildGraphs,"commonUpChildGraphs", true),
  1461. DebugOption(options.detectAmbiguousSelector,"detectAmbiguousSelector", false),
  1462. DebugOption(options.allowAmbiguousSelector,"allowAmbiguousSelector", false),
  1463. #ifdef _DEBUG
  1464. DebugOption(options.regressionTest,"regressionTest", true),
  1465. #else
  1466. DebugOption(options.regressionTest,"regressionTest", false),
  1467. #endif
  1468. //recreating case can cause duplicate branches in weird situations.
  1469. DebugOption(options.recreateMapFromIf,"recreateMapFromIf", !targetThor()),
  1470. DebugOption(options.showMetaText,"debugShowMetaText", false),
  1471. DebugOption(options.resourceSequential,"resourceSequential", false),
  1472. DebugOption(options.workunitTemporaries,"workunitTemporaries", true),
  1473. DebugOption(options.resourceConditionalActions,"resourceConditionalActions", false), //targetRoxie() ??
  1474. DebugOption(options.actionLinkInNewGraph,"actionLinkInNewGraph", false),
  1475. DebugOption(options.minimizeWorkunitTemporaries, "<exception>", false),
  1476. DebugOption(options.pickBestEngine,"pickBestEngine", true),
  1477. DebugOption(options.groupedChildIterators,"groupedChildIterators", false),
  1478. DebugOption(options.noAllToLookupConversion,"noAllToLookupConversion", false),
  1479. DebugOption(options.notifyWorkflowCse,"notifyWorkflowCse", true),
  1480. DebugOption(options.performWorkflowCse,"performWorkflowCse", false),
  1481. DebugOption(options.warnOnImplicitJoinLimit,"warnOnImplicitJoinLimit", targetRoxie()),
  1482. DebugOption(options.warnOnImplicitReadLimit,"warnOnImplicitReadLimit", targetRoxie()),
  1483. DebugOption(options.convertJoinToLookup,"convertJoinToLookup", true),
  1484. DebugOption(options.convertJoinToLookupIfSorted,"convertJoinToLookupIfSorted", false),
  1485. DebugOption(options.spotCSE,"spotCSE", true),
  1486. DebugOption(options.spotCseInIfDatasetConditions,"spotCseInIfDatasetConditions", true),
  1487. DebugOption(options.optimizeNonEmpty,"optimizeNonEmpty", !targetThor()), // not sure that it will be conditional resourced correctly for thor
  1488. DebugOption(options.allowVariableRoxieFilenames,"allowVariableRoxieFilenames", false),
  1489. DebugOption(options.foldConstantDatasets,"foldConstantDatasets", true),
  1490. DebugOption(options.hoistSimpleGlobal,"hoistSimpleGlobal", true),
  1491. DebugOption(options.percolateConstants,"percolateConstants", true),
  1492. DebugOption(options.percolateFilters,"percolateFilters", false),
  1493. DebugOption(options.usePrefetchForAllProjects,"usePrefetchForAllProjects", false),
  1494. DebugOption(options.allFilenamesDynamic,"allFilenamesDynamic", false),
  1495. DebugOption(options.optimizeSteppingPostfilter,"optimizeSteppingPostfilter", true),
  1496. DebugOption(options.moveUnconditionalActions,"moveUnconditionalActions", false),
  1497. DebugOption(options.paranoidCheckNormalized, "paranoidCheckNormalized", paranoid),
  1498. DebugOption(options.paranoidCheckDependencies, "paranoidCheckDependencies", paranoid),
  1499. DebugOption(options.paranoidCheckSelects, "paranoidCheckSelects", paranoid),
  1500. DebugOption(options.preventKeyedSplit,"preventKeyedSplit", true),
  1501. DebugOption(options.preventSteppedSplit,"preventSteppedSplit", true),
  1502. DebugOption(options.canGenerateSimpleAction,"canGenerateSimpleAction", true),
  1503. DebugOption(options.minimizeActivityClasses,"minimizeActivityClasses", true),
  1504. DebugOption(options.maxRootMaybeThorActions, "maxRootMaybeThorActions", 0),
  1505. DebugOption(options.minimizeSkewBeforeSpill,"minimizeSkewBeforeSpill", false),
  1506. DebugOption(options.createSerializeForUnknownSize,"createSerializeForUnknownSize", false),
  1507. DebugOption(options.implicitLinkedChildRows,"implicitLinkedChildRows", false),
  1508. DebugOption(options.mainRowsAreLinkCounted,"mainRowsAreLinkCounted", true),
  1509. DebugOption(options.allowSections,"allowSections", true),
  1510. DebugOption(options.autoPackRecords,"autoPackRecords", false),
  1511. DebugOption(options.commonUniqueNameAttributes,"commonUniqueNameAttributes", true),
  1512. DebugOption(options.sortIndexPayload,"sortIndexPayload", true),
  1513. DebugOption(options.foldFilter,"foldFilter", true),
  1514. DebugOption(options.finalizeAllRows, "finalizeAllRows", false),
  1515. DebugOption(options.maxLocalRowSize , "maxLocalRowSize", MAX_LOCAL_ROW_SIZE),
  1516. DebugOption(options.optimizeGraph,"optimizeGraph", true),
  1517. DebugOption(options.orderDiskFunnel,"orderDiskFunnel", false),
  1518. DebugOption(options.alwaysAllowAllNodes,"alwaysAllowAllNodes", false),
  1519. DebugOption(options.slidingJoins,"slidingJoins", false),
  1520. DebugOption(options.foldOptimized,"foldOptimized", false),
  1521. DebugOption(options.globalOptimize,"globalOptimize", false),
  1522. DebugOption(options.applyInstantEclTransformations,"applyInstantEclTransformations", false), // testing option
  1523. DebugOption(options.calculateComplexity,"calculateComplexity", false),
  1524. DebugOption(options.generateLogicalGraph,"generateLogicalGraph", false),
  1525. DebugOption(options.generateLogicalGraphOnly,"generateLogicalGraphOnly", false),
  1526. DebugOption(options.globalAutoHoist,"globalAutoHoist", true),
  1527. DebugOption(options.applyInstantEclTransformationsLimit, "applyInstantEclTransformationsLimit", 100),
  1528. DebugOption(options.insertProjectCostLevel, "insertProjectCostLevel", (unsigned)-1),
  1529. DebugOption(options.dfaRepeatMax, "dfaRepeatMax", 10),
  1530. DebugOption(options.dfaRepeatMaxScore, "dfaRepeatMaxScore", 100),
  1531. DebugOption(options.debugNlp, "debugNlp", DEFAULT_NLP_DETAIL),
  1532. DebugOption(options.regexVersion, "regexVersion",0),
  1533. DebugOption(options.parseDfaComplexity, "parseDfaComplexity", (unsigned)-1),
  1534. DebugOption(options.expandRepeatAnyAsDfa,"expandRepeatAnyAsDfa", true),
  1535. DebugOption(options.resourceMaxMemory, "resourceMaxMemory", 0),
  1536. DebugOption(options.resourceMaxSockets, "resourceMaxSockets", 0),
  1537. DebugOption(options.resourceMaxActivities, "resourceMaxActivities", 0),
  1538. DebugOption(options.resourceMaxHeavy, "resourceMaxHeavy", 1),
  1539. DebugOption(options.resourceMaxDistribute, "resourceMaxDistribute", 8),
  1540. DebugOption(options.unlimitedResources,"unlimitedResources", false),
  1541. DebugOption(options.filteredReadSpillThreshold, "filteredReadSpillThreshold", 999),
  1542. DebugOption(options.allowThroughSpill,"allowThroughSpill", true),
  1543. DebugOption(options.minimiseSpills,"minimiseSpills", false),
  1544. DebugOption(options.spillMultiCondition,"spillMultiCondition", false),
  1545. DebugOption(options.spotThroughAggregate,"spotThroughAggregate", true),
  1546. DebugOption(options.hoistResourced,"hoistResourced", true),
  1547. DebugOption(options.minimizeSpillSize, "minimizeSpillSize", 0),
  1548. DebugOption(options.maximizeLexer,"maximizeLexer", false),
  1549. DebugOption(options.foldStored,"foldStored", false),
  1550. DebugOption(options.spotTopN,"spotTopN", true),
  1551. DebugOption(options.topnLimit, "topnLimit", 10000),
  1552. DebugOption(options.groupAllDistribute,"groupAllDistribute", true),
  1553. DebugOption(options.spotLocalMerge,"spotLocalMerge", true),
  1554. DebugOption(options.spotPotentialKeyedJoins,"spotPotentialKeyedJoins", false),
  1555. DebugOption(options.combineTrivialStored,"combineTrivialStored", true),
  1556. DebugOption(options.combineAllStored,"combineAllStored", false),
  1557. DebugOption(options.allowStoredDuplicate,"allowStoredDuplicate", false), // only here as a temporary workaround
  1558. DebugOption(options.specifiedClusterSize, "clusterSize", 0),
  1559. DebugOption(options.globalFoldOptions, "globalFoldOptions", (unsigned)-1),
  1560. DebugOption(options.allowScopeMigrate,"allowScopeMigrate", true),
  1561. DebugOption(options.supportFilterProject,"supportFilterProject", true),
  1562. DebugOption(options.normalizeExplicitCasts,"normalizeExplicitCasts", true),
  1563. DebugOption(options.optimizeInlineSource,"optimizeInlineSource", false),
  1564. DebugOption(options.optimizeDiskSource,"optimizeDiskSource", true),
  1565. DebugOption(options.optimizeIndexSource,"optimizeIndexSource", true),
  1566. DebugOption(options.optimizeChildSource,"optimizeChildSource", false),
  1567. DebugOption(options.reportLocations,"reportLocations", true),
  1568. DebugOption(options.debugGeneratedCpp,"debugGeneratedCpp", false),
  1569. DebugOption(options.addFilesnamesToGraph,"addFilesnamesToGraph", true),
  1570. DebugOption(options.normalizeLocations,"normalizeLocations", true),
  1571. DebugOption(options.ensureRecordsHaveSymbols,"ensureRecordsHaveSymbols", true),
  1572. DebugOption(options.constantFoldNormalize,"constantFoldNormalize", true),
  1573. DebugOption(options.constantFoldPostNormalize,"constantFoldPostNormalize", false),
  1574. DebugOption(options.optimizeGrouping,"optimizeGrouping", true),
  1575. DebugOption(options.showMetaInGraph,"showMetaInGraph", true),
  1576. DebugOption(options.spotComplexClasses,"spotComplexClasses", true),
  1577. DebugOption(options.complexClassesThreshold,"complexClassesThreshold", 5000),
  1578. DebugOption(options.complexClassesActivityFilter,"complexClassesActivityFilter", 0),
  1579. DebugOption(options.optimizeString1Compare,"optimizeString1Compare", true),
  1580. DebugOption(options.optimizeSpillProject,"optimizeSpillProject", true),
  1581. DebugOption(options.expressionPeephole,"expressionPeephole", false),
  1582. DebugOption(options.optimizeIncrement,"optimizeIncrement", true),
  1583. DebugOption(options.supportsMergeDistribute,"supportsMergeDistribute", true),
  1584. DebugOption(options.debugNlpAsHint,"debugNlpAsHint", false),
  1585. DebugOption(options.forceVariableWuid,"forceVariableWuid", false),
  1586. DebugOption(options.okToDeclareAndAssign,"okToDeclareAndAssign", false),
  1587. DebugOption(options.noteRecordSizeInGraph,"noteRecordSizeInGraph", true),
  1588. DebugOption(options.convertRealAssignToMemcpy,"convertRealAssignToMemcpy", false),
  1589. DebugOption(options.allowActivityForKeyedJoin,"allowActivityForKeyedJoin", false),
  1590. DebugOption(options.forceActivityForKeyedJoin,"forceActivityForKeyedJoin", false),
  1591. DebugOption(options.addLibraryInputsToGraph,"addLibraryInputsToGraph", false),
  1592. DebugOption(options.showRecordCountInGraph,"showRecordCountInGraph", true),
  1593. DebugOption(options.serializeRowsetInExtract,"serializeRowsetInExtract", false),
  1594. DebugOption(options.testIgnoreMaxLength,"testIgnoreMaxLength", false),
  1595. DebugOption(options.trackDuplicateActivities,"trackDuplicateActivities", false),
  1596. DebugOption(options.showActivitySizeInGraph,"showActivitySizeInGraph", false),
  1597. DebugOption(options.addLocationToCpp,"addLocationToCpp", false),
  1598. DebugOption(options.alwaysCreateRowBuilder,"alwaysCreateRowBuilder", false),
  1599. DebugOption(options.precalculateFieldOffsets,"precalculateFieldOffsets", false),
  1600. DebugOption(options.generateStaticInlineTables,"generateStaticInlineTables", true),
  1601. DebugOption(options.staticRowsUseStringInitializer,"staticRowsUseStringInitializer", true),
  1602. DebugOption(options.convertWhenExecutedToCompound,"convertWhenExecutedToCompound", queryLegacyWhenSemantics()),
  1603. DebugOption(options.standAloneExe,"standAloneExe", false),
  1604. DebugOption(options.enableCompoundCsvRead,"enableCompoundCsvRead", true),
  1605. // The following works 99% of the time, but disabled due to potential problems with the ambiguity of LEFT
  1606. //possibly causing filters on nested records to be incorrectly removed.
  1607. DebugOption(options.optimizeNestedConditional,"optimizeNestedConditional", false),
  1608. DebugOption(options.createImplicitAliases,"createImplicitAliases", false),
  1609. DebugOption(options.combineSiblingGraphs,"combineSiblingGraphs", true),
  1610. DebugOption(options.optimizeSharedGraphInputs,"optimizeSharedGraphInputs", true),
  1611. DebugOption(options.supportsSubSortActivity,"supportsSubSortActivity",false),
  1612. DebugOption(options.implicitSubSort,"implicitSubSort",true),
  1613. DebugOption(options.implicitBuildIndexSubSort,"implicitBuildIndexSubSort",true),
  1614. DebugOption(options.implicitJoinSubSort,"implicitJoinSubSort",true),
  1615. DebugOption(options.implicitGroupSubSort,"implicitGroupSubSort",true),
  1616. DebugOption(options.implicitGroupHashAggregate,"implicitGroupHashAggregate",false),
  1617. DebugOption(options.implicitGroupHashDedup,"implicitGroupHashDedup",false),
  1618. DebugOption(options.reportFieldUsage,"reportFieldUsage",false),
  1619. DebugOption(options.reportFileUsage,"reportFileUsage",false),
  1620. DebugOption(options.recordFieldUsage,"recordFieldUsage",false),
  1621. DebugOption(options.subsortLocalJoinConditions,"subsortLocalJoinConditions",false),
  1622. DebugOption(options.projectNestedTables,"projectNestedTables",true),
  1623. DebugOption(options.showSeqInGraph,"showSeqInGraph",false), // For tracking down why projects are not commoned up
  1624. DebugOption(options.normalizeSelectorSequence,"normalizeSelectorSequence",false), // For tracking down why projects are not commoned up
  1625. DebugOption(options.removeXpathFromOutput,"removeXpathFromOutput",false),
  1626. DebugOption(options.canLinkConstantRows,"canLinkConstantRows",true),
  1627. DebugOption(options.checkAmbiguousRollupCondition,"checkAmbiguousRollupCondition",true),
  1628. DebugOption(options.matchExistingDistributionForJoin,"matchExistingDistributionForJoin",true),
  1629. DebugOption(options.createImplicitKeyedDistributeForJoin,"createImplicitKeyedDistributeForJoin",false),
  1630. DebugOption(options.expandHashJoin,"expandHashJoin",true),
  1631. DebugOption(options.traceIR,"traceIR",false),
  1632. DebugOption(options.preserveCaseExternalParameter,"preserveCaseExternalParameter",true),
  1633. DebugOption(options.optimizeParentAccess,"optimizeParentAccess",false),
  1634. DebugOption(options.expandPersistInputDependencies,"expandPersistInputDependencies",true),
  1635. DebugOption(options.multiplePersistInstances,"multiplePersistInstances",true),
  1636. DebugOption(options.defaultNumPersistInstances,"defaultNumPersistInstances",-1),
  1637. DebugOption(options.optimizeMax,"optimizeMax",false),
  1638. DebugOption(options.useResultsForChildSpills,"useResultsForChildSpills",false),
  1639. DebugOption(options.alwaysUseGraphResults,"alwaysUseGraphResults",false),
  1640. DebugOption(options.noConditionalLinks,"noConditionalLinks",false),
  1641. DebugOption(options.reportAssertFilenameTail,"reportAssertFilenameTail",false),
  1642. DebugOption(options.newBalancedSpotter,"newBalancedSpotter",true),
  1643. DebugOption(options.keyedJoinPreservesOrder,"keyedJoinPreservesOrder",true),
  1644. DebugOption(options.expandSelectCreateRow,"expandSelectCreateRow",false),
  1645. DebugOption(options.obfuscateOutput,"obfuscateOutput",false),
  1646. DebugOption(options.showEclInGraph,"showEclInGraph",true),
  1647. DebugOption(options.showChildCountInGraph,"showChildCountInGraph",false),
  1648. DebugOption(options.optimizeSortAllFields,"optimizeSortAllFields",true),
  1649. DebugOption(options.optimizeSortAllFieldsStrict,"optimizeSortAllFieldsStrict",false),
  1650. DebugOption(options.alwaysReuseGlobalSpills,"alwaysReuseGlobalSpills",true),
  1651. DebugOption(options.forceAllDatasetsParallel,"forceAllDatasetsParallel",false), // Purely for regression testing.
  1652. DebugOption(options.embeddedWarningsAsErrors,"embeddedWarningsAreFatal70",true),
  1653. DebugOption(options.optimizeCriticalFunctions,"optimizeCriticalFunctions",true),
  1654. DebugOption(options.addLikelihoodToGraph,"addLikelihoodToGraph", true),
  1655. DebugOption(options.varFieldAccessorThreshold,"varFieldAccessorThreshold",3), // Generate accessor classes for rows with #variable width fields >= threshold
  1656. DebugOption(options.translateDFSlayouts,"translateDFSlayouts", false),
  1657. DebugOption(options.timeTransforms,"timeTransforms", false),
  1658. DebugOption(options.reportDFSinfo,"reportDFSinfo", 0),
  1659. DebugOption(options.useGlobalCompareClass,"useGlobalCompareClass", false),
  1660. DebugOption(options.createValueSets,"createValueSets", true),
  1661. DebugOption(options.implicitKeyedDiskFilter,"implicitKeyedDiskFilter", false),
  1662. DebugOption(options.addDefaultBloom,"addDefaultBloom", true),
  1663. DebugOption(options.newDiskReadMapping, "newDiskReadMapping", true),
  1664. DebugOption(options.transformNestedSequential, "transformNestedSequential", true),
  1665. DebugOption(options.preserveWhenSequential, "preserveWhenSequential", true),
  1666. DebugOption(options.forceAllProjectedDiskSerialized, "internalForceAllProjectedDiskSerialized", false), // Delete in 8.0 once new code has been proved in anger
  1667. DebugOption(options.newIndexReadMapping, "newIndexReadMapping", false), // Not yet enabled due to problems with merging mapped fields and roxie/thor integration
  1668. DebugOption(options.checkDuplicateThreshold, "checkDuplicateThreshold", 0), // If non zero, create a warning if duplicates > this percentage increase
  1669. DebugOption(options.checkDuplicateMinActivities, "checkDuplicateMinActivities", 100),
  1670. DebugOption(options.diskReadsAreSimple, "diskReadsAreSimple", false), // Not yet enabled - needs filters to default to generating keyed info first
  1671. DebugOption(options.genericDiskReads, "genericDiskReads", false),
  1672. DebugOption(options.generateActivityFormats, "generateActivityFormats", false),
  1673. DebugOption(options.generateDiskFormats, "generateDiskFormats", false),
  1674. DebugOption(options.maxOptimizeSize, "maxOptimizeSize", 5), // Remove the overhead from very small functions e.g. function prolog
  1675. DebugOption(options.minNoOptimizeSize, "minNoOptimizeSize", 10000), // functions larger than this will take a long time to optimize, better to not try
  1676. };
  1677. //get options values from workunit
  1678. const unsigned numDebugOptions = _elements_in(debugOptions);
  1679. Owned<IStringIterator> debugs(&wu()->getDebugValues());
  1680. SCMStringBuffer name, val;
  1681. ForEach(*debugs)
  1682. {
  1683. debugs->str(name);
  1684. wu()->getDebugValue(name.str(),val);
  1685. unsigned x = 0;
  1686. for (; x < numDebugOptions; x++)
  1687. {
  1688. if (0 == stricmp(name.str(), debugOptions[x].optName))
  1689. {
  1690. debugOptions[x].setValue(val.str());
  1691. break;
  1692. }
  1693. }
  1694. }
  1695. //Configure the divide by zero action
  1696. options.divideByZeroAction = DBZzero;
  1697. const char * dbz = wu()->getDebugValue("divideByZero",val).str();
  1698. if (strieq(dbz, "0") || strieq(dbz, "zero"))
  1699. options.divideByZeroAction = DBZzero;
  1700. else if (strieq(dbz, "nan"))
  1701. options.divideByZeroAction = DBZnan;
  1702. else if (strieq(dbz, "fail") || strieq(dbz, "throw"))
  1703. options.divideByZeroAction = DBZfail;
  1704. else if (val.length())
  1705. throwError2(HQLERR_UnexpectedOptionValue_XY, "divideByZero", dbz);
  1706. //The following cases handle options whose default values are dependent on other options.
  1707. //Or where one debug options sets more than one option
  1708. if (options.spanMultipleCpp)
  1709. {
  1710. code->cppInfo.append(* new CppFileInfo(0)); // Add an entry for the main file which contains no activities
  1711. options.activitiesPerCpp = wu()->getDebugValueInt("activitiesPerCpp", DEFAULT_ACTIVITIES_PER_CPP);
  1712. curCppFile = 1;
  1713. }
  1714. code->cppInfo.append(* new CppFileInfo(0));
  1715. options.targetCompiler = DEFAULT_COMPILER;
  1716. if (wu()->hasDebugValue("targetGcc"))
  1717. options.targetCompiler = wu()->getDebugValueBool("targetGcc", false) ? GccCppCompiler : Vs6CppCompiler;
  1718. SCMStringBuffer compilerText;
  1719. wu()->getDebugValue("targetCompiler", compilerText);
  1720. for (CompilerType iComp = (CompilerType)0; iComp < MaxCompiler; iComp = (CompilerType)(iComp+1))
  1721. {
  1722. if (stricmp(compilerText.s.str(), compilerTypeText[iComp]) == 0)
  1723. options.targetCompiler = iComp;
  1724. }
  1725. if (getDebugFlag("optimizeProjects", true))
  1726. {
  1727. options.optimizeGlobalProjects = true;
  1728. options.optimizeResourcedProjects = true;
  1729. }
  1730. options.minimizeWorkunitTemporaries = !options.workunitTemporaries || getDebugFlag("minimizeWorkunitTemporaries", false);//options.resourceConditionalActions);
  1731. options.inlineStringThreshold = wu()->getDebugValueInt("inlineStringThreshold", (options.targetCompiler != Vs6CppCompiler) ? 0 : 10000);
  1732. options.implicitLinkedChildRows = true;
  1733. options.finalizeAllRows = true; // inline temporary rows should actually be ok.
  1734. postProcessOptions();
  1735. }
  1736. void HqlCppTranslator::postProcessOptions()
  1737. {
  1738. if (options.optimizeMax)
  1739. {
  1740. //Enable any extra potentially expensive optimizations options here...
  1741. options.foldConstantDatasets = true;
  1742. options.percolateConstants = true;
  1743. options.percolateFilters = true;
  1744. }
  1745. //Any post processing - e.g., dependent flags goes here...
  1746. options.optimizeDiskFlag = 0;
  1747. if (options.optimizeInlineSource)
  1748. options.optimizeDiskFlag |= CSFnewinline;
  1749. if (options.optimizeDiskSource)
  1750. options.optimizeDiskFlag |= CSFnewdisk;
  1751. if (options.optimizeIndexSource)
  1752. options.optimizeDiskFlag |= CSFnewindex;
  1753. if (options.optimizeChildSource)
  1754. options.optimizeDiskFlag |= CSFnewchild;
  1755. if (!targetThor())
  1756. {
  1757. //Roxie doesn't gain from additional projects, hthor doesn't support split
  1758. options.optimizeSpillProject = false;
  1759. }
  1760. if (!targetHThor())
  1761. options.genericDiskReads = false;
  1762. if (options.resourceSequential)
  1763. options.resourceConditionalActions = true;
  1764. options.generateActivityThresholdCycles = nanosec_to_cycle(options.generateActivityThreshold * I64C(1000000));
  1765. //Probably best to ignore this warning. - possibly configure it based on some other option
  1766. globalOnWarnings->addOnWarning(HQLWRN_FoldRemoveKeyed, ignoreAtom);
  1767. //Ensure the settings for the following options are always present in the workunit
  1768. wu()->setDebugValueInt("expandPersistInputDependencies",options.expandPersistInputDependencies,true);
  1769. if (options.forceVariableWuid)
  1770. wu()->setCloneable(true);
  1771. }
  1772. unsigned HqlCppTranslator::getOptimizeFlags(bool insideChildQuery) const
  1773. {
  1774. unsigned optFlags = HOOfold;
  1775. switch (targetClusterType)
  1776. {
  1777. case RoxieCluster:
  1778. optFlags |= HOOnoclonelimit|HOOalwayslocal;
  1779. break;
  1780. case HThorCluster:
  1781. optFlags |= HOOnocloneindexlimit|HOOalwayslocal;
  1782. break;
  1783. case ThorLCRCluster:
  1784. break;
  1785. default:
  1786. UNIMPLEMENTED;
  1787. }
  1788. if ((options.optimizeDiskFlag & CSFnewdisk) && (options.optimizeDiskFlag & CSFnewindex))
  1789. optFlags |= HOOhascompoundaggregate;
  1790. if (options.foldConstantDatasets)
  1791. optFlags |= HOOfoldconstantdatasets;
  1792. if (options.optimizeMax)
  1793. optFlags |= HOOexpensive;
  1794. if (options.expandSelectCreateRow)
  1795. optFlags |= HOOexpandselectcreaterow;
  1796. //The following flag should possibly be dependent on this condition:
  1797. //if (targetThor() && !insideChildQuery)
  1798. //However it may be better to err on the side of caution - see HPCC-10144 since moving a project over a barrier may
  1799. //cause it in some circumstances to be evaluated many more times. See HPCC-17439 to revisit later.
  1800. optFlags |= HOOminimizeNetworkAndMemory;
  1801. return optFlags;
  1802. }
  1803. void HqlCppTranslator::exportWarningMappings()
  1804. {
  1805. globalOnWarnings->exportMappings(wu());
  1806. }
  1807. void HqlCppTranslator::overrideOptionsForLibrary()
  1808. {
  1809. options.workunitTemporaries = false;
  1810. options.pickBestEngine = false;
  1811. options.minimizeWorkunitTemporaries = true;
  1812. }
  1813. void HqlCppTranslator::overrideOptionsForQuery()
  1814. {
  1815. options.workunitTemporaries = getDebugFlag("workunitTemporaries", true);
  1816. options.pickBestEngine = getDebugFlag("pickBestEngine", true);
  1817. options.minimizeWorkunitTemporaries = !options.workunitTemporaries || getDebugFlag("minimizeWorkunitTemporaries", false);//options.resourceConditionalActions);
  1818. }
  1819. bool HqlCppTranslator::needToSerializeToSlave(IHqlExpression * expr) const
  1820. {
  1821. if (targetThor())
  1822. return true;
  1823. switch (expr->getOperator())
  1824. {
  1825. case no_getresult:
  1826. case no_workunit_dataset:
  1827. return !matchesConstantValue(queryAttributeChild(expr, sequenceAtom, 0), ResultSequenceOnce);
  1828. default:
  1829. return true;
  1830. }
  1831. }
  1832. IHqlExpression *HqlCppTranslator::addBigLiteral(const char *lit, unsigned litLen)
  1833. {
  1834. unsigned resid = code->addStringResource(litLen, lit);
  1835. HqlExprArray args;
  1836. args.append(*getSizetConstant(resid));
  1837. return bindTranslatedFunctionCall(loadResourceId, args);
  1838. }
  1839. IHqlExpression * HqlCppTranslator::addLiteral(const char * text)
  1840. {
  1841. return createConstant(text);
  1842. }
  1843. IHqlExpression *HqlCppTranslator::addDataLiteral(const char *lit, unsigned litLen)
  1844. {
  1845. if (!canGenerateStringInline(litLen))
  1846. return addBigLiteral(lit, litLen);
  1847. else
  1848. return createConstant(createStringValue(lit, litLen));
  1849. }
  1850. IHqlExpression *HqlCppTranslator::addStringLiteral(const char *lit)
  1851. {
  1852. unsigned litLen = strlen(lit);
  1853. if (!canGenerateStringInline(litLen))
  1854. return addBigLiteral(lit, litLen+1);
  1855. else
  1856. return createConstant(createStringValue(lit, litLen));
  1857. }
  1858. IHqlExpression * HqlCppTranslator::bindFunctionCall(IIdAtom * name, HqlExprArray & args)
  1859. {
  1860. OwnedHqlExpr function = needFunction(name);
  1861. assertex(function != NULL);
  1862. return bindFunctionCall(function, args);
  1863. }
  1864. IHqlExpression * HqlCppTranslator::bindFunctionCall(IIdAtom * name, IHqlExpression * arg1)
  1865. {
  1866. HqlExprArray args;
  1867. args.append(*arg1);
  1868. return bindFunctionCall(name, args);
  1869. }
  1870. IHqlExpression * HqlCppTranslator::bindFunctionCall(IHqlExpression * function, HqlExprArray & args)
  1871. {
  1872. useFunction(function);
  1873. IHqlExpression * ret = createBoundFunction(NULL, function, args, NULL, false);
  1874. assertex(ret->queryExternalDefinition());
  1875. args.kill();
  1876. return ret;
  1877. }
  1878. IHqlExpression * HqlCppTranslator::bindFunctionCall(IIdAtom * name, HqlExprArray & args, ITypeInfo * newType)
  1879. {
  1880. if (!newType)
  1881. return bindFunctionCall(name, args);
  1882. OwnedHqlExpr function = needFunction(name);
  1883. useFunction(function);
  1884. assertex(function->getOperator() == no_funcdef);
  1885. IFunctionTypeExtra * funcTypeExtra = queryFunctionTypeExtra(function->queryType());
  1886. assertex(funcTypeExtra);
  1887. IHqlExpression * body = function->queryChild(0);
  1888. HqlExprArray bodyArgs;
  1889. unwindChildren(bodyArgs, body);
  1890. HqlExprArray funcArgs;
  1891. funcArgs.append(*createValue(body->getOperator(), LINK(newType), bodyArgs));
  1892. unwindChildren(funcArgs, function, 1);
  1893. ITypeInfo * funcType = makeFunctionType(LINK(newType), LINK(function->queryChild(1)), LINK(function->queryChild(2)), LINK(funcTypeExtra->queryAttributes()));
  1894. OwnedHqlExpr newFunction = createValue(function->getOperator(), funcType, funcArgs);
  1895. return bindFunctionCall(newFunction, args);
  1896. }
  1897. IHqlExpression * HqlCppTranslator::bindTranslatedFunctionCall(IHqlExpression * function, HqlExprArray & args)
  1898. {
  1899. useFunction(function);
  1900. IHqlExpression * ret = createTranslatedExternalCall(NULL, function, args);
  1901. assertex(ret->queryExternalDefinition());
  1902. args.kill();
  1903. return ret;
  1904. }
  1905. IHqlExpression * HqlCppTranslator::bindTranslatedFunctionCall(IIdAtom * name, HqlExprArray & args)
  1906. {
  1907. OwnedHqlExpr function = needFunction(name);
  1908. return bindTranslatedFunctionCall(function, args);
  1909. }
  1910. void HqlCppTranslator::buildTranslatedFunctionCall(BuildCtx & ctx, IIdAtom * name, HqlExprArray & args)
  1911. {
  1912. OwnedHqlExpr call = bindTranslatedFunctionCall(name, args);
  1913. ctx.addExpr(call);
  1914. }
  1915. void HqlCppTranslator::buildFunctionCall(BuildCtx & ctx, IIdAtom * name, HqlExprArray & args)
  1916. {
  1917. OwnedHqlExpr call = bindFunctionCall(name, args);
  1918. buildStmt(ctx, call);
  1919. }
  1920. /* Args: all elements in it are LINKED */
  1921. void HqlCppTranslator::callProcedure(BuildCtx & ctx, IIdAtom * name, HqlExprArray & args)
  1922. {
  1923. OwnedHqlExpr call = bindTranslatedFunctionCall(name, args);
  1924. assertex(call->queryExternalDefinition());
  1925. ctx.addExpr(call);
  1926. }
  1927. bool HqlCppTranslator::getDebugFlag(const char * name, bool defValue)
  1928. {
  1929. return wu()->getDebugValueBool(name, defValue);
  1930. }
  1931. void HqlCppTranslator::doReportWarning(WarnErrorCategory category, ErrorSeverity explicitSeverity, IHqlExpression * expr, unsigned id, const char * msg)
  1932. {
  1933. Owned<IError> warnError;
  1934. IHqlExpression * location = queryAnnotation(expr, annotate_location);
  1935. if (!location)
  1936. location = queryAnnotation(expr, annotate_symbol);
  1937. if (!location)
  1938. location = queryActiveActivityLocation();
  1939. unsigned activity = 0;
  1940. const char * scope = nullptr;
  1941. StringBuffer scopeText;
  1942. if (activeActivities.ordinality())
  1943. {
  1944. ABoundActivity & top = activeActivities.tos();
  1945. activity = top.queryActivityId();
  1946. ActivityInstance * active = top.queryActive();
  1947. dbgassertex(active);
  1948. if (active)
  1949. {
  1950. active->getScope(scopeText);
  1951. scope = scopeText;
  1952. }
  1953. }
  1954. ErrorSeverity severity = (explicitSeverity == SeverityUnknown) ? queryDefaultSeverity(category) : explicitSeverity;
  1955. if (location)
  1956. warnError.setown(createError(category, severity, id, msg, str(location->querySourcePath()), location->getStartLine(), location->getStartColumn(), 0, activity, scope));
  1957. else
  1958. warnError.setown(createError(category, severity, id, msg, activity, scope));
  1959. errorProcessor->report(warnError);
  1960. }
  1961. void HqlCppTranslator::reportWarning(WarnErrorCategory category, ErrorSeverity explicitSeverity, IHqlExpression * location, unsigned id, const char * msg, ...)
  1962. {
  1963. StringBuffer s;
  1964. va_list args;
  1965. va_start(args, msg);
  1966. s.valist_appendf(msg, args);
  1967. va_end(args);
  1968. doReportWarning(category, explicitSeverity, location, id, s.str());
  1969. }
  1970. void HqlCppTranslator::reportWarning(WarnErrorCategory category, unsigned id, const char * msg, ...)
  1971. {
  1972. StringBuffer s;
  1973. va_list args;
  1974. va_start(args, msg);
  1975. s.valist_appendf(msg, args);
  1976. va_end(args);
  1977. doReportWarning(category, SeverityUnknown, NULL, id, s.str());
  1978. }
  1979. void HqlCppTranslator::addWorkunitException(ErrorSeverity severity, unsigned code, const char * text, IHqlExpression * location)
  1980. {
  1981. Owned<IWUException> msg = wu()->createException();
  1982. msg->setExceptionSource("eclcc");
  1983. if (code)
  1984. msg->setExceptionCode(code);
  1985. msg->setExceptionMessage(text);
  1986. msg->setSeverity(severity);
  1987. msg->setTimeStamp(NULL);
  1988. if (!location)
  1989. location = queryActiveActivityLocation();
  1990. if (location)
  1991. {
  1992. msg->setExceptionFileName(str(location->querySourcePath()));
  1993. msg->setExceptionLineNo(location->getStartLine());
  1994. msg->setExceptionColumn(location->getStartColumn());
  1995. }
  1996. }
  1997. IHqlExpression * HqlCppTranslator::queryActiveNamedActivity()
  1998. {
  1999. ForEachItemInRev(i, activityExprStack)
  2000. {
  2001. IHqlExpression & cur = activityExprStack.item(i);
  2002. IHqlExpression * symbol = queryNamedSymbol(&cur);
  2003. if (symbol && symbol->querySourcePath())
  2004. return symbol;
  2005. if (isCompoundSource(&cur))
  2006. {
  2007. IHqlExpression * child = cur.queryChild(0);
  2008. if (hasNamedSymbol(child))
  2009. return child;
  2010. }
  2011. }
  2012. return NULL;
  2013. }
  2014. IHqlExpression * HqlCppTranslator::queryActiveActivityLocation() const
  2015. {
  2016. ForEachItemInRev(i, activityExprStack)
  2017. {
  2018. IHqlExpression & cur = activityExprStack.item(i);
  2019. IHqlExpression * location = queryLocation(&cur);
  2020. if (location)
  2021. return location;
  2022. if (isCompoundSource(&cur))
  2023. {
  2024. location = queryLocation(cur.queryChild(0));
  2025. if (location)
  2026. return location;
  2027. }
  2028. }
  2029. return NULL;
  2030. }
  2031. void HqlCppTranslator::report(IError* error)
  2032. {
  2033. return errorProcessor->report(error);
  2034. }
  2035. IError * HqlCppTranslator::mapError(IError * error)
  2036. {
  2037. return errorProcessor->mapError(error);
  2038. }
  2039. size32_t HqlCppTranslator::errCount()
  2040. {
  2041. return errorProcessor->errCount();
  2042. }
  2043. size32_t HqlCppTranslator::warnCount()
  2044. {
  2045. return errorProcessor->warnCount();
  2046. }
  2047. void HqlCppTranslator::exportMappings(IWorkUnit * wu) const
  2048. {
  2049. errorProcessor->exportMappings(wu);
  2050. }
  2051. void HqlCppTranslator::throwStringExceptionV(int code,const char *format, ...) const
  2052. {
  2053. IHqlExpression * location = queryActiveActivityLocation();
  2054. if (errorProcessor && location)
  2055. {
  2056. StringBuffer errorMsg;
  2057. va_list args;
  2058. va_start(args, format);
  2059. errorMsg.valist_appendf(format, args);
  2060. va_end(args);
  2061. throw createError(code, errorMsg.str(), str(location->querySourcePath()), location->getStartLine(), location->getStartColumn(), 0);
  2062. }
  2063. va_list args;
  2064. va_start(args, format);
  2065. IException *ret = MakeStringExceptionVA(code, format, args);
  2066. va_end(args);
  2067. throw ret;
  2068. }
  2069. void HqlCppTranslator::reportErrorDirect(IHqlExpression * exprOrLocation, int code,const char *msg, bool alwaysAbort)
  2070. {
  2071. ECLlocation loc;
  2072. if (!loc.extractLocationAttr(exprOrLocation))
  2073. loc.extractLocationAttr(queryActiveActivityLocation());
  2074. const char * sourcePath = str(loc.sourcePath);
  2075. if (alwaysAbort)
  2076. throw createError(code, msg, sourcePath, loc.lineno, loc.column, loc.position);
  2077. errorProcessor->reportError(code, msg, sourcePath, loc.lineno, loc.column, loc.position);
  2078. }
  2079. void HqlCppTranslator::reportError(IHqlExpression * location, int code,const char *format, ...)
  2080. {
  2081. StringBuffer errorMsg;
  2082. va_list args;
  2083. va_start(args, format);
  2084. errorMsg.valist_appendf(format, args);
  2085. va_end(args);
  2086. reportErrorDirect(location, code, errorMsg.str(), true);
  2087. }
  2088. void HqlCppTranslator::reportErrorNoAbort(IHqlExpression * location, int code,const char *format, ...)
  2089. {
  2090. StringBuffer errorMsg;
  2091. va_list args;
  2092. va_start(args, format);
  2093. errorMsg.valist_appendf(format, args);
  2094. va_end(args);
  2095. reportErrorDirect(location, code, errorMsg.str(), false);
  2096. }
  2097. //---------------------------------------------------------------------------
  2098. void HqlCppTranslator::doBuildStmtAssign(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * expr)
  2099. {
  2100. buildAssign(ctx, target, expr);
  2101. }
  2102. void HqlCppTranslator::buildAddress(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  2103. {
  2104. node_operator op = expr->getOperator();
  2105. switch (op)
  2106. {
  2107. case no_address:
  2108. buildExpr(ctx, expr->queryChild(0), tgt);
  2109. break;
  2110. case no_typetransfer:
  2111. buildAddress(ctx, expr->queryChild(0), tgt);
  2112. break;
  2113. default:
  2114. {
  2115. Owned<IReferenceSelector> selector = buildReference(ctx, expr);
  2116. selector->buildAddress(ctx, tgt);
  2117. break;
  2118. }
  2119. }
  2120. }
  2121. bool HqlCppTranslator::hasAddress(BuildCtx & ctx, IHqlExpression * expr)
  2122. {
  2123. switch (expr->getOperator())
  2124. {
  2125. case no_deref:
  2126. case no_variable:
  2127. return true;
  2128. case no_field:
  2129. case no_select:
  2130. {
  2131. Owned<IReferenceSelector> selector = buildReference(ctx, expr);
  2132. return !selector->isConditional();
  2133. }
  2134. case no_typetransfer:
  2135. return hasAddress(ctx, expr->queryChild(0));
  2136. case no_constant:
  2137. return isTypePassedByAddress(expr->queryType());
  2138. default:
  2139. return false;
  2140. }
  2141. }
  2142. void HqlCppTranslator::buildAssign(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * expr)
  2143. {
  2144. #ifdef ADD_ASSIGNMENT_COMMENTS
  2145. if (target->getOperator() == no_select)
  2146. {
  2147. StringBuffer s;
  2148. ctx.addQuoted(s.append("//Assign to field ").append(target->queryChild(1)->queryName()));
  2149. }
  2150. #endif
  2151. Owned<IReferenceSelector> selector = buildReference(ctx, target);
  2152. if (expr->getOperator() == no_null)
  2153. selector->buildClear(ctx, 0);
  2154. else if (target->isDatarow() && (!hasReferenceModifier(target->queryType()) || !recordTypesMatch(target->queryType(), expr->queryType())))
  2155. buildRowAssign(ctx, selector, expr);
  2156. else
  2157. selector->set(ctx, expr);
  2158. }
  2159. void HqlCppTranslator::doBuildStmtAssignModify(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * expr, node_operator assignOp)
  2160. {
  2161. Owned<IReferenceSelector> selector = buildReference(ctx, target);
  2162. selector->modifyOp(ctx, expr, assignOp);
  2163. }
  2164. void HqlCppTranslator::buildExprAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  2165. {
  2166. /*
  2167. switch (target.queryType().getTypeCode())
  2168. {
  2169. case type_table:
  2170. case type_groupedtable:
  2171. buildDatasetAssign(ctx, target, expr);
  2172. break;
  2173. case type_row:
  2174. buildAssignRow(ctx, target, expr);
  2175. break;
  2176. }
  2177. */
  2178. node_operator op = expr->getOperator();
  2179. switch (op)
  2180. {
  2181. case no_constant:
  2182. if (!isNullAssign(target, expr))
  2183. doBuildExprAssign(ctx, target, expr);
  2184. else
  2185. ctx.addAssign(target.length, queryZero());
  2186. break;
  2187. case no_regex_find:
  2188. case no_regex_replace:
  2189. doBuildAssignRegexFindReplace(ctx, target, expr);
  2190. break;
  2191. case no_matched:
  2192. case no_matchtext:
  2193. case no_matchlength:
  2194. case no_matchposition:
  2195. case no_matchunicode:
  2196. case no_matchutf8:
  2197. doBuildMatched(ctx, &target, expr, NULL);
  2198. break;
  2199. case no_matchattr:
  2200. doBuildMatchAttr(ctx, &target, expr, NULL);
  2201. break;
  2202. case no_loopcounter:
  2203. doBuildAssignLoopCounter(ctx, target, expr);
  2204. break;
  2205. case no_evalonce:
  2206. doBuildEvalOnce(ctx, &target, expr, NULL);
  2207. break;
  2208. case no_alias_scope:
  2209. {
  2210. expandAliasScope(ctx, expr);
  2211. buildExprAssign(ctx, target, expr->queryChild(0));
  2212. break;
  2213. }
  2214. case no_case:
  2215. case no_map:
  2216. {
  2217. HqlCppCaseInfo info(*this);
  2218. doBuildCaseInfo(expr, info);
  2219. info.buildAssign(ctx, target);
  2220. break;
  2221. }
  2222. case no_which:
  2223. case no_rejected:
  2224. doBuildAssignWhich(ctx, target, expr);
  2225. break;
  2226. case no_call:
  2227. case no_externalcall:
  2228. doBuildAssignCall(ctx, target, expr);
  2229. break;
  2230. case no_cast:
  2231. case no_implicitcast:
  2232. doBuildAssignCast(ctx, target, expr);
  2233. break;
  2234. case no_choose:
  2235. doBuildAssignChoose(ctx, target, expr);
  2236. break;
  2237. case no_comma:
  2238. case no_compound:
  2239. buildStmt(ctx, expr->queryChild(0));
  2240. buildExprAssign(ctx, target, expr->queryChild(1));
  2241. break;
  2242. case no_executewhen:
  2243. doBuildAssignExecuteWhen(ctx, target, expr);
  2244. break;
  2245. case no_concat:
  2246. doBuildAssignConcat(ctx, target, expr);
  2247. break;
  2248. case no_div:
  2249. case no_modulus:
  2250. doBuildAssignDivide(ctx, target, expr);
  2251. break;
  2252. case no_crc:
  2253. case no_hash:
  2254. case no_hash32:
  2255. case no_hash64:
  2256. doBuildAssignHashCrc(ctx, target, expr);
  2257. break;
  2258. case no_hashmd5:
  2259. doBuildAssignHashMd5(ctx, target, expr);
  2260. break;
  2261. case no_if:
  2262. doBuildAssignIf(ctx, target, expr);
  2263. break;
  2264. case no_index:
  2265. doBuildAssignIndex(ctx, target, expr);
  2266. break;
  2267. case no_in:
  2268. case no_notin:
  2269. {
  2270. OwnedHqlExpr optimized = querySimplifyInExpr(expr);
  2271. if (optimized)
  2272. {
  2273. OwnedHqlExpr folded = foldHqlExpression(optimized);
  2274. buildExprAssign(ctx, target, folded);
  2275. }
  2276. else
  2277. doBuildAssignIn(ctx, target, expr);
  2278. break;
  2279. }
  2280. case no_intformat:
  2281. doBuildAssignFormat(intFormatId, ctx, target, expr);
  2282. break;
  2283. case no_nofold:
  2284. case no_nohoist:
  2285. case no_section:
  2286. case no_sectioninput:
  2287. case no_forcegraph:
  2288. case no_nocombine:
  2289. case no_likely:
  2290. case no_unlikely:
  2291. case no_pure:
  2292. buildExprAssign(ctx, target, expr->queryChild(0));
  2293. break;
  2294. case no_realformat:
  2295. doBuildAssignFormat(realFormatId, ctx, target, expr);
  2296. break;
  2297. case no_order:
  2298. doBuildAssignOrder(ctx, target, expr);
  2299. break;
  2300. case no_unicodeorder:
  2301. doBuildAssignUnicodeOrder(ctx, target, expr);
  2302. break;
  2303. case no_substring:
  2304. doBuildAssignSubString(ctx, target, expr);
  2305. break;
  2306. case no_trim:
  2307. doBuildAssignTrim(ctx, target, expr);
  2308. break;
  2309. case no_field:
  2310. throwUnexpected();
  2311. case no_select:
  2312. {
  2313. OwnedHqlExpr aggregate = convertToSimpleAggregate(expr);
  2314. if (aggregate && canProcessInline(&ctx, aggregate->queryChild(0)))
  2315. {
  2316. buildExprAssign(ctx, target, aggregate);
  2317. return;
  2318. }
  2319. if (shouldEvaluateSelectAsAlias(ctx, expr) && !insideOnStart(ctx))
  2320. {
  2321. CHqlBoundExpr temp;
  2322. doBuildAliasValue(ctx, expr, temp, NULL);
  2323. assign(ctx, target, temp);
  2324. return;
  2325. }
  2326. Owned<IReferenceSelector> selector = buildReference(ctx, expr);
  2327. selector->assignTo(ctx, target);
  2328. return;
  2329. }
  2330. break;
  2331. case no_not:
  2332. {
  2333. IHqlExpression * child = expr->queryChild(0);
  2334. node_operator childOp = child->getOperator();
  2335. if (((childOp == no_and) || (childOp == no_or)) && requiresTempAfterFirst(ctx, child))
  2336. {
  2337. if (childOp == no_and)
  2338. doBuildAssignAnd(ctx, target, child, true);
  2339. else
  2340. {
  2341. OwnedHqlExpr inverted = convertOrToAnd(expr);
  2342. buildExprAssign(ctx, target, inverted);
  2343. }
  2344. }
  2345. else
  2346. doBuildExprAssign(ctx, target, expr);
  2347. break;
  2348. }
  2349. case no_or:
  2350. {
  2351. IHqlExpression * left = expr->queryChild(0);
  2352. //in always goes via an assign, so do this first, and then filter on result.
  2353. if (left->getOperator() == no_in)
  2354. {
  2355. BuildCtx subctx(ctx);
  2356. buildExprAssign(subctx, target, left);
  2357. OwnedHqlExpr inverse = getInverse(target.expr);
  2358. subctx.addFilter(inverse);
  2359. buildExprAssign(subctx, target, expr->queryChild(1));
  2360. }
  2361. else if (requiresTempAfterFirst(ctx, expr))
  2362. {
  2363. OwnedHqlExpr inverted = convertOrToAnd(expr);
  2364. buildExprAssign(ctx, target, inverted);
  2365. }
  2366. else
  2367. doBuildExprAssign(ctx, target, expr);
  2368. break;
  2369. }
  2370. case no_and:
  2371. if (requiresTempAfterFirst(ctx, expr))
  2372. doBuildAssignAnd(ctx, target, expr, false);
  2373. else
  2374. doBuildExprAssign(ctx, target, expr);
  2375. break;
  2376. case no_fromunicode:
  2377. case no_tounicode:
  2378. doBuildAssignToFromUnicode(ctx, target, expr);
  2379. break;
  2380. case no_toxml:
  2381. case no_tojson:
  2382. doBuildAssignToXmlorJson(ctx, target, expr);
  2383. break;
  2384. case no_wuid:
  2385. doBuildAssignWuid(ctx, target, expr);
  2386. break;
  2387. case no_xmldecode:
  2388. case no_xmlencode:
  2389. doBuildXmlEncode(ctx, &target, expr, NULL);
  2390. break;
  2391. case no_all:
  2392. doBuildAssignAll(ctx, target, expr);
  2393. return;
  2394. case no_list:
  2395. doBuildAssignList(ctx, target, expr);
  2396. return;
  2397. case no_addsets:
  2398. doBuildAssignAddSets(ctx, target, expr);
  2399. return;
  2400. case no_createset:
  2401. buildSetAssignViaBuilder(ctx, target, expr);
  2402. return;
  2403. case no_failmessage:
  2404. doBuildAssignFailMessage(ctx, target, expr);
  2405. return;
  2406. case no_eventname:
  2407. doBuildAssignEventName(ctx, target, expr);
  2408. return;
  2409. case no_eventextra:
  2410. doBuildAssignEventExtra(ctx, target, expr);
  2411. return;
  2412. case no_catch:
  2413. doBuildAssignCatch(ctx, target, expr);
  2414. break;
  2415. case no_id2blob:
  2416. doBuildAssignIdToBlob(ctx, target, expr);
  2417. break;
  2418. case no_getresult:
  2419. case no_workunit_dataset:
  2420. if (isSameFullyUnqualifiedType(expr->queryType(), target.queryType()))
  2421. doBuildAssignGetResult(ctx, target, expr);
  2422. else
  2423. doBuildExprAssign(ctx, target, expr);
  2424. break;
  2425. case no_getgraphresult:
  2426. doBuildAssignGetGraphResult(ctx, target, expr);
  2427. break;
  2428. case no_existslist:
  2429. doBuildAggregateList(ctx, &target, expr, NULL);
  2430. break;
  2431. case no_countlist:
  2432. doBuildAggregateList(ctx, &target, expr, NULL);
  2433. break;
  2434. case no_sumlist:
  2435. doBuildAggregateList(ctx, &target, expr, NULL);
  2436. break;
  2437. case no_minlist:
  2438. doBuildAggregateList(ctx, &target, expr, NULL);
  2439. break;
  2440. case no_maxlist:
  2441. doBuildAggregateList(ctx, &target, expr, NULL);
  2442. break;
  2443. case no_skip:
  2444. {
  2445. bool canReachFollowing = false;
  2446. doBuildStmtSkip(ctx, expr, &canReachFollowing);
  2447. if (canReachFollowing)
  2448. {
  2449. OwnedHqlExpr null = createNullExpr(expr);
  2450. doBuildExprAssign(ctx, target, null);
  2451. }
  2452. break;
  2453. }
  2454. case no_count:
  2455. case no_max:
  2456. case no_min:
  2457. case no_sum:
  2458. case no_exists:
  2459. doBuildAssignAggregate(ctx, target, expr);
  2460. break;
  2461. case no_getenv:
  2462. {
  2463. OwnedHqlExpr mapped = cvtGetEnvToCall(expr);
  2464. buildExprAssign(ctx, target, mapped);
  2465. break;
  2466. }
  2467. default:
  2468. doBuildExprAssign(ctx, target, expr);
  2469. break;
  2470. }
  2471. }
  2472. void HqlCppTranslator::buildExprAssignViaType(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, ITypeInfo * type)
  2473. {
  2474. OwnedHqlExpr temp = createValue(no_implicitcast, LINK(type), LINK(expr));
  2475. buildExprAssign(ctx, target, temp);
  2476. }
  2477. void HqlCppTranslator::buildExprAssignViaString(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, ITypeInfo *dest)
  2478. {
  2479. unsigned len;
  2480. switch (dest->getTypeCode())
  2481. {
  2482. case type_varstring:
  2483. case type_varunicode:
  2484. len = UNKNOWN_LENGTH;
  2485. break;
  2486. default:
  2487. len = dest->getStringLen();
  2488. break;
  2489. }
  2490. OwnedITypeInfo type = makeStringType(len, NULL, NULL);
  2491. buildExprAssignViaType(ctx, target, expr, type);
  2492. }
  2493. void HqlCppTranslator::buildAssignToTemp(BuildCtx & ctx, IHqlExpression * variable, IHqlExpression * expr)
  2494. {
  2495. CHqlBoundTarget boundTarget;
  2496. boundTarget.expr.set(variable);
  2497. buildExprAssign(ctx, boundTarget, expr);
  2498. }
  2499. void HqlCppTranslator::buildAssignViaTemp(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  2500. {
  2501. CHqlBoundExpr temp;
  2502. buildTempExpr(ctx, expr, temp);
  2503. buildExprAssign(ctx, target, temp.expr);
  2504. }
  2505. static bool canOptimizeIncrementAssign(ITypeInfo * type)
  2506. {
  2507. switch (type->getTypeCode())
  2508. {
  2509. case type_real:
  2510. return true;
  2511. case type_int:
  2512. switch (type->getSize())
  2513. {
  2514. case 1:
  2515. case 2:
  2516. case 4:
  2517. case 8:
  2518. return true;
  2519. }
  2520. }
  2521. return false;
  2522. }
  2523. IHqlExpression * HqlCppTranslator::optimizeIncrementAssign(BuildCtx & ctx, IHqlExpression * value)
  2524. {
  2525. //MORE: Could spot x += if(cond, y, 0) and convert to if (cond) x+= y; (especially if y is 1)
  2526. if (value->getOperator() == no_if)
  2527. {
  2528. IHqlExpression * left = value->queryChild(1);
  2529. IHqlExpression * right = value->queryChild(2);
  2530. if (isZero(right))
  2531. {
  2532. buildFilter(ctx, value->queryChild(0));
  2533. return optimizeIncrementAssign(ctx, left);
  2534. }
  2535. if (isZero(left))
  2536. {
  2537. OwnedHqlExpr filter = getInverse(value->queryChild(0));
  2538. buildFilter(ctx, filter);
  2539. return optimizeIncrementAssign(ctx, right);
  2540. }
  2541. }
  2542. if (isCast(value))
  2543. {
  2544. IHqlExpression * uncast = value->queryChild(0);
  2545. OwnedHqlExpr optimizedValue = optimizeIncrementAssign(ctx, uncast);
  2546. if (optimizedValue != uncast)
  2547. return ensureExprType(optimizedValue, value->queryType());
  2548. }
  2549. return LINK(value);
  2550. }
  2551. void HqlCppTranslator::buildIncrementAssign(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * value)
  2552. {
  2553. // CHqlBoundExpr bound;
  2554. // buildExpr(ctx, target, bound);
  2555. ITypeInfo * type = target->queryType();
  2556. OwnedHqlExpr castValue = ensureExprType(value, type);
  2557. BuildCtx condctx(ctx);
  2558. if (options.optimizeIncrement)
  2559. {
  2560. castValue.setown(optimizeIncrementAssign(condctx, castValue));
  2561. if (isZero(castValue))
  2562. return;
  2563. if (canOptimizeIncrementAssign(type))
  2564. {
  2565. CHqlBoundExpr boundTarget;
  2566. buildExpr(condctx, target, boundTarget); // Not very clean!
  2567. CHqlBoundExpr boundValue;
  2568. buildExpr(condctx, castValue, boundValue);
  2569. condctx.addAssignIncrement(boundTarget.expr, boundValue.expr);
  2570. return;
  2571. }
  2572. }
  2573. OwnedHqlExpr plus = createValue(no_add, LINK(type), LINK(target), castValue.getClear());
  2574. buildAssign(condctx, target, plus);
  2575. }
  2576. void HqlCppTranslator::buildIncrementAssign(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * value)
  2577. {
  2578. buildIncrementAssign(ctx, target->queryExpr(), value);
  2579. // OwnedHqlExpr plus = createValue(no_add, LINK(type), ensureExprType(target->queryExpr(), type), ensureExprType(value, type));
  2580. // target->set(condctx, plus);
  2581. }
  2582. void HqlCppTranslator::buildIncrementAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * value)
  2583. {
  2584. ITypeInfo * type = target.queryType();
  2585. OwnedHqlExpr castValue = ensureExprType(value, type);
  2586. BuildCtx condctx(ctx);
  2587. if (options.optimizeIncrement)
  2588. {
  2589. castValue.setown(optimizeIncrementAssign(condctx, castValue));
  2590. if (isZero(castValue))
  2591. return;
  2592. if (canOptimizeIncrementAssign(type))
  2593. {
  2594. CHqlBoundExpr boundValue;
  2595. buildExpr(ctx, castValue, boundValue);
  2596. ctx.addAssignIncrement(target.expr, boundValue.expr);
  2597. return;
  2598. }
  2599. }
  2600. OwnedHqlExpr plus = createValue(no_add, LINK(type), target.getTranslatedExpr(), castValue.getClear());
  2601. buildExprAssign(ctx, target, plus);
  2602. }
  2603. void HqlCppTranslator::buildClear(BuildCtx & ctx, IHqlExpression * expr)
  2604. {
  2605. OwnedHqlExpr null = createNullExpr(expr);
  2606. buildAssign(ctx, expr, null);
  2607. }
  2608. void HqlCppTranslator::buildClear(BuildCtx & ctx, const CHqlBoundTarget & target)
  2609. {
  2610. if (target.length)
  2611. {
  2612. buildAssignToTemp(ctx, target.length, queryZero());
  2613. //NB: Don't need to clear target.pointer/target.variable if a length is defined......
  2614. return;
  2615. }
  2616. if (target.isFixedSize())
  2617. {
  2618. OwnedHqlExpr null = createNullExpr(target.expr);
  2619. buildExprAssign(ctx, target, null);
  2620. }
  2621. else
  2622. {
  2623. StringBuffer code;
  2624. if (hasWrapperModifier(target.queryType()))
  2625. generateExprCpp(code, target.expr).append(".clear();");
  2626. else
  2627. generateExprCpp(code, target.expr).append(" = 0;");
  2628. ctx.addQuoted(code);
  2629. }
  2630. }
  2631. void HqlCppTranslator::buildFilter(BuildCtx & ctx, IHqlExpression * expr)
  2632. {
  2633. node_operator op = expr->getOperator();
  2634. switch (op)
  2635. {
  2636. case no_attr:
  2637. case no_attr_expr:
  2638. case no_attr_link:
  2639. return;
  2640. case no_and:
  2641. doBuildFilterAnd(ctx, expr);
  2642. return;
  2643. case no_not:
  2644. {
  2645. IHqlExpression * child = expr->queryChild(0);
  2646. if ((child->getOperator() == no_or) && requiresTempAfterFirst(ctx, child))
  2647. {
  2648. OwnedHqlExpr inverted = convertOrToAnd(expr);
  2649. buildFilter(ctx,inverted);
  2650. return;
  2651. }
  2652. }
  2653. break;
  2654. case no_or:
  2655. if (requiresTempAfterFirst(ctx, expr))
  2656. {
  2657. OwnedHqlExpr inverted = convertOrToAnd(expr);
  2658. buildFilter(ctx, inverted);
  2659. return;
  2660. }
  2661. break;
  2662. case no_between:
  2663. case no_notbetween:
  2664. {
  2665. OwnedHqlExpr between = expandBetween(expr);
  2666. buildFilter(ctx, between);
  2667. return;
  2668. }
  2669. case no_alias_scope:
  2670. {
  2671. expandAliasScope(ctx, expr);
  2672. buildFilter(ctx, expr->queryChild(0));
  2673. return;
  2674. }
  2675. case no_compound:
  2676. {
  2677. buildStmt(ctx, expr->queryChild(0));
  2678. buildFilter(ctx, expr->queryChild(1));
  2679. break;
  2680. }
  2681. }
  2682. buildFilterViaExpr(ctx, expr);
  2683. }
  2684. IHqlStmt * HqlCppTranslator::buildFilterViaExpr(BuildCtx & ctx, IHqlExpression * expr)
  2685. {
  2686. //default action...
  2687. CHqlBoundExpr pure;
  2688. buildExpr(ctx, expr, pure);
  2689. if (pure.length) // check length is non zero
  2690. return ctx.addFilter(pure.length);
  2691. else
  2692. {
  2693. IHqlStmt * stmt = ctx.addFilter(pure.expr);
  2694. ctx.associateExpr(expr, queryBoolExpr(true));
  2695. return stmt;
  2696. }
  2697. }
  2698. void HqlCppTranslator::tidyupExpr(BuildCtx & ctx, CHqlBoundExpr & bound)
  2699. {
  2700. if (isPushed(bound))
  2701. {
  2702. HqlExprArray args;
  2703. callProcedure(ctx, DecPopLongId, args);
  2704. bound.expr.set(NULL);
  2705. }
  2706. }
  2707. void HqlCppTranslator::expandTranslated(IHqlExpression * expr, CHqlBoundExpr & tgt)
  2708. {
  2709. tgt.setFromTranslated(expr);
  2710. }
  2711. void HqlCppTranslator::buildCachedExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  2712. {
  2713. buildExpr(ctx, expr, tgt);
  2714. }
  2715. void HqlCppTranslator::buildAnyExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  2716. {
  2717. if (expr->isDataset())
  2718. buildDataset(ctx, expr, tgt, FormatNatural);
  2719. else if (expr->isDatarow())
  2720. {
  2721. Owned<IReferenceSelector> selector = buildNewRow(ctx, expr);
  2722. selector->buildAddress(ctx, tgt);
  2723. }
  2724. else
  2725. buildExpr(ctx, expr, tgt);
  2726. }
  2727. bool HqlCppTranslator::shouldEvaluateSelectAsAlias(BuildCtx & ctx, IHqlExpression * expr)
  2728. {
  2729. //If we're inside an activity that serializes onStart data, then the code to serialize fields
  2730. //selected from a row is generally simpler than the code to serialize the row itself.
  2731. if (insideActivityRemoteSerialize(ctx) && !expr->isList())
  2732. {
  2733. bool isNew;
  2734. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  2735. if (isNew && ds->getOperator() == no_getgraphresult)
  2736. {
  2737. IHqlExpression * graphId = ds->queryChild(1);
  2738. if (isCurrentActiveGraph(ctx, graphId))
  2739. return true;
  2740. }
  2741. }
  2742. return false;
  2743. }
  2744. void HqlCppTranslator::buildExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  2745. {
  2746. node_operator op = expr->getOperator();
  2747. switch (op)
  2748. {
  2749. case no_counter:
  2750. doBuildExprCounter(ctx, expr, tgt);
  2751. return;
  2752. case no_evaluate:
  2753. doBuildExprEvaluate(ctx, expr, tgt);
  2754. return;
  2755. case no_thor:
  2756. throwUnexpectedX("THOR() annotation created in a scalar context");
  2757. // assertex(expr->queryType()->isScalar());
  2758. // buildExpr(ctx, expr->queryChild(0), tgt);
  2759. return;
  2760. case no_count:
  2761. if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
  2762. doBuildExprCount(ctx, expr, tgt);
  2763. return;
  2764. case no_max:
  2765. case no_min:
  2766. case no_sum:
  2767. if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
  2768. doBuildExprAggregate(ctx, expr, tgt);
  2769. return;
  2770. case no_exists:
  2771. if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
  2772. doBuildExprExists(ctx, expr, tgt);
  2773. return;
  2774. case no_countdict:
  2775. if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
  2776. doBuildExprCountDict(ctx, expr, tgt);
  2777. return;
  2778. case no_existsdict:
  2779. if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
  2780. doBuildExprExistsDict(ctx, expr, tgt);
  2781. return;
  2782. case no_existslist:
  2783. doBuildAggregateList(ctx, NULL, expr, &tgt);
  2784. return;
  2785. case no_countlist:
  2786. doBuildAggregateList(ctx, NULL, expr, &tgt);
  2787. return;
  2788. case no_sumlist:
  2789. doBuildAggregateList(ctx, NULL, expr, &tgt);
  2790. return;
  2791. case no_minlist:
  2792. doBuildAggregateList(ctx, NULL, expr, &tgt);
  2793. return;
  2794. case no_maxlist:
  2795. doBuildAggregateList(ctx, NULL, expr, &tgt);
  2796. return;
  2797. case no_sizeof:
  2798. doBuildExprSizeof(ctx, expr, tgt);
  2799. return;
  2800. case no_filepos:
  2801. doBuildExprFilepos(ctx, expr, tgt);
  2802. return;
  2803. case no_file_logicalname:
  2804. doBuildExprFileLogicalName(ctx, expr, tgt);
  2805. return;
  2806. case no_getresult:
  2807. case no_workunit_dataset:
  2808. doBuildExprGetResult(ctx, expr, tgt);
  2809. return;
  2810. case no_getgraphresult:
  2811. doBuildExprGetGraphResult(ctx, expr, tgt, FormatNatural);
  2812. return;
  2813. case no_regex_find:
  2814. case no_regex_replace:
  2815. doBuildExprRegexFindReplace(ctx, expr, tgt);
  2816. return;
  2817. case no_regex_findset:
  2818. doBuildExprRegexFindSet(ctx, expr, tgt);
  2819. return;
  2820. case no_skip:
  2821. case no_assert:
  2822. {
  2823. buildStmt(ctx, expr);
  2824. OwnedHqlExpr null = createNullExpr(expr);
  2825. buildExpr(ctx, null, tgt);
  2826. return;
  2827. }
  2828. case no_matched_injoin:
  2829. doBuildExprMatchedInJoin(ctx, expr, tgt);
  2830. return;
  2831. case no_matched:
  2832. case no_matchtext:
  2833. case no_matchlength:
  2834. case no_matchposition:
  2835. case no_matchunicode:
  2836. case no_matchutf8:
  2837. doBuildMatched(ctx, NULL, expr, &tgt);
  2838. return;
  2839. case no_matchattr:
  2840. doBuildMatchAttr(ctx, NULL, expr, &tgt);
  2841. return;
  2842. case no_rowdiff:
  2843. doBuildExprRowDiff(ctx, expr, tgt);
  2844. return;
  2845. case no_xmltext:
  2846. doBuildExprXmlText(ctx, expr, tgt);
  2847. return;
  2848. case no_xmlunicode:
  2849. doBuildExprXmlUnicode(ctx, expr, tgt);
  2850. return;
  2851. case no_evalonce:
  2852. doBuildEvalOnce(ctx, NULL, expr, &tgt);
  2853. return;
  2854. case no_alias:
  2855. doBuildExprAlias(ctx, expr, &tgt, NULL);
  2856. return;
  2857. case no_alias_scope:
  2858. {
  2859. expandAliasScope(ctx, expr);
  2860. buildExpr(ctx, expr->queryChild(0), tgt);
  2861. return;
  2862. }
  2863. case no_between:
  2864. case no_notbetween:
  2865. {
  2866. OwnedHqlExpr between = expandBetween(expr);
  2867. buildExpr(ctx, between, tgt);
  2868. return;
  2869. }
  2870. case no_libraryinput:
  2871. doBuildAliasValue(ctx, expr, tgt, NULL);
  2872. return;
  2873. case no_externalcall:
  2874. case no_call:
  2875. if (isTimed(expr))
  2876. buildTempExpr(ctx, expr, tgt);
  2877. else
  2878. doBuildExprCall(ctx, expr, tgt);
  2879. return;
  2880. case no_comma:
  2881. case no_compound:
  2882. buildStmt(ctx, expr->queryChild(0));
  2883. buildExpr(ctx, expr->queryChild(1), tgt);
  2884. return;
  2885. case no_cast:
  2886. case no_implicitcast:
  2887. doBuildExprCast(ctx, expr, tgt);
  2888. return;
  2889. case no_charlen:
  2890. tgt.expr.setown(doBuildCharLength(ctx, expr->queryChild(0)));
  2891. return;
  2892. case no_add:
  2893. doBuildExprAdd(ctx, expr, tgt);
  2894. return;
  2895. case no_mul:
  2896. case no_sub:
  2897. doBuildExprArith(ctx, expr, tgt);
  2898. return;
  2899. case no_abs:
  2900. doBuildExprAbs(ctx, expr, tgt);
  2901. return;
  2902. case no_negate:
  2903. doBuildExprNegate(ctx, expr, tgt);
  2904. return;
  2905. case no_div:
  2906. case no_modulus:
  2907. doBuildExprDivide(ctx, expr, tgt);
  2908. return;
  2909. case no_if:
  2910. doBuildExprIf(ctx, expr, tgt);
  2911. return;
  2912. case no_index:
  2913. doBuildExprIndex(ctx, expr, tgt);
  2914. return;
  2915. case no_list:
  2916. doBuildExprList(ctx, expr, tgt);
  2917. return;
  2918. case no_all:
  2919. doBuildExprAll(ctx, expr, tgt);
  2920. return;
  2921. case no_trim:
  2922. doBuildExprTrim(ctx, expr, tgt);
  2923. return;
  2924. case no_intformat:
  2925. doBuildExprFormat(intFormatId, ctx, expr, tgt);
  2926. return;
  2927. case no_realformat:
  2928. doBuildExprFormat(realFormatId, ctx, expr, tgt);
  2929. return;
  2930. case no_exp:
  2931. doBuildExprSysFunc(ctx, expr, tgt, clibExpId);
  2932. return;
  2933. case no_ln:
  2934. doBuildExprSysFunc(ctx, expr, tgt, lnId, options.divideByZeroAction);
  2935. return;
  2936. case no_sin:
  2937. doBuildExprSysFunc(ctx, expr, tgt, sinId);
  2938. return;
  2939. case no_cos:
  2940. doBuildExprSysFunc(ctx, expr, tgt, cosId);
  2941. return;
  2942. case no_tan:
  2943. doBuildExprSysFunc(ctx, expr, tgt, tanId);
  2944. return;
  2945. case no_asin:
  2946. doBuildExprSysFunc(ctx, expr, tgt, asinId, options.divideByZeroAction);
  2947. return;
  2948. case no_acos:
  2949. doBuildExprSysFunc(ctx, expr, tgt, acosId, options.divideByZeroAction);
  2950. return;
  2951. case no_atan:
  2952. doBuildExprSysFunc(ctx, expr, tgt, atanId);
  2953. return;
  2954. case no_atan2:
  2955. doBuildExprSysFunc(ctx, expr, tgt, atan2Id);
  2956. return;
  2957. case no_sinh:
  2958. doBuildExprSysFunc(ctx, expr, tgt, sinhId);
  2959. return;
  2960. case no_cosh:
  2961. doBuildExprSysFunc(ctx, expr, tgt, coshId);
  2962. return;
  2963. case no_tanh:
  2964. doBuildExprSysFunc(ctx, expr, tgt, tanhId);
  2965. return;
  2966. case no_log10:
  2967. doBuildExprSysFunc(ctx, expr, tgt, log10Id, options.divideByZeroAction);
  2968. return;
  2969. case no_power:
  2970. doBuildExprSysFunc(ctx, expr, tgt, powerId);
  2971. return;
  2972. case no_fail:
  2973. doBuildStmtFail(ctx, expr);
  2974. tgt.expr.setown(createConstant(0));
  2975. return;
  2976. case no_failcode:
  2977. doBuildExprFailCode(ctx, expr, tgt);
  2978. return;
  2979. case no_ordered:
  2980. doBuildExprOrdered(ctx, expr, tgt);
  2981. return;
  2982. case no_random:
  2983. doBuildExprSysFunc(ctx, expr, tgt, rtlRandomId);
  2984. return;
  2985. case no_rank:
  2986. doBuildExprRank(ctx, expr, tgt);
  2987. return;
  2988. case no_ranked:
  2989. doBuildExprRanked(ctx, expr, tgt);
  2990. return;
  2991. case no_round:
  2992. case no_roundup:
  2993. doBuildExprRound(ctx, expr, tgt);
  2994. return;
  2995. case no_sqrt:
  2996. doBuildExprSysFunc(ctx, expr, tgt, sqrtId, options.divideByZeroAction);
  2997. return;
  2998. case no_truncate:
  2999. doBuildExprTrunc(ctx, expr, tgt);
  3000. return;
  3001. case no_offsetof:
  3002. doBuildExprOffsetOf(ctx, expr, tgt);
  3003. return;
  3004. case no_substring:
  3005. doBuildExprSubString(ctx, expr, tgt);
  3006. return;
  3007. case no_in:
  3008. case no_notin:
  3009. {
  3010. if (expr->queryChild(1)->getOperator() == no_all)
  3011. tgt.expr.setown(createConstant(op == no_in));
  3012. else
  3013. {
  3014. OwnedHqlExpr optimized = querySimplifyInExpr(expr);
  3015. if (optimized)
  3016. {
  3017. OwnedHqlExpr folded = foldHqlExpression(optimized);
  3018. buildExpr(ctx, folded, tgt);
  3019. }
  3020. else
  3021. buildTempExpr(ctx, expr, tgt);
  3022. }
  3023. return;
  3024. }
  3025. case no_indict:
  3026. doBuildExprInDict(ctx, expr, tgt);
  3027. return;
  3028. case no_case:
  3029. case no_choose:
  3030. case no_concat:
  3031. case no_crc:
  3032. case no_hash:
  3033. case no_hash32:
  3034. case no_hash64:
  3035. case no_hashmd5:
  3036. case no_map:
  3037. case no_order:
  3038. case no_unicodeorder:
  3039. case no_rejected:
  3040. case no_which:
  3041. case no_addsets:
  3042. case no_createset:
  3043. case no_catch:
  3044. case no_failmessage:
  3045. case no_eventname:
  3046. case no_eventextra:
  3047. case no_loopcounter:
  3048. case no_toxml:
  3049. case no_tojson:
  3050. case no_executewhen:
  3051. buildTempExpr(ctx, expr, tgt);
  3052. return;
  3053. case no_asstring:
  3054. case no_typetransfer:
  3055. doBuildExprTransfer(ctx, expr, tgt);
  3056. return;
  3057. case no_translated:
  3058. {
  3059. expandTranslated(expr, tgt);
  3060. return;
  3061. }
  3062. case no_eq:
  3063. case no_ne:
  3064. case no_le:
  3065. case no_lt:
  3066. case no_ge:
  3067. case no_gt:
  3068. if (options.expressionPeephole)
  3069. {
  3070. OwnedHqlExpr optimized = peepholeOptimize(ctx, expr);
  3071. if (optimized != expr)
  3072. {
  3073. buildExpr(ctx, optimized, tgt);
  3074. return;
  3075. }
  3076. }
  3077. doBuildExprCompare(ctx, expr, tgt);
  3078. return;
  3079. case no_wuid:
  3080. doBuildExprWuid(ctx, expr, tgt);
  3081. return;
  3082. case no_getenv:
  3083. {
  3084. OwnedHqlExpr mapped = cvtGetEnvToCall(expr);
  3085. buildExpr(ctx, mapped, tgt);
  3086. return;
  3087. }
  3088. case no_notnot:
  3089. {
  3090. OwnedHqlExpr castChild = ensureExprType(expr->queryChild(0), queryBoolType());
  3091. buildExpr(ctx, castChild, tgt);
  3092. }
  3093. return;
  3094. case no_not:
  3095. {
  3096. IHqlExpression * child = expr->queryChild(0);
  3097. node_operator childOp = child->getOperator();
  3098. if (((childOp == no_and) || (childOp == no_or)) && requiresTempAfterFirst(ctx, child))
  3099. buildTempExpr(ctx, expr, tgt);
  3100. else
  3101. doBuildExprNot(ctx, expr, tgt);
  3102. return;
  3103. }
  3104. case no_constant:
  3105. {
  3106. ITypeInfo * type = expr->queryType();
  3107. if ((options.inlineStringThreshold > 0) && (type->getSize() > options.inlineStringThreshold) && (type->getSize() != UNKNOWN_LENGTH))
  3108. {
  3109. IHqlExpression * literal = addBigLiteral((const char *)expr->queryValue()->queryValue(), type->getSize());
  3110. Owned<ITypeInfo> retType = makeReferenceModifier(LINK(type));
  3111. switch (type->getTypeCode())
  3112. {
  3113. case type_unicode:
  3114. case type_varunicode:
  3115. case type_utf8:
  3116. literal = createValue(no_implicitcast, LINK(retType), literal);
  3117. break;
  3118. }
  3119. if (literal->queryType() != retType)
  3120. literal = createValue(no_typetransfer, LINK(retType), literal);
  3121. tgt.expr.setown(literal);
  3122. }
  3123. else
  3124. tgt.expr.set(expr);
  3125. return;
  3126. }
  3127. case no_quoted:
  3128. case no_variable:
  3129. tgt.expr.set(expr);
  3130. return;
  3131. case no_globalscope:
  3132. if (options.regressionTest && !ctx.queryMatchExpr(globalContextMarkerExpr))
  3133. throwUnexpected();
  3134. buildExpr(ctx, expr->queryChild(0), tgt);
  3135. return;
  3136. case no_nothor:
  3137. case no_nofold:
  3138. case no_nohoist:
  3139. case no_section:
  3140. case no_sectioninput:
  3141. case no_pure:
  3142. case no_forcegraph:
  3143. case no_nocombine:
  3144. case no_likely:
  3145. case no_unlikely:
  3146. buildExpr(ctx, expr->queryChild(0), tgt);
  3147. return;
  3148. case no_band:
  3149. case no_bor:
  3150. case no_bnot:
  3151. case no_bxor:
  3152. case no_lshift:
  3153. case no_rshift:
  3154. doBuildPureSubExpr(ctx, expr, tgt);
  3155. return;
  3156. //MORE: Shouldn't these be special cased?
  3157. case no_xor:
  3158. doBuildPureSubExpr(ctx, expr, tgt);
  3159. return;
  3160. case no_select:
  3161. {
  3162. OwnedHqlExpr aggregate = convertToSimpleAggregate(expr);
  3163. if (aggregate && canProcessInline(&ctx, aggregate->queryChild(0)))
  3164. {
  3165. buildExpr(ctx, aggregate, tgt);
  3166. return;
  3167. }
  3168. if (shouldEvaluateSelectAsAlias(ctx, expr))
  3169. {
  3170. doBuildAliasValue(ctx, expr, tgt, NULL);
  3171. return;
  3172. }
  3173. Owned<IReferenceSelector> selector = buildReference(ctx, expr);
  3174. selector->get(ctx, tgt);
  3175. return;
  3176. }
  3177. case no_field:
  3178. throwUnexpected();
  3179. case no_is_null:
  3180. {
  3181. //Until we have something better in place isNull is the inverse of isValid().
  3182. IHqlExpression * child = expr->queryChild(0);
  3183. OwnedHqlExpr null = createValue(no_not, makeBoolType(), createValue(no_is_valid, makeBoolType(), LINK(child)));
  3184. buildExpr(ctx, null, tgt);
  3185. }
  3186. return;
  3187. case no_is_valid:
  3188. doBuildExprIsValid(ctx, expr, tgt);
  3189. return;
  3190. case no_fromunicode:
  3191. case no_tounicode:
  3192. doBuildExprToFromUnicode(ctx, expr, tgt);
  3193. return;
  3194. case no_keyunicode:
  3195. doBuildExprKeyUnicode(ctx, expr, tgt);
  3196. return;
  3197. case no_xmldecode:
  3198. case no_xmlencode:
  3199. buildTempExpr(ctx, expr, tgt);
  3200. return;
  3201. case no_and:
  3202. case no_or:
  3203. if (requiresTempAfterFirst(ctx, expr))
  3204. buildTempExpr(ctx, expr, tgt);
  3205. else
  3206. doBuildPureSubExpr(ctx, expr, tgt);
  3207. return;
  3208. case no_assertkeyed:
  3209. case no_assertwild:
  3210. {
  3211. StringBuffer s;
  3212. throwError1(HQLERR_KeyedWildNoIndex, getExprECL(expr, s).str());
  3213. }
  3214. case no_assertstepped:
  3215. {
  3216. StringBuffer s;
  3217. throwError1(HQLERR_SteppedNoJoin, getExprECL(expr, s).str());
  3218. }
  3219. case no_id2blob:
  3220. doBuildExprIdToBlob(ctx, expr, tgt);
  3221. return;
  3222. case no_blob2id:
  3223. doBuildExprBlobToId(ctx, expr, tgt);
  3224. return;
  3225. case no_embedbody:
  3226. doBuildExprEmbedBody(ctx, expr, &tgt);
  3227. return;
  3228. case no_null:
  3229. tgt.length.setown(getSizetConstant(0));
  3230. tgt.expr.setown(createValue(no_nullptr, makeReferenceModifier(expr->getType())));
  3231. return;
  3232. case no_clustersize:
  3233. doBuildExprSysFunc(ctx, expr, tgt, getClusterSizeId);
  3234. return;
  3235. case no_deref:
  3236. //Untested
  3237. buildExpr(ctx, expr->queryChild(0), tgt);
  3238. if (tgt.expr->getOperator() == no_address)
  3239. tgt.expr.setown(createValue(no_typetransfer, expr->getType(), LINK(tgt.expr->queryChild(0))));
  3240. else
  3241. tgt.expr.setown(createValue(no_deref, expr->getType(), LINK(tgt.expr)));
  3242. return;
  3243. case no_funcdef:
  3244. tgt.expr.setown(doBuildInternalFunction(expr));
  3245. useFunction(tgt.expr);
  3246. return;
  3247. case no_purevirtual:
  3248. case no_internalselect:
  3249. {
  3250. //This shouldn't happen we should have an no_checkconcrete wrapper inserted into the tree like checkconstant,
  3251. //but it currently can in obscure library contexts (e.g., library3ie2.xhql)
  3252. IAtom * name = expr->queryName();
  3253. throwError1(HQLERR_ConcreteMemberRequired, name ? str(name) : "");
  3254. }
  3255. case NO_AGGREGATEGROUP:
  3256. throwError1(HQLERR_OutsideGroupAggregate, getOpString(op));
  3257. default:
  3258. break;
  3259. }
  3260. EclIR::dbglogIR(expr);
  3261. StringBuffer msg;
  3262. msg.append("Unexpected operator '").append(getOpString(op)).append("' in: HqlCppTranslator::buildExpr(");
  3263. toECL(expr, msg, true);
  3264. msg.append(")");
  3265. throw MakeStringException(HQLERR_UnexpectedOperator, "%s", msg.str());
  3266. }
  3267. void HqlCppTranslator::buildExprOrAssign(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * tgt)
  3268. {
  3269. if (target)
  3270. buildExprAssign(ctx, *target, expr);
  3271. else if (tgt)
  3272. buildExpr(ctx, expr, *tgt);
  3273. else
  3274. buildStmt(ctx, expr);
  3275. }
  3276. bool HqlCppTranslator::specialCaseBoolReturn(BuildCtx & ctx, IHqlExpression * expr)
  3277. {
  3278. if (!options.optimizeBoolReturn)
  3279. return false;
  3280. if ((expr->getOperator() == no_and) && (unwoundCount(expr, no_and) <= MAX_NESTED_CASES))
  3281. return true;
  3282. if (expr->getOperator() == no_not)
  3283. expr = expr->queryChild(0);
  3284. if (!requiresTemp(ctx, expr, true))
  3285. return false;
  3286. if (expr->getOperator() == no_alias_scope)
  3287. expr = expr->queryChild(0);
  3288. if (expr->getOperator() == no_compound)
  3289. expr = expr->queryChild(1);
  3290. if ((expr->getOperator() == no_and) || (expr->getOperator() == no_or))
  3291. return true;
  3292. return false;
  3293. }
  3294. void HqlCppTranslator::buildReturn(BuildCtx & ctx, IHqlExpression * expr, ITypeInfo * retType)
  3295. {
  3296. ITypeInfo * exprType = expr->queryType();
  3297. if (!retType) retType = exprType;
  3298. expr = queryExpandAliasScope(ctx, expr);
  3299. node_operator op = expr->getOperator();
  3300. type_t returntc = retType->getTypeCode();
  3301. if ((retType->getSize() == UNKNOWN_LENGTH) && (returntc == type_varstring))
  3302. {
  3303. if (hasConstModifier(retType) && (hasConstModifier(exprType) || expr->queryValue()))
  3304. {
  3305. OwnedHqlExpr cast = ensureExprType(expr, retType);
  3306. CHqlBoundExpr ret;
  3307. buildCachedExpr(ctx, cast, ret);
  3308. ctx.setNextDestructor();
  3309. ctx.addReturn(ret.expr);
  3310. }
  3311. else
  3312. {
  3313. if (hasConstModifier(retType))
  3314. {
  3315. IIdAtom * funcAtom;
  3316. if (expr->queryType()->getTypeCode()==type_varstring)
  3317. funcAtom = cloneVStringId;
  3318. else
  3319. funcAtom = cloneVStringXId;
  3320. HqlExprArray args;
  3321. args.append(*LINK(expr));
  3322. OwnedHqlExpr call = bindFunctionCall(funcAtom, args);
  3323. CHqlBoundExpr ret;
  3324. buildExpr(ctx, call, ret);
  3325. ctx.addReturn(ret.expr);
  3326. return;
  3327. }
  3328. CHqlBoundTarget retVar;
  3329. retVar.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
  3330. buildExprAssign(ctx, retVar, expr);
  3331. ctx.setNextDestructor();
  3332. StringBuffer s;
  3333. retVar.expr->toString(s);
  3334. switch (retType->getTypeCode())
  3335. {
  3336. case type_varstring:
  3337. s.append(".detachstr()");
  3338. break;
  3339. case type_varunicode:
  3340. s.append(".detachustr()");
  3341. break;
  3342. default:
  3343. UNIMPLEMENTED;
  3344. }
  3345. OwnedHqlExpr temp = createQuoted(s.str(), LINK(exprType));
  3346. ctx.addReturn(temp);
  3347. }
  3348. }
  3349. else if ((returntc == type_row) && hasLinkCountedModifier(retType))
  3350. {
  3351. CHqlBoundTarget result;
  3352. buildTempExpr(ctx, ctx, result, expr, FormatNatural, false);
  3353. //MORE: There should be a cleaner way of doing this
  3354. StringBuffer s;
  3355. result.expr->toString(s);
  3356. s.append(".getClear()");
  3357. OwnedHqlExpr temp = createQuoted(s.str(), LINK(exprType));
  3358. ctx.addReturn(temp);
  3359. }
  3360. else if ((returntc == type_table) && hasStreamedModifier(retType))
  3361. {
  3362. CHqlBoundTarget result;
  3363. buildTempExpr(ctx, ctx, result, expr, FormatStreamedDataset, false);
  3364. //MORE: There should be a cleaner way of doing this
  3365. StringBuffer s;
  3366. result.expr->toString(s);
  3367. s.append(".getClear()");
  3368. OwnedHqlExpr temp = createQuoted(s.str(), LINK(exprType));
  3369. ctx.addReturn(temp);
  3370. }
  3371. else if ((returntc == type_boolean) && specialCaseBoolReturn(ctx, expr))
  3372. {
  3373. bool successValue = true;
  3374. if (op == no_not)
  3375. {
  3376. //!(a and b) is converted into !a || !b. Otherwise just invert the test condition.
  3377. IHqlExpression * child = expr->queryChild(0);
  3378. if (child->getOperator() == no_alias_scope)
  3379. child = child->queryChild(0);
  3380. if (child->getOperator() != no_and)
  3381. {
  3382. successValue = false;
  3383. expr = expr->queryChild(0);
  3384. }
  3385. }
  3386. BuildCtx condctx(ctx);
  3387. buildFilteredReturn(condctx, expr, queryBoolExpr(successValue));
  3388. buildReturn(ctx, queryBoolExpr(!successValue));
  3389. }
  3390. else if (op == no_if)
  3391. {
  3392. OwnedHqlExpr castTrue = ensureExprType(expr->queryChild(1), retType);
  3393. OwnedHqlExpr castFalse = ensureExprType(expr->queryChild(2), retType);
  3394. BuildCtx condctx(ctx);
  3395. buildFilter(condctx, expr->queryChild(0));
  3396. buildReturn(condctx, castTrue);
  3397. buildReturn(ctx, castFalse);
  3398. }
  3399. else if (op == no_map || op == no_case)
  3400. {
  3401. HqlCppCaseInfo info(*this);
  3402. doBuildCaseInfo(expr, info);
  3403. info.buildReturn(ctx);
  3404. }
  3405. else
  3406. {
  3407. CHqlBoundExpr ret;
  3408. OwnedHqlExpr castExpr = ensureExprType(expr, retType);
  3409. buildExpr(ctx, castExpr, ret);
  3410. ctx.addReturn(ret.expr);
  3411. }
  3412. }
  3413. //Assumes that the value being returned is simple.
  3414. //for (a || b || c) gen if (a) return x; if (b) return x; if (c) return x;
  3415. //and !(a && b && c) -> !a || !b || !c
  3416. void HqlCppTranslator::buildFilteredReturn(BuildCtx & ctx, IHqlExpression * filter, IHqlExpression * value)
  3417. {
  3418. filter = queryExpandAliasScope(ctx, filter);
  3419. HqlExprArray conds;
  3420. node_operator op = filter->getOperator();
  3421. if (op == no_or)
  3422. {
  3423. buildFilteredReturn(ctx, filter->queryChild(0), value);
  3424. buildFilteredReturn(ctx, filter->queryChild(1), value);
  3425. return;
  3426. }
  3427. if (op == no_not)
  3428. {
  3429. IHqlExpression * child = filter->queryChild(0);
  3430. node_operator childOp = child->getOperator();
  3431. if (childOp == no_and)
  3432. {
  3433. child->unwindList(conds, no_and);
  3434. ForEachItemIn(i, conds)
  3435. {
  3436. IHqlExpression & cur = conds.item(i);
  3437. OwnedHqlExpr inverse = getInverse(&cur);
  3438. buildFilteredReturn(ctx, inverse, value);
  3439. }
  3440. return;
  3441. }
  3442. if (childOp == no_alias_scope)
  3443. {
  3444. expandAliasScope(ctx, child);
  3445. OwnedHqlExpr inverse = getInverse(child->queryChild(0));
  3446. buildFilteredReturn(ctx, inverse, value);
  3447. return;
  3448. }
  3449. }
  3450. BuildCtx condctx(ctx);
  3451. buildFilter(condctx, filter);
  3452. if (value)
  3453. buildReturn(condctx, value);
  3454. else
  3455. condctx.addReturn(NULL);
  3456. }
  3457. void HqlCppTranslator::buildStmt(BuildCtx & _ctx, IHqlExpression * expr)
  3458. {
  3459. BuildCtx ctx(_ctx);
  3460. node_operator op = expr->getOperator();
  3461. switch (op)
  3462. {
  3463. case no_assign:
  3464. doBuildStmtAssign(ctx, expr->queryChild(0), expr->queryChild(1));
  3465. return;
  3466. case no_assign_addfiles:
  3467. doBuildStmtAssignModify(ctx, expr->queryChild(0), expr->queryChild(1), op);
  3468. return;
  3469. case no_alias:
  3470. doBuildExprAlias(ctx, expr, NULL, NULL);
  3471. return;
  3472. case no_alias_scope:
  3473. {
  3474. expandAliasScope(ctx, expr);
  3475. buildStmt(ctx, expr->queryChild(0));
  3476. return;
  3477. }
  3478. case no_assignall:
  3479. {
  3480. unsigned idx;
  3481. unsigned kids = expr->numChildren();
  3482. for (idx = 0; idx < kids; idx++)
  3483. buildStmt(ctx, expr->queryChild(idx));
  3484. return;
  3485. }
  3486. case no_comma:
  3487. case no_compound:
  3488. buildStmt(ctx, expr->queryChild(0));
  3489. buildStmt(ctx, expr->queryChild(1));
  3490. return;
  3491. case no_if:
  3492. doBuildStmtIf(ctx, expr);
  3493. return;
  3494. case no_case:
  3495. {
  3496. HqlCppCaseInfo info(*this);
  3497. doBuildCaseInfo(expr, info);
  3498. ExprEvaluateProcessor assigner;
  3499. info.buildProcess(ctx, assigner);
  3500. return;
  3501. }
  3502. case no_call:
  3503. case no_externalcall:
  3504. doBuildStmtCall(ctx, expr);
  3505. return;
  3506. case no_nofold:
  3507. case no_nohoist:
  3508. case no_nothor:
  3509. case no_section:
  3510. case no_sectioninput:
  3511. case no_forcegraph:
  3512. case no_nocombine:
  3513. case no_likely:
  3514. case no_unlikely:
  3515. case no_pure:
  3516. buildStmt(ctx, expr->queryChild(0));
  3517. return;
  3518. case no_null:
  3519. return;
  3520. case no_fail:
  3521. doBuildStmtFail(ctx, expr);
  3522. return;
  3523. case no_setmeta:
  3524. return;
  3525. case no_update:
  3526. doBuildStmtUpdate(ctx, expr);
  3527. return;
  3528. case no_output:
  3529. doBuildStmtOutput(ctx, expr);
  3530. return;
  3531. case no_subgraph:
  3532. doBuildThorChildSubGraph(ctx, expr, SubGraphRoot);
  3533. return;
  3534. case no_thor:
  3535. doBuildThorGraph(ctx, expr);
  3536. return;
  3537. case no_workflow_action:
  3538. return;
  3539. case no_ensureresult:
  3540. doBuildStmtEnsureResult(ctx, expr);
  3541. return;
  3542. case no_extractresult:
  3543. case no_setresult:
  3544. doBuildStmtSetResult(ctx, expr);
  3545. return;
  3546. case no_parallel:
  3547. case no_sequential:
  3548. case no_actionlist:
  3549. case no_orderedactionlist:
  3550. {
  3551. ForEachChild(idx, expr)
  3552. {
  3553. BuildCtx subctx(ctx);
  3554. //Add a group for each branch of a sequential to ensure all branches are independent
  3555. if (op == no_sequential)
  3556. subctx.addGroup();
  3557. buildStmt(subctx, expr->queryChild(idx));
  3558. }
  3559. return;
  3560. }
  3561. case no_wait:
  3562. doBuildStmtWait(ctx, expr);
  3563. return;
  3564. case no_notify:
  3565. doBuildStmtNotify(ctx, expr);
  3566. return;
  3567. case no_skip:
  3568. doBuildStmtSkip(ctx, expr, NULL);
  3569. return;
  3570. case no_assert:
  3571. doBuildStmtAssert(ctx, expr);
  3572. return;
  3573. case no_embedbody:
  3574. doBuildExprEmbedBody(ctx, expr, NULL);
  3575. return;
  3576. case no_setworkflow_cond:
  3577. {
  3578. HqlExprArray args;
  3579. args.append(*LINK(expr->queryChild(0)));
  3580. buildFunctionCall(ctx, setWorkflowConditionId, args);
  3581. return;
  3582. }
  3583. case no_apply:
  3584. doBuildStmtApply(ctx, expr);
  3585. return;
  3586. case no_cluster:
  3587. doBuildStmtCluster(ctx, expr);
  3588. return;
  3589. case no_choose:
  3590. doBuildChoose(ctx, NULL, expr);
  3591. return;
  3592. case no_persist_check:
  3593. buildWorkflowPersistCheck(ctx, expr);
  3594. return;
  3595. case no_childquery:
  3596. buildChildGraph(ctx, expr);
  3597. return;
  3598. case no_evaluate_stmt:
  3599. expr = expr->queryChild(0);
  3600. if (expr->queryValue())
  3601. return;
  3602. break; // evaluate default behaviour.
  3603. }
  3604. CHqlBoundExpr tgt;
  3605. buildAnyExpr(ctx, expr, tgt);
  3606. ctx.addExpr(tgt.expr);
  3607. tidyupExpr(ctx, tgt);
  3608. }
  3609. class AliasExpansionInfo
  3610. {
  3611. public:
  3612. void pushCondition(IHqlExpression * expr, unsigned branch) { conditions.append(*createAttribute(branchAtom, LINK(expr), getSizetConstant(branch))); }
  3613. void popCondition() { conditions.pop(); }
  3614. void popConditions(unsigned num) { conditions.popn(num); }
  3615. bool isConditional() { return conditions.ordinality() != 0; }
  3616. IHqlExpression * createConditionIntersection(IHqlExpression * prev)
  3617. {
  3618. if (conditions.ordinality() == 0)
  3619. return NULL;
  3620. if (!prev)
  3621. return createValueSafe(no_sortlist, makeSortListType(NULL), conditions);
  3622. unsigned maxPrev = prev->numChildren();
  3623. unsigned max = maxPrev;
  3624. if (max > conditions.ordinality())
  3625. max = conditions.ordinality();
  3626. for (unsigned i=0; i < max; i++)
  3627. {
  3628. if (&conditions.item(i) != prev->queryChild(i))
  3629. {
  3630. if (i == 0)
  3631. return NULL;
  3632. return createValueSafe(no_sortlist, makeSortListType(NULL), conditions, 0, i);
  3633. }
  3634. }
  3635. if (max == maxPrev)
  3636. return LINK(prev);
  3637. return createValueSafe(no_sortlist, makeSortListType(NULL), conditions);
  3638. }
  3639. HqlExprArray conditions;
  3640. };
  3641. void HqlCppTranslator::doExpandAliases(BuildCtx & ctx, IHqlExpression * expr, AliasExpansionInfo & info)
  3642. {
  3643. IHqlExpression * prev = static_cast<IHqlExpression *>(expr->queryTransformExtra());
  3644. if (prev == expr)
  3645. return;
  3646. #ifdef USE_NEW_ALIAS_CODE
  3647. OwnedHqlExpr commonPath = info.createConditionIntersection(prev);
  3648. if (prev == commonPath)
  3649. return;
  3650. if (commonPath)
  3651. expr->setTransformExtra(commonPath);
  3652. else
  3653. expr->setTransformExtraUnlinked(expr);
  3654. node_operator op = expr->getOperator();
  3655. switch (op)
  3656. {
  3657. //MORE: Anything that creates a child query shouldn't be included here...
  3658. case no_select:
  3659. case NO_AGGREGATE:
  3660. case no_alias_scope:
  3661. break;
  3662. case no_alias:
  3663. {
  3664. IHqlExpression * value = expr->queryChild(0);
  3665. if ((commonPath == NULL) && !ctx.queryMatchExpr(value))
  3666. {
  3667. if (containsAliasLocally(value) && !expr->hasAttribute(globalAtom))
  3668. doExpandAliases(ctx, value, info);
  3669. doBuildExprAlias(ctx, expr, NULL, &info);
  3670. }
  3671. break;
  3672. }
  3673. case no_and:
  3674. case no_or:
  3675. {
  3676. HqlExprArray args;
  3677. expr->unwindList(args, op);
  3678. doExpandAliases(ctx, &args.item(0), info);
  3679. unsigned max = args.ordinality();
  3680. for (unsigned i=1; i < max; i++)
  3681. {
  3682. info.pushCondition(expr, i);
  3683. doExpandAliases(ctx, &args.item(i), info);
  3684. }
  3685. info.popConditions(max-1);
  3686. break;
  3687. }
  3688. case no_if:
  3689. {
  3690. doExpandAliases(ctx, expr->queryChild(0), info);
  3691. info.pushCondition(expr, 1);
  3692. doExpandAliases(ctx, expr->queryChild(1), info);
  3693. info.popCondition();
  3694. info.pushCondition(expr, 2);
  3695. doExpandAliases(ctx, expr->queryChild(2), info);
  3696. info.popCondition();
  3697. break;
  3698. }
  3699. case no_case:
  3700. {
  3701. doExpandAliases(ctx, expr->queryChild(0), info);
  3702. unsigned max = expr->numChildren();
  3703. for (unsigned i=1; i < max-1; i++)
  3704. {
  3705. info.pushCondition(expr, i*2);
  3706. doExpandAliases(ctx, expr->queryChild(i)->queryChild(0), info);
  3707. info.popCondition();
  3708. info.pushCondition(expr, i*2+1);
  3709. doExpandAliases(ctx, expr->queryChild(i)->queryChild(1), info);
  3710. info.popCondition();
  3711. }
  3712. info.pushCondition(expr, (max-1)*2);
  3713. doExpandAliases(ctx, expr->queryChild(max-1), info);
  3714. info.popCondition();
  3715. break;
  3716. }
  3717. case no_map:
  3718. {
  3719. //The following is equivalent to old, code; I'm not sure it is the best implementation
  3720. unsigned max = expr->numChildren();
  3721. for (unsigned i=0; i < max-1; i++)
  3722. {
  3723. info.pushCondition(expr, i*2);
  3724. doExpandAliases(ctx, expr->queryChild(i)->queryChild(0), info);
  3725. info.popCondition();
  3726. info.pushCondition(expr, i*2+1);
  3727. doExpandAliases(ctx, expr->queryChild(i)->queryChild(1), info);
  3728. info.popCondition();
  3729. }
  3730. info.pushCondition(expr, (max-1)*2);
  3731. doExpandAliases(ctx, expr->queryChild(max-1), info);
  3732. info.popCondition();
  3733. break;
  3734. }
  3735. default:
  3736. if (containsAliasLocally(expr))
  3737. {
  3738. ForEachChild(i, expr)
  3739. doExpandAliases(ctx, expr->queryChild(i), info);
  3740. }
  3741. break;
  3742. }
  3743. #else
  3744. expr->setTransformExtraUnlinked(expr);
  3745. node_operator op = expr->getOperator();
  3746. switch (op)
  3747. {
  3748. //MORE: Anything that creates a child query shouldn't be included here...
  3749. case no_select:
  3750. case NO_AGGREGATE:
  3751. case no_alias_scope:
  3752. break;
  3753. case no_alias:
  3754. {
  3755. doBuildExprAlias(ctx, expr, NULL, &info);
  3756. break;
  3757. }
  3758. default:
  3759. if (containsAliasLocally(expr))
  3760. {
  3761. ForEachChild(i, expr)
  3762. doExpandAliases(ctx, expr->queryChild(i), info);
  3763. }
  3764. break;
  3765. }
  3766. #endif
  3767. }
  3768. void HqlCppTranslator::expandAliases(BuildCtx & ctx, IHqlExpression * expr, AliasExpansionInfo * parentInfo)
  3769. {
  3770. if (containsAliasLocally(expr))
  3771. {
  3772. if (!parentInfo)
  3773. {
  3774. TransformMutexBlock block;
  3775. AliasExpansionInfo info;
  3776. doExpandAliases(ctx, expr, info);
  3777. }
  3778. else
  3779. doExpandAliases(ctx, expr, *parentInfo);
  3780. }
  3781. }
  3782. void HqlCppTranslator::expandAliasScope(BuildCtx & ctx, IHqlExpression * expr)
  3783. {
  3784. TransformMutexBlock block;
  3785. AliasExpansionInfo info;
  3786. unsigned max = expr->numChildren();
  3787. for (unsigned idx = 1; idx < max; idx++)
  3788. {
  3789. IHqlExpression * child = expr->queryChild(idx);
  3790. if (containsAliasLocally(child))
  3791. doExpandAliases(ctx, child, info);
  3792. }
  3793. }
  3794. //------------------------------------------------------------------------------
  3795. void HqlCppTranslator::gatherActiveCursors(BuildCtx & ctx, HqlExprCopyArray & activeRows)
  3796. {
  3797. AssociationIterator iter(ctx);
  3798. ForEach(iter)
  3799. {
  3800. HqlExprAssociation & cur = iter.get();
  3801. if (cur.isRowAssociation())
  3802. {
  3803. BoundRow & curRow = static_cast<BoundRow &>(cur);
  3804. if ((curRow.querySide() != no_self) && !curRow.isBuilder())
  3805. activeRows.append(*curRow.querySelector());
  3806. }
  3807. else if (cur.represents->getOperator() == no_counter)
  3808. activeRows.append(*cur.represents);
  3809. }
  3810. }
  3811. bool HqlCppTranslator::canEvaluateInContext(BuildCtx & ctx, IHqlExpression * expr)
  3812. {
  3813. HqlExprCopyArray cursors;
  3814. gatherActiveCursors(ctx, cursors);
  3815. return ::canEvaluateInScope(cursors, expr);
  3816. }
  3817. bool mustEvaluateInContext(BuildCtx & ctx, IHqlExpression * expr)
  3818. {
  3819. HqlExprCopyArray required;
  3820. expr->gatherTablesUsed(required);
  3821. if (required.ordinality() == 0)
  3822. return false;
  3823. HqlExprCopyArray activeRows;
  3824. HqlExprCopyArray inheritedRows;
  3825. RowAssociationIterator iter(ctx);
  3826. ForEach(iter)
  3827. {
  3828. BoundRow & cur = iter.get();
  3829. if ((cur.querySide() != no_self) && !cur.isBuilder())
  3830. {
  3831. IHqlExpression * selector = cur.querySelector();
  3832. if (cur.isInherited())
  3833. inheritedRows.append(*selector);
  3834. else if (!cur.isSerialization())
  3835. activeRows.append(*selector);
  3836. }
  3837. }
  3838. //Ensure all instances of activeRows which match the inherited rows are removed
  3839. ForEachItemInRev(i, activeRows)
  3840. {
  3841. if (inheritedRows.contains(activeRows.item(i)))
  3842. activeRows.remove(i);
  3843. }
  3844. //If any of the selectors required by the expression are defined locally then the meaning will change if is moved
  3845. ForEachItemIn(iReq, required)
  3846. {
  3847. if (activeRows.contains(required.item(iReq)))
  3848. return true;
  3849. }
  3850. return false;
  3851. }
  3852. bool filterIsTableInvariant(IHqlExpression * expr)
  3853. {
  3854. IHqlExpression * dsSelector = expr->queryChild(0)->queryNormalizedSelector();
  3855. ForEachChildFrom(i, expr, 1)
  3856. {
  3857. IHqlExpression * cur = expr->queryChild(i);
  3858. if (containsSelector(cur, dsSelector))
  3859. return false;
  3860. }
  3861. return true;
  3862. }
  3863. //-----------------------------------------------------------------------------
  3864. bool LoopInvariantHelper::getBestContext(BuildCtx & ctx, IHqlExpression * expr)
  3865. {
  3866. finished();
  3867. active = ctx.selectBestContext(expr);
  3868. return (active != NULL);
  3869. }
  3870. void LoopInvariantHelper::finished()
  3871. {
  3872. if (active)
  3873. {
  3874. active->mergeScopeWithContainer();
  3875. active = NULL;
  3876. }
  3877. }
  3878. //---------------------------------------------------------------------------
  3879. void HqlCppTranslator::buildBlockCopy(BuildCtx & ctx, IHqlExpression * tgt, CHqlBoundExpr & src)
  3880. {
  3881. OwnedHqlExpr size = getBoundSize(src);
  3882. if (!size->queryValue() || size->queryValue()->getIntValue() != 0)
  3883. {
  3884. HqlExprArray args;
  3885. args.append(*getPointer(tgt));
  3886. args.append(*getPointer(src.expr));
  3887. args.append(*size.getClear());
  3888. callProcedure(ctx, memcpyId, args);
  3889. }
  3890. }
  3891. void HqlCppTranslator::buildSimpleExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  3892. {
  3893. node_operator op = expr->getOperator();
  3894. bool simple = false;
  3895. switch (op)
  3896. {
  3897. case no_alias_scope:
  3898. {
  3899. expandAliasScope(ctx, expr);
  3900. buildSimpleExpr(ctx, expr->queryChild(0), tgt);
  3901. return;
  3902. }
  3903. case no_preservemeta:
  3904. buildSimpleExpr(ctx, expr->queryChild(0), tgt);
  3905. return;
  3906. case no_constant:
  3907. case no_variable:
  3908. case no_getresult: // gets forced into a variable.
  3909. case no_workunit_dataset: // gets forced into a variable.
  3910. case no_getgraphresult: // gets forced into a variable.
  3911. case no_alias:
  3912. case no_list:
  3913. case no_all:
  3914. case no_null:
  3915. case no_id2blob:
  3916. case no_rows:
  3917. case no_libraryinput:
  3918. simple = true;
  3919. break;
  3920. case no_compound:
  3921. buildStmt(ctx, expr->queryChild(0));
  3922. buildSimpleExpr(ctx, expr->queryChild(1), tgt);
  3923. return;
  3924. case no_field:
  3925. throwUnexpected();
  3926. case no_select:
  3927. {
  3928. CHqlBoundExpr bound;
  3929. buildCachedExpr(ctx, expr, bound);
  3930. if (isSimpleTranslatedExpr(bound.expr))
  3931. tgt.set(bound);
  3932. else
  3933. {
  3934. OwnedHqlExpr trans = bound.getTranslatedExpr();
  3935. buildTempExpr(ctx, trans, tgt);
  3936. }
  3937. return;
  3938. }
  3939. break; // should depend on whether conditional etc....
  3940. case no_translated:
  3941. simple = isSimpleTranslatedExpr(expr->queryChild(0));
  3942. break;
  3943. case no_substring:
  3944. {
  3945. SubStringInfo info(expr);
  3946. if (info.canGenerateInline() || expr->hasAttribute(quickAtom))
  3947. simple = true;
  3948. break;
  3949. }
  3950. case no_cast:
  3951. case no_implicitcast:
  3952. {
  3953. //special case casting a string to (string) - saves lots of temporaries.
  3954. ITypeInfo * exprType = expr->queryType();
  3955. IHqlExpression * child = expr->queryChild(0);
  3956. ITypeInfo * childType = child->queryType();
  3957. if ((exprType->getTypeCode() == type_string) && (exprType->getSize() == UNKNOWN_LENGTH))
  3958. {
  3959. if ((childType->getTypeCode() == type_string) && (exprType->queryCharset() == childType->queryCharset()))
  3960. {
  3961. buildSimpleExpr(ctx, child, tgt);
  3962. return;
  3963. }
  3964. }
  3965. if (options.foldConstantCast && (child->getOperator() == no_constant))
  3966. simple = true;
  3967. break;
  3968. }
  3969. case no_sizeof:
  3970. case no_offsetof:
  3971. simple = true;
  3972. break;
  3973. case no_regex_find:
  3974. simple = expr->isBoolean();
  3975. break;
  3976. case no_call:
  3977. case no_externalcall:
  3978. {
  3979. ITypeInfo * type = expr->queryType();
  3980. switch (type->getTypeCode())
  3981. {
  3982. case type_set:
  3983. simple = true;
  3984. break;
  3985. case type_string:
  3986. case type_data:
  3987. case type_qstring:
  3988. if (type->getSize() == UNKNOWN_LENGTH)
  3989. simple = true;
  3990. break;
  3991. }
  3992. }
  3993. }
  3994. if (simple)
  3995. buildCachedExpr(ctx, expr, tgt);
  3996. else
  3997. buildTempExpr(ctx, expr, tgt);
  3998. }
  3999. IHqlExpression * HqlCppTranslator::buildSimplifyExpr(BuildCtx & ctx, IHqlExpression * expr)
  4000. {
  4001. node_operator op = expr->getOperator();
  4002. switch (op)
  4003. {
  4004. case no_constant:
  4005. case no_all:
  4006. case no_null:
  4007. return LINK(expr);
  4008. case no_list:
  4009. if (expr->isConstant())
  4010. return LINK(expr);
  4011. break;
  4012. }
  4013. CHqlBoundExpr bound;
  4014. buildSimpleExpr(ctx, expr, bound);
  4015. return bound.getTranslatedExpr();
  4016. }
  4017. /* In type: not linked. Return: linked */
  4018. IHqlExpression * HqlCppTranslator::createWrapperTemp(BuildCtx & ctx, ITypeInfo * type, typemod_t modifier)
  4019. {
  4020. Linked<ITypeInfo> rawType = queryUnqualifiedType(type);
  4021. if (hasStreamedModifier(type))
  4022. rawType.setown(setStreamedAttr(rawType, true));
  4023. else if (hasLinkCountedModifier(type))
  4024. rawType.setown(makeAttributeModifier(rawType.getClear(), getLinkCountedAttr()));
  4025. Owned<ITypeInfo> declType = makeWrapperModifier(rawType.getClear());
  4026. declType.setown(makeModifier(declType.getClear(), modifier));
  4027. switch (declType->getTypeCode())
  4028. {
  4029. case type_set: //needed if we have sets with link counted elements
  4030. case type_row:
  4031. case type_array:
  4032. case type_dictionary:
  4033. case type_table:
  4034. case type_groupedtable:
  4035. //Ensure row and dataset temporaries are active throughout a function, so pointers to the row
  4036. //or rows within a dataset remain valid (e.g., outside conditions).
  4037. if ((modifier != typemod_member) && ctx.queryMatchExpr(queryConditionalRowMarker()))
  4038. ctx.setNextPriority(BuildCtx::OutermostScopePrio);
  4039. break;
  4040. }
  4041. return ctx.getTempDeclare(declType, NULL);
  4042. }
  4043. void HqlCppTranslator::createTempFor(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundTarget & target)
  4044. {
  4045. createTempFor(ctx, expr->queryType(), target, typemod_none, FormatNatural);
  4046. }
  4047. void HqlCppTranslator::createTempFor(BuildCtx & ctx, ITypeInfo * _exprType, CHqlBoundTarget & target, typemod_t modifier, ExpressionFormat format)
  4048. {
  4049. Owned<ITypeInfo> exprType = makeModifier(LINK(_exprType->queryPromotedType()), modifier);
  4050. type_t tc = exprType->getTypeCode();
  4051. switch (tc)
  4052. {
  4053. case type_array:
  4054. case type_dictionary:
  4055. case type_table:
  4056. case type_groupedtable:
  4057. {
  4058. if (format == FormatStreamedDataset || hasStreamedModifier(exprType))
  4059. {
  4060. }
  4061. else
  4062. {
  4063. if (recordRequiresLinkCount(::queryRecord(exprType)) || hasLinkCountedModifier(_exprType))
  4064. {
  4065. assertex(format != FormatBlockedDataset);
  4066. format = FormatLinkedDataset;
  4067. }
  4068. else if (format == FormatNatural)
  4069. format = FormatLinkedDataset;
  4070. }
  4071. break;
  4072. }
  4073. }
  4074. switch (format)
  4075. {
  4076. case FormatBlockedDataset:
  4077. exprType.setown(setLinkCountedAttr(exprType, false));
  4078. break;
  4079. case FormatLinkedDataset:
  4080. case FormatArrayDataset:
  4081. exprType.setown(setLinkCountedAttr(exprType, true));
  4082. break;
  4083. case FormatStreamedDataset:
  4084. exprType.setown(setStreamedAttr(exprType, true));
  4085. break;
  4086. case FormatNatural:
  4087. if (hasStreamedModifier(exprType))
  4088. format = FormatStreamedDataset;
  4089. else if (hasLinkCountedModifier(exprType))
  4090. format = FormatLinkedDataset;
  4091. else
  4092. format = FormatBlockedDataset;
  4093. break;
  4094. }
  4095. size32_t size = exprType->getSize();
  4096. if (size == UNKNOWN_LENGTH)
  4097. {
  4098. switch (tc)
  4099. {
  4100. case type_string:
  4101. case type_data:
  4102. case type_qstring:
  4103. case type_unicode:
  4104. case type_utf8:
  4105. {
  4106. OwnedITypeInfo lenType = makeModifier(LINK(sizetType), modifier);
  4107. target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
  4108. target.length.setown(ctx.getTempDeclare(lenType, NULL));
  4109. break;
  4110. }
  4111. case type_varstring:
  4112. case type_varunicode:
  4113. {
  4114. target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
  4115. break;
  4116. }
  4117. case type_set:
  4118. case type_array:
  4119. case type_table:
  4120. case type_groupedtable:
  4121. case type_dictionary:
  4122. case type_row:
  4123. break;
  4124. default:
  4125. {
  4126. UNIMPLEMENTED;
  4127. break;
  4128. }
  4129. }
  4130. }
  4131. else if (size > MAX_SIMPLE_VAR_SIZE)
  4132. {
  4133. switch (tc)
  4134. {
  4135. case type_string:
  4136. case type_data:
  4137. case type_qstring:
  4138. case type_unicode:
  4139. case type_varstring:
  4140. case type_varunicode:
  4141. case type_utf8:
  4142. {
  4143. target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
  4144. break;
  4145. }
  4146. }
  4147. }
  4148. switch (tc)
  4149. {
  4150. case type_set:
  4151. {
  4152. OwnedITypeInfo isAllType = makeModifier(LINK(boolType), modifier);
  4153. target.isAll.setown(ctx.getTempDeclare(isAllType, NULL));
  4154. }
  4155. //fall through
  4156. case type_array:
  4157. case type_table:
  4158. case type_groupedtable:
  4159. case type_dictionary:
  4160. {
  4161. OwnedITypeInfo lenType = makeModifier(LINK(sizetType), modifier);
  4162. target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
  4163. if (!hasStreamedModifier(exprType))
  4164. {
  4165. if (isArrayRowset(exprType))
  4166. {
  4167. //A bit of a hack, but the cleanest I could come up with... really access to the count member should be wrapped in
  4168. //member functions, but getting them created needs a whole new level of complication (probably moving out out of hqlwcpp)
  4169. StringBuffer name;
  4170. target.expr->toString(name).append(".count");
  4171. target.count.setown(createVariable(name, LINK(lenType)));
  4172. }
  4173. else
  4174. target.length.setown(ctx.getTempDeclare(lenType, NULL));
  4175. break;
  4176. }
  4177. }
  4178. }
  4179. if (!target.expr)
  4180. {
  4181. target.expr.setown(ctx.getTempDeclare(exprType, NULL));
  4182. }
  4183. }
  4184. void HqlCppTranslator::buildTempExpr(BuildCtx & ctx, BuildCtx & declareCtx, CHqlBoundTarget & tempTarget, IHqlExpression * expr, ExpressionFormat format, bool ignoreSetAll)
  4185. {
  4186. if (options.addLocationToCpp && !options.obfuscateOutput)
  4187. {
  4188. IHqlExpression * location = queryLocation(expr);
  4189. if (location)
  4190. {
  4191. StringBuffer s;
  4192. s.append("// ").append(str(location->querySourcePath())).append("(").append(location->getStartLine()).append(",").append(location->getStartColumn()).append(") ").append(expr->queryName());
  4193. ctx.addQuoted(s);
  4194. }
  4195. else if (expr->queryName())
  4196. {
  4197. StringBuffer s;
  4198. s.append("// ").append(expr->queryName());
  4199. ctx.addQuoted(s);
  4200. }
  4201. }
  4202. typemod_t modifier = !ctx.isSameLocation(declareCtx) ? typemod_member : typemod_none;
  4203. OwnedITypeInfo type = makeModifier(expr->getType(), modifier);
  4204. BuildCtx subctx(ctx);
  4205. switch (type->getTypeCode())
  4206. {
  4207. case type_row:
  4208. {
  4209. Owned<BoundRow> tempRow = declareTempRow(declareCtx, subctx, expr);
  4210. buildRowAssign(subctx, tempRow, expr);
  4211. tempTarget.expr.set(tempRow->queryBound());
  4212. ctx.associate(*tempRow);
  4213. break;
  4214. }
  4215. break;
  4216. case type_table:
  4217. case type_groupedtable:
  4218. case type_dictionary:
  4219. {
  4220. createTempFor(declareCtx, type, tempTarget, modifier, format);
  4221. TemporaryGroup group(subctx);
  4222. buildDatasetAssign(subctx, tempTarget, expr);
  4223. break;
  4224. }
  4225. default:
  4226. {
  4227. createTempFor(declareCtx, type, tempTarget, modifier, format);
  4228. if (ignoreSetAll)
  4229. tempTarget.isAll.clear();
  4230. TemporaryGroup group(subctx);
  4231. buildExprAssign(subctx, tempTarget, expr);
  4232. break;
  4233. }
  4234. }
  4235. }
  4236. void HqlCppTranslator::buildTempExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
  4237. {
  4238. node_operator op = expr->getOperator();
  4239. if (op == no_alias)
  4240. {
  4241. doBuildExprAlias(ctx, expr, &tgt, NULL);
  4242. //very unusually an alias may generate a function call (e.g., for an int6 - this ensures it is forced into a variable).
  4243. if (!hasAddress(ctx, tgt.expr))
  4244. ensureHasAddress(ctx, tgt);
  4245. return;
  4246. }
  4247. if (isCast(expr))
  4248. {
  4249. ITypeInfo * exprType = expr->queryType();
  4250. if (exprType->getStringLen() == UNKNOWN_LENGTH)
  4251. {
  4252. unsigned bestLen = getBestLengthEstimate(expr);
  4253. if (bestLen != UNKNOWN_LENGTH)
  4254. {
  4255. IHqlExpression * uncast = expr->queryChild(0);
  4256. Owned<ITypeInfo> stretchedType = getStretchedType(bestLen, exprType);
  4257. OwnedHqlExpr castExpr = ensureExprType(uncast, stretchedType);
  4258. buildTempExpr(ctx, castExpr, tgt, format);
  4259. ctx.associateExpr(expr, tgt);
  4260. return;
  4261. }
  4262. }
  4263. }
  4264. BuildCtx bestctx(ctx);
  4265. if (expr->isPure() && ctx.getMatchExpr(expr, tgt))
  4266. return;
  4267. switch (expr->getOperator())
  4268. {
  4269. case no_variable:
  4270. tgt.expr.set(expr);
  4271. return;
  4272. case no_translated:
  4273. {
  4274. if (!expr->queryChild(1))
  4275. {
  4276. IHqlExpression * value = expr->queryChild(0);
  4277. if (value->getOperator() == no_variable)
  4278. {
  4279. tgt.expr.set(value);
  4280. return;
  4281. }
  4282. }
  4283. break;
  4284. }
  4285. case no_getresult:
  4286. case no_deserialize:
  4287. if (expr->isDatarow())
  4288. {
  4289. buildAnyExpr(ctx, expr, tgt);
  4290. return;
  4291. }
  4292. break;
  4293. case no_id2blob:
  4294. buildExpr(ctx, expr, tgt);
  4295. return;
  4296. case no_call:
  4297. if (!isEmbedCall(expr))
  4298. break;
  4299. //fall through
  4300. case no_externalcall:
  4301. if (format == FormatNatural && expr->isDataset())
  4302. {
  4303. ITypeInfo * exprType = expr->queryType();
  4304. if (hasStreamedModifier(exprType))
  4305. format = FormatStreamedDataset;
  4306. else if (hasLinkCountedModifier(exprType) || hasOutOfLineModifier(exprType))
  4307. format = FormatLinkedDataset;
  4308. else
  4309. format = FormatBlockedDataset;
  4310. }
  4311. break;
  4312. }
  4313. LoopInvariantHelper helper;
  4314. if (options.optimizeLoopInvariant)
  4315. helper.getBestContext(bestctx, expr);
  4316. bool canBeAll = canSetBeAll(expr);
  4317. CHqlBoundTarget tempTarget;
  4318. buildTempExpr(bestctx, bestctx, tempTarget, expr, format, !canBeAll);
  4319. tgt.setFromTarget(tempTarget);
  4320. bestctx.associateExpr(expr, tgt);
  4321. }
  4322. void HqlCppTranslator::buildExprViaTypedTemp(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ITypeInfo * type)
  4323. {
  4324. OwnedHqlExpr cast = createValue(no_implicitcast, LINK(type), LINK(expr));
  4325. if (cast->isPure() && ctx.getMatchExpr(cast, tgt))
  4326. return;
  4327. LoopInvariantHelper helper;
  4328. BuildCtx bestctx(ctx);
  4329. if (options.optimizeLoopInvariant)
  4330. helper.getBestContext(bestctx, expr);
  4331. CHqlBoundTarget tempTarget;
  4332. createTempFor(bestctx, type, tempTarget, typemod_none, FormatNatural);
  4333. buildExprAssign(bestctx, tempTarget, expr);
  4334. tgt.setFromTarget(tempTarget);
  4335. if (cast->isPure())
  4336. bestctx.associateExpr(cast, tgt);
  4337. }
  4338. void HqlCppTranslator::buildExprEnsureType(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ITypeInfo * type)
  4339. {
  4340. if (queryUnqualifiedType(expr->queryType()) != queryUnqualifiedType(type))
  4341. buildExprViaTypedTemp(ctx, expr, tgt, type);
  4342. else
  4343. buildExpr(ctx, expr, tgt);
  4344. }
  4345. AliasKind HqlCppTranslator::doBuildAliasValue(BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt, AliasExpansionInfo * parentInfo)
  4346. {
  4347. //can happen when this is called for non no_alias arguments
  4348. if (value->getOperator() == no_alias)
  4349. value = value->queryChild(0);
  4350. EvalContext * instance = queryEvalContext(ctx);
  4351. if (instance)
  4352. return instance->evaluateExpression(ctx, value, tgt, true);
  4353. expandAliases(ctx, value, parentInfo);
  4354. buildTempExpr(ctx, value, tgt);
  4355. return RuntimeAlias;
  4356. }
  4357. void HqlCppTranslator::doBuildExprAlias(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * tgt, AliasExpansionInfo * parentInfo)
  4358. {
  4359. //MORE These will be declared in a different context later.
  4360. IHqlExpression * value = expr->queryChild(0);
  4361. while (value->getOperator() == no_alias)
  4362. value = value->queryChild(0);
  4363. CHqlBoundExpr bound;
  4364. if (!tgt)
  4365. tgt = &bound;
  4366. //The second half of this test could cause aliases to be duplicated, but has the significant effect of reducing the amount of data that is serialised.
  4367. //so far on my examples it does the latter, but doesn't seem to cause the former
  4368. if (expr->hasAttribute(localAtom) || (insideOnCreate(ctx) && !expr->hasAttribute(globalAtom)))
  4369. {
  4370. expandAliases(ctx, value, parentInfo);
  4371. switch (value->getOperator())
  4372. {
  4373. // these operations generate temporaries anyway, and the row versions are inefficient via a buildTempExpr
  4374. case no_getresult:
  4375. case no_getgraphresult:
  4376. case no_getgraphloopresult:
  4377. buildAnyExpr(ctx, value, *tgt);
  4378. break;
  4379. default:
  4380. buildTempExpr(ctx, value, *tgt);
  4381. break;
  4382. }
  4383. }
  4384. else
  4385. {
  4386. doBuildAliasValue(ctx, value, *tgt, parentInfo);
  4387. }
  4388. }
  4389. void HqlCppTranslator::doBuildBoolAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4390. {
  4391. if (requiresTemp(ctx, expr, true))
  4392. {
  4393. BuildCtx subctx(ctx);
  4394. assignBound(subctx, target, queryBoolExpr(false));
  4395. buildFilter(subctx, expr);
  4396. assignBound(subctx, target, queryBoolExpr(true));
  4397. }
  4398. else
  4399. {
  4400. CHqlBoundExpr temp;
  4401. buildCachedExpr(ctx, expr, temp);
  4402. assign(ctx, target, temp);
  4403. }
  4404. }
  4405. void HqlCppTranslator::doBuildExprAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4406. {
  4407. CHqlBoundExpr temp;
  4408. buildExpr(ctx, expr, temp);
  4409. assign(ctx, target, temp);
  4410. }
  4411. void HqlCppTranslator::ensureSimpleExpr(BuildCtx & ctx, CHqlBoundExpr & tgt)
  4412. {
  4413. if (!isSimpleTranslatedExpr(tgt.expr))
  4414. {
  4415. OwnedHqlExpr bound = tgt.getTranslatedExpr();
  4416. buildTempExpr(ctx, bound, tgt);
  4417. }
  4418. }
  4419. IHqlExpression * HqlCppTranslator::ensureSimpleTranslatedExpr(BuildCtx & ctx, IHqlExpression * expr)
  4420. {
  4421. if (isSimpleTranslatedExpr(expr))
  4422. return LINK(expr);
  4423. OwnedHqlExpr translated = createTranslated(expr);
  4424. CHqlBoundExpr bound;
  4425. buildTempExpr(ctx, translated, bound);
  4426. return LINK(bound.expr);
  4427. }
  4428. void HqlCppTranslator::ensureHasAddress(BuildCtx & ctx, CHqlBoundExpr & tgt)
  4429. {
  4430. IHqlExpression * expr = tgt.expr;
  4431. node_operator op = expr->getOperator();
  4432. switch (op)
  4433. {
  4434. case no_deref:
  4435. case no_variable:
  4436. break;
  4437. default:
  4438. if (!isTypePassedByAddress(expr->queryType()) || (expr->getOperator() == no_decimalstack))
  4439. {
  4440. OwnedHqlExpr bound = tgt.getTranslatedExpr();
  4441. buildTempExpr(ctx, bound, tgt);
  4442. }
  4443. break;
  4444. }
  4445. }
  4446. //---------------------------------------------------------------------------
  4447. bool optimizeVarStringCompare(node_operator op, const CHqlBoundExpr & lhs, const CHqlBoundExpr & rhs, CHqlBoundExpr & tgt)
  4448. {
  4449. IHqlExpression * rhsExpr = rhs.expr;
  4450. if ((rhsExpr->getOperator() == no_constant) && (rhsExpr->queryType()->getStringLen() == 0))
  4451. {
  4452. if ((op == no_eq) || (op == no_ne))
  4453. {
  4454. tgt.expr.setown(createValue(op, LINK(boolType), createValue(no_deref, makeCharType(), lhs.expr.getLink()), getZero()));
  4455. return true;
  4456. }
  4457. }
  4458. return false;
  4459. }
  4460. void HqlCppTranslator::doBuildExprSetCompareAll(BuildCtx & ctx, IHqlExpression * set, CHqlBoundExpr & tgt, bool invert)
  4461. {
  4462. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, set);
  4463. cursor->buildIsAll(ctx, tgt);
  4464. if (invert)
  4465. tgt.expr.setown(getInverse(tgt.expr));
  4466. }
  4467. void HqlCppTranslator::doBuildExprSetCompareNone(BuildCtx & ctx, IHqlExpression * set, CHqlBoundExpr & tgt, bool invert)
  4468. {
  4469. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, set);
  4470. cursor->buildExists(ctx, tgt);
  4471. if (!invert)
  4472. tgt.expr.setown(getInverse(tgt.expr));
  4473. }
  4474. bool HqlCppTranslator::doBuildExprSetCompare(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  4475. {
  4476. //Special case comparison against all and null set. All other work goes through a the order code.
  4477. node_operator exprOp = expr->getOperator();
  4478. if ((exprOp == no_eq) || (exprOp == no_ne))
  4479. {
  4480. OwnedHqlExpr left = normalizeListCasts(expr->queryChild(0));
  4481. OwnedHqlExpr right = normalizeListCasts(expr->queryChild(1));
  4482. if (right->getOperator() == no_all)
  4483. doBuildExprSetCompareAll(ctx, left, tgt, exprOp==no_ne);
  4484. else if (left->getOperator() == no_all)
  4485. doBuildExprSetCompareAll(ctx, right, tgt, exprOp==no_ne);
  4486. else if (isNullList(right))
  4487. doBuildExprSetCompareNone(ctx, left, tgt, exprOp==no_ne);
  4488. else if (isNullList(left))
  4489. doBuildExprSetCompareNone(ctx, right, tgt, exprOp==no_ne);
  4490. else
  4491. return false;
  4492. return true;
  4493. }
  4494. return false;
  4495. }
  4496. IHqlExpression * HqlCppTranslator::convertBoundStringToChar(const CHqlBoundExpr & bound)
  4497. {
  4498. OwnedHqlExpr element = getElementPointer(bound.expr);
  4499. Owned<ITypeInfo> charType = makeCharType(true);
  4500. switch (element->getOperator())
  4501. {
  4502. case no_constant:
  4503. {
  4504. IValue * value = element->queryValue();
  4505. return createConstant(value->castTo(charType));
  4506. }
  4507. case no_address:
  4508. return LINK(element->queryChild(0));
  4509. }
  4510. return createValue(no_deref, charType.getClear(), element.getClear());
  4511. }
  4512. void HqlCppTranslator::doBuildExprCompare(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  4513. {
  4514. IHqlExpression * left = expr->queryChild(0);
  4515. IHqlExpression * right = expr->queryChild(1);
  4516. ITypeInfo * leftType = left->queryType()->queryPromotedType();
  4517. ITypeInfo * rightType = right->queryType()->queryPromotedType();
  4518. assertex(areTypesComparable(leftType,rightType));
  4519. OwnedHqlExpr orderExpr;
  4520. CHqlBoundExpr lhs, rhs;
  4521. node_operator compareOp = expr->getOperator();
  4522. type_t tc = leftType->getTypeCode();
  4523. switch (tc)
  4524. {
  4525. case type_string:
  4526. case type_data:
  4527. case type_qstring:
  4528. {
  4529. OwnedHqlExpr simpleLeft = getSimplifyCompareArg(left);
  4530. OwnedHqlExpr simpleRight = getSimplifyCompareArg(right);
  4531. HqlExprArray args;
  4532. buildCachedExpr(ctx, simpleLeft, lhs);
  4533. buildCachedExpr(ctx, simpleRight, rhs);
  4534. //update types - lengths may be constant by now..
  4535. leftType = lhs.queryType();
  4536. rightType = rhs.queryType();
  4537. IIdAtom * func = queryStrCompareFunc(leftType);
  4538. //MORE: Move blank string compare here?
  4539. if (lhs.length || rhs.length || needVarStringCompare(leftType, rightType))
  4540. {
  4541. args.append(*getBoundLength(lhs));
  4542. args.append(*getElementPointer(lhs.expr));
  4543. if (func == compareStrStrId && isBlankString(rhs.expr))
  4544. {
  4545. func = compareStrBlankId;
  4546. }
  4547. else
  4548. {
  4549. args.append(*getBoundLength(rhs));
  4550. args.append(*getElementPointer(rhs.expr));
  4551. }
  4552. orderExpr.setown(bindTranslatedFunctionCall(func, args));
  4553. }
  4554. else if (options.optimizeString1Compare &&
  4555. ((tc == type_string && isAscii(leftType)) || tc == type_data) &&
  4556. (leftType->getSize() == 1) && (rightType->getSize() == 1) &&
  4557. ((compareOp == no_eq) || (compareOp == no_ne)))
  4558. {
  4559. //Optimize equality/non equality of a single character string.
  4560. //Not done for > etc because of potential issues with signed/unsigned chars
  4561. args.append(*convertBoundStringToChar(lhs));
  4562. args.append(*convertBoundStringToChar(rhs));
  4563. tgt.expr.setown(createValue(compareOp, makeBoolType(), args));
  4564. return;
  4565. }
  4566. else
  4567. {
  4568. args.append(*getElementPointer(lhs.expr));
  4569. args.append(*getElementPointer(rhs.expr));
  4570. args.append(*getSizetConstant(leftType->getSize()));
  4571. orderExpr.setown(bindTranslatedFunctionCall(memcmpId, args));
  4572. }
  4573. break;
  4574. }
  4575. case type_unicode:
  4576. {
  4577. OwnedHqlExpr simpleLeft = LINK(left);//getSimplifyCompareArg(left);
  4578. OwnedHqlExpr simpleRight = LINK(right);//getSimplifyCompareArg(right);
  4579. HqlExprArray args;
  4580. buildCachedExpr(ctx, simpleLeft, lhs);
  4581. buildCachedExpr(ctx, simpleRight, rhs);
  4582. assertex(haveCommonLocale(leftType, rightType));
  4583. char const * locale = str(getCommonLocale(leftType, rightType));
  4584. args.append(*getBoundLength(lhs));
  4585. args.append(*getElementPointer(lhs.expr));
  4586. args.append(*getBoundLength(rhs));
  4587. args.append(*getElementPointer(rhs.expr));
  4588. args.append(*createConstant(locale));
  4589. orderExpr.setown(bindTranslatedFunctionCall(compareUnicodeUnicodeId, args));
  4590. break;
  4591. }
  4592. case type_varunicode:
  4593. {
  4594. HqlExprArray args;
  4595. buildCachedExpr(ctx, left, lhs);
  4596. buildCachedExpr(ctx, right, rhs);
  4597. assertex(haveCommonLocale(leftType, rightType));
  4598. char const * locale = str(getCommonLocale(leftType, rightType));
  4599. args.append(*getElementPointer(lhs.expr));
  4600. args.append(*getElementPointer(rhs.expr));
  4601. args.append(*createConstant(locale));
  4602. orderExpr.setown(bindTranslatedFunctionCall(compareVUnicodeVUnicodeId, args));
  4603. break;
  4604. }
  4605. case type_utf8:
  4606. {
  4607. OwnedHqlExpr simpleLeft = LINK(left);//getSimplifyCompareArg(left);
  4608. OwnedHqlExpr simpleRight = LINK(right);//getSimplifyCompareArg(right);
  4609. HqlExprArray args;
  4610. buildCachedExpr(ctx, simpleLeft, lhs);
  4611. buildCachedExpr(ctx, simpleRight, rhs);
  4612. assertex(haveCommonLocale(leftType, rightType));
  4613. char const * locale = str(getCommonLocale(leftType, rightType));
  4614. args.append(*getBoundLength(lhs));
  4615. args.append(*getElementPointer(lhs.expr));
  4616. args.append(*getBoundLength(rhs));
  4617. args.append(*getElementPointer(rhs.expr));
  4618. args.append(*createConstant(locale));
  4619. orderExpr.setown(bindTranslatedFunctionCall(compareUtf8Utf8Id, args));
  4620. break;
  4621. }
  4622. case type_varstring:
  4623. {
  4624. HqlExprArray args;
  4625. buildCachedExpr(ctx, left, lhs);
  4626. buildCachedExpr(ctx, right, rhs);
  4627. //optimize comparison against null string.
  4628. if (optimizeVarStringCompare(compareOp, lhs, rhs, tgt) || optimizeVarStringCompare(compareOp, rhs, lhs, tgt))
  4629. return;
  4630. args.append(*getElementPointer(lhs.expr));
  4631. args.append(*getElementPointer(rhs.expr));
  4632. orderExpr.setown(bindTranslatedFunctionCall(compareVStrVStrId, args));
  4633. break;
  4634. }
  4635. case type_decimal:
  4636. {
  4637. HqlExprArray args;
  4638. buildCachedExpr(ctx, left, lhs);
  4639. buildCachedExpr(ctx, right, rhs);
  4640. if (!isPushed(lhs) && !isPushed(rhs) && isSameBasicType(lhs.queryType(), rhs.queryType()))
  4641. {
  4642. args.append(*getSizetConstant(leftType->getSize()));
  4643. args.append(*getPointer(lhs.expr));
  4644. args.append(*getPointer(rhs.expr));
  4645. orderExpr.setown(bindTranslatedFunctionCall(leftType->isSigned() ? DecCompareDecimalId : DecCompareUDecimalId, args));
  4646. }
  4647. else
  4648. {
  4649. bool pushedLhs = ensurePushed(ctx, lhs);
  4650. bool pushedRhs = ensurePushed(ctx, rhs);
  4651. //NB: Arguments could be pushed in opposite order 1 <=> x *2
  4652. if (pushedLhs && !pushedRhs)
  4653. orderExpr.setown(bindTranslatedFunctionCall(DecDistinctRId, args));
  4654. else
  4655. orderExpr.setown(bindTranslatedFunctionCall(DecDistinctId, args));
  4656. }
  4657. break;
  4658. }
  4659. case type_set:
  4660. case type_array:
  4661. {
  4662. if (doBuildExprSetCompare(ctx, expr, tgt))
  4663. return;
  4664. //fallthrough....
  4665. }
  4666. case type_dictionary:
  4667. case type_table:
  4668. case type_groupedtable:
  4669. case type_row:
  4670. case type_record:
  4671. {
  4672. IHqlExpression * orderExpr = createValue(no_order, LINK(signedType), LINK(left), LINK(right));
  4673. OwnedHqlExpr cmpExpr = createBoolExpr(compareOp, orderExpr, createConstant(signedType->castFrom(true, 0)));
  4674. buildExpr(ctx, cmpExpr, tgt);
  4675. return;
  4676. }
  4677. case type_swapint:
  4678. case type_packedint:
  4679. {
  4680. Owned<ITypeInfo> type = makeIntType(leftType->getSize(), leftType->isSigned());
  4681. IHqlExpression * intLeft = createValue(no_implicitcast, type.getLink(), LINK(left));
  4682. IHqlExpression * intRight = createValue(no_implicitcast, type.getLink(), LINK(right));
  4683. OwnedHqlExpr transformed = createValue(compareOp, makeBoolType(), intLeft, intRight);
  4684. doBuildPureSubExpr(ctx, transformed, tgt);
  4685. return;
  4686. }
  4687. default:
  4688. doBuildPureSubExpr(ctx, expr, tgt);
  4689. return;
  4690. }
  4691. tgt.expr.setown(createValue(compareOp, LINK(boolType), LINK(orderExpr), createConstant(orderExpr->queryType()->castFrom(true, 0))));
  4692. }
  4693. //---------------------------------------------------------------------------
  4694. //-- no_and --
  4695. void HqlCppTranslator::doBuildFilterToTarget(BuildCtx & ctx, const CHqlBoundTarget & isOk, HqlExprArray & conds, bool invert)
  4696. {
  4697. LinkedHqlExpr test = isOk.expr;
  4698. if (invert)
  4699. test.setown(getInverse(test));
  4700. unsigned max = conds.ordinality();
  4701. unsigned curIndex = 0;
  4702. for (unsigned outer =0; curIndex < max; outer += MAX_NESTED_CASES)
  4703. {
  4704. BuildCtx subctx(ctx);
  4705. if (outer != 0)
  4706. subctx.addFilter(test);
  4707. buildExprAssign(subctx, isOk, queryBoolExpr(invert)); // if(!invert,false,true) => invert
  4708. doBuildFilterNextAndRange(subctx, curIndex, MAX_NESTED_CASES, conds);
  4709. buildExprAssign(subctx, isOk, queryBoolExpr(!invert)); // if(!invert,true,false) => !invert
  4710. }
  4711. }
  4712. void HqlCppTranslator::doBuildFilterAnd(BuildCtx & ctx, IHqlExpression * expr)
  4713. {
  4714. HqlExprArray conds;
  4715. expr->unwindList(conds, no_and);
  4716. //Estimate the depth generated by the conditions - it may be wrong because
  4717. //aliases generated in outer levels can stop temporaries being required later.
  4718. unsigned numConds = conds.ordinality();
  4719. unsigned depthEstimate = 1;
  4720. for (unsigned i=1; i < numConds; i++)
  4721. if (requiresTemp(ctx, &conds.item(i), true))
  4722. depthEstimate++;
  4723. if (depthEstimate < MAX_NESTED_CASES)
  4724. {
  4725. unsigned curIndex = 0;
  4726. doBuildFilterNextAndRange(ctx, curIndex, numConds, conds);
  4727. }
  4728. else
  4729. {
  4730. CHqlBoundTarget isOk;
  4731. createTempFor(ctx, expr, isOk);
  4732. doBuildFilterToTarget(ctx, isOk, conds, false);
  4733. ctx.addFilter(isOk.expr);
  4734. }
  4735. }
  4736. void HqlCppTranslator::doBuildFilterNextAndRange(BuildCtx & ctx, unsigned & curIndex, unsigned maxIterations, HqlExprArray & conds)
  4737. {
  4738. unsigned max = conds.ordinality();
  4739. for (unsigned i=0; (i < maxIterations) && (curIndex != max); i++)
  4740. {
  4741. unsigned last;
  4742. expandAliases(ctx, &conds.item(curIndex), NULL);
  4743. for (last = curIndex+1; last < max; last++)
  4744. if (requiresTemp(ctx, &conds.item(last), true))
  4745. break;
  4746. doBuildFilterAndRange(ctx, curIndex, last, conds);
  4747. curIndex = last;
  4748. }
  4749. }
  4750. void HqlCppTranslator::doBuildFilterAndRange(BuildCtx & ctx, unsigned first, unsigned last, HqlExprArray & conds)
  4751. {
  4752. if (first+1 == last)
  4753. buildFilter(ctx, &conds.item(first));
  4754. else
  4755. {
  4756. HqlExprArray args;
  4757. for (unsigned k = first; k < last; k++)
  4758. args.append(OLINK(conds.item(k)));
  4759. OwnedHqlExpr test = createValue(no_and, makeBoolType(), args);
  4760. buildFilterViaExpr(ctx, test);
  4761. }
  4762. }
  4763. void HqlCppTranslator::doBuildAssignAnd(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, bool invert)
  4764. {
  4765. HqlExprArray conds;
  4766. expr->unwindList(conds, no_and);
  4767. doBuildFilterToTarget(ctx, target, conds, invert);
  4768. }
  4769. void HqlCppTranslator::doBuildAssignOr(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4770. {
  4771. BuildCtx subctx(ctx);
  4772. HqlExprArray conds;
  4773. expr->unwindList(conds, no_or);
  4774. unsigned first = 0;
  4775. unsigned max = conds.ordinality();
  4776. while (first < max)
  4777. {
  4778. unsigned last = first+1;
  4779. //special case no_in because it always creates a temporary, so may as well assign on its own
  4780. if (conds.item(first).getOperator() != no_in)
  4781. {
  4782. for (; last < max; last++)
  4783. {
  4784. IHqlExpression & cur = conds.item(last);
  4785. if ((cur.getOperator() == no_in) || requiresTemp(subctx, &cur, true))
  4786. break;
  4787. }
  4788. }
  4789. if (first != 0 || last != max)
  4790. {
  4791. if (last != first+1)
  4792. {
  4793. OwnedHqlExpr left = createBalanced(no_or, queryBoolType(), conds, first, last);
  4794. doBuildExprAssign(subctx, target, left);
  4795. }
  4796. else
  4797. buildExprAssign(subctx, target, &conds.item(first));
  4798. if (last != max)
  4799. {
  4800. OwnedHqlExpr inverse = getInverse(target.expr);
  4801. subctx.addFilter(inverse);
  4802. }
  4803. }
  4804. else
  4805. {
  4806. doBuildExprAssign(subctx, target, expr);
  4807. }
  4808. first = last;
  4809. }
  4810. }
  4811. //---------------------------------------------------------------------------
  4812. //-- no_case --
  4813. void HqlCppTranslator::doBuildCaseInfo(IHqlExpression * expr, HqlCppCaseInfo & info)
  4814. {
  4815. unsigned maxMaps = expr->numChildren()-1;
  4816. unsigned index = 0;
  4817. if (expr->getOperator() == no_case)
  4818. {
  4819. info.setCond(expr->queryChild(0));
  4820. index++;
  4821. }
  4822. for (;index<maxMaps;index++)
  4823. info.addPair(expr->queryChild(index));
  4824. info.setDefault(expr->queryChild(maxMaps));
  4825. }
  4826. void HqlCppTranslator::doBuildInCaseInfo(IHqlExpression * expr, HqlCppCaseInfo & info, IHqlExpression * normalized)
  4827. {
  4828. bool valueIfMatch = (expr->getOperator() == no_in);
  4829. HqlExprArray args;
  4830. LinkedHqlExpr values = normalized;
  4831. if (!normalized)
  4832. values.setown(normalizeListCasts(expr->queryChild(1)));
  4833. info.setCond(expr->queryChild(0));
  4834. cvtInListToPairs(args, values, valueIfMatch);
  4835. info.addPairs(args);
  4836. info.setDefault(queryBoolExpr(!valueIfMatch));
  4837. }
  4838. void HqlCppTranslator::doBuildAssignInStored(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4839. {
  4840. OwnedHqlExpr values = normalizeListCasts(expr->queryChild(1));
  4841. CHqlBoundExpr bound;
  4842. if (values->isPure())
  4843. ctx.getMatchExpr(values, bound);
  4844. if (options.optimizeLoopInvariant && !bound.expr)
  4845. {
  4846. if (values->getOperator() == no_createset)
  4847. {
  4848. IHqlExpression * ds = values->queryChild(0);
  4849. //MORE: This is a special case - it should check if the dataset can be iterated without any projection
  4850. switch (ds->getOperator())
  4851. {
  4852. case no_select:
  4853. case no_rows:
  4854. break;
  4855. default:
  4856. {
  4857. //Evaluate the dataset into a temporary - the iterator will match it up later
  4858. //Evaluating the dataset instead of the set since this is likely to avoid a memcpy with link counted rows enabled.
  4859. LoopInvariantHelper helper;
  4860. BuildCtx bestctx(ctx);
  4861. if (helper.getBestContext(bestctx, ds))
  4862. {
  4863. CHqlBoundExpr temp;
  4864. buildTempExpr(ctx, ds, temp);
  4865. }
  4866. break;
  4867. }
  4868. }
  4869. }
  4870. else
  4871. {
  4872. LoopInvariantHelper helper;
  4873. BuildCtx bestctx(ctx);
  4874. if (helper.getBestContext(bestctx, values))
  4875. {
  4876. //Unfortunately this will do strength reduction again, but shouldn't take too long.
  4877. buildTempExpr(bestctx, values, bound);
  4878. }
  4879. }
  4880. }
  4881. if (bound.expr)
  4882. values.setown(bound.getTranslatedExpr());
  4883. bool valueIfMatch = (expr->getOperator() == no_in);
  4884. ITypeInfo * elementType = values->queryType()->queryChildType();
  4885. Owned<ITypeInfo> compareType = getPromotedECLCompareType(expr->queryChild(0)->queryType(), elementType);
  4886. CHqlBoundExpr boundSearch;
  4887. OwnedHqlExpr castSearch = ensureExprType(expr->queryChild(0), compareType);
  4888. BuildCtx subctx(ctx);
  4889. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, values);
  4890. CHqlBoundExpr isAll;
  4891. cursor->buildIsAll(ctx, isAll);
  4892. if (isAll.expr->queryValue())
  4893. {
  4894. if (isAll.expr->queryValue()->getBoolValue())
  4895. {
  4896. buildExprAssign(subctx, target, queryBoolExpr(valueIfMatch));
  4897. //If this inverted the test we would need to do more.
  4898. return;
  4899. }
  4900. }
  4901. else
  4902. {
  4903. IHqlStmt * stmt = subctx.addFilter(isAll.expr);
  4904. buildExprAssign(subctx, target, queryBoolExpr(valueIfMatch));
  4905. subctx.selectElse(stmt);
  4906. }
  4907. //result = false/true
  4908. buildSimpleExpr(subctx, castSearch, boundSearch);
  4909. buildExprAssign(subctx, target, queryBoolExpr(!valueIfMatch));
  4910. //iterate through the set
  4911. bool needToBreak = !cursor->isSingleValued();
  4912. CHqlBoundExpr boundCurElement;
  4913. cursor->buildIterateLoop(subctx, boundCurElement, needToBreak);
  4914. OwnedHqlExpr curElement = boundCurElement.getTranslatedExpr();
  4915. OwnedHqlExpr castCurElement = ensureExprType(curElement, compareType);
  4916. //if match then
  4917. OwnedHqlExpr matchTest = createValue(no_eq, makeBoolType(), boundSearch.getTranslatedExpr(), LINK(castCurElement));
  4918. buildFilter(subctx, matchTest);
  4919. //result = true/false + break loop.
  4920. buildExprAssign(subctx, target, queryBoolExpr(valueIfMatch));
  4921. if (needToBreak)
  4922. subctx.addBreak();
  4923. }
  4924. void HqlCppTranslator::doBuildAssignInCreateSet(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4925. {
  4926. IHqlExpression * setExpr = expr->queryChild(1);
  4927. IHqlExpression * dataset = setExpr->queryChild(0);
  4928. IHqlExpression * selected = setExpr->queryChild(1);
  4929. bool valueIfMatch = (expr->getOperator() == no_in);
  4930. ITypeInfo * elementType = setExpr->queryType()->queryChildType();
  4931. Owned<ITypeInfo> compareType = getPromotedECLCompareType(expr->queryChild(0)->queryType(), elementType);
  4932. CHqlBoundExpr boundSearch;
  4933. OwnedHqlExpr castSearch = ensureExprType(expr->queryChild(0), compareType);
  4934. //result = false/true
  4935. buildSimpleExpr(ctx, castSearch, boundSearch);
  4936. buildExprAssign(ctx, target, queryBoolExpr(!valueIfMatch));
  4937. //iterate through the set
  4938. bool needToBreak = !hasNoMoreRowsThan(dataset, 1);
  4939. BuildCtx loopctx(ctx);
  4940. buildDatasetIterate(loopctx, dataset, needToBreak);
  4941. //if match then
  4942. OwnedHqlExpr matchTest = createValue(no_eq, makeBoolType(), boundSearch.getTranslatedExpr(), ensureExprType(selected, compareType));
  4943. buildFilter(loopctx, matchTest);
  4944. //result = true/false + break loop.
  4945. buildExprAssign(loopctx, target, queryBoolExpr(valueIfMatch));
  4946. if (needToBreak)
  4947. loopctx.addBreak();
  4948. }
  4949. void HqlCppTranslator::doBuildAssignIn(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  4950. {
  4951. OwnedHqlExpr values = normalizeListCasts(expr->queryChild(1));
  4952. node_operator op = expr->getOperator();
  4953. bool valueIfMatch = (op == no_in);
  4954. switch (values->getOperator())
  4955. {
  4956. case no_all:
  4957. buildExprAssign(ctx, target, queryBoolExpr(valueIfMatch));
  4958. break;
  4959. case no_null:
  4960. buildExprAssign(ctx, target, queryBoolExpr(!valueIfMatch));
  4961. break;
  4962. case no_list:
  4963. {
  4964. HqlCppCaseInfo info(*this);
  4965. doBuildInCaseInfo(expr, info, values);
  4966. info.buildAssign(ctx, target);
  4967. break;
  4968. }
  4969. case no_createset:
  4970. {
  4971. //Look further at bug #52745.eclxml and what causes the poor code.
  4972. //if (canIterateInline(&ctx, values->queryChild(0)))
  4973. // doBuildAssignInCreateSet(ctx, target, expr);
  4974. //else
  4975. doBuildAssignInStored(ctx, target, expr);
  4976. break;
  4977. }
  4978. #if 0
  4979. //Possible optimizations, but I don't have any examples that would trigger them, so don't enable
  4980. case no_if:
  4981. {
  4982. BuildCtx subctx(ctx);
  4983. OwnedHqlExpr inLhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(1)));
  4984. OwnedHqlExpr inRhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(2)));
  4985. IHqlStmt * stmt = buildFilterViaExpr(subctx, values->queryChild(0));
  4986. buildExprAssign(subctx, target, inLhs);
  4987. subctx.selectElse(stmt);
  4988. buildExprAssign(subctx, target, inRhs);
  4989. break;
  4990. }
  4991. case no_addsets:
  4992. if (op == no_in)
  4993. {
  4994. BuildCtx subctx(ctx);
  4995. OwnedHqlExpr inLhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(0)));
  4996. OwnedHqlExpr inRhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(1)));
  4997. buildExprAssign(ctx, target, inLhs);
  4998. OwnedHqlExpr test = getInverse(target.expr);
  4999. subctx.addFilter(test);
  5000. buildExprAssign(subctx, target, inRhs);
  5001. break;
  5002. }
  5003. #endif
  5004. //fall through
  5005. default:
  5006. doBuildAssignInStored(ctx, target, expr);
  5007. break;
  5008. }
  5009. }
  5010. //---------------------------------------------------------------------------
  5011. void HqlCppTranslator::doBuildExprInDict(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5012. {
  5013. IHqlExpression *dict = expr->queryChild(1);
  5014. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dict);
  5015. cursor->buildInDataset(ctx, expr, tgt);
  5016. }
  5017. void HqlCppTranslator::doBuildExprCountDict(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5018. {
  5019. IHqlExpression *dict = expr->queryChild(0);
  5020. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dict);
  5021. cursor->buildCountDict(ctx, tgt); // not the same as buildCount - that is the size of the table, we want the number of populated entries
  5022. }
  5023. void HqlCppTranslator::doBuildExprExistsDict(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5024. {
  5025. IHqlExpression *dict = expr->queryChild(0);
  5026. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dict);
  5027. cursor->buildExistsDict(ctx, tgt);
  5028. }
  5029. //---------------------------------------------------------------------------
  5030. void HqlCppTranslator::doBuildExprArith(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5031. {
  5032. ITypeInfo * type = expr->queryType();
  5033. switch (type->getTypeCode())
  5034. {
  5035. case type_decimal:
  5036. {
  5037. bindAndPush(ctx, expr->queryChild(0));
  5038. bindAndPush(ctx, expr->queryChild(1));
  5039. HqlExprArray args;
  5040. IIdAtom * func;
  5041. switch (expr->getOperator())
  5042. {
  5043. case no_add:
  5044. func = DecAddId;
  5045. break;
  5046. case no_div:
  5047. func = DecDivideId;
  5048. args.append(*getSizetConstant(options.divideByZeroAction));
  5049. break;
  5050. case no_modulus:
  5051. func = DecModulusId;
  5052. args.append(*getSizetConstant(options.divideByZeroAction));
  5053. break;
  5054. case no_mul:
  5055. func = DecMulId;
  5056. break;
  5057. case no_sub:
  5058. func = DecSubId;
  5059. break;
  5060. default: UNIMPLEMENTED;
  5061. }
  5062. callProcedure(ctx, func, args);
  5063. tgt.expr.setown(createValue(no_decimalstack, LINK(type)));
  5064. }
  5065. break;
  5066. case type_swapint:
  5067. case type_packedint:
  5068. {
  5069. //someone is being deliberately perverse....
  5070. ITypeInfo * type = expr->queryType();
  5071. ITypeInfo * intType = makeIntType(type->getSize(), type->isSigned());
  5072. IHqlExpression * lhs = expr->queryChild(0);
  5073. IHqlExpression * rhs = expr->queryChild(1);
  5074. assertex(isSameBasicType(type, lhs->queryType()));
  5075. assertex(isSameBasicType(type, rhs->queryType()));
  5076. lhs = createValue(no_implicitcast, LINK(intType), LINK(lhs));
  5077. rhs = createValue(no_implicitcast, LINK(intType), LINK(rhs));
  5078. IHqlExpression * newExpr = createValue(expr->getOperator(), intType, lhs, rhs);
  5079. OwnedHqlExpr castNewExpr = createValue(no_implicitcast, LINK(type), newExpr);
  5080. buildExpr(ctx, castNewExpr, tgt);
  5081. break;
  5082. }
  5083. default:
  5084. doBuildPureSubExpr(ctx, expr, tgt);
  5085. break;
  5086. }
  5087. }
  5088. void HqlCppTranslator::doBuildExprAdd(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5089. {
  5090. if (expr->queryType()->getTypeCode() != type_int)
  5091. {
  5092. doBuildExprArith(ctx, expr, tgt);
  5093. return;
  5094. }
  5095. CHqlBoundExpr boundL, boundR;
  5096. buildExpr(ctx, expr->queryChild(0), boundL);
  5097. buildExpr(ctx, expr->queryChild(1), boundR);
  5098. tgt.expr.setown(adjustBoundIntegerValues(boundL.expr, boundR.expr, false));
  5099. }
  5100. //---------------------------------------------------------------------------
  5101. void HqlCppTranslator::doBuildExprNegate(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5102. {
  5103. ITypeInfo * type = expr->queryType();
  5104. switch (type->getTypeCode())
  5105. {
  5106. case type_decimal:
  5107. {
  5108. bindAndPush(ctx, expr->queryChild(0));
  5109. HqlExprArray args;
  5110. callProcedure(ctx, DecNegateId, args);
  5111. tgt.expr.setown(createValue(no_decimalstack, LINK(type)));
  5112. }
  5113. break;
  5114. case type_data:
  5115. case type_qstring:
  5116. case type_string:
  5117. case type_varstring:
  5118. case type_unicode:
  5119. case type_varunicode:
  5120. case type_utf8:
  5121. throwError(HQLERR_MinusOnString);
  5122. default:
  5123. doBuildPureSubExpr(ctx, expr, tgt);
  5124. break;
  5125. }
  5126. }
  5127. //---------------------------------------------------------------------------
  5128. void HqlCppTranslator::doBuildExprRound(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5129. {
  5130. IHqlExpression * arg = expr->queryChild(0);
  5131. node_operator op = expr->getOperator();
  5132. switch (arg->queryType()->getTypeCode())
  5133. {
  5134. case type_decimal:
  5135. {
  5136. bindAndPush(ctx, arg);
  5137. HqlExprArray args;
  5138. if (op == no_round)
  5139. {
  5140. IHqlExpression * places = queryRealChild(expr, 1);
  5141. if (places)
  5142. {
  5143. args.append(*LINK(places));
  5144. callProcedure(ctx, DecRoundToId, args);
  5145. }
  5146. else
  5147. callProcedure(ctx, DecRoundId, args);
  5148. }
  5149. else
  5150. callProcedure(ctx, DecRoundUpId, args);
  5151. assertex(expr->queryType()->getTypeCode() == type_decimal);
  5152. tgt.expr.setown(createValue(no_decimalstack, expr->getType()));
  5153. }
  5154. break;
  5155. default:
  5156. {
  5157. if (op == no_round)
  5158. {
  5159. if (queryRealChild(expr, 1))
  5160. doBuildExprSysFunc(ctx, expr, tgt, roundToId);
  5161. else
  5162. doBuildExprSysFunc(ctx, expr, tgt, roundId);
  5163. }
  5164. else
  5165. doBuildExprSysFunc(ctx, expr, tgt, roundupId);
  5166. break;
  5167. }
  5168. }
  5169. }
  5170. void HqlCppTranslator::doBuildExprTrunc(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5171. {
  5172. IHqlExpression * arg = expr->queryChild(0);
  5173. switch (arg->queryType()->getTypeCode())
  5174. {
  5175. case type_decimal:
  5176. {
  5177. bindAndPush(ctx, arg);
  5178. HqlExprArray args;
  5179. callProcedure(ctx, DecTruncateId, args);
  5180. assertex(expr->queryType()->getTypeCode() == type_decimal);
  5181. tgt.expr.setown(createValue(no_decimalstack, expr->getType()));
  5182. }
  5183. break;
  5184. default:
  5185. {
  5186. doBuildExprSysFunc(ctx, expr, tgt, truncateId);
  5187. break;
  5188. }
  5189. }
  5190. }
  5191. //---------------------------------------------------------------------------
  5192. void HqlCppTranslator::doBuildExprAbs(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5193. {
  5194. ITypeInfo * type = expr->queryType();
  5195. switch (type->getTypeCode())
  5196. {
  5197. case type_decimal:
  5198. {
  5199. bindAndPush(ctx, expr->queryChild(0));
  5200. HqlExprArray args;
  5201. IIdAtom * func = DecAbsId;
  5202. callProcedure(ctx, func, args);
  5203. tgt.expr.setown(createValue(no_decimalstack, LINK(type)));
  5204. }
  5205. break;
  5206. case type_int:
  5207. case type_swapint:
  5208. case type_packedint:
  5209. case type_real:
  5210. {
  5211. CHqlBoundExpr temp;
  5212. buildTempExpr(ctx, expr->queryChild(0), temp);
  5213. ITypeInfo * type = expr->getType();
  5214. IHqlExpression * cond = createValue(no_ge, makeBoolType(), temp.expr.getLink(), createConstant(type->castFrom(true, 0)));
  5215. tgt.expr.setown(createValue(no_if, type, cond, temp.expr.getLink(), createValue(no_negate, LINK(type), temp.expr.getLink())));
  5216. }
  5217. break;
  5218. default:
  5219. buildExpr(ctx, expr->queryChild(0), tgt);
  5220. break;
  5221. }
  5222. }
  5223. //---------------------------------------------------------------------------
  5224. void HqlCppTranslator::doBuildAssignCatch(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  5225. {
  5226. BuildCtx subctx(ctx);
  5227. subctx.addGroup();
  5228. BuildCtx tryctx(subctx);
  5229. tryctx.addQuotedCompoundLiteral("try");
  5230. buildExprAssign(tryctx, target, expr->queryChild(0));
  5231. BuildCtx catchctx(subctx);
  5232. catchctx.addQuotedCompoundLiteral("catch (IException * e)");
  5233. IHqlExpression * exceptVar = associateLocalFailure(catchctx, "e");
  5234. buildExprAssign(catchctx, target, expr->queryChild(1));
  5235. HqlExprArray args;
  5236. args.append(*LINK(exceptVar));
  5237. callProcedure(catchctx, freeExceptionId, args);
  5238. }
  5239. //---------------------------------------------------------------------------
  5240. //-- no_externalcall --
  5241. static IHqlExpression * getCastParameter(IHqlExpression * curParam, ITypeInfo * argType, const char * argName)
  5242. {
  5243. type_t atc = argType->getTypeCode();
  5244. //Remove a few unnecessary casts which clutter up the code/or make it less efficient
  5245. if (isCast(curParam) && (curParam->queryType() == argType))
  5246. {
  5247. //If the following code is incorrect, the casts should get added back by the code that follows
  5248. IHqlExpression * uncast = curParam->queryChild(0);
  5249. //casts to larger size integers
  5250. if (atc == type_int)
  5251. curParam = uncast;
  5252. else if ((atc == type_unicode) && (uncast->queryType()->getTypeCode() == type_varunicode))
  5253. curParam = uncast;
  5254. else if ((atc == type_string) && (uncast->queryType()->getTypeCode() == type_varstring))
  5255. curParam = uncast;
  5256. }
  5257. ITypeInfo * paramType = curParam->queryType();
  5258. type_t ptc = paramType->getTypeCode();
  5259. if (atc != ptc)
  5260. {
  5261. switch (atc)
  5262. {
  5263. case type_unicode:
  5264. if ((argType->getSize() == UNKNOWN_LENGTH) && (ptc == type_varunicode))
  5265. return LINK(curParam);
  5266. break;
  5267. case type_string:
  5268. if ((argType->getSize() == UNKNOWN_LENGTH) &&
  5269. ((ptc == type_varstring) && (argType->queryCharset() == paramType->queryCharset())))
  5270. return LINK(curParam);
  5271. break;
  5272. case type_row:
  5273. if (curParam->isDataset())
  5274. throwError1(HQLERR_DatasetPassedToRowArg, argName);
  5275. // fallthrough
  5276. case type_dictionary:
  5277. case type_table:
  5278. case type_groupedtable:
  5279. {
  5280. IHqlExpression * record = queryRecord(argType);
  5281. if (record && (record->numChildren() != 0))
  5282. {
  5283. //really need to project instead.
  5284. //return ensureExprType(curParam, argType);
  5285. }
  5286. return LINK(curParam);
  5287. }
  5288. }
  5289. return ensureExprType(curParam, argType);
  5290. }
  5291. ITypeInfo * childType = argType->queryChildType();
  5292. if (paramType->queryTypeBase() != argType)
  5293. {
  5294. size32_t argSize = argType->getSize();
  5295. switch (atc)
  5296. {
  5297. case type_int:
  5298. case type_real:
  5299. if (argSize <= paramType->getSize())
  5300. return ensureExprType(curParam, argType);
  5301. break;
  5302. case type_decimal:
  5303. //Don't need explicit cast to cast between different sizes of these types...
  5304. //Will be done automatically by the compiler.
  5305. break;
  5306. case type_unicode:
  5307. //Don't need cast between different locales
  5308. if ((argSize != paramType->getSize()) && (argSize != UNKNOWN_LENGTH))
  5309. {
  5310. Owned<ITypeInfo> modArgType = makeUnicodeType(argType->getStringLen(), curParam->queryType()->queryLocale());
  5311. return ensureExprType(curParam, modArgType);
  5312. }
  5313. break;
  5314. case type_varunicode:
  5315. //Don't need cast between different locales
  5316. if(argSize != paramType->getSize())
  5317. {
  5318. Owned<ITypeInfo> modArgType = makeVarUnicodeType(argType->getStringLen(), curParam->queryType()->queryLocale());
  5319. return ensureExprType(curParam, modArgType);
  5320. }
  5321. break;
  5322. case type_utf8:
  5323. //Don't need cast between different locales
  5324. if(argSize != paramType->getSize())
  5325. {
  5326. Owned<ITypeInfo> modArgType = makeUtf8Type(argType->getStringLen(), curParam->queryType()->queryLocale());
  5327. return ensureExprType(curParam, modArgType);
  5328. }
  5329. break;
  5330. case type_set:
  5331. if (childType)
  5332. return ensureExprType(curParam, argType);
  5333. break;
  5334. case type_dictionary:
  5335. case type_table:
  5336. case type_groupedtable:
  5337. case type_row:
  5338. {
  5339. IHqlExpression * record = queryRecord(argType);
  5340. if (record && (record->numChildren() != 0))
  5341. {
  5342. //really need to project instead.
  5343. //return ensureExprType(curParam, argType);
  5344. }
  5345. break;
  5346. }
  5347. default:
  5348. return ensureExprType(curParam, argType);
  5349. }
  5350. }
  5351. // if (argType->queryCharset() != paramType->queryCharset())
  5352. // return ensureExprType(curParam, argType);
  5353. return LINK(curParam);
  5354. }
  5355. void HqlCppTranslator::normalizeBoundExpr(BuildCtx & ctx, CHqlBoundExpr & bound)
  5356. {
  5357. bound.expr.setown(convertWrapperToPointer(bound.expr));
  5358. }
  5359. IHqlExpression * HqlCppTranslator::doBuildInternalFunction(IHqlExpression * funcdef)
  5360. {
  5361. if (funcdef->queryChild(0)->getOperator() == no_external)
  5362. return LINK(funcdef);
  5363. unsigned match = internalFunctions.find(*funcdef);
  5364. if (match != NotFound)
  5365. return LINK(&internalFunctionExternals.item(match));
  5366. OwnedHqlExpr externalFuncdef = createExternalFuncdefFromInternal(funcdef);
  5367. internalFunctions.append(*LINK(funcdef));
  5368. internalFunctionExternals.append(*LINK(externalFuncdef));
  5369. buildFunctionDefinition(funcdef);
  5370. return LINK(externalFuncdef);
  5371. }
  5372. void HqlCppTranslator::doBuildCall(BuildCtx & ctx, const CHqlBoundTarget * tgt, IHqlExpression * expr, CHqlBoundExpr * result)
  5373. {
  5374. if (result && expr->isPure() && ctx.getMatchExpr(expr, *result))
  5375. return;
  5376. LinkedHqlExpr funcdef;
  5377. if (expr->getOperator() == no_externalcall)
  5378. {
  5379. funcdef.set(expr->queryExternalDefinition());
  5380. assertex(funcdef != NULL);
  5381. useFunction(funcdef);
  5382. }
  5383. else
  5384. {
  5385. IHqlExpression * def = expr->queryBody()->queryFunctionDefinition();
  5386. assertex(def);
  5387. if (def->getOperator() == no_param)
  5388. {
  5389. ITypeInfo * type = def->queryType();
  5390. IFunctionTypeExtra * extra = queryFunctionTypeExtra(type);
  5391. IHqlExpression * params = (IHqlExpression *)extra->queryParameters();
  5392. IHqlExpression * defaults = (IHqlExpression *)extra->queryDefaults();
  5393. HqlExprArray attrs;
  5394. attrs.append(*LINK(params));
  5395. if (defaults)
  5396. attrs.append(*LINK(defaults));
  5397. attrs.append(*createAttribute(contextAtom));
  5398. ITypeInfo * returnType = type->queryChildType();
  5399. OwnedHqlExpr externalExpr = createExternalReference(def->queryId(), LINK(returnType), attrs);
  5400. funcdef.setown(createFunctionDefinition(def->queryId(), LINK(externalExpr), LINK(params), LINK(defaults), NULL));
  5401. }
  5402. else
  5403. {
  5404. assertex(def && def->getOperator() == no_funcdef);
  5405. funcdef.setown(doBuildInternalFunction(def));
  5406. }
  5407. }
  5408. IHqlExpression * external = funcdef->queryChild(0);
  5409. IHqlExpression * formals = funcdef->queryChild(1);
  5410. if (external->hasAttribute(ctxmethodAtom) || external->hasAttribute(contextAtom))
  5411. ensureContextAvailable(ctx);
  5412. if (external->hasAttribute(gctxmethodAtom) || external->hasAttribute(globalContextAtom))
  5413. {
  5414. if (!ctx.queryMatchExpr(globalContextMarkerExpr))
  5415. throwError1(HQLERR_FuncNotInGlobalContext, str(external->queryName()));
  5416. }
  5417. unsigned maxArg = formals->numChildren();
  5418. unsigned maxParam = expr->numChildren();
  5419. bool returnByReference = false;
  5420. bool returnMustAssign = false;
  5421. HqlExprArray args;
  5422. unsigned arg = 0;
  5423. unsigned param;
  5424. unsigned firstParam = 0;
  5425. bool isMethod = external->hasAttribute(methodAtom) || external->hasAttribute(omethodAtom) ;
  5426. bool newFormatSet = !external->hasAttribute(oldSetFormatAtom);
  5427. bool translateSetReturn = false;
  5428. if (isMethod)
  5429. {
  5430. CHqlBoundExpr bound;
  5431. buildExpr(ctx, expr->queryChild(firstParam++), bound);
  5432. args.append(*bound.expr.getClear());
  5433. }
  5434. if (external->hasAttribute(userMatchFunctionAtom))
  5435. {
  5436. //MORE: Test valid in this location...
  5437. args.append(*createVariable("walker", makeBoolType()));
  5438. }
  5439. IHqlExpression * extendAttr = external->queryAttribute(extendAtom);
  5440. bool doneAssign = false;
  5441. CHqlBoundExpr localBound;
  5442. CHqlBoundTarget localTarget;
  5443. Linked<BoundRow> resultRow;
  5444. Linked<BoundRow> resultRowBuilder;
  5445. Owned<ITypeInfo> targetType = tgt ? LINK(tgt->queryType()) : makeVoidType();
  5446. ITypeInfo * retType = funcdef->queryType()->queryChildType();
  5447. BoundRow * resultSelfCursor = NULL;
  5448. switch (retType->getTypeCode())
  5449. {
  5450. case type_varstring:
  5451. case type_varunicode:
  5452. if (retType->getSize() == UNKNOWN_LENGTH)
  5453. {
  5454. if (hasConstModifier(retType))
  5455. break;
  5456. returnMustAssign = true;
  5457. if (tgt && !tgt->isFixedSize())
  5458. {
  5459. doneAssign = true;
  5460. localBound.expr.set(tgt->expr);
  5461. }
  5462. else
  5463. localBound.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
  5464. break;
  5465. }
  5466. else
  5467. {
  5468. //fixed size strings => just pass pointer
  5469. IHqlExpression * resultVar = ctx.getTempDeclare(retType, NULL);
  5470. args.append(*getElementPointer(resultVar));
  5471. localBound.expr.setown(resultVar);
  5472. }
  5473. returnByReference = true;
  5474. break;
  5475. case type_string:
  5476. case type_data:
  5477. case type_qstring:
  5478. case type_unicode:
  5479. case type_utf8:
  5480. if (retType->getSize() == UNKNOWN_LENGTH)
  5481. {
  5482. OwnedHqlExpr lenVar;
  5483. OwnedHqlExpr strVar;
  5484. if (tgt && !tgt->isFixedSize())
  5485. {
  5486. doneAssign = true;
  5487. strVar.set(tgt->expr);
  5488. lenVar.set(tgt->length);
  5489. }
  5490. else
  5491. {
  5492. strVar.setown(createWrapperTemp(ctx, retType, typemod_none));
  5493. lenVar.setown(ctx.getTempDeclare(sizetType, NULL));
  5494. }
  5495. args.append(*LINK(lenVar));
  5496. args.append(*createValue(no_reference, strVar->getType(), LINK(strVar), LINK(extendAttr)));
  5497. localBound.length.set(lenVar);
  5498. localBound.expr.set(strVar);
  5499. }
  5500. else
  5501. {
  5502. //fixed size strings => just pass pointer
  5503. if (tgt && tgt->isFixedSize() && targetType->queryPromotedType() == retType)
  5504. {
  5505. doneAssign = true;
  5506. args.append(*getElementPointer(tgt->expr));
  5507. localBound.expr.set(tgt->expr);
  5508. }
  5509. else
  5510. {
  5511. IHqlExpression * resultVar = ctx.getTempDeclare(retType, NULL);
  5512. args.append(*getElementPointer(resultVar));
  5513. localBound.expr.setown(resultVar);
  5514. }
  5515. }
  5516. returnByReference = true;
  5517. break;
  5518. case type_decimal:
  5519. {
  5520. OwnedHqlExpr result;
  5521. if (tgt)
  5522. {
  5523. doneAssign = true;
  5524. result.set(tgt->expr);
  5525. }
  5526. else
  5527. {
  5528. result.setown(ctx.getTempDeclare(retType, NULL));
  5529. }
  5530. args.append(*createValue(no_reference, result->getType(), LINK(result)));
  5531. localBound.expr.set(result);
  5532. returnByReference = true;
  5533. break;
  5534. }
  5535. case type_set:
  5536. {
  5537. translateSetReturn = !newFormatSet;
  5538. OwnedHqlExpr lenVar;
  5539. OwnedHqlExpr strVar;
  5540. OwnedHqlExpr isAll;
  5541. if (tgt && !tgt->isFixedSize())
  5542. {
  5543. doneAssign = true;
  5544. strVar.set(tgt->expr);
  5545. if (translateSetReturn)
  5546. lenVar.setown(ctx.getTempDeclare(unsignedType, NULL));
  5547. else
  5548. lenVar.set(tgt->length);
  5549. assertex(tgt->isAll != NULL);
  5550. isAll.set(tgt->isAll);
  5551. }
  5552. else
  5553. {
  5554. Owned<ITypeInfo> dataType = makeDataType(UNKNOWN_LENGTH);
  5555. strVar.setown(createWrapperTemp(ctx, dataType, typemod_none));
  5556. if (translateSetReturn)
  5557. {
  5558. lenVar.setown(ctx.getTempDeclare(unsignedType, NULL));
  5559. }
  5560. else
  5561. {
  5562. lenVar.setown(ctx.getTempDeclare(sizetType, NULL));
  5563. isAll.setown(ctx.getTempDeclare(boolType, NULL));
  5564. }
  5565. }
  5566. if (newFormatSet)
  5567. args.append(*LINK(isAll));
  5568. args.append(*LINK(lenVar));
  5569. args.append(*createValue(no_reference, strVar->getType(), LINK(strVar)));
  5570. if (newFormatSet)
  5571. {
  5572. localBound.length.set(lenVar);
  5573. }
  5574. else
  5575. {
  5576. localBound.count.set(lenVar);
  5577. if (isAll && !isAll->queryValue())
  5578. ctx.addAssign(isAll, queryBoolExpr(false));
  5579. }
  5580. localBound.isAll.set(isAll);
  5581. localBound.expr.setown(createValue(no_implicitcast, makeReferenceModifier(LINK(retType)), LINK(strVar)));
  5582. returnByReference = true;
  5583. break;
  5584. }
  5585. case type_dictionary:
  5586. case type_table:
  5587. case type_groupedtable:
  5588. {
  5589. if (hasStreamedModifier(retType))
  5590. {
  5591. if (getBoolAttribute(external, allocatorAtom, true))
  5592. args.append(*createRowAllocator(ctx, ::queryRecord(retType)));
  5593. returnMustAssign = true;
  5594. if (tgt && hasStreamedModifier(targetType) && recordTypesMatch(targetType, retType))
  5595. {
  5596. doneAssign = true;
  5597. localBound.expr.set(tgt->expr);
  5598. }
  5599. else
  5600. localBound.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
  5601. break;
  5602. }
  5603. const CHqlBoundTarget * curTarget;
  5604. if (tgt && !tgt->isFixedSize() &&
  5605. (hasLinkCountedModifier(targetType) == hasLinkCountedModifier(retType)) &&
  5606. !hasStreamedModifier(targetType))
  5607. {
  5608. doneAssign = true;
  5609. curTarget = tgt;
  5610. }
  5611. else
  5612. {
  5613. curTarget = &localTarget;
  5614. ExpressionFormat format = (hasLinkCountedModifier(retType) ? FormatLinkedDataset : FormatBlockedDataset);
  5615. createTempFor(ctx, retType, localTarget, typemod_none, format);
  5616. }
  5617. if (curTarget->count)
  5618. args.append(*LINK(curTarget->count));
  5619. if (curTarget->length)
  5620. args.append(*LINK(curTarget->length));
  5621. args.append(*createValue(no_reference, curTarget->expr->getType(), LINK(curTarget->expr)));
  5622. if (hasLinkCountedModifier(retType) && getBoolAttribute(external, allocatorAtom, true))
  5623. args.append(*createRowAllocator(ctx, ::queryRecord(retType)));
  5624. localBound.setFromTarget(*curTarget);
  5625. // localBound.expr.setown(createValue(no_implicitcast, makeReferenceModifier(LINK(retType)), LINK(strVar)));
  5626. returnByReference = true;
  5627. break;
  5628. }
  5629. case type_row:
  5630. {
  5631. if (hasLinkCountedModifier(retType))
  5632. {
  5633. if (hasNonNullRecord(retType) && getBoolAttribute(external, allocatorAtom, true))
  5634. args.append(*createRowAllocator(ctx, ::queryRecord(retType)));
  5635. //Always assign link counted rows to a temporary (or the target) to ensure the are not leaked.
  5636. returnMustAssign = true;
  5637. if (tgt && hasLinkCountedModifier(targetType) && recordTypesMatch(targetType, retType))
  5638. {
  5639. doneAssign = true;
  5640. localBound.expr.set(tgt->expr);
  5641. }
  5642. else
  5643. localBound.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
  5644. }
  5645. else
  5646. {
  5647. //row, just pass pointer
  5648. if (tgt && recordTypesMatch(targetType, retType) && !hasLinkCountedModifier(targetType))
  5649. {
  5650. doneAssign = true;
  5651. args.append(*getPointer(tgt->expr));
  5652. localBound.expr.set(tgt->expr);
  5653. }
  5654. else
  5655. {
  5656. if (isVariableSizeRecord(expr->queryRecord()))
  5657. {
  5658. const char * name = str(expr->queryName());
  5659. throwError1(HQLERR_VariableRowMustBeLinked, name ? name : "");
  5660. }
  5661. resultRow.setown(declareTempRow(ctx, ctx, expr));
  5662. resultRowBuilder.setown(createRowBuilder(ctx, resultRow));
  5663. IHqlExpression * bound = resultRowBuilder->queryBound();
  5664. args.append(*getPointer(bound));
  5665. localBound.expr.setown(getPointer(resultRow->queryBound()));
  5666. }
  5667. returnByReference = true;
  5668. }
  5669. break;
  5670. }
  5671. case type_transform:
  5672. {
  5673. //Ugly, but target selector is passed in as the target
  5674. assertex(tgt && tgt->expr);
  5675. resultSelfCursor = resolveSelectorDataset(ctx, tgt->expr);
  5676. assertex(resultSelfCursor);
  5677. if (resultSelfCursor->queryBuilder())
  5678. args.append(*LINK(resultSelfCursor->queryBuilder()));
  5679. else
  5680. throwUnexpectedX("Expected a dynamic target for a transform - legacy not supported");
  5681. returnByReference = true;
  5682. doneAssign = true;
  5683. break;
  5684. }
  5685. case type_array:
  5686. UNIMPLEMENTED;
  5687. }
  5688. for (param = firstParam; param < maxParam; param++)
  5689. {
  5690. IHqlExpression * curParam = expr->queryChild(param);
  5691. if (curParam->isAttribute())
  5692. continue;
  5693. if (arg >= maxArg)
  5694. {
  5695. IERRLOG("Too many parameters passed to function '%s'", str(expr->queryName()));
  5696. throwError1(HQLERR_TooManyParameters, str(expr->queryName()));
  5697. }
  5698. CHqlBoundExpr bound;
  5699. IHqlExpression * curArg = formals->queryChild(arg);
  5700. ITypeInfo * argType = curArg->queryType();
  5701. OwnedHqlExpr castParam = getCastParameter(curParam, argType, curArg->queryId()->queryStr());
  5702. type_t atc = argType->getTypeCode();
  5703. switch (atc)
  5704. {
  5705. case type_dictionary:
  5706. case type_table:
  5707. case type_groupedtable:
  5708. {
  5709. IHqlExpression* passParamAttr = getFunctionBodyAttribute(external, passParameterMetaAtom);
  5710. if (getBoolAttributeValue(passParamAttr))
  5711. args.append(*buildMetaParameter(curParam));
  5712. ExpressionFormat format = queryNaturalFormat(argType);
  5713. doBuildDataset(ctx, castParam, bound, format);
  5714. ensureDatasetFormat(ctx, argType, bound, format);
  5715. break;
  5716. }
  5717. case type_row:
  5718. {
  5719. IHqlExpression* passParamAttr = getFunctionBodyAttribute(external, passParameterMetaAtom);
  5720. if (getBoolAttributeValue(passParamAttr))
  5721. args.append(*buildMetaParameter(curParam));
  5722. Owned<IReferenceSelector> selector = buildNewRow(ctx, castParam);
  5723. if (hasLinkCountedModifier(argType))
  5724. selector.setown(ensureLinkCountedRow(ctx, selector));
  5725. selector->buildAddress(ctx, bound);
  5726. break;
  5727. }
  5728. case type_set:
  5729. {
  5730. ITypeInfo * elemType = argType->queryChildType();
  5731. if (newFormatSet && elemType && (elemType->getTypeCode() != type_any) && (elemType != castParam->queryType()->queryChildType()))
  5732. buildExprEnsureType(ctx, castParam, bound, argType);
  5733. else
  5734. buildExpr(ctx, castParam, bound);
  5735. if (isUnknownSize(elemType))
  5736. {
  5737. ITypeInfo * boundElemType = bound.queryType()->queryChildType();
  5738. assertex(!boundElemType || isUnknownSize(boundElemType));
  5739. }
  5740. normalizeBoundExpr(ctx, bound);
  5741. break;
  5742. }
  5743. case type_decimal:
  5744. {
  5745. buildSimpleExpr(ctx, castParam, bound);
  5746. normalizeBoundExpr(ctx, bound);
  5747. break;
  5748. }
  5749. case type_record:
  5750. {
  5751. args.append(*buildMetaParameter(curParam));
  5752. break;
  5753. }
  5754. default:
  5755. {
  5756. buildExpr(ctx, castParam, bound);
  5757. normalizeBoundExpr(ctx, bound);
  5758. break;
  5759. }
  5760. }
  5761. bool done = false;
  5762. switch (atc)
  5763. {
  5764. case type_string:
  5765. case type_data:
  5766. case type_qstring:
  5767. case type_unicode:
  5768. case type_utf8:
  5769. if (argType->getSize() == UNKNOWN_LENGTH)
  5770. args.append(*getBoundLength(bound));
  5771. /*
  5772. Ensure parameter is passed as non-const if the argument does not have const.
  5773. if (!curArg->hasAttribute(constAtom))//!argType->isConstantType())// && bound.queryType()->isConstantType())
  5774. bound.expr.setown(createValue(no_cast, LINK(argType), LINK(bound.expr)));
  5775. */
  5776. break;
  5777. case type_varstring:
  5778. case type_varunicode:
  5779. //MORE: pass length only if an out parameter
  5780. break;
  5781. case type_set:
  5782. {
  5783. if (newFormatSet)
  5784. {
  5785. args.append(*bound.getIsAll());
  5786. args.append(*getBoundSize(bound));
  5787. }
  5788. else
  5789. {
  5790. if (castParam->getOperator() == no_all)
  5791. throwError(HQLERR_AllPassedExternal);
  5792. args.append(*getBoundCount(bound));
  5793. }
  5794. break;
  5795. }
  5796. case type_dictionary:
  5797. case type_table:
  5798. case type_groupedtable:
  5799. {
  5800. if (!hasStreamedModifier(argType))
  5801. {
  5802. if (isArrayRowset(argType))
  5803. args.append(*getBoundCount(bound));
  5804. else
  5805. args.append(*getBoundSize(bound));
  5806. }
  5807. bound.expr.setown(getPointer(bound.expr));
  5808. break;
  5809. }
  5810. case type_record:
  5811. done = true;
  5812. break;
  5813. case type_array:
  5814. UNIMPLEMENTED;
  5815. }
  5816. if (!done)
  5817. args.append(*bound.expr.getClear());
  5818. arg++;
  5819. }
  5820. if (arg < maxArg)
  5821. {
  5822. //MORE: Process default parameters...
  5823. IERRLOG("Not enough parameters passed to function '%s'", str(expr->queryName()));
  5824. throwError1(HQLERR_TooFewParameters, str(expr->queryName()));
  5825. }
  5826. OwnedHqlExpr call = bindTranslatedFunctionCall(funcdef, args);
  5827. CHqlBoundExpr boundTimer, boundStart;
  5828. if (external->hasAttribute(timeAtom))
  5829. {
  5830. StringBuffer nameTemp;
  5831. const char * name = str(external->queryId());
  5832. if (getStringValue(nameTemp, queryAttributeChild(external, timeAtom, 0)).length())
  5833. name = nameTemp;
  5834. buildStartTimer(ctx, boundTimer, boundStart, name);
  5835. }
  5836. //either copy the integral value across, or a var string to fixed string
  5837. if (returnMustAssign)
  5838. {
  5839. ctx.addAssign(localBound.expr, call);
  5840. }
  5841. else if (resultSelfCursor)
  5842. {
  5843. OwnedHqlExpr sizeVar = ctx.getTempDeclare(unsignedType, call);
  5844. OwnedHqlExpr sizeOfExpr = createSizeof(resultSelfCursor->querySelector());
  5845. ctx.associateExpr(sizeOfExpr, sizeVar);
  5846. }
  5847. else if (returnByReference || (!tgt && !result))
  5848. {
  5849. ctx.addExpr(call);
  5850. if (translateSetReturn && tgt)
  5851. {
  5852. CHqlBoundTarget targetLength;
  5853. CHqlBoundExpr boundLength;
  5854. boundLength.expr.setown(getBoundLength(localBound));
  5855. targetLength.expr.set(tgt->length);
  5856. assign(ctx, targetLength, boundLength);
  5857. }
  5858. }
  5859. else
  5860. localBound.expr.set(call);
  5861. if (localBound.expr)
  5862. localBound.expr.setown(convertWrapperToPointer(localBound.expr));
  5863. if (tgt && !doneAssign)
  5864. assign(ctx, *tgt, localBound);
  5865. else if (result)
  5866. result->set(localBound);
  5867. //Old style row target where the row is passed in as a parameter
  5868. if (resultRow)
  5869. finalizeTempRow(ctx, resultRow, resultRowBuilder);
  5870. if (external->hasAttribute(timeAtom))
  5871. buildStopTimer(ctx, boundTimer, boundStart);
  5872. if (returnByReference)
  5873. ctx.associateExpr(expr, localBound);
  5874. }
  5875. void HqlCppTranslator::doBuildExprCall(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  5876. {
  5877. doBuildCall(ctx, NULL, expr, &tgt);
  5878. }
  5879. void HqlCppTranslator::doBuildAssignCall(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  5880. {
  5881. ITypeInfo * exprType = expr->queryType()->queryPromotedType();
  5882. if ((exprType->getSize() == UNKNOWN_LENGTH) && target.isFixedSize())
  5883. {
  5884. doBuildExprAssign(ctx, target, expr);
  5885. return;
  5886. }
  5887. ITypeInfo * targetType = target.queryType()->queryPromotedType();
  5888. if ((isStringType(exprType) || isUnicodeType(exprType) || isStringType(targetType) || isUnicodeType(targetType)) && exprType->getTypeCode() != targetType->getTypeCode())
  5889. {
  5890. doBuildExprAssign(ctx, target, expr);
  5891. return;
  5892. }
  5893. if ((exprType->getTypeCode() == type_set) && (queryUnqualifiedType(targetType) != queryUnqualifiedType(exprType)))
  5894. {
  5895. if (exprType->queryChildType()) // allow direct assignment of generic set functions. (e.g., internal)
  5896. {
  5897. doBuildExprAssign(ctx, target, expr);
  5898. return;
  5899. }
  5900. }
  5901. doBuildCall(ctx, &target, expr, NULL);
  5902. }
  5903. void HqlCppTranslator::doBuildStmtCall(BuildCtx & ctx, IHqlExpression * expr)
  5904. {
  5905. doBuildCall(ctx, NULL, expr, NULL);
  5906. }
  5907. //---------------------------------------------------------------------------
  5908. void HqlCppTranslator::doBuildXmlEncode(BuildCtx & ctx, const CHqlBoundTarget * tgt, IHqlExpression * expr, CHqlBoundExpr * result)
  5909. {
  5910. node_operator op = expr->getOperator();
  5911. bool isUnicode = isUnicodeType(expr->queryType());
  5912. HqlExprArray args;
  5913. IIdAtom * func;
  5914. args.append(*LINK(expr->queryChild(0)));
  5915. if (op == no_xmldecode)
  5916. func = isUnicode ? xmlDecodeUStrId : xmlDecodeStrId;
  5917. else
  5918. {
  5919. func = isUnicode ? xmlEncodeUStrId : xmlEncodeStrId;
  5920. __int64 flags = 0;
  5921. if (expr->hasAttribute(allAtom))
  5922. flags = ENCODE_WHITESPACE;
  5923. args.append(*createConstant(flags));
  5924. }
  5925. OwnedHqlExpr call = bindFunctionCall(func, args);
  5926. if (tgt)
  5927. buildExprAssign(ctx, *tgt, call);
  5928. else
  5929. buildExpr(ctx, call, *result);
  5930. }
  5931. //---------------------------------------------------------------------------
  5932. //-- no_cast --
  5933. //-- no_implicitcast --
  5934. IValue * getCastValue(ITypeInfo * cast, IHqlExpression * arg)
  5935. {
  5936. Owned<IValue> value;
  5937. switch (arg->getOperator())
  5938. {
  5939. case no_constant:
  5940. value.set(arg->queryValue());
  5941. break;
  5942. case no_cast: case no_implicitcast:
  5943. value.setown(getCastValue(arg->queryType(), arg->queryChild(0)));
  5944. break;
  5945. default:
  5946. return NULL;
  5947. }
  5948. if (!value)
  5949. return NULL;
  5950. return value->castTo(cast);
  5951. }
  5952. inline IHqlExpression * getCastExpr(ITypeInfo * cast, IHqlExpression * arg)
  5953. {
  5954. IValue * value = getCastValue(cast, arg);
  5955. if (value)
  5956. return createConstant(value);
  5957. return NULL;
  5958. }
  5959. void HqlCppTranslator::doBuildAssignCast(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  5960. {
  5961. IHqlExpression * left = expr->queryChild(0);
  5962. if (options.foldConstantCast)
  5963. {
  5964. //remove when we have constant folding installed...
  5965. OwnedHqlExpr cast = getCastExpr(expr->queryType(), left);
  5966. if (cast)
  5967. {
  5968. buildExprAssign(ctx, target, cast);
  5969. return;
  5970. }
  5971. }
  5972. #if 0
  5973. StringBuffer s;
  5974. s.append("assign cast from=");
  5975. left->queryType()->getECLType(s);
  5976. target.queryType()->getECLType(s.append(" target="));
  5977. expr->queryType()->getECLType(s.append(" expr="));
  5978. DBGLOG("%s",s.str());
  5979. #endif
  5980. ITypeInfo * targetType = target.queryType();
  5981. ITypeInfo * exprType = expr->queryType();
  5982. if ((targetType->queryPromotedType() == exprType->queryPromotedType()))
  5983. {
  5984. CHqlBoundExpr bound;
  5985. if (ctx.getMatchExpr(left, bound))
  5986. assignAndCast(ctx, target, bound);
  5987. else
  5988. {
  5989. OwnedHqlExpr values = normalizeListCasts(expr);
  5990. if (values != expr)
  5991. {
  5992. buildExprAssign(ctx, target, values);
  5993. return;
  5994. }
  5995. node_operator leftOp = left->getOperator();
  5996. bool useTemp = requiresTemp(ctx, left, false) && (leftOp != no_concat) && (leftOp != no_createset);
  5997. if (useTemp && target.isFixedSize())
  5998. {
  5999. bool ignoreStretched = false;
  6000. switch (leftOp)
  6001. {
  6002. case no_case:
  6003. case no_map:
  6004. //MORE: If the length of the bulk of the branches match then it is worth ignoring.
  6005. //would be worthwhile if isStringType(targetType) || isUnicodeType(targetType);
  6006. break;
  6007. case no_substring:
  6008. //don't do this if the target type is unicode at the moment
  6009. ignoreStretched = isStringType(targetType);
  6010. break;
  6011. }
  6012. if (ignoreStretched)
  6013. {
  6014. Owned<ITypeInfo> stretchedType = getStretchedType(targetType->getStringLen(), exprType);
  6015. if (isSameBasicType(stretchedType, targetType->queryPromotedType()))
  6016. useTemp = false;
  6017. }
  6018. }
  6019. if (useTemp)
  6020. {
  6021. buildExpr(ctx, left, bound);
  6022. assignAndCast(ctx, target, bound);
  6023. }
  6024. else
  6025. {
  6026. buildExprAssign(ctx, target, left);
  6027. }
  6028. }
  6029. return;
  6030. }
  6031. ITypeInfo * leftType = left->queryType();
  6032. if ((targetType->queryPromotedType() == left->queryType()->queryPromotedType()))
  6033. {
  6034. if (preservesValue(exprType, leftType))
  6035. {
  6036. buildExprAssign(ctx, target, left);
  6037. return;
  6038. }
  6039. }
  6040. CHqlBoundExpr pure;
  6041. bool assignDirect = false;
  6042. if ((exprType->getSize() == UNKNOWN_LENGTH) && (targetType->getTypeCode() == exprType->getTypeCode()) &&
  6043. (isStringType(exprType) || isUnicodeType(exprType)))
  6044. {
  6045. OwnedITypeInfo stretched = getStretchedType(UNKNOWN_LENGTH, targetType->queryPromotedType());
  6046. if (stretched == exprType->queryPromotedType())
  6047. assignDirect = true;
  6048. }
  6049. if (assignDirect)
  6050. buildExpr(ctx, left, pure);
  6051. else
  6052. buildExpr(ctx, expr, pure);
  6053. assignAndCast(ctx, target, pure);
  6054. }
  6055. void HqlCppTranslator::doBuildExprCast(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6056. {
  6057. IHqlExpression * arg = expr->queryChild(0);
  6058. ITypeInfo * exprType = expr->queryType();
  6059. if (exprType->getTypeCode() == type_set)
  6060. {
  6061. OwnedHqlExpr castArg = ensureExprType(arg, exprType);
  6062. if ((castArg->getOperator() != no_cast) && (castArg->getOperator() != no_implicitcast))
  6063. {
  6064. buildExpr(ctx, castArg, tgt);
  6065. return;
  6066. }
  6067. //The case is almost certainly going to go via a temporary anyway, better code is generated if we can avoid an extra assign
  6068. buildTempExpr(ctx, expr, tgt);
  6069. return;
  6070. }
  6071. if (options.foldConstantCast)
  6072. {
  6073. //remove when we have constant folding installed...
  6074. IHqlExpression * cast = getCastExpr(exprType, arg);
  6075. if (cast)
  6076. {
  6077. tgt.expr.setown(cast);
  6078. return;
  6079. }
  6080. }
  6081. // weird special case.... (int4)(swapint4)int4_x - remove both casts...
  6082. switch (arg->getOperator())
  6083. {
  6084. case no_cast:
  6085. case no_implicitcast:
  6086. {
  6087. IHqlExpression * child = arg->queryChild(0);
  6088. if (child->queryType() == exprType)
  6089. {
  6090. if ((exprType->getTypeCode() == type_int) || (exprType->getTypeCode() == type_swapint) || (exprType->getTypeCode() == type_packedint))
  6091. {
  6092. ITypeInfo * argType = arg->queryType();
  6093. if ((argType->getTypeCode() == type_int) || (argType->getTypeCode() == type_swapint) || (argType->getTypeCode() == type_packedint))
  6094. {
  6095. if (argType->getSize() == exprType->getSize())
  6096. {
  6097. buildExpr(ctx, child, tgt);
  6098. return;
  6099. }
  6100. }
  6101. }
  6102. }
  6103. break;
  6104. }
  6105. #if 0
  6106. case no_if:
  6107. {
  6108. //optimize cast of an if where one of the arguments is already the correct type
  6109. //this doesn't really improve things
  6110. IHqlExpression * lhs = arg->queryChild(1);
  6111. IHqlExpression * rhs = arg->queryChild(2);
  6112. if (lhs->queryType() == exprType || lhs->getOperator() == no_constant ||
  6113. rhs->queryType() == exprType || rhs->getOperator() == no_constant)
  6114. {
  6115. HqlExprArray args;
  6116. args.append(*LINK(arg->queryChild(0)));
  6117. args.append(*ensureExprType(lhs, exprType));
  6118. args.append(*ensureExprType(rhs, exprType));
  6119. unwindChildren(args, arg, 3);
  6120. OwnedHqlExpr next = createValue(no_if, LINK(exprType), args);
  6121. buildExpr(ctx, next, tgt);
  6122. return;
  6123. }
  6124. break;
  6125. }
  6126. #endif
  6127. case no_substring:
  6128. {
  6129. ITypeInfo * argType = arg->queryType();
  6130. if ((exprType->getSize() != UNKNOWN_LENGTH) && (argType->getSize() == UNKNOWN_LENGTH) && (exprType->getTypeCode() == argType->getTypeCode()))
  6131. {
  6132. OwnedITypeInfo stretched = getStretchedType(exprType->getStringLen(), argType);
  6133. if (stretched == exprType)
  6134. {
  6135. buildTempExpr(ctx, expr, tgt);
  6136. return;
  6137. }
  6138. }
  6139. break;
  6140. }
  6141. }
  6142. CHqlBoundExpr pure;
  6143. buildExpr(ctx, arg, pure);
  6144. doBuildExprCast(ctx, exprType, pure, tgt);
  6145. if ((arg->queryType()->getTypeCode() == type_decimal) && !isTypePassedByAddress(exprType))
  6146. {
  6147. OwnedHqlExpr translated = tgt.getTranslatedExpr();
  6148. buildTempExpr(ctx, translated, tgt);
  6149. }
  6150. }
  6151. void HqlCppTranslator::doBuildCastViaTemp(BuildCtx & ctx, ITypeInfo * to, CHqlBoundExpr & pure, CHqlBoundExpr & tgt)
  6152. {
  6153. CHqlBoundTarget boundTarget;
  6154. Linked<ITypeInfo> targetType = to;
  6155. //If the temporary size can be deduced, then use a fixed length temporary to save a heap operation.
  6156. ITypeInfo * fromType = pure.expr->queryType();
  6157. if (isStringType(to) && to->getSize() == UNKNOWN_LENGTH && isStringType(fromType) && !pure.length)
  6158. {
  6159. assertex(fromType->getSize() != UNKNOWN_LENGTH);
  6160. targetType.setown(getStretchedType(fromType->getStringLen(), to));
  6161. }
  6162. OwnedHqlExpr translated = pure.getTranslatedExpr();
  6163. OwnedHqlExpr cast = ensureExprType(translated, targetType);
  6164. buildTempExpr(ctx, cast, tgt);
  6165. }
  6166. void HqlCppTranslator::doBuildCastViaString(BuildCtx & ctx, ITypeInfo * to, const CHqlBoundExpr & pure, CHqlBoundExpr & tgt)
  6167. {
  6168. ITypeInfo * from = pure.expr->queryType();
  6169. Owned<ITypeInfo> tempType = makeStringType(from->getStringLen(), NULL, NULL);
  6170. OwnedHqlExpr temp = createValue(no_implicitcast, LINK(to),
  6171. createValue(no_implicitcast, tempType.getLink(), pure.getTranslatedExpr()));
  6172. buildExpr(ctx, temp, tgt);
  6173. }
  6174. void HqlCppTranslator::doBuildExprCast(BuildCtx & ctx, ITypeInfo * to, CHqlBoundExpr & pure, CHqlBoundExpr & tgt)
  6175. {
  6176. ITypeInfo * from = pure.expr->queryType();
  6177. HqlExprArray args;
  6178. IIdAtom * funcName = NULL;
  6179. OwnedHqlExpr op;
  6180. switch (to->getTypeCode())
  6181. {
  6182. case type_boolean:
  6183. {
  6184. switch (from->getTypeCode())
  6185. {
  6186. case type_string:
  6187. funcName = an2bId;
  6188. args.append(*getBoundLength(pure));
  6189. args.append(*getElementPointer(pure.expr));
  6190. break;
  6191. case type_data:
  6192. funcName = data2BoolId;
  6193. args.append(*getBoundLength(pure));
  6194. args.append(*getElementPointer(pure.expr));
  6195. break;
  6196. case type_qstring:
  6197. funcName = qstr2BoolId;
  6198. args.append(*getBoundLength(pure));
  6199. args.append(*getElementPointer(pure.expr));
  6200. break;
  6201. case type_varstring:
  6202. funcName = vn2bId;
  6203. args.append(*getElementPointer(pure.expr));
  6204. break;
  6205. case type_decimal:
  6206. ensurePushed(ctx, pure);
  6207. funcName = DecCompareNullId;
  6208. break;
  6209. case type_unicode:
  6210. case type_varunicode:
  6211. case type_utf8:
  6212. doBuildCastViaString(ctx, to, pure, tgt);
  6213. return;
  6214. case type_real:
  6215. default:
  6216. //default action
  6217. break;
  6218. }
  6219. break;
  6220. }
  6221. case type_packedint:
  6222. {
  6223. ITypeInfo * logicalType = to->queryPromotedType();
  6224. size32_t toSize = logicalType->getSize();
  6225. if ((from->getTypeCode() != type_int) || (toSize != from->getSize()))
  6226. {
  6227. OwnedHqlExpr translated = pure.getTranslatedExpr();
  6228. OwnedHqlExpr castTranslated = createValue(no_implicitcast, LINK(logicalType), LINK(translated));
  6229. buildExpr(ctx, castTranslated, tgt);
  6230. return;
  6231. }
  6232. tgt.set(pure);
  6233. return;
  6234. }
  6235. case type_swapint:
  6236. {
  6237. if ((from->getTypeCode() == type_swapint) && (to->getSize() == from->getSize()))
  6238. {
  6239. break; // default behaviour
  6240. //MORE: Could special case cast between diff size swapints, but a bit too complicated.
  6241. }
  6242. if (from->getTypeCode() != type_int)
  6243. {
  6244. ITypeInfo * tempType = makeIntType(to->getSize(), to->isSigned());
  6245. IHqlExpression * translated = pure.getTranslatedExpr();
  6246. translated = createValue(no_implicitcast, tempType, translated);
  6247. OwnedHqlExpr castTranslated = createValue(no_implicitcast, LINK(to), translated);
  6248. buildExpr(ctx, castTranslated, tgt);
  6249. return;
  6250. }
  6251. unsigned toSize = to->getSize();
  6252. unsigned fromSize = from->getSize();
  6253. if ((toSize == 1) && (fromSize == 1))
  6254. {
  6255. if (to->isSigned() != from->isSigned())
  6256. break;
  6257. tgt.expr.setown(createValue(no_typetransfer, LINK(to), LINK(pure.expr)));
  6258. return;
  6259. }
  6260. if (toSize != fromSize)
  6261. {
  6262. Owned<ITypeInfo> tempType = makeIntType(toSize, from->isSigned());
  6263. CHqlBoundExpr tempInt;
  6264. tempInt.expr.setown(ensureExprType(pure.expr, tempType));
  6265. doBuildCastViaTemp(ctx, to, tempInt, tgt);
  6266. }
  6267. else
  6268. doBuildCastViaTemp(ctx, to, pure, tgt);
  6269. return;
  6270. }
  6271. case type_int:
  6272. {
  6273. switch (from->getTypeCode())
  6274. {
  6275. case type_qstring:
  6276. {
  6277. //Need to go via a temporary string.
  6278. Owned<ITypeInfo> tempType = makeStringType(from->getStringLen(), NULL, NULL);
  6279. OwnedHqlExpr temp = createValue(no_implicitcast, LINK(to),
  6280. createValue(no_implicitcast, tempType.getLink(), pure.getTranslatedExpr()));
  6281. buildExpr(ctx, temp, tgt);
  6282. return;
  6283. }
  6284. case type_string:
  6285. case type_data:
  6286. {
  6287. IAtom * charset = from->queryCharset()->queryName();
  6288. if (charset == ebcdicAtom)
  6289. {
  6290. if (to->isSigned())
  6291. funcName = (to->getSize() > 4 ? en2ls8Id : en2ls4Id);
  6292. else
  6293. funcName = (to->getSize() > 4 ? en2l8Id : en2l4Id);
  6294. }
  6295. else if ((charset == asciiAtom) || (charset == dataAtom))
  6296. {
  6297. if (to->isSigned())
  6298. funcName = (to->getSize() > 4 ? an2ls8Id : an2ls4Id);
  6299. else
  6300. funcName = (to->getSize() > 4 ? an2l8Id : an2l4Id);
  6301. }
  6302. else
  6303. assertex(!"Unknown character set");
  6304. //MORE: This should really cast the result to the real width to remove extra bytes.
  6305. //e.g. (unsigned3)-1 should be 0xffffff, not 0xffffffff
  6306. args.append(*getBoundLength(pure));
  6307. args.append(*getElementPointer(pure.expr));
  6308. break;
  6309. }
  6310. case type_varstring:
  6311. if (to->isSigned())
  6312. funcName = (to->getSize() > 4 ? vn2ls8Id : vn2ls4Id);
  6313. else
  6314. funcName = (to->getSize() > 4 ? vn2l8Id : vn2l4Id);
  6315. args.append(*getElementPointer(pure.expr));
  6316. break;
  6317. case type_decimal:
  6318. ensurePushed(ctx, pure);
  6319. if (to->getSize() > 4)
  6320. funcName = DecPopInt64Id;
  6321. else
  6322. funcName = DecPopLongId;
  6323. break;
  6324. case type_packedint:
  6325. {
  6326. if (to->getSize() < from->getSize())
  6327. {
  6328. funcName = castIntId[to->getSize()][to->isSigned()];
  6329. args.append(*LINK(pure.expr));
  6330. }
  6331. else
  6332. tgt.set(pure);
  6333. break;
  6334. }
  6335. case type_swapint:
  6336. case type_keyedint:
  6337. {
  6338. unsigned toSize = to->getSize();
  6339. unsigned fromSize = from->getSize();
  6340. if ((toSize == 1) && (fromSize == 1))
  6341. {
  6342. if (to->isSigned() != from->isSigned())
  6343. break;
  6344. tgt.expr.setown(createValue(no_typetransfer, LINK(to), LINK(pure.expr)));
  6345. return;
  6346. }
  6347. if (toSize != fromSize)
  6348. {
  6349. Owned<ITypeInfo> tempType = makeIntType(fromSize, from->isSigned());
  6350. CHqlBoundExpr tempInt;
  6351. doBuildCastViaTemp(ctx, tempType, pure, tempInt);
  6352. funcName = castIntId[to->getSize()][to->isSigned()];
  6353. if (funcName && toSize < fromSize)
  6354. {
  6355. args.append(*LINK(tempInt.expr));
  6356. tgt.expr.setown(bindTranslatedFunctionCall(funcName, args));
  6357. }
  6358. else
  6359. tgt.expr.setown(ensureExprType(tempInt.expr, to));
  6360. }
  6361. else
  6362. doBuildCastViaTemp(ctx, to, pure, tgt);
  6363. return;
  6364. }
  6365. case type_int:
  6366. if (to->getSize() < from->getSize())
  6367. {
  6368. IIdAtom * name = castIntId[to->getSize()][to->isSigned()];
  6369. if (name)
  6370. {
  6371. args.append(*LINK(pure.expr));
  6372. IHqlExpression * call = bindTranslatedFunctionCall(name, args);
  6373. op.setown(createValue(no_typetransfer, LINK(to), call));
  6374. }
  6375. }
  6376. break;
  6377. case type_unicode:
  6378. case type_varunicode:
  6379. case type_utf8:
  6380. doBuildCastViaString(ctx, to, pure, tgt);
  6381. return;
  6382. case type_real:
  6383. default:
  6384. //default action
  6385. break;
  6386. }
  6387. break;
  6388. }
  6389. case type_real:
  6390. switch (from->getTypeCode())
  6391. {
  6392. case type_qstring:
  6393. case type_unicode:
  6394. case type_varunicode:
  6395. case type_utf8:
  6396. doBuildCastViaString(ctx, to, pure, tgt);
  6397. return;
  6398. case type_data:
  6399. case type_string:
  6400. funcName = from->queryCharset()->queryName() != ebcdicAtom ? an2fId : en2fId;
  6401. args.append(*getBoundLength(pure));
  6402. args.append(*getElementPointer(pure.expr));
  6403. break;
  6404. case type_varstring:
  6405. funcName = from->queryCharset()->queryName() != ebcdicAtom ? vn2fId : ex2fId;
  6406. args.append(*getElementPointer(pure.expr));
  6407. break;
  6408. case type_decimal:
  6409. ensurePushed(ctx, pure);
  6410. funcName = DecPopRealId;
  6411. break;
  6412. case type_swapint:
  6413. {
  6414. //cast via intermediate int.
  6415. ITypeInfo * type = makeIntType(from->getSize(), from->isSigned());
  6416. IHqlExpression * translated = pure.getTranslatedExpr();
  6417. OwnedHqlExpr castTranslated = createValue(no_implicitcast, type, translated);
  6418. pure.clear();
  6419. buildExpr(ctx, castTranslated, pure);
  6420. from = type;
  6421. }
  6422. //fallthrough
  6423. case type_int:
  6424. case type_boolean:
  6425. case type_packedint:
  6426. default:
  6427. //default action
  6428. break;
  6429. }
  6430. break;
  6431. case type_decimal:
  6432. {
  6433. ensurePushed(ctx, pure);
  6434. bool needToSetPrecision = true;
  6435. unsigned toDigits = to->getDigits();
  6436. unsigned toPrecision = to->getPrecision();
  6437. switch (from->getTypeCode())
  6438. {
  6439. case type_int:
  6440. case type_swapint:
  6441. if (toDigits >= from->getDigits())
  6442. needToSetPrecision = false;
  6443. break;
  6444. case type_decimal:
  6445. {
  6446. unsigned fromDigits = from->getDigits();
  6447. unsigned fromPrecision = from->getPrecision();
  6448. if (((toDigits - toPrecision) >= (fromDigits - fromPrecision)) &&
  6449. (toPrecision >= fromPrecision))
  6450. needToSetPrecision = false;
  6451. break;
  6452. }
  6453. }
  6454. if ((toDigits == MAX_DECIMAL_DIGITS) && (toPrecision == MAX_DECIMAL_PRECISION))
  6455. needToSetPrecision = false;
  6456. if (needToSetPrecision)
  6457. {
  6458. args.append(*createConstant(createIntValue(to->getDigits(), 1, false)));
  6459. args.append(*createConstant(createIntValue(to->getPrecision(), 1, false)));
  6460. callProcedure(ctx, DecSetPrecisionId, args);
  6461. }
  6462. op.setown(createValue(no_decimalstack, LINK(to)));
  6463. }
  6464. break;
  6465. case type_set:
  6466. {
  6467. //MORE: Shouldn't have to create this node...
  6468. OwnedHqlExpr cast = createValue(no_implicitcast, LINK(to), pure.getTranslatedExpr());
  6469. buildTempExpr(ctx, cast, tgt);
  6470. return;
  6471. }
  6472. case type_pointer:
  6473. case type_row:
  6474. break;
  6475. case type_varstring:
  6476. if ((to->getSize() == UNKNOWN_LENGTH) && (from->getTypeCode() == type_varstring))
  6477. tgt.set(pure);
  6478. else
  6479. doBuildCastViaTemp(ctx, to, pure, tgt);
  6480. return;
  6481. case type_string:
  6482. case type_data:
  6483. {
  6484. if (canRemoveStringCast(to, from))
  6485. {
  6486. ICharsetInfo * srcset = from->queryCharset();
  6487. ICharsetInfo * tgtset = to->queryCharset();
  6488. //Data never calls a conversion function... but does add a cast
  6489. if ((srcset == tgtset) || (to->getTypeCode() == type_data) || (from->getTypeCode() == type_data))
  6490. {
  6491. if (from->getTypeCode() == type_varstring)
  6492. tgt.length.setown(getBoundLength(pure));
  6493. else
  6494. tgt.length.set(pure.length);
  6495. Owned<ITypeInfo> newType;
  6496. if (to->getSize() == UNKNOWN_LENGTH)
  6497. newType.setown(getStretchedType(from->getSize(), to));
  6498. else
  6499. newType.set(to);
  6500. if (from->getTypeCode() != type_data)
  6501. {
  6502. newType.setown(cloneModifiers(from, newType));
  6503. tgt.expr.setown(createValue(no_typetransfer, newType.getClear(), pure.expr.getLink()));
  6504. }
  6505. else
  6506. {
  6507. IHqlExpression * base = queryStripCasts(pure.expr);
  6508. newType.setown(makeReferenceModifier(newType.getClear()));
  6509. tgt.expr.setown(createValue(no_cast, newType.getClear(), LINK(base)));
  6510. }
  6511. return;
  6512. }
  6513. }
  6514. }
  6515. doBuildCastViaTemp(ctx, to, pure, tgt);
  6516. return;
  6517. case type_unicode:
  6518. case type_varunicode:
  6519. case type_utf8:
  6520. if ((from->getTypeCode() == to->getTypeCode()) && (to->getSize() == UNKNOWN_LENGTH))
  6521. {
  6522. tgt.set(pure);
  6523. return;
  6524. }
  6525. doBuildCastViaTemp(ctx, to, pure, tgt);
  6526. return;
  6527. default:
  6528. doBuildCastViaTemp(ctx, to, pure, tgt);
  6529. return;
  6530. }
  6531. if (funcName)
  6532. op.setown(bindTranslatedFunctionCall(funcName, args));
  6533. if (!op)
  6534. op.setown(ensureExprType(pure.expr, to));
  6535. if (queryUnqualifiedType(op->queryType()) != queryUnqualifiedType(to))
  6536. {
  6537. OwnedHqlExpr translated = createTranslated(op);
  6538. OwnedHqlExpr cast = ensureExprType(translated, to);
  6539. buildExpr(ctx, cast, tgt);
  6540. }
  6541. else
  6542. tgt.expr.setown(op.getClear());
  6543. }
  6544. //---------------------------------------------------------------------------
  6545. //-- no_char_length --
  6546. //NB: parameter is expression to take length of - not the length node.
  6547. IHqlExpression * HqlCppTranslator::doBuildCharLength(BuildCtx & ctx, IHqlExpression * expr)
  6548. {
  6549. CHqlBoundExpr bound;
  6550. buildCachedExpr(ctx, expr, bound);
  6551. return getBoundLength(bound);
  6552. }
  6553. //---------------------------------------------------------------------------
  6554. //-- no_choose
  6555. void HqlCppTranslator::doBuildChoose(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr)
  6556. {
  6557. CHqlBoundExpr test;
  6558. BuildCtx subctx(ctx);
  6559. buildExpr(subctx, expr->queryChild(0), test);
  6560. IHqlStmt * stmt = subctx.addSwitch(test.expr);
  6561. unsigned max = expr->numChildren()-1;
  6562. unsigned idx;
  6563. for (idx = 1; idx < max; idx++)
  6564. {
  6565. OwnedHqlExpr branch = getSizetConstant(idx);
  6566. subctx.addCase(stmt, branch);
  6567. buildExprOrAssign(subctx, target, expr->queryChild(idx), NULL);
  6568. }
  6569. IHqlExpression * defaultExpr = expr->queryChild(max);
  6570. if (target || !isNullAction(defaultExpr))
  6571. {
  6572. subctx.addDefault(stmt);
  6573. buildExprOrAssign(subctx, target, defaultExpr, NULL);
  6574. }
  6575. }
  6576. void HqlCppTranslator::doBuildAssignChoose(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6577. {
  6578. unsigned max = expr->numChildren()-1;
  6579. unsigned idx;
  6580. bool allConstant = true;
  6581. for (idx = 1; idx < max; idx++)
  6582. {
  6583. if (!expr->queryChild(idx)->queryValue())
  6584. allConstant = false;
  6585. }
  6586. if (allConstant)
  6587. {
  6588. //MORE: Need to calculate the correct type.
  6589. HqlExprArray args;
  6590. args.append(*LINK(expr->queryChild(0)));
  6591. for (idx = 1; idx < max; idx++)
  6592. {
  6593. IHqlExpression * v1 = createConstant(createIntValue(idx, LINK(unsignedType)));
  6594. IHqlExpression * v2 = expr->queryChild(idx);
  6595. ITypeInfo * type = v2->queryType();
  6596. args.append(* createValue(no_mapto, LINK(type), v1, LINK(v2)));
  6597. }
  6598. args.append(*LINK(expr->queryChild(max)));
  6599. OwnedHqlExpr caseExpr = createValue(no_case, expr->getType(), args);
  6600. buildExprAssign(ctx, target, caseExpr);
  6601. }
  6602. else
  6603. {
  6604. doBuildChoose(ctx, &target, expr);
  6605. }
  6606. }
  6607. //---------------------------------------------------------------------------
  6608. //-- compare (no_eq,no_ne,no_lt,no_gt,no_le,no_ge) --
  6609. //Are the arguments scalar? If so return the scalar arguments.
  6610. static bool getIsScalarCompare(IHqlExpression * expr, SharedHqlExpr & left, SharedHqlExpr & right)
  6611. {
  6612. left.set(expr->queryChild(0));
  6613. right.set(expr->queryChild(1));
  6614. ITypeInfo * lType = left->queryType();
  6615. ITypeInfo * rType = right->queryType();
  6616. type_t leftTypeCode = lType ? lType->getTypeCode() : type_row;
  6617. type_t rightTypeCode = rType ? rType->getTypeCode() : type_row;
  6618. assertex(leftTypeCode == rightTypeCode);
  6619. switch (leftTypeCode)
  6620. {
  6621. case type_row:
  6622. case type_set:
  6623. return false;
  6624. default:
  6625. return true;
  6626. }
  6627. }
  6628. void HqlCppTranslator::doBuildAssignCompare(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6629. {
  6630. OwnedHqlExpr left;
  6631. OwnedHqlExpr right;
  6632. if (getIsScalarCompare(expr, left, right))
  6633. {
  6634. doBuildExprAssign(ctx, target, expr);
  6635. return;
  6636. }
  6637. //Comparing a row - calculate the ordering and then compare against zero...
  6638. IHqlExpression * compare = createValue(no_order, LINK(signedType), LINK(left), LINK(right));
  6639. OwnedHqlExpr temp = createBoolExpr(expr->getOperator(), compare, getZero());
  6640. buildExprAssign(ctx, target, temp);
  6641. }
  6642. //---------------------------------------------------------------------------
  6643. //-- no_concat --
  6644. void HqlCppTranslator::buildConcatFArgs(HqlExprArray & args, BuildCtx & ctx, const HqlExprArray & values, ITypeInfo * argType)
  6645. {
  6646. ForEachItemIn(idx, values)
  6647. {
  6648. IHqlExpression * cur = &values.item(idx);
  6649. OwnedHqlExpr value = getCastParameter(cur, argType, "");
  6650. CHqlBoundExpr bound;
  6651. buildCachedExpr(ctx, value, bound);
  6652. //The function takes ... so the length must be 4 bytes or the stack
  6653. //gets out of sync...
  6654. OwnedHqlExpr length = getBoundLength(bound);
  6655. args.append(*ensureExprType(length, unsignedType));
  6656. args.append(*getElementPointer(bound.expr));
  6657. }
  6658. args.append(*createConstant(signedType->castFrom(true, -1))); // correct size terminator
  6659. }
  6660. void HqlCppTranslator::doBuildVarLengthConcatF(BuildCtx & ctx, const CHqlBoundTarget & target, const HqlExprArray & values)
  6661. {
  6662. ITypeInfo * targetType = target.queryType();
  6663. Linked<ITypeInfo> argType = targetType;
  6664. type_t ttc = targetType->getTypeCode();
  6665. HqlExprArray args;
  6666. IIdAtom * func;
  6667. if (ttc == type_varstring)
  6668. {
  6669. func = concatVStrId;
  6670. argType.setown(makeStringType(UNKNOWN_LENGTH, LINK(targetType->queryCharset()), LINK(targetType->queryCollation())));
  6671. }
  6672. else if (ttc == type_unicode)
  6673. {
  6674. args.append(*target.length.getLink());
  6675. func = concatUnicodeId;
  6676. }
  6677. else if (ttc == type_utf8)
  6678. {
  6679. args.append(*target.length.getLink());
  6680. func = concatUtf8Id;
  6681. }
  6682. else if (ttc == type_varunicode)
  6683. {
  6684. func = concatVUnicodeId;
  6685. argType.setown(makeUnicodeType(UNKNOWN_LENGTH, targetType->queryLocale()));
  6686. }
  6687. else
  6688. {
  6689. args.append(*target.length.getLink());
  6690. func = concatId;
  6691. }
  6692. IHqlExpression * tgt = createValue(no_address, makeVoidType(), LINK(target.expr));
  6693. if (ttc == type_data)
  6694. tgt = createValue(no_implicitcast, makePointerType(makeStringType(UNKNOWN_LENGTH, NULL, NULL)), tgt);
  6695. args.append(*tgt);
  6696. buildConcatFArgs(args, ctx, values, argType);
  6697. callProcedure(ctx, func, args);
  6698. }
  6699. bool HqlCppTranslator::doBuildFixedLengthConcatF(BuildCtx & ctx, const CHqlBoundTarget & target, const HqlExprArray & values)
  6700. {
  6701. ITypeInfo * targetType = target.queryType();
  6702. Owned<ITypeInfo> argType = getStretchedType(UNKNOWN_LENGTH, targetType);
  6703. type_t ttc = targetType->getTypeCode();
  6704. HqlExprArray args;
  6705. IIdAtom * func = NULL;
  6706. OwnedHqlExpr fill;
  6707. switch (ttc)
  6708. {
  6709. case type_varstring:
  6710. func = concatVStrFId;
  6711. argType.setown(makeStringType(UNKNOWN_LENGTH, LINK(targetType->queryCharset()), LINK(targetType->queryCollation())));
  6712. break;
  6713. case type_varunicode:
  6714. func = concatVUnicodeFId;
  6715. argType.setown(makeUnicodeType(UNKNOWN_LENGTH, targetType->queryLocale()));
  6716. break;
  6717. case type_unicode:
  6718. func = concatUnicodeFId;
  6719. break;
  6720. case type_string:
  6721. func = concatStrFId;
  6722. if (targetType->queryCharset()->queryName() == ebcdicAtom)
  6723. fill.setown(getSizetConstant('@'));
  6724. else
  6725. fill.setown(getSizetConstant(' '));
  6726. break;
  6727. case type_data:
  6728. func = concatStrFId;
  6729. fill.setown(getSizetConstant(0));
  6730. break;
  6731. }
  6732. if (func)
  6733. {
  6734. args.append(*getSizetConstant(targetType->getStringLen()));
  6735. args.append(*getPointer(target.expr));
  6736. if (fill)
  6737. args.append(*LINK(fill));
  6738. buildConcatFArgs(args, ctx, values, argType);
  6739. callProcedure(ctx, func, args);
  6740. return true;
  6741. }
  6742. return false;
  6743. }
  6744. void HqlCppTranslator::doBuildAssignConcat(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6745. {
  6746. ITypeInfo * targetType = target.queryType();
  6747. ICharsetInfo * targetCharset = targetType->queryCharset();
  6748. type_t ttc = targetType->getTypeCode();
  6749. switch (ttc)
  6750. {
  6751. case type_unicode:
  6752. case type_varunicode:
  6753. case type_utf8:
  6754. break;
  6755. case type_string:
  6756. case type_varstring:
  6757. case type_data:
  6758. if (!queryDefaultTranslation(targetCharset, expr->queryType()->queryCharset()))
  6759. break;
  6760. //fallthrough
  6761. default:
  6762. doBuildExprAssign(ctx, target, expr);
  6763. return;
  6764. }
  6765. HqlExprArray values;
  6766. expr->unwindList(values, no_concat);
  6767. //Combine adjacent constants (not folded previously because of the tree structure)
  6768. //Not optimized in the folder since it can mess up cse evaluation
  6769. for (unsigned i=0; i < values.ordinality()-1; i++)
  6770. {
  6771. IValue * firstValue = values.item(i).queryValue();
  6772. if (firstValue)
  6773. {
  6774. Linked<IValue> combinedValue = firstValue;
  6775. while (i+1 < values.ordinality())
  6776. {
  6777. IValue * nextValue = values.item(i+1).queryValue();
  6778. if (!nextValue)
  6779. break;
  6780. combinedValue.setown(concatValues(combinedValue, nextValue));
  6781. values.remove(i+1);
  6782. }
  6783. if (combinedValue->queryType()->getStringLen() == 0)
  6784. {
  6785. values.remove(i);
  6786. i--; // not nice, but will be incremented before comparison so safe
  6787. }
  6788. else if (combinedValue != firstValue)
  6789. values.replace(*createConstant(combinedValue.getClear()), i);
  6790. }
  6791. }
  6792. if (!target.isFixedSize())
  6793. {
  6794. doBuildVarLengthConcatF(ctx, target, values);
  6795. }
  6796. else if (!doBuildFixedLengthConcatF(ctx, target, values))
  6797. {
  6798. Owned<ITypeInfo> varType = getStretchedType(UNKNOWN_LENGTH, targetType);
  6799. OwnedHqlExpr castValue = createValue(no_concat, LINK(varType), values);
  6800. doBuildExprAssign(ctx, target, castValue);
  6801. }
  6802. }
  6803. void HqlCppTranslator::doBuildAssignExecuteWhen(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6804. {
  6805. IHqlExpression * value = expr->queryChild(0);
  6806. IHqlExpression * action = expr->queryChild(1);
  6807. if (expr->hasAttribute(beforeAtom))
  6808. {
  6809. buildStmt(ctx, action);
  6810. buildExprAssign(ctx, target, value);
  6811. }
  6812. else if (expr->hasAttribute(failureAtom))
  6813. {
  6814. BuildCtx tryctx(ctx);
  6815. tryctx.addTry();
  6816. buildExprAssign(tryctx, target, value);
  6817. BuildCtx catchctx(ctx);
  6818. catchctx.addCatch(NULL);
  6819. buildStmt(catchctx, action);
  6820. catchctx.addThrow(NULL);
  6821. }
  6822. else
  6823. {
  6824. buildExprAssign(ctx, target, value);
  6825. buildStmt(ctx, action);
  6826. }
  6827. }
  6828. //---------------------------------------------------------------------------
  6829. //-- no_div --
  6830. // also used for no_modulus
  6831. void HqlCppTranslator::doBuildExprDivide(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6832. {
  6833. if (expr->queryType()->getTypeCode() == type_decimal)
  6834. {
  6835. doBuildExprArith(ctx, expr, tgt);
  6836. return;
  6837. }
  6838. IHqlExpression * left = expr->queryChild(0);
  6839. IHqlExpression * right = expr->queryChild(1);
  6840. assertex(left->queryType() == right->queryType());
  6841. IValue * value = right->queryValue();
  6842. if (value)
  6843. {
  6844. Owned<IValue> zero = right->queryType()->castFrom(false, 0);
  6845. int cmp = value->compare(zero);
  6846. if (cmp == 0)
  6847. {
  6848. OwnedHqlExpr eZero = createConstant(LINK(zero));
  6849. doBuildDivideByZero(ctx, NULL, eZero, &tgt);
  6850. }
  6851. else
  6852. doBuildPureSubExpr(ctx, expr, tgt);
  6853. }
  6854. else
  6855. {
  6856. buildTempExpr(ctx, expr, tgt);
  6857. }
  6858. }
  6859. void HqlCppTranslator::doBuildDivideByZero(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * zero, CHqlBoundExpr * bound)
  6860. {
  6861. //Always assign something to bound - even if it is replaced further down.
  6862. if (bound)
  6863. buildExpr(ctx, zero, *bound);
  6864. switch (options.divideByZeroAction)
  6865. {
  6866. case DBZzero:
  6867. if (target)
  6868. assignBound(ctx, *target, zero);
  6869. break;
  6870. case DBZfail:
  6871. {
  6872. HqlExprArray noArgs;
  6873. buildFunctionCall(ctx, failDivideByZeroId, noArgs);
  6874. break;
  6875. }
  6876. case DBZnan:
  6877. {
  6878. LinkedHqlExpr nan = zero;
  6879. if (zero->queryType()->getTypeCode() == type_real)
  6880. {
  6881. HqlExprArray noArgs;
  6882. nan.setown(bindFunctionCall(createRealInfId, noArgs));
  6883. }
  6884. if (target)
  6885. assignBound(ctx, *target, nan);
  6886. else
  6887. buildExpr(ctx, nan, *bound);
  6888. break;
  6889. }
  6890. default:
  6891. throwUnexpected();
  6892. }
  6893. }
  6894. void HqlCppTranslator::doBuildAssignDivide(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6895. {
  6896. if (expr->queryType()->getTypeCode() == type_decimal)
  6897. {
  6898. doBuildExprAssign(ctx, target, expr);
  6899. return;
  6900. }
  6901. IHqlExpression * left = expr->queryChild(0);
  6902. IHqlExpression * right = expr->queryChild(1);
  6903. assertex(left->queryType() == right->queryType());
  6904. CHqlBoundExpr lhs,rhs;
  6905. buildExpr(ctx, left, lhs);
  6906. buildSimpleExpr(ctx, right, rhs);
  6907. IHqlExpression * divisor = rhs.expr.get();
  6908. OwnedHqlExpr pureExpr = createValue(expr->getOperator(), left->getType(), lhs.expr.getClear(), LINK(divisor));
  6909. IValue * zero = pureExpr->queryType()->castFrom(false, 0);
  6910. OwnedHqlExpr eZero = createConstant(zero);
  6911. IValue * value = rhs.expr->queryValue();
  6912. if (value)
  6913. {
  6914. int cmp = value->compare(eZero->queryValue());
  6915. if (cmp == 0)
  6916. doBuildDivideByZero(ctx, &target, eZero, NULL);
  6917. else
  6918. assignBound(ctx, target, pureExpr);
  6919. }
  6920. else
  6921. {
  6922. BuildCtx subctx(ctx);
  6923. IHqlStmt * stmt = subctx.addFilter(divisor);
  6924. assignBound(subctx, target, pureExpr);
  6925. subctx.selectElse(stmt);
  6926. doBuildDivideByZero(subctx, &target, eZero, NULL);
  6927. }
  6928. }
  6929. //---------------------------------------------------------------------------
  6930. //-- no_if --
  6931. bool HqlCppTranslator::ifRequiresAssignment(BuildCtx & ctx, IHqlExpression * expr)
  6932. {
  6933. IHqlExpression * trueExpr = expr->queryChild(1);
  6934. IHqlExpression * falseExpr = expr->queryChild(2);
  6935. if (requiresTemp(ctx, trueExpr, true) || requiresTemp(ctx, falseExpr, true) || expr->queryType()->getSize() == UNKNOWN_LENGTH)
  6936. return true;
  6937. if (trueExpr->queryType() != falseExpr->queryType() && isStringType(expr->queryType()))
  6938. return true;
  6939. type_t tc = expr->queryType()->getTypeCode();
  6940. if ((tc == type_decimal) || (tc == type_data))
  6941. return true;
  6942. return false;
  6943. }
  6944. void HqlCppTranslator::doBuildAssignIf(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  6945. {
  6946. CHqlBoundExpr bound;
  6947. if (expr->isPure() && ctx.getMatchExpr(expr, bound))
  6948. {
  6949. assign(ctx, target, bound);
  6950. return;
  6951. }
  6952. if (!ifRequiresAssignment(ctx, expr))
  6953. {
  6954. doBuildExprAssign(ctx, target, expr);
  6955. return;
  6956. }
  6957. IHqlExpression * trueExpr = expr->queryChild(1);
  6958. IHqlExpression * falseExpr = expr->queryChild(2);
  6959. BuildCtx subctx(ctx);
  6960. CHqlBoundExpr cond;
  6961. buildCachedExpr(subctx, expr->queryChild(0), cond);
  6962. IHqlStmt * test = subctx.addFilter(cond.expr);
  6963. buildExprAssign(subctx, target, trueExpr);
  6964. subctx.selectElse(test);
  6965. buildExprAssign(subctx, target, falseExpr);
  6966. }
  6967. void HqlCppTranslator::doBuildExprIf(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  6968. {
  6969. if (ifRequiresAssignment(ctx, expr))
  6970. {
  6971. buildTempExpr(ctx, expr, tgt);
  6972. return;
  6973. }
  6974. IHqlExpression * trueExpr = expr->queryChild(1);
  6975. IHqlExpression * falseExpr = expr->queryChild(2);
  6976. //Length should not be conditional...
  6977. CHqlBoundExpr cond;
  6978. CHqlBoundExpr boundTrue;
  6979. CHqlBoundExpr boundFalse;
  6980. buildCachedExpr(ctx, expr->queryChild(0), cond);
  6981. buildCachedExpr(ctx, trueExpr, boundTrue);
  6982. buildCachedExpr(ctx, falseExpr, boundFalse);
  6983. //true and false should have same type...
  6984. tgt.expr.setown(createValue(no_if, expr->getType(), cond.expr.getClear(), boundTrue.expr.getClear(), boundFalse.expr.getClear()));
  6985. }
  6986. void HqlCppTranslator::doBuildStmtIf(BuildCtx & ctx, IHqlExpression * expr)
  6987. {
  6988. OwnedHqlExpr converted = combineIfsToCase(expr);
  6989. if (converted)
  6990. return buildStmt(ctx, converted);
  6991. BuildCtx subctx(ctx);
  6992. CHqlBoundExpr cond;
  6993. buildCachedExpr(subctx, expr->queryChild(0), cond);
  6994. IHqlStmt * test = subctx.addFilter(cond.expr);
  6995. optimizeBuildActionList(subctx, expr->queryChild(1));
  6996. IHqlExpression * elseExpr = queryRealChild(expr, 2);
  6997. if (elseExpr && elseExpr->getOperator() != no_null)
  6998. {
  6999. subctx.selectElse(test);
  7000. optimizeBuildActionList(subctx, elseExpr);
  7001. }
  7002. }
  7003. //---------------------------------------------------------------------------
  7004. //-- no_intformat --
  7005. IHqlExpression * HqlCppTranslator::createFormatCall(IIdAtom * func, IHqlExpression * expr)
  7006. {
  7007. HqlExprArray args;
  7008. unsigned max = expr->numChildren();
  7009. unsigned idx;
  7010. for (idx=0; idx < max; idx++)
  7011. {
  7012. IHqlExpression * cur = expr->queryChild(idx);;
  7013. args.append(*LINK(cur));
  7014. }
  7015. return bindFunctionCall(func, args);
  7016. }
  7017. void HqlCppTranslator::doBuildExprFormat(IIdAtom * func, BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7018. {
  7019. OwnedHqlExpr call = createFormatCall(func, expr);
  7020. buildExpr(ctx, call, tgt);
  7021. }
  7022. void HqlCppTranslator::doBuildAssignFormat(IIdAtom * func, BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  7023. {
  7024. OwnedHqlExpr call = createFormatCall(func, expr);
  7025. buildExprAssign(ctx, target, call);
  7026. }
  7027. //---------------------------------------------------------------------------
  7028. void HqlCppTranslator::doBuildAssignToXmlorJson(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  7029. {
  7030. IHqlExpression * row = expr->queryChild(0);
  7031. HqlExprArray args;
  7032. args.append(*buildMetaParameter(row));
  7033. args.append(*LINK(row));
  7034. args.append(*getSizetConstant(XWFtrim|XWFopt|XWFnoindent));
  7035. node_operator op = expr->getOperator();
  7036. OwnedHqlExpr call = bindFunctionCall((op==no_tojson) ? ctxGetRowJsonId : ctxGetRowXmlId, args);
  7037. buildExprAssign(ctx, target, call);
  7038. }
  7039. //---------------------------------------------------------------------------
  7040. void HqlCppTranslator::processCppBodyDirectives(IHqlExpression * expr)
  7041. {
  7042. ForEachChild(i, expr)
  7043. {
  7044. IHqlExpression * cur = expr->queryChild(i);
  7045. if (cur->isAttribute())
  7046. {
  7047. IAtom * name = cur->queryName();
  7048. if (name == linkAtom)
  7049. {
  7050. //MORE: Add code to add the argument to the linker options.
  7051. }
  7052. else if (name == libraryAtom)
  7053. {
  7054. StringBuffer libraryName;
  7055. getStringValue(libraryName, cur->queryChild(0));
  7056. if (libraryName.length())
  7057. useLibrary(libraryName.str());
  7058. }
  7059. else if (name == sourceAtom)
  7060. {
  7061. StringBuffer sourceName;
  7062. getStringValue(sourceName, cur->queryChild(0));
  7063. if (sourceName.length())
  7064. code->useSourceFile(sourceName.str(), nullptr, false);
  7065. }
  7066. }
  7067. }
  7068. }
  7069. void HqlCppTranslator::doBuildExprEmbedBody(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * tgt)
  7070. {
  7071. if (expr->hasAttribute(_disallowed_Atom))
  7072. throwError(HQLERR_EmbeddedCppNotAllowed);
  7073. processCppBodyDirectives(expr);
  7074. IHqlExpression *languageAttr = expr->queryAttribute(languageAtom);
  7075. if (languageAttr)
  7076. {
  7077. UNIMPLEMENTED; // It's not clear if this can ever happen - perhaps a parameterless function that used EMBED ?
  7078. }
  7079. StringBuffer text;
  7080. expr->queryChild(0)->queryValue()->getUTF8Value(text);
  7081. text.setLength(cleanupEmbeddedCpp(text.length(), (char*)text.str()));
  7082. OwnedHqlExpr quoted = createQuoted(text.str(), expr->getType());
  7083. if (tgt)
  7084. {
  7085. ITypeInfo * type = expr->queryType();
  7086. assertex(type->getTypeCode() == type_varstring || type->getSize() != UNKNOWN_LENGTH);
  7087. tgt->expr.set(quoted);
  7088. }
  7089. else
  7090. ctx.addExpr(quoted);
  7091. }
  7092. //---------------------------------------------------------------------------
  7093. //-- no_index --
  7094. IHqlExpression * getSimpleListIndex(BuildCtx & ctx, IHqlExpression * expr)
  7095. {
  7096. IHqlExpression * index = expr->queryChild(1);
  7097. if (!index->isConstant())
  7098. return NULL;
  7099. OwnedHqlExpr set = normalizeListCasts(expr->queryChild(0));
  7100. switch (set->getOperator())
  7101. {
  7102. case no_null:
  7103. case no_list:
  7104. break;
  7105. default:
  7106. return NULL;
  7107. }
  7108. OwnedHqlExpr folded = foldHqlExpression(index);
  7109. assertex(folded->queryValue());
  7110. __int64 which = folded->queryValue()->getIntValue();
  7111. if ((which > 0) && (which <= set->numChildren()))
  7112. return LINK(set->queryChild((unsigned)which-1));
  7113. return createNullExpr(expr);
  7114. }
  7115. void HqlCppTranslator::doBuildExprIndex(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7116. {
  7117. OwnedHqlExpr simple = getSimpleListIndex(ctx, expr);
  7118. if (simple)
  7119. buildExpr(ctx, simple, tgt);
  7120. else
  7121. {
  7122. OwnedHqlExpr simpleList = simplifyFixedLengthList(expr->queryChild(0));
  7123. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, simpleList);
  7124. cursor->buildExprSelect(ctx, expr, tgt);
  7125. }
  7126. }
  7127. void HqlCppTranslator::doBuildAssignIndex(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  7128. {
  7129. OwnedHqlExpr simple = getSimpleListIndex(ctx, expr);
  7130. if (simple)
  7131. buildExprAssign(ctx, target, simple);
  7132. else
  7133. {
  7134. OwnedHqlExpr simpleList = simplifyFixedLengthList(expr->queryChild(0));
  7135. Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, simpleList);
  7136. cursor->buildAssignSelect(ctx, target, expr);
  7137. }
  7138. }
  7139. //---------------------------------------------------------------------------
  7140. //-- no_list --
  7141. bool isComplexSet(ITypeInfo * type, bool isConstant)
  7142. {
  7143. ITypeInfo * childType = type->queryChildType();
  7144. if (!childType)
  7145. return false;
  7146. switch (childType->getTypeCode())
  7147. {
  7148. case type_alien:
  7149. return true;
  7150. case type_string:
  7151. case type_qstring:
  7152. case type_data:
  7153. case type_unicode:
  7154. case type_varstring:
  7155. case type_varunicode:
  7156. return isUnknownSize(childType) && !isConstant;
  7157. case type_utf8:
  7158. case type_swapint:
  7159. case type_packedint:
  7160. return true;
  7161. case type_int:
  7162. switch (childType->getSize())
  7163. {
  7164. case 3: case 5: case 6: case 7:
  7165. return true;
  7166. }
  7167. return false;
  7168. }
  7169. return false;
  7170. }
  7171. bool isComplexSet(IHqlExpression * expr)
  7172. {
  7173. return isComplexSet(expr->queryType(), isConstantSet(expr));
  7174. }
  7175. bool isConstantSet(IHqlExpression * expr)
  7176. {
  7177. unsigned max = expr->numChildren();
  7178. unsigned idx;
  7179. for (idx = 0; idx < max; idx++)
  7180. {
  7181. IHqlExpression * child = expr->queryChild(idx);
  7182. if (!child->queryValue())
  7183. return false;
  7184. }
  7185. return true;
  7186. }
  7187. bool createUnknownLengthStringSet(MemoryBuffer & target, IHqlExpression * set)
  7188. {
  7189. ITypeInfo * elemType = set->queryType()->queryChildType();
  7190. type_t tc = elemType->getTypeCode();
  7191. ForEachChild(i, set)
  7192. {
  7193. IHqlExpression * cur = set->queryChild(i);
  7194. IValue * curValue = cur->queryValue();
  7195. if (!curValue)
  7196. return false;
  7197. size32_t sizeValue = curValue->getSize();
  7198. if ((tc != type_varstring) && (tc != type_varunicode))
  7199. {
  7200. size32_t lenValue = curValue->queryType()->getStringLen();
  7201. rtlWriteInt4(target.reserve(sizeof(size32_t)), lenValue);
  7202. }
  7203. curValue->toMem(target.reserve(sizeValue));
  7204. }
  7205. return true;
  7206. }
  7207. void HqlCppTranslator::doBuildExprConstList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7208. {
  7209. BuildCtx declareCtx(*code, literalAtom);
  7210. if (!declareCtx.getMatchExpr(expr, tgt))
  7211. {
  7212. ITypeInfo * type = expr->queryType();
  7213. Linked<ITypeInfo> elementType = type->queryChildType();
  7214. if (!elementType)
  7215. throwError(HQLERR_NullSetCannotGenerate);
  7216. Owned<ITypeInfo> transferType;
  7217. OwnedHqlExpr table;
  7218. OwnedHqlExpr declare;
  7219. unsigned numElements = expr->numChildren();
  7220. LinkedHqlExpr values = expr;
  7221. if ((isTypePassedByAddress(elementType) && ((elementType->getTypeCode() != type_varstring) || isUnknownSize(elementType))))
  7222. {
  7223. if (isUnknownSize(elementType))
  7224. {
  7225. MemoryBuffer serialized;
  7226. bool ok = createUnknownLengthStringSet(serialized, values);
  7227. assertex(ok);
  7228. Owned<IValue> value = createDataValue(serialized.toByteArray(), serialized.length());
  7229. OwnedHqlExpr constValue = createConstant(LINK(value));
  7230. OwnedHqlExpr initializer = createValue(no_create_initializer, constValue->getType(), LINK(constValue));
  7231. Owned<ITypeInfo> declareType = makeConstantModifier(constValue->getType());
  7232. declare.setown(declareCtx.getTempDeclare(declareType, initializer));
  7233. ITypeInfo * arrayType = makeReferenceModifier(makeSetType(LINK(elementType)));
  7234. table.setown(createValue(no_typetransfer, arrayType, LINK(declare)));
  7235. tgt.length.setown(getSizetConstant(serialized.length()));
  7236. }
  7237. else if (elementType->isReference())
  7238. {
  7239. // use a var string type to get better C++ generated...
  7240. transferType.set(elementType);
  7241. elementType.setown(makeVarStringType(UNKNOWN_LENGTH));
  7242. }
  7243. else
  7244. {
  7245. // for string, data and qstring we need to initialize the array with a list of characters instead of
  7246. // a cstring e.g., char[][2] = { { 'a','b' }, { 'c', 'd' } };
  7247. HqlExprArray newValues;
  7248. ForEachChild(idx, expr)
  7249. {
  7250. IHqlExpression * next = expr->queryChild(idx);
  7251. newValues.append(*createValue(no_create_initializer, next->getType(), LINK(next)));
  7252. }
  7253. values.setown(createValue(no_list, makeSetType(LINK(elementType)), newValues));
  7254. }
  7255. }
  7256. if (!declare)
  7257. {
  7258. Owned<ITypeInfo> t = makeConstantModifier(makeArrayType(LINK(elementType), numElements));
  7259. declare.setown(declareCtx.getTempDeclare(t, values));
  7260. if (transferType)
  7261. {
  7262. ITypeInfo * arrayType = makeArrayType(LINK(transferType), numElements);
  7263. table.setown(createValue(no_typetransfer, arrayType, LINK(declare)));
  7264. }
  7265. }
  7266. tgt.count.setown(getSizetConstant(numElements));
  7267. tgt.expr.set(table ? table : declare);
  7268. //make sure tables get added before any global functions
  7269. declareCtx.associateExpr(expr, tgt);
  7270. if (options.spanMultipleCpp)
  7271. {
  7272. BuildCtx protoctx(*code, mainprototypesAtom);
  7273. protoctx.addDeclareExternal(declare);
  7274. }
  7275. }
  7276. }
  7277. void HqlCppTranslator::doBuildExprDynList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7278. {
  7279. if (!ctx.getMatchExpr(expr, tgt))
  7280. {
  7281. ITypeInfo * type = expr->queryType();
  7282. ITypeInfo * elementType = type->queryChildType();
  7283. unsigned max = expr->numChildren();
  7284. //MORE: What if this is an array of variable length strings?
  7285. Owned<ITypeInfo> t = makeArrayType(LINK(elementType), max);
  7286. IHqlExpression * table = ctx.getTempDeclare(t, NULL);
  7287. // new code - should really use a selector...
  7288. unsigned idx;
  7289. CHqlBoundTarget boundTarget;
  7290. for (idx = 0; idx < max; idx++)
  7291. {
  7292. IHqlExpression * child = expr->queryChild(idx);
  7293. boundTarget.expr.setown(createValue(no_index, LINK(elementType), LINK(table), createConstant((int)idx)));
  7294. buildExprAssign(ctx, boundTarget, child);
  7295. }
  7296. tgt.count.setown(getSizetConstant(max));
  7297. tgt.expr.setown(table);
  7298. ctx.associateExpr(expr, tgt);
  7299. }
  7300. }
  7301. void HqlCppTranslator::doBuildExprList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7302. {
  7303. ITypeInfo * type = expr->queryType();
  7304. switch (type->getTypeCode())
  7305. {
  7306. case type_set:
  7307. case type_array:
  7308. {
  7309. LinkedHqlExpr values = expr;
  7310. //MORE: Also alien data types and other weird things...
  7311. //if (childType->getSize() == UNKNOWN_LENGTH)
  7312. if (expr->numChildren() == 0)
  7313. {
  7314. tgt.length.setown(getSizetConstant(0));
  7315. tgt.expr.setown(createValue(no_nullptr, makeReferenceModifier(LINK(type))));
  7316. return;
  7317. }
  7318. else if (isComplexSet(expr))
  7319. {
  7320. buildTempExpr(ctx, expr, tgt);
  7321. return;
  7322. }
  7323. if (isConstantSet(expr))
  7324. doBuildExprConstList(ctx, values, tgt);
  7325. else
  7326. doBuildExprDynList(ctx, values, tgt);
  7327. tgt.isAll.set(queryBoolExpr(false));
  7328. }
  7329. break;
  7330. default:
  7331. throwUnexpectedX("This type of list not supported yet");
  7332. }
  7333. }
  7334. void HqlCppTranslator::doBuildAssignList(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * _expr)
  7335. {
  7336. OwnedHqlExpr expr = simplifyFixedLengthList(_expr);
  7337. node_operator op = expr->getOperator();
  7338. assertex(op == no_list);
  7339. ITypeInfo * type = expr->queryType();
  7340. switch (type->getTypeCode())
  7341. {
  7342. case type_set:
  7343. case type_array:
  7344. break;
  7345. default:
  7346. throwUnexpectedX("This type of list not supported yet");
  7347. }
  7348. //This is an assignment, a non-constant set would end up creating two temporaries.
  7349. unsigned numItems = expr->numChildren();
  7350. ITypeInfo * elementType = type->queryChildType();
  7351. if (((numItems > 0) && (numItems < 3) && !isUnknownSize(elementType)) || isComplexSet(expr) || !isConstantSet(expr))
  7352. {
  7353. Owned<IHqlCppSetBuilder> builder = createTempSetBuilder(target.queryType()->queryChildType(), target.isAll);
  7354. builder->buildDeclare(ctx);
  7355. buildSetAssign(ctx, builder, expr);
  7356. builder->buildFinish(ctx, target);
  7357. }
  7358. else if (numItems == 0)
  7359. {
  7360. CHqlBoundExpr temp;
  7361. buildExpr(ctx, expr, temp);
  7362. if (target.isAll)
  7363. {
  7364. if (temp.isAll)
  7365. ctx.addAssign(target.isAll, temp.isAll);
  7366. else
  7367. ctx.addAssign(target.isAll, queryBoolExpr(false));
  7368. }
  7369. ctx.addAssign(target.length, temp.length);
  7370. ctx.addAssign(target.expr, temp.expr);
  7371. }
  7372. else
  7373. {
  7374. OwnedHqlExpr cast = ensureExprType(expr, target.queryType());
  7375. OwnedHqlExpr simpleCast = simplifyFixedLengthList(cast);
  7376. // can do a direct assignment without any casts
  7377. doBuildExprAssign(ctx, target, simpleCast);
  7378. }
  7379. }
  7380. void HqlCppTranslator::doBuildExprAll(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7381. {
  7382. tgt.isAll.set(queryBoolExpr(true));
  7383. tgt.length.setown(getSizetConstant(0));
  7384. tgt.expr.setown(createQuoted("0", makeSetType(NULL)));
  7385. }
  7386. void HqlCppTranslator::doBuildAssignAll(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  7387. {
  7388. CHqlBoundExpr temp;
  7389. buildExpr(ctx, expr, temp);
  7390. ctx.addAssign(target.isAll, temp.isAll);
  7391. ctx.addAssign(target.length, temp.length);
  7392. ctx.addAssign(target.expr, temp.expr);
  7393. }
  7394. //---------------------------------------------------------------------------
  7395. //-- no_not --
  7396. void HqlCppTranslator::doBuildExprNot(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  7397. {
  7398. assertex(expr->queryChild(0)->isBoolean());
  7399. CHqlBoundExpr bound;
  7400. buildExpr(ctx, expr->queryChild(0), bound);
  7401. tgt.expr.setown(getInverse(bound.expr));
  7402. }
  7403. //---------------------------------------------------------------------------
  7404. //-- no_or --
  7405. IHqlExpression * HqlCppTranslator::convertOrToAnd(IHqlExpression * expr)
  7406. {
  7407. bool invert = true;
  7408. if (expr->getOperator() == no_not)
  7409. {
  7410. invert = false;
  7411. expr = expr->queryChild(0);
  7412. }
  7413. assertex(expr->getOperator() == no_or);
  7414. HqlExprArray original, inverted;
  7415. expr->unwindList(original, no_or);
  7416. ForEachItemIn(idx, original)
  7417. inverted.append(*getInverse(&original.item(idx)));
  7418. IHqlExpression * ret = createValue(no_and, makeBoolType(), inverted);
  7419. if (invert)
  7420. ret = createValue(no_not, makeBoolType(), ret);
  7421. return ret;
  7422. }
  7423. //---------------------------------------------------------------------------
  7424. // no_unicodeorder
  7425. void HqlCppTranslator::doBuildAssignUnicodeOrder(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  7426. {
  7427. CHqlBoundExpr lhs, rhs, locale, strength;
  7428. buildCachedExpr(ctx, expr->queryChild(0), lhs);
  7429. buildCachedExpr(ctx, expr->queryChild(1), rhs);
  7430. buildCachedExpr(ctx, expr->queryChild(2), locale);
  7431. buildCachedExpr(ctx, expr->queryChild(3), strength);
  7432. Owned<IHqlExpression> op;
  7433. HqlExprArray args;
  7434. ITypeInfo * realType = lhs.expr->queryType()->queryPromotedType();
  7435. switch(realType->getTypeCode())
  7436. {
  7437. case type_unicode:
  7438. args.append(*getBoundLength(lhs));
  7439. args.append(*getElementPointer(lhs.expr));
  7440. args.append(*getBoundLength(rhs));
  7441. args.append(*getElementPointer(rhs.expr));
  7442. args.append(*getElementPointer(locale.expr));
  7443. args.append(*strength.expr.getLink());
  7444. op.setown(bindTranslatedFunctionCall(compareUnicodeUnicodeStrengthId, args));
  7445. break;
  7446. case type_varunicode:
  7447. args.append(*getElementPointer(lhs.expr));
  7448. args.append(*getElementPointer(rhs.expr));
  7449. args.append(*getElementPointer(locale.expr));
  7450. args.append(*strength.expr.getLink());
  7451. op.setown(bindTranslatedFunctionCall(compareVUnicodeVUnicodeStrengthId, args));
  7452. break;
  7453. case type_utf8:
  7454. args.append(*getBoundLength(lhs));
  7455. args.append(*getElementPointer(lhs.expr));
  7456. args.append(*getBoundLength(rhs));
  7457. args.append(*getElementPointer(rhs.expr));
  7458. args.append(*getElementPointer(locale.expr));
  7459. args.append(*strength.expr.getLink());
  7460. op.setown(bindTranslatedFunctionCall(compareUtf8Utf8StrengthId, args));
  7461. break;
  7462. default:
  7463. UNIMPLEMENTED;
  7464. }
  7465. assignBound(ctx, target, op);
  7466. }
  7467. //---------------------------------------------------------------------------
  7468. //-- no_order --
  7469. static void buildIteratorIsValid(BuildCtx & ctx, IHqlExpression * iter, IHqlExpression * row, CHqlBoundExpr & bound)
  7470. {
  7471. bound.expr.set(row);
  7472. }
  7473. void HqlCppTranslator::buildIteratorFirst(BuildCtx & ctx, IHqlExpression * iter, IHqlExpression * row)
  7474. {
  7475. StringBuffer s;
  7476. generateExprCpp(s, row).append(" = (byte*)");
  7477. generateExprCpp(s, iter).append(".first();");
  7478. ctx.addQuoted(s);
  7479. }
  7480. void HqlCppTranslator::buildIteratorNext(BuildCtx & ctx, IHqlExpression * iter, IHqlExpression * row)
  7481. {
  7482. StringBuffer s;
  7483. generateExprCpp(s, row).append(" = (byte*)");
  7484. generateExprCpp(s, iter).append(".next();");
  7485. ctx.addQuoted(s);
  7486. }
  7487. void HqlCppTranslator::doBuildAssignCompareRow(BuildCtx & ctx, EvaluateCompareInfo & info, IHqlExpression * left, IHqlExpression * right)
  7488. {
  7489. HqlExprArray leftValues, rightValues;
  7490. expandRowOrder(left->queryNormalizedSelector(), left->queryRecord(), leftValues, false);
  7491. expandRowOrder(right->queryNormalizedSelector(), right->queryRecord(), rightValues, false);
  7492. optimizeOrderValues(leftValues, rightValues, false);
  7493. doBuildAssignCompare(ctx, info, leftValues, rightValues, true, false); //MORE: ,no_break,true
  7494. }
  7495. void HqlCppTranslator::doBuildAssignCompareTable(BuildCtx & ctx, EvaluateCompareInfo & info, IHqlExpression * left, IHqlExpression * right)
  7496. {
  7497. ITypeInfo * targetType = info.target.queryType();
  7498. OwnedHqlExpr zeroTarget = createConstant(targetType->castFrom(true, 0));
  7499. OwnedHqlExpr plusOne = createConstant(targetType->castFrom(true, +1));
  7500. OwnedHqlExpr minusOne = createConstant(targetType->castFrom(true, -1));
  7501. // cmp = 0;
  7502. assignBound(ctx, info.target, zeroTarget);
  7503. BuildCtx subctx(ctx);
  7504. subctx.addGroup(); // stop bound cursors leaking outside the testing block.
  7505. // i1 iter1; i1.first();
  7506. HqlExprAttr leftIter, leftRow;
  7507. Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(subctx, left);
  7508. cursor->buildIterateClass(subctx, leftIter, leftRow);
  7509. buildIteratorFirst(subctx, leftIter, leftRow);
  7510. // i2; forEachIn(i2); {
  7511. CHqlBoundExpr isValid;
  7512. BuildCtx loopctx(subctx);
  7513. if (buildDatasetIterate(loopctx, right, true))
  7514. {
  7515. bindTableCursor(loopctx, left, leftRow);
  7516. // if (!i1.isValid()) { cmp = -1; break; }
  7517. buildIteratorIsValid(loopctx, leftIter, leftRow, isValid);
  7518. OwnedHqlExpr test = createValue(no_not, makeBoolType(), isValid.expr.getClear());
  7519. BuildCtx moreRightCtx(loopctx);
  7520. moreRightCtx.addFilter(test);
  7521. if (info.actionIfDiffer == return_stmt)
  7522. {
  7523. if (info.isEqualityCompare())
  7524. {
  7525. OwnedHqlExpr returnValue = info.getEqualityReturnValue();
  7526. moreRightCtx.addReturn(returnValue);
  7527. }
  7528. else
  7529. moreRightCtx.addReturn(minusOne);
  7530. }
  7531. else
  7532. {
  7533. buildExprAssign(moreRightCtx, info.target, minusOne);
  7534. moreRightCtx.addBreak();
  7535. }
  7536. //Now do the comparison....
  7537. {
  7538. EvaluateCompareInfo childInfo(info);
  7539. if (childInfo.actionIfDiffer == break_stmt)
  7540. childInfo.actionIfDiffer = null_stmt;
  7541. //***childInfo??
  7542. doBuildAssignCompareRow(loopctx, info, left, right);
  7543. }
  7544. if (info.actionIfDiffer != return_stmt)
  7545. {
  7546. // if (cmp != 0) break;
  7547. BuildCtx donectx(loopctx);
  7548. donectx.addFilter(info.target.expr);
  7549. donectx.addQuotedLiteral("break;");
  7550. }
  7551. // i1.next();
  7552. buildIteratorNext(loopctx, leftIter, leftRow);
  7553. }
  7554. buildIteratorIsValid(subctx, leftIter, leftRow, isValid);
  7555. if (info.actionIfDiffer == return_stmt)
  7556. {
  7557. //if (i1.isValid) return +1;
  7558. BuildCtx moreLeftCtx(subctx);
  7559. moreLeftCtx.addFilter(isValid.expr);
  7560. if (info.isEqualityCompare())
  7561. {
  7562. OwnedHqlExpr returnValue = info.getEqualityReturnValue();
  7563. moreLeftCtx.addReturn(returnValue);
  7564. }
  7565. else
  7566. moreLeftCtx.addReturn(plusOne);
  7567. }
  7568. else
  7569. {
  7570. //if (cmp == 0 && i1.isValid) cmp = +1;
  7571. OwnedHqlExpr cmp = createBoolExpr(no_and, createBoolExpr(no_eq, LINK(info.target.expr), LINK(zeroTarget)), LINK(isValid.expr));
  7572. BuildCtx moreLeftCtx(subctx);
  7573. moreLeftCtx.addFilter(cmp);
  7574. buildExprAssign(moreLeftCtx, info.target, plusOne);
  7575. BuildCtx tailctx(ctx);
  7576. if (info.actionIfDiffer == break_stmt)
  7577. {
  7578. tailctx.addFilter(info.target.expr);
  7579. tailctx.addBreak();
  7580. }
  7581. }
  7582. }
  7583. void HqlCppTranslator::expandRowOrder(IHqlExpression * selector, IHqlExpression * record, HqlExprArray & values, bool isRow)
  7584. {
  7585. ForEachChild(idx, record)
  7586. {
  7587. IHqlExpression * field = record->queryChild(idx);
  7588. switch (field->getOperator())
  7589. {
  7590. case no_ifblock:
  7591. expandRowOrder(selector, field->queryChild(1), values, isRow);
  7592. break;
  7593. case no_record:
  7594. expandRowOrder(selector, field, values, isRow);
  7595. break;
  7596. case no_field:
  7597. {
  7598. OwnedHqlExpr selected;
  7599. if (isRow)
  7600. selected.setown(createNewSelectExpr(LINK(selector), LINK(field)));
  7601. else
  7602. selected.setown(createSelectExpr(LINK(selector), LINK(field)));
  7603. if (field->isDatarow())
  7604. expandRowOrder(selected, field->queryRecord(), values, false);
  7605. else
  7606. values.append(*LINK(selected));
  7607. break;
  7608. }
  7609. }
  7610. }
  7611. }
  7612. void HqlCppTranslator::expandSimpleOrder(IHqlExpression * left, IHqlExpression * right, HqlExprArray & leftValues, HqlExprArray & rightValues)
  7613. {
  7614. while ((left->getOperator() == no_negate) && (right->getOperator() == no_negate))
  7615. {
  7616. IHqlExpression * temp = right->queryChild(0);
  7617. right = left->queryChild(0);
  7618. left = temp;
  7619. }
  7620. if (left == right)
  7621. {
  7622. //Weird code is here just so I can force some strange exceptions in the regression suite.
  7623. IHqlExpression * cur = left;
  7624. if (cur->getOperator() == no_alias)
  7625. cur = cur->queryChild(0);
  7626. if (cur->getOperator() != no_nofold)
  7627. return;
  7628. }
  7629. if (left->isDatarow())
  7630. {
  7631. IHqlExpression * leftRecord = left->queryRecord();
  7632. IHqlExpression * rightRecord = right->queryRecord();
  7633. assertex(right->isDatarow());
  7634. if (leftRecord != rightRecord)
  7635. {
  7636. OwnedHqlExpr leftSerialRecord = getSerializedForm(leftRecord, diskAtom);
  7637. OwnedHqlExpr rightSerialRecord = getSerializedForm(rightRecord, diskAtom);
  7638. assertex(leftSerialRecord == rightSerialRecord);
  7639. }
  7640. expandRowOrder(left, leftRecord, leftValues, !isActiveRow(left) && (left->getOperator() != no_select));
  7641. expandRowOrder(right, rightRecord, rightValues, !isActiveRow(right) && (right->getOperator() != no_select));
  7642. }
  7643. else
  7644. {
  7645. leftValues.append(*LINK(left));
  7646. rightValues.append(*LINK(right));
  7647. }
  7648. }
  7649. void HqlCppTranslator::expandOrder(IHqlExpression * expr, HqlExprArray & leftValues, HqlExprArray & rightValues, SharedHqlExpr & defaultValue)
  7650. {
  7651. OwnedHqlExpr left = normalizeListCasts(expr->queryChild(0));
  7652. OwnedHqlExpr right = normalizeListCasts(expr->queryChild(1));
  7653. if ((isFixedLengthList(left) || isNullList(left)) && (isFixedLengthList(right) || isNullList(right)))
  7654. {
  7655. unsigned maxLeft = left->numChildren();
  7656. unsigned maxRight = right->numChildren();
  7657. unsigned max = std::min(maxLeft, maxRight);
  7658. for (unsigned i=0; i < max; i++)
  7659. expandSimpleOrder(left->queryChild(i), right->queryChild(i), leftValues, rightValues);
  7660. if (maxLeft != maxRight)
  7661. defaultValue.setown(createConstant(signedType->castFrom(true, ((maxLeft > maxRight) ? +1 : -1))));
  7662. }
  7663. else
  7664. expandSimpleOrder(left, right, leftValues, rightValues);
  7665. }
  7666. IHqlExpression * HqlCppTranslator::querySimpleOrderSelector(IHqlExpression * expr, bool & isNew)
  7667. {
  7668. if (expr->getOperator() != no_select)
  7669. return NULL;
  7670. return querySelectorDataset(expr, isNew);
  7671. }
  7672. static unsigned getMemcmpSize(IHqlExpression * left, IHqlExpression * right, bool isEqualityCompare)
  7673. {
  7674. ITypeInfo * leftType = left->queryType();
  7675. if (!leftType)
  7676. return 0;
  7677. if (!isSameBasicType(leftType, right->queryType()))
  7678. return 0;
  7679. unsigned size = leftType->getSize();
  7680. switch (leftType->getTypeCode())
  7681. {
  7682. case type_bigendianint:
  7683. case type_boolean:
  7684. return size;
  7685. case type_littleendianint:
  7686. if ((size == 1) && !leftType->isSigned())
  7687. return 1;
  7688. if (isEqualityCompare)
  7689. return size;
  7690. break;
  7691. case type_string:
  7692. case type_data:
  7693. case type_qstring:
  7694. if (size != UNKNOWN_LENGTH)
  7695. return size;
  7696. break;
  7697. }
  7698. return 0;
  7699. }
  7700. void HqlCppTranslator::optimizeOrderValues(HqlExprArray & leftValues, HqlExprArray & rightValues, bool isEqualityCompare)
  7701. {
  7702. unsigned max = leftValues.ordinality();
  7703. if (max <= 1)
  7704. return;
  7705. for (unsigned i=0; i < max-1; i++)
  7706. {
  7707. IHqlExpression * curFirstLeft = &leftValues.item(i);
  7708. IHqlExpression * curFirstRight = &rightValues.item(i);
  7709. bool leftIsNew;
  7710. bool rightIsNew;
  7711. IHqlExpression * leftSel = querySimpleOrderSelector(curFirstLeft, leftIsNew);
  7712. IHqlExpression * rightSel = querySimpleOrderSelector(curFirstRight, rightIsNew);
  7713. if (!leftSel || !rightSel)
  7714. continue;
  7715. unsigned compareSize = getMemcmpSize(curFirstLeft, curFirstRight, isEqualityCompare);
  7716. if (!compareSize)
  7717. continue;
  7718. bool nextLeftIsNew = false;
  7719. bool nextRightIsNew = false;
  7720. IHqlExpression * nextLeft = &leftValues.item(i+1);
  7721. IHqlExpression * nextRight = &rightValues.item(i+1);
  7722. if (querySimpleOrderSelector(nextLeft, nextLeftIsNew) != leftSel || querySimpleOrderSelector(nextRight, nextRightIsNew) != rightSel ||
  7723. (getMemcmpSize(nextLeft, nextRight, isEqualityCompare) == 0))
  7724. continue;
  7725. //Worth iterating the selectors...
  7726. RecordSelectIterator leftIter(leftSel->queryRecord(), leftSel, leftIsNew);
  7727. ForEach(leftIter)
  7728. if (leftIter.query() == curFirstLeft)
  7729. break;
  7730. if (!leftIter.isValid() || leftIter.isInsideIfBlock())
  7731. continue;
  7732. RecordSelectIterator rightIter(rightSel->queryRecord(), rightSel, rightIsNew);
  7733. ForEach(rightIter)
  7734. if (rightIter.query() == curFirstRight)
  7735. break;
  7736. if (!rightIter.isValid() || rightIter.isInsideIfBlock())
  7737. continue;
  7738. unsigned j; // linux wants it declared outside of 'for'
  7739. for (j=i+1; j < max; j++)
  7740. {
  7741. if (!leftIter.next() || leftIter.isInsideIfBlock())
  7742. break;
  7743. if (!rightIter.next() || rightIter.isInsideIfBlock())
  7744. break;
  7745. IHqlExpression * nextLeft = &leftValues.item(j);
  7746. IHqlExpression * nextRight = &rightValues.item(j);
  7747. if (leftIter.query() != nextLeft || rightIter.query() != nextRight)
  7748. break;
  7749. unsigned thisSize = getMemcmpSize(nextLeft, nextRight, isEqualityCompare);
  7750. if (!thisSize)
  7751. break;
  7752. compareSize += thisSize;
  7753. }
  7754. if (j != i+1)
  7755. {
  7756. IHqlExpression * newLeft = createValue(no_typetransfer, makeStringType(compareSize), LINK(curFirstLeft));
  7757. IHqlExpression * newRight = createValue(no_typetransfer, makeStringType(compareSize), LINK(curFirstRight));
  7758. leftValues.replace(*newLeft, i);
  7759. rightValues.replace(*newRight, i);
  7760. leftValues.removen(i+1, j-(i+1));
  7761. rightValues.removen(i+1, j-(i+1));
  7762. max -= (j - (i+1));
  7763. }
  7764. }
  7765. }
  7766. inline IHqlExpression * createSignedConstant(__int64 value)
  7767. {
  7768. return createConstant(signedType->castFrom(true, value));
  7769. }
  7770. static IHqlExpression * convertAllToInteger(IHqlExpression * allExpr)
  7771. {
  7772. IValue * allValue = allExpr->queryValue();
  7773. if (allValue)
  7774. return createSignedConstant(allValue->getBoolValue() ? 1 : 0);
  7775. return createValue(no_if, LINK(signedType), LINK(allExpr), createSignedConstant(1), createSignedConstant(0));
  7776. }
  7777. void HqlCppTranslator::doBuildAssignCompareElement(BuildCtx & ctx, EvaluateCompareInfo & info, IHqlExpression * left, IHqlExpression * right, bool isFirst, bool isLast)
  7778. {
  7779. if (left->getOperator() == no_if && right->getOperator() == no_if && left->queryChild(0) == right->queryChild(0))
  7780. {
  7781. BuildCtx subctx(ctx);
  7782. IHqlStmt * filter = buildFilterViaExpr(subctx, left->queryChild(0));
  7783. doBuildAssignCompareElement(subctx, info, left->queryChild(1), right->queryChild(1), isFirst, false);
  7784. if ((isFirst && (info.actionIfDiffer != return_stmt)) || left->queryChild(2) != right->queryChild(2))
  7785. {
  7786. subctx.selectElse(filter);
  7787. doBuildAssignCompareElement(subctx, info, left->queryChild(2), right->queryChild(2), isFirst, false);
  7788. }
  7789. return;
  7790. }
  7791. if (left == right)
  7792. {
  7793. //Can happen from conditions expanded above
  7794. if (isFirst)
  7795. {
  7796. if (info.actionIfDiffer != return_stmt)
  7797. buildExprAssign(ctx, info.target, queryZero());
  7798. }
  7799. return;
  7800. }
  7801. ITypeInfo * leftType = left->queryType();
  7802. type_t tc;
  7803. if (leftType)
  7804. tc = leftType->getTypeCode();
  7805. else
  7806. tc = type_set;
  7807. CHqlBoundExpr lhs,rhs;
  7808. bool useMemCmp = false;
  7809. switch (tc)
  7810. {
  7811. case type_dictionary:
  7812. {
  7813. //You can't iterate dictionaries, so convert to datasets first. A bit of a silly comparison anyway
  7814. OwnedHqlExpr dsLeft = createDataset(no_datasetfromdictionary, LINK(left));
  7815. OwnedHqlExpr dsRight = createDataset(no_datasetfromdictionary, LINK(right));
  7816. doBuildAssignCompareTable(ctx, info, dsLeft, dsRight);
  7817. return;
  7818. }
  7819. case type_table:
  7820. case type_groupedtable:
  7821. doBuildAssignCompareTable(ctx, info, left, right);
  7822. return;
  7823. case type_row:
  7824. doBuildAssignCompareRow(ctx, info, left, right);
  7825. return;
  7826. case type_bigendianint:
  7827. {
  7828. //MORE: Compare big endian integers with a memcmp
  7829. if (hasAddress(ctx, left) && hasAddress(ctx, right) && isSameBasicType(leftType, right->queryType()))
  7830. {
  7831. buildAddress(ctx, left, lhs);
  7832. buildAddress(ctx, right, rhs);
  7833. useMemCmp = true;
  7834. break;
  7835. }
  7836. Owned<ITypeInfo> type = makeIntType(leftType->getSize(), leftType->isSigned());
  7837. OwnedHqlExpr intLeft = createValue(no_implicitcast, type.getLink(), LINK(left));
  7838. OwnedHqlExpr intRight = createValue(no_implicitcast, type.getLink(), LINK(right));
  7839. buildCachedExpr(ctx, intLeft, lhs);
  7840. buildCachedExpr(ctx, intRight, rhs);
  7841. break;
  7842. }
  7843. case type_string:
  7844. case type_data:
  7845. case type_qstring:
  7846. {
  7847. OwnedHqlExpr simpleLeft = getSimplifyCompareArg(left);
  7848. OwnedHqlExpr simpleRight = getSimplifyCompareArg(right);
  7849. buildCachedExpr(ctx, simpleLeft, lhs);
  7850. buildCachedExpr(ctx, simpleRight, rhs);
  7851. break;
  7852. }
  7853. default:
  7854. buildCachedExpr(ctx, left, lhs);
  7855. buildCachedExpr(ctx, right, rhs);
  7856. break;
  7857. }
  7858. ITypeInfo * realType = lhs.queryType()->queryPromotedType();
  7859. tc = realType->getTypeCode();
  7860. IHqlExpression * op = NULL;
  7861. switch (tc)
  7862. {
  7863. //MORE: Should common up with comparison code...
  7864. case type_string:
  7865. case type_data:
  7866. case type_qstring:
  7867. {
  7868. HqlExprArray args;
  7869. IIdAtom * func;
  7870. if (lhs.length || rhs.length || needVarStringCompare(realType, rhs.queryType()->queryPromotedType()))
  7871. {
  7872. //MORE: This does not cope with different padding characters...
  7873. func = queryStrCompareFunc(realType);
  7874. args.append(*getBoundLength(lhs));
  7875. args.append(*getElementPointer(lhs.expr));
  7876. args.append(*getBoundLength(rhs));
  7877. args.append(*getElementPointer(rhs.expr));
  7878. }
  7879. else
  7880. {
  7881. func = memcmpId;
  7882. args.append(*getElementPointer(lhs.expr));
  7883. args.append(*getElementPointer(rhs.expr));
  7884. args.append(*getSizetConstant(realType->getSize()));
  7885. }
  7886. op = bindTranslatedFunctionCall(func, args);
  7887. break;
  7888. }
  7889. case type_unicode:
  7890. {
  7891. HqlExprArray args;
  7892. assertex(haveCommonLocale(leftType, right->queryType()));
  7893. char const * locale = str(getCommonLocale(leftType, right->queryType()));
  7894. args.append(*getBoundLength(lhs));
  7895. args.append(*getElementPointer(lhs.expr));
  7896. args.append(*getBoundLength(rhs));
  7897. args.append(*getElementPointer(rhs.expr));
  7898. args.append(*createConstant(locale));
  7899. op = bindTranslatedFunctionCall(compareUnicodeUnicodeId, args);
  7900. break;
  7901. }
  7902. case type_varunicode:
  7903. {
  7904. HqlExprArray args;
  7905. assertex(haveCommonLocale(leftType, right->queryType()));
  7906. char const * locale = str(getCommonLocale(leftType, right->queryType()));
  7907. args.append(*getElementPointer(lhs.expr));
  7908. args.append(*getElementPointer(rhs.expr));
  7909. args.append(*createConstant(locale));
  7910. op = bindTranslatedFunctionCall(compareVUnicodeVUnicodeId, args);
  7911. break;
  7912. }
  7913. case type_utf8:
  7914. {
  7915. HqlExprArray args;
  7916. assertex(haveCommonLocale(leftType, right->queryType()));
  7917. char const * locale = str(getCommonLocale(leftType, right->queryType()));
  7918. args.append(*getBoundLength(lhs));
  7919. args.append(*getElementPointer(lhs.expr));
  7920. args.append(*getBoundLength(rhs));
  7921. args.append(*getElementPointer(rhs.expr));
  7922. args.append(*createConstant(locale));
  7923. op = bindTranslatedFunctionCall(compareUtf8Utf8Id, args);
  7924. break;
  7925. }
  7926. case type_varstring:
  7927. {
  7928. HqlExprArray args;
  7929. args.append(*getElementPointer(lhs.expr));
  7930. args.append(*getElementPointer(rhs.expr));
  7931. op = bindTranslatedFunctionCall(compareVStrVStrId, args);
  7932. break;
  7933. }
  7934. case type_decimal:
  7935. {
  7936. HqlExprArray args;
  7937. if (!isPushed(lhs) && !isPushed(rhs) && (leftType->queryPromotedType() == right->queryType()->queryPromotedType()))
  7938. {
  7939. args.append(*getSizetConstant(leftType->queryPromotedType()->getSize()));
  7940. args.append(*getPointer(lhs.expr));
  7941. args.append(*getPointer(rhs.expr));
  7942. op = bindTranslatedFunctionCall(leftType->isSigned() ? DecCompareDecimalId : DecCompareUDecimalId, args);
  7943. }
  7944. else
  7945. {
  7946. bool pushedLhs = ensurePushed(ctx, lhs);
  7947. bool pushedRhs = ensurePushed(ctx, rhs);
  7948. //NB: Arguments could be pushed in opposite order 1 <=> x *2
  7949. if (pushedLhs && !pushedRhs)
  7950. op = bindTranslatedFunctionCall(DecDistinctRId, args);
  7951. else
  7952. op = bindTranslatedFunctionCall(DecDistinctId, args);
  7953. }
  7954. break;
  7955. }
  7956. case type_set:
  7957. case type_array:
  7958. {
  7959. //compare all
  7960. OwnedHqlExpr leftAll = lhs.getIsAll();
  7961. OwnedHqlExpr rightAll = rhs.getIsAll();
  7962. assertex(leftAll && rightAll);
  7963. if (leftAll != rightAll)
  7964. {
  7965. if (leftAll->queryValue() && rightAll->queryValue())
  7966. {
  7967. op = createConstant(leftAll->queryValue()->getIntValue() - rightAll->queryValue()->getIntValue());
  7968. break;
  7969. }
  7970. if (getIntValue(leftAll, false) || getIntValue(rightAll, false))
  7971. {
  7972. op = createValue(no_sub, LINK(signedType), convertAllToInteger(leftAll), convertAllToInteger(rightAll));
  7973. break;
  7974. }
  7975. }
  7976. if (lhs.expr != rhs.expr)
  7977. {
  7978. HqlExprArray args;
  7979. args.append(*getBoundLength(lhs));
  7980. args.append(*getElementPointer(lhs.expr));
  7981. args.append(*getBoundLength(rhs));
  7982. args.append(*getElementPointer(rhs.expr));
  7983. op = bindTranslatedFunctionCall(compareDataDataId, args);
  7984. }
  7985. if (leftAll != rightAll)
  7986. {
  7987. IHqlExpression * orderAll = createValue(no_sub, LINK(signedType), convertAllToInteger(leftAll), convertAllToInteger(rightAll));
  7988. if (op)
  7989. {
  7990. IHqlExpression * cond = NULL;
  7991. if (!getIntValue(leftAll, true))
  7992. {
  7993. if (!getIntValue(rightAll, true))
  7994. cond = NULL;
  7995. else
  7996. cond = LINK(rightAll);
  7997. }
  7998. else
  7999. {
  8000. if (!getIntValue(rightAll, true))
  8001. cond = LINK(leftAll);
  8002. else
  8003. cond = createBoolExpr(no_or, LINK(leftAll), LINK(rightAll));
  8004. }
  8005. if (cond)
  8006. op = createValue(no_if, LINK(signedType), cond, orderAll, op);
  8007. else
  8008. orderAll->Release();
  8009. }
  8010. else
  8011. op = orderAll;
  8012. }
  8013. if (!op)
  8014. op = getZero();
  8015. break;
  8016. }
  8017. case type_boolean:
  8018. case type_swapint:
  8019. case type_packedint:
  8020. case type_int:
  8021. if (!useMemCmp && !info.isEqualityCompare() && (realType->getSize() < signedType->getSize()))
  8022. {
  8023. op = createValue(no_sub, LINK(signedType),
  8024. createValue(no_implicitcast, LINK(signedType), lhs.expr.getLink()),
  8025. createValue(no_implicitcast, LINK(signedType), rhs.expr.getLink()));
  8026. break;
  8027. }
  8028. //fall through
  8029. default:
  8030. if (useMemCmp)
  8031. {
  8032. HqlExprArray args;
  8033. args.append(*lhs.expr.getLink());
  8034. args.append(*rhs.expr.getLink());
  8035. args.append(*getSizetConstant(leftType->getSize()));
  8036. op = bindTranslatedFunctionCall(memcmpId, args);
  8037. }
  8038. else
  8039. {
  8040. if (info.isEqualityCompare())
  8041. {
  8042. op = createBoolExpr(no_ne, LINK(lhs.expr), LINK(rhs.expr));
  8043. }
  8044. else
  8045. {
  8046. ensureSimpleExpr(ctx, lhs);
  8047. ensureSimpleExpr(ctx, rhs);
  8048. OwnedHqlExpr testlt = createBoolExpr(no_lt, lhs.expr.getLink(), rhs.expr.getLink());
  8049. OwnedHqlExpr retlt = createIntConstant(-1);
  8050. OwnedHqlExpr testgt = createBoolExpr(no_gt, lhs.expr.getLink(), rhs.expr.getLink());
  8051. OwnedHqlExpr retgt = createIntConstant(+1);
  8052. if (info.actionIfDiffer == return_stmt)
  8053. {
  8054. BuildCtx subctx1(ctx);
  8055. subctx1.addFilter(testlt);
  8056. subctx1.addReturn(retlt);
  8057. BuildCtx subctx2(ctx);
  8058. subctx2.addFilter(testgt);
  8059. subctx2.addReturn(retgt);
  8060. return;
  8061. }
  8062. else
  8063. {
  8064. // generate (a < b ? -1 : (a > b ? +1 : 0))
  8065. op = createValue(no_if, LINK(signedType),
  8066. LINK(testlt), LINK(retlt),
  8067. createValue(no_if, LINK(signedType), LINK(testgt), LINK(retgt), getZero()));
  8068. }
  8069. }
  8070. }
  8071. break;
  8072. }
  8073. OwnedHqlExpr safeReleaseOp = op;
  8074. assertex(op);
  8075. BuildCtx subctx(ctx);
  8076. if (info.isEqualityCompare() && (info.actionIfDiffer == return_stmt))
  8077. {
  8078. subctx.addFilter(op);
  8079. OwnedHqlExpr returnValue = info.getEqualityReturnValue();
  8080. subctx.addReturn(returnValue);
  8081. }
  8082. else
  8083. {
  8084. assignBound(subctx, info.target, op);
  8085. switch (info.actionIfDiffer)
  8086. {
  8087. case break_stmt:
  8088. subctx.addFilter(info.target.expr);
  8089. subctx.addBreak();
  8090. break;
  8091. case return_stmt:
  8092. if (!isLast || info.neverReturnMatch)
  8093. subctx.addFilter(info.target.expr);
  8094. else
  8095. info.alwaysReturns = true;
  8096. subctx.addReturn(info.target.expr);
  8097. break;
  8098. }
  8099. }
  8100. }
  8101. void HqlCppTranslator::doBuildAssignCompare(BuildCtx & ctx, EvaluateCompareInfo & info, HqlExprArray & leftValues, HqlExprArray & rightValues, bool isFirst, bool isOuter)
  8102. {
  8103. assertex(leftValues.ordinality() == rightValues.ordinality());
  8104. Owned<BuildCtx> subctx = new BuildCtx(ctx);
  8105. OwnedHqlExpr compare = createBoolExpr(no_not, LINK(info.target.expr));
  8106. unsigned idx;
  8107. unsigned max = leftValues.ordinality();
  8108. for (idx = 0; idx < max; idx++)
  8109. {
  8110. if ((idx & 7) == 0)
  8111. subctx.setown(new BuildCtx(ctx));
  8112. if (!info.actionIfDiffer && !isFirst)
  8113. subctx->addFilter(compare);
  8114. doBuildAssignCompareElement(*subctx, info, &leftValues.item(idx), &rightValues.item(idx), isFirst, isOuter && (idx == max-1));
  8115. isFirst = false;
  8116. }
  8117. }
  8118. void HqlCppTranslator::doBuildAssignOrder(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8119. {
  8120. HqlExprArray leftValues, rightValues;
  8121. OwnedHqlExpr defaultValue;
  8122. expandOrder(expr, leftValues, rightValues, defaultValue);
  8123. optimizeOrderValues(leftValues, rightValues, false);
  8124. EvaluateCompareInfo info(no_order);
  8125. info.target.set(target);
  8126. doBuildAssignCompare(ctx, info, leftValues, rightValues, true, false);
  8127. unsigned maxLeft = leftValues.ordinality();
  8128. if (defaultValue)
  8129. {
  8130. if (maxLeft != 0)
  8131. {
  8132. OwnedHqlExpr compare = createBoolExpr(no_not, LINK(target.expr));
  8133. ctx.addFilter(compare);
  8134. }
  8135. buildExprAssign(ctx, target, defaultValue);
  8136. }
  8137. else if (maxLeft == 0)
  8138. buildExprAssign(ctx, target, queryZero());
  8139. }
  8140. void HqlCppTranslator::doBuildReturnCompare(BuildCtx & ctx, IHqlExpression * expr, node_operator op, bool isBoolEquality, bool neverReturnTrue)
  8141. {
  8142. HqlExprArray leftValues, rightValues;
  8143. OwnedHqlExpr defaultValue;
  8144. expandOrder(expr, leftValues, rightValues, defaultValue);
  8145. optimizeOrderValues(leftValues, rightValues, (op == no_eq));
  8146. EvaluateCompareInfo info(op);
  8147. info.actionIfDiffer = return_stmt;
  8148. info.isBoolEquality = isBoolEquality;
  8149. info.neverReturnMatch = (defaultValue != NULL) || neverReturnTrue;
  8150. createTempFor(ctx, expr, info.target);
  8151. doBuildAssignCompare(ctx, info, leftValues, rightValues, true, true);
  8152. assertex(!(neverReturnTrue && info.alwaysReturns));
  8153. if (!info.alwaysReturns && !neverReturnTrue)
  8154. {
  8155. if (info.isBoolEquality)
  8156. {
  8157. OwnedHqlExpr returnValue = createConstant(defaultValue == NULL);
  8158. buildReturn(ctx, returnValue);
  8159. }
  8160. else
  8161. {
  8162. if (defaultValue)
  8163. buildReturn(ctx, defaultValue);
  8164. else
  8165. buildReturn(ctx, queryZero());
  8166. }
  8167. }
  8168. }
  8169. //---------------------------------------------------------------------------
  8170. //-- no_hash --
  8171. class HashCodeCreator
  8172. {
  8173. public:
  8174. HashCodeCreator(HqlCppTranslator & _translator, const CHqlBoundTarget & _target, node_operator _hashKind, bool _optimizeInternal)
  8175. : translator(_translator), target(_target), hashKind(_hashKind), optimizeInternal(_optimizeInternal)
  8176. {
  8177. prevFunc = NULL;
  8178. }
  8179. //Combine calls to the hash function on adjacent memory to minimise the number of calls
  8180. //and the generated code size.
  8181. void buildHash(BuildCtx & ctx, IIdAtom * func, IHqlExpression * length, IHqlExpression * ptr)
  8182. {
  8183. if ((func == hash32DataId) || (func == hash64DataId))
  8184. {
  8185. ptr = stripTranslatedCasts(ptr);
  8186. if (prevFunc)
  8187. {
  8188. if ((prevFunc == func) && rightFollowsLeft(prevPtr, prevLength, ptr))
  8189. {
  8190. prevLength.setown(peepholeAddExpr(prevLength, length));
  8191. return;
  8192. }
  8193. flush(ctx);
  8194. }
  8195. prevFunc = func;
  8196. prevLength.set(length);
  8197. prevPtr.set(ptr);
  8198. return;
  8199. }
  8200. flush(ctx);
  8201. buildCall(ctx, func, length, ptr);
  8202. }
  8203. void beginCondition(BuildCtx & ctx)
  8204. {
  8205. ensureInitialAssigned(ctx);
  8206. flush(ctx);
  8207. }
  8208. void endCondition(BuildCtx & ctx)
  8209. {
  8210. flush(ctx);
  8211. }
  8212. void finish(BuildCtx & ctx)
  8213. {
  8214. flush(ctx);
  8215. ensureInitialAssigned(ctx);
  8216. }
  8217. void setInitialValue(IHqlExpression * expr)
  8218. {
  8219. initialValue.set(expr);
  8220. }
  8221. inline node_operator kind() const { return hashKind; }
  8222. inline bool optimize() const { return optimizeInternal; }
  8223. protected:
  8224. void buildCall(BuildCtx & ctx, IIdAtom * func, IHqlExpression * length, IHqlExpression * ptr)
  8225. {
  8226. if (func == hash32DataId)
  8227. {
  8228. unsigned fixedSize = (unsigned)getIntValue(length, 0);
  8229. switch (fixedSize)
  8230. {
  8231. case 1: func = hash32Data1Id; break;
  8232. case 2: func = hash32Data2Id; break;
  8233. case 3: func = hash32Data3Id; break;
  8234. case 4: func = hash32Data4Id; break;
  8235. case 5: func = hash32Data5Id; break;
  8236. case 6: func = hash32Data6Id; break;
  8237. case 7: func = hash32Data7Id; break;
  8238. case 8: func = hash32Data8Id; break;
  8239. }
  8240. if (func != hash32DataId)
  8241. length = NULL;
  8242. }
  8243. HqlExprArray args;
  8244. if (length)
  8245. args.append(*LINK(length));
  8246. args.append(*LINK(ptr));
  8247. if (initialValue)
  8248. args.append(*initialValue.getClear());
  8249. else
  8250. args.append(*LINK(target.expr));
  8251. CHqlBoundExpr boundHash;
  8252. boundHash.expr.setown(translator.bindTranslatedFunctionCall(func, args));
  8253. translator.assign(ctx, target, boundHash);
  8254. }
  8255. void ensureInitialAssigned(BuildCtx & ctx)
  8256. {
  8257. if (initialValue)
  8258. {
  8259. translator.assignBound(ctx, target, initialValue);
  8260. initialValue.clear();
  8261. }
  8262. }
  8263. void flush(BuildCtx & ctx)
  8264. {
  8265. if (prevFunc)
  8266. {
  8267. buildCall(ctx, prevFunc, prevLength, prevPtr);
  8268. prevFunc = NULL;
  8269. }
  8270. }
  8271. protected:
  8272. HqlCppTranslator & translator;
  8273. const CHqlBoundTarget & target;
  8274. LinkedHqlExpr initialValue;
  8275. node_operator hashKind;
  8276. bool optimizeInternal;
  8277. IIdAtom * prevFunc;
  8278. OwnedHqlExpr prevLength;
  8279. OwnedHqlExpr prevPtr;
  8280. };
  8281. void HqlCppTranslator::doBuildAssignHashCrc(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8282. {
  8283. IHqlExpression * child = expr->queryChild(0);
  8284. LinkedHqlExpr initialValue = queryZero();
  8285. node_operator op = expr->getOperator();
  8286. if (op == no_hash32)
  8287. initialValue.setown(createConstant(createIntValue(HASH32_INIT, 4, false)));
  8288. else if (op == no_hash64)
  8289. initialValue.setown(createConstant(createIntValue(HASH64_INIT, 8, false)));
  8290. HashCodeCreator creator(*this, target, op, expr->hasAttribute(internalAtom));
  8291. creator.setInitialValue(initialValue);
  8292. if (child->getOperator() != no_sortlist)
  8293. doBuildAssignHashElement(ctx, creator, child);
  8294. else
  8295. {
  8296. unsigned max = child->numChildren();
  8297. unsigned idx;
  8298. for (idx = 0; idx < max; idx++)
  8299. doBuildAssignHashElement(ctx, creator, child->queryChild(idx));
  8300. }
  8301. creator.finish(ctx);
  8302. }
  8303. void HqlCppTranslator::doBuildAssignHashElement(BuildCtx & ctx, HashCodeCreator & creator, IHqlExpression * elem, IHqlExpression * record)
  8304. {
  8305. bool useNewSelector = elem->isDatarow() && ((elem->getOperator() != no_select) || isNewSelector(elem));
  8306. ForEachChild(i, record)
  8307. {
  8308. IHqlExpression * cur = record->queryChild(i);
  8309. switch (cur->getOperator())
  8310. {
  8311. case no_field:
  8312. {
  8313. OwnedHqlExpr selected = useNewSelector ? createNewSelectExpr(LINK(elem), LINK(cur)) : createSelectExpr(LINK(elem), LINK(cur));
  8314. doBuildAssignHashElement(ctx, creator, selected);
  8315. break;
  8316. }
  8317. case no_record:
  8318. doBuildAssignHashElement(ctx, creator, elem, cur);
  8319. break;
  8320. case no_ifblock:
  8321. doBuildAssignHashElement(ctx, creator, elem, cur->queryChild(1));
  8322. break;
  8323. }
  8324. }
  8325. }
  8326. void HqlCppTranslator::doBuildAssignHashElement(BuildCtx & ctx, HashCodeCreator & creator, IHqlExpression * elem)
  8327. {
  8328. if (creator.optimize())
  8329. {
  8330. switch (elem->getOperator())
  8331. {
  8332. case no_if:
  8333. {
  8334. BuildCtx subctx(ctx);
  8335. creator.beginCondition(subctx);
  8336. IHqlStmt * cond = buildFilterViaExpr(subctx, elem->queryChild(0));
  8337. doBuildAssignHashElement(subctx, creator, elem->queryChild(1));
  8338. creator.endCondition(subctx);
  8339. IHqlExpression * elseValue = elem->queryChild(2);
  8340. if (elseValue && elseValue->getOperator() != no_constant)
  8341. {
  8342. subctx.selectElse(cond);
  8343. creator.beginCondition(subctx);
  8344. doBuildAssignHashElement(subctx, creator, elseValue);
  8345. creator.endCondition(subctx);
  8346. }
  8347. return;
  8348. }
  8349. case no_constant:
  8350. return;
  8351. }
  8352. }
  8353. Linked<ITypeInfo> type = elem->queryType()->queryPromotedType(); // skip alien data types, to logical type.
  8354. if (type->getTypeCode() == type_row)
  8355. {
  8356. doBuildAssignHashElement(ctx, creator, elem, elem->queryRecord());
  8357. return;
  8358. }
  8359. IIdAtom * func=NULL;
  8360. switch (creator.kind())
  8361. {
  8362. case no_hash: func = hashDataId; break;
  8363. case no_hash32: func = hash32DataId; break;
  8364. case no_hash64: func = hash64DataId; break;
  8365. case no_crc: func = crcDataId; break;
  8366. }
  8367. CHqlBoundExpr bound;
  8368. OwnedHqlExpr length;
  8369. OwnedHqlExpr ptr;
  8370. bool alreadyTrimmedRight = (elem->getOperator() == no_trim) && (elem->hasAttribute(rightAtom) || !elem->hasAttribute(leftAtom));
  8371. //If this hash is generated internally (e.g., for a dedup) and fixed length, then can simplify the hash calculation
  8372. bool canOptimizeHash = (creator.optimize() && isFixedSize(type));
  8373. bool optimizeTrim = alreadyTrimmedRight || canOptimizeHash;
  8374. switch (type->getTypeCode())
  8375. {
  8376. case type_string:
  8377. {
  8378. if (!optimizeTrim)
  8379. {
  8380. OwnedHqlExpr trimmed = createValue(no_trim, getStretchedType(UNKNOWN_LENGTH, type), LINK(elem));
  8381. buildCachedExpr(ctx, trimmed, bound);
  8382. }
  8383. else
  8384. buildCachedExpr(ctx, elem, bound);
  8385. length.setown(getBoundLength(bound));
  8386. ptr.setown(getElementPointer(bound.expr));
  8387. }
  8388. break;
  8389. case type_unicode:
  8390. {
  8391. if (!optimizeTrim)
  8392. {
  8393. OwnedHqlExpr trimmed = createValue(no_trim, getStretchedType(UNKNOWN_LENGTH, type), LINK(elem));
  8394. buildCachedExpr(ctx, trimmed, bound);
  8395. }
  8396. else
  8397. buildCachedExpr(ctx, elem, bound);
  8398. length.setown(getBoundLength(bound));
  8399. ptr.setown(getElementPointer(bound.expr));
  8400. switch (creator.kind())
  8401. {
  8402. case no_hash: func = hashUnicodeId; break;
  8403. case no_hash32: func = hash32UnicodeId; break;
  8404. case no_hash64: func = hash64UnicodeId; break;
  8405. case no_crc: func = crcUnicodeId; break;
  8406. }
  8407. }
  8408. break;
  8409. case type_utf8:
  8410. {
  8411. if (!optimizeTrim)
  8412. {
  8413. OwnedHqlExpr trimmed = createValue(no_trim, getStretchedType(UNKNOWN_LENGTH, type), LINK(elem));
  8414. buildCachedExpr(ctx, trimmed, bound);
  8415. }
  8416. else
  8417. buildCachedExpr(ctx, elem, bound);
  8418. length.setown(getBoundLength(bound));
  8419. ptr.setown(getElementPointer(bound.expr));
  8420. switch (creator.kind())
  8421. {
  8422. case no_hash: func = hashUtf8Id; break;
  8423. case no_hash32: func = hash32Utf8Id; break;
  8424. case no_hash64: func = hash64Utf8Id; break;
  8425. case no_crc: func = crcUtf8Id; break;
  8426. }
  8427. }
  8428. break;
  8429. case type_data:
  8430. {
  8431. buildCachedExpr(ctx, elem, bound);
  8432. length.setown(getBoundLength(bound));
  8433. ptr.setown(getElementPointer(bound.expr));
  8434. break;
  8435. }
  8436. case type_qstring:
  8437. {
  8438. LinkedHqlExpr exprToHash = elem;
  8439. if (!canOptimizeHash)
  8440. {
  8441. //Always convert to a string so the hash is compatible with a string.
  8442. OwnedHqlExpr cast = ensureExprType(elem, unknownStringType);
  8443. if (alreadyTrimmedRight)
  8444. {
  8445. exprToHash.set(cast);
  8446. }
  8447. else
  8448. {
  8449. OwnedHqlExpr trimmed = createValue(no_trim, LINK(unknownStringType), LINK(cast));
  8450. exprToHash.setown(foldHqlExpression(trimmed));
  8451. }
  8452. }
  8453. buildCachedExpr(ctx, exprToHash, bound);
  8454. length.setown(getBoundSize(bound));
  8455. ptr.setown(getElementPointer(bound.expr));
  8456. break;
  8457. }
  8458. case type_varstring:
  8459. buildCachedExpr(ctx, elem, bound);
  8460. ptr.setown(getElementPointer(bound.expr));
  8461. switch (creator.kind())
  8462. {
  8463. case no_hash: func = hashVStrId; break;
  8464. case no_hash32: func = hash32VStrId; break;
  8465. case no_hash64: func = hash64VStrId; break;
  8466. case no_crc: func = crcVStrId; break;
  8467. }
  8468. break;
  8469. case type_varunicode:
  8470. buildCachedExpr(ctx, elem, bound);
  8471. ptr.setown(getElementPointer(bound.expr));
  8472. switch (creator.kind())
  8473. {
  8474. case no_hash: func = hashVUnicodeId; break;
  8475. case no_hash32: func = hash32VUnicodeId; break;
  8476. case no_hash64: func = hash64VUnicodeId; break;
  8477. case no_crc: func = crcVUnicodeId; break;
  8478. }
  8479. break;
  8480. case type_boolean:
  8481. case type_int:
  8482. case type_swapint:
  8483. case type_real:
  8484. if (creator.optimize() && hasAddress(ctx, elem))
  8485. {
  8486. buildAddress(ctx, elem, bound);
  8487. length.setown(getSizetConstant(type->getSize()));
  8488. ptr.setown(LINK(bound.expr));
  8489. }
  8490. else
  8491. {
  8492. if (!creator.optimize())
  8493. type.setown(makeIntType(8, true));
  8494. OwnedHqlExpr castElem = ensureExprType(elem, type);
  8495. buildTempExpr(ctx, castElem, bound);
  8496. length.setown(getSizetConstant(type->getSize()));
  8497. ptr.setown(getPointer(bound.expr));
  8498. }
  8499. break;
  8500. case type_row:
  8501. throwUnexpected();
  8502. break;
  8503. case type_dictionary:
  8504. case type_groupedtable:
  8505. case type_table:
  8506. //MORE: Should be handle this differently, with an iterator for the link counted rows case?
  8507. //Not sure if that is a good idea - we need to be certain we get the same values with
  8508. //LCR rows enabled and disabled. But this won't be very efficient with lcr rows.
  8509. //fallthrough
  8510. if (creator.optimize() && hasOutOfLineRows(elem->queryType()))
  8511. {
  8512. creator.beginCondition(ctx);
  8513. BuildCtx iterctx(ctx);
  8514. if (buildDatasetIterate(iterctx, elem, false))
  8515. doBuildAssignHashElement(iterctx, creator, elem->queryNormalizedSelector(), elem->queryRecord());
  8516. creator.endCondition(iterctx);
  8517. return;
  8518. }
  8519. else
  8520. {
  8521. OwnedHqlExpr serialized = ::ensureSerialized(elem, diskAtom);
  8522. buildDataset(ctx, serialized, bound, FormatBlockedDataset);
  8523. length.setown(getBoundSize(bound));
  8524. ptr.setown(getPointer(bound.expr));
  8525. }
  8526. break;
  8527. default:
  8528. buildTempExpr(ctx, elem, bound, FormatBlockedDataset);
  8529. length.setown(getBoundSize(bound));
  8530. ptr.setown(getPointer(bound.expr));
  8531. break;
  8532. }
  8533. creator.buildHash(ctx, func, length, ptr);
  8534. }
  8535. //---------------------------------------------------------------------------
  8536. //-- no_hash --
  8537. void HqlCppTranslator::doBuildAssignHashMd5(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8538. {
  8539. IHqlExpression * child = expr->queryChild(0);
  8540. Owned<ITypeInfo> stateType = makeDataType(sizeof(md5_state_s));
  8541. //initialize the state object
  8542. CHqlBoundTarget stateTemp;
  8543. CHqlBoundExpr state;
  8544. createTempFor(ctx, stateType, stateTemp, typemod_none, FormatNatural);
  8545. state.setFromTarget(stateTemp);
  8546. OwnedHqlExpr stateExpr = state.getTranslatedExpr();
  8547. HqlExprArray args;
  8548. args.append(*LINK(stateExpr));
  8549. OwnedHqlExpr callInit = bindFunctionCall(hashMd5InitId, args);
  8550. buildStmt(ctx, callInit);
  8551. //Now hash each of the elements in turn.
  8552. if (child->getOperator() != no_sortlist)
  8553. doBuildHashMd5Element(ctx, child, state);
  8554. else
  8555. {
  8556. unsigned max = child->numChildren();
  8557. for (unsigned idx = 0; idx < max; idx++)
  8558. doBuildHashMd5Element(ctx, child->queryChild(idx), state);
  8559. }
  8560. //finalise the md5, and get the result.
  8561. args.append(*LINK(stateExpr));
  8562. OwnedHqlExpr callFinish = bindFunctionCall(hashMd5FinishId, args);
  8563. buildExprAssign(ctx, target, callFinish);
  8564. }
  8565. void HqlCppTranslator::doBuildHashMd5Element(BuildCtx & ctx, IHqlExpression * elem, CHqlBoundExpr & state)
  8566. {
  8567. CHqlBoundExpr bound;
  8568. Linked<ITypeInfo> type = elem->queryType()->queryPromotedType(); // skip alien data types, to logical type.
  8569. HqlExprArray args;
  8570. switch (type->getTypeCode())
  8571. {
  8572. case type_string:
  8573. case type_unicode:
  8574. case type_data:
  8575. case type_qstring:
  8576. case type_varstring:
  8577. case type_varunicode:
  8578. case type_utf8:
  8579. buildExpr(ctx, elem, bound);
  8580. args.append(*getBoundSize(bound));
  8581. args.append(*getElementPointer(bound.expr));
  8582. break;
  8583. case type_int:
  8584. case type_swapint:
  8585. case type_packedint:
  8586. {
  8587. type.setown(makeIntType(8, true));
  8588. OwnedHqlExpr castElem = ensureExprType(elem, type);
  8589. buildTempExpr(ctx, castElem, bound);
  8590. args.append(*getSizetConstant(type->getSize()));
  8591. args.append(*getPointer(bound.expr));
  8592. break;
  8593. }
  8594. default:
  8595. buildTempExpr(ctx, elem, bound);
  8596. args.append(*getSizetConstant(type->getSize()));
  8597. args.append(*getPointer(bound.expr));
  8598. break;
  8599. }
  8600. args.append(*getBoundSize(state));
  8601. args.append(*LINK(state.expr));
  8602. OwnedHqlExpr call = bindTranslatedFunctionCall(hashMd5DataId, args);
  8603. ctx.addExpr(call);
  8604. }
  8605. //---------------------------------------------------------------------------
  8606. void HqlCppTranslator::doBuildExprTransfer(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8607. {
  8608. CHqlBoundExpr bound;
  8609. //Ensure the bound result has an address
  8610. IHqlExpression * src = expr->queryChild(0);
  8611. bool gotAddress = false;
  8612. if (src->isDataset())
  8613. {
  8614. buildDataset(ctx, src, bound, FormatBlockedDataset);
  8615. bound.expr.setown(getPointer(bound.expr));
  8616. }
  8617. else if (src->isDatarow())
  8618. {
  8619. Owned<IReferenceSelector> ref = buildNewRow(ctx, src);
  8620. ref->get(ctx, bound);
  8621. bound.expr.setown(getPointer(bound.expr));
  8622. }
  8623. else if (isTypePassedByAddress(src->queryType()))
  8624. buildCachedExpr(ctx, src, bound);
  8625. else if (hasAddress(ctx, src))
  8626. {
  8627. buildAddress(ctx, src, bound);
  8628. gotAddress = true;
  8629. }
  8630. else
  8631. buildTempExpr(ctx, src, bound);
  8632. OwnedITypeInfo from = bound.expr->getType();
  8633. ITypeInfo * to = expr->queryType();
  8634. //Must calculate the size of the bound value before we start messing about with stripping casts etc.
  8635. OwnedHqlExpr size;
  8636. if (to->getSize() == UNKNOWN_LENGTH)
  8637. {
  8638. if (from->getSize() == UNKNOWN_LENGTH)
  8639. size.setown(getBoundSize(bound));
  8640. else
  8641. size.setown(getSizetConstant(from->getSize()));
  8642. }
  8643. if (!isTypePassedByAddress(from) && !gotAddress)
  8644. bound.expr.setown(getAddress(bound.expr));
  8645. //strip unnecessary casts...
  8646. while (bound.expr->getOperator() == no_implicitcast)
  8647. bound.expr.set(bound.expr->queryChild(0));
  8648. if (isTypePassedByAddress(to))
  8649. {
  8650. to->Link();
  8651. if (!to->isReference())
  8652. to = makeReferenceModifier(to);
  8653. tgt.expr.setown(createValue(no_implicitcast, to, LINK(bound.expr)));
  8654. if (to->getSize() == UNKNOWN_LENGTH)
  8655. {
  8656. switch (to->getTypeCode())
  8657. {
  8658. case type_unicode:
  8659. if (size->isConstant())
  8660. tgt.length.setown(getSizetConstant((size32_t)getIntValue(size)/sizeof(UChar)));
  8661. else
  8662. tgt.length.setown(createValue(no_div, LINK(sizetType), LINK(size), getSizetConstant(2)));
  8663. break;
  8664. case type_qstring:
  8665. if (size->isConstant())
  8666. tgt.length.setown(getSizetConstant(rtlQStrLength((size32_t)getIntValue(size))));
  8667. else
  8668. tgt.length.setown(createValue(no_div, LINK(sizetType), multiplyValue(size, 4), getSizetConstant(3)));
  8669. break;
  8670. case type_varstring:
  8671. case type_varunicode:
  8672. break;
  8673. default:
  8674. tgt.length.set(size);
  8675. break;
  8676. }
  8677. }
  8678. }
  8679. else
  8680. {
  8681. tgt.length.clear();
  8682. tgt.expr.set(bound.expr);
  8683. if (hasWrapperModifier(tgt.expr->queryType()))
  8684. tgt.expr.setown(createValue(no_implicitcast, makeReferenceModifier(LINK(queryUnqualifiedType(from))), LINK(tgt.expr)));
  8685. tgt.expr.setown(createValue(no_implicitcast, makePointerType(LINK(to)), tgt.expr.getClear()));
  8686. tgt.expr.setown(createValue(no_deref, LINK(to), tgt.expr.getClear()));
  8687. }
  8688. }
  8689. //---------------------------------------------------------------------------
  8690. //-- no_ordered
  8691. void HqlCppTranslator::doBuildExprOrdered(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8692. {
  8693. if (ctx.getMatchExpr(expr, tgt))
  8694. return;
  8695. bool ascending = true;
  8696. OwnedHqlExpr list = simplifyFixedLengthList(expr->queryChild(0));
  8697. IHqlExpression * attr = expr->queryChild(1);
  8698. if (attr && attr->isAttribute() && (attr->queryName() == descAtom))
  8699. ascending = false;
  8700. if (list->numChildren() == 0)
  8701. throwError(HQLERR_RankOnNull);
  8702. //create the list that is going to be sorted
  8703. CHqlBoundExpr boundList;
  8704. OwnedHqlExpr optimalList = getOptimialListFormat(list);
  8705. buildExpr(ctx, optimalList, boundList);
  8706. //create a compare function....
  8707. ITypeInfo * elementType = boundList.expr->queryType()->queryChildType();
  8708. unsigned elementSize = elementType->getSize();
  8709. if (elementSize == UNKNOWN_LENGTH)
  8710. throwError(HQLERR_OrderOnVarlengthStrings);
  8711. StringBuffer tempName;
  8712. getUniqueId(tempName.append('v'));
  8713. IHqlExpression * tempCompare = createVariable(tempName.str(), makeVoidType());
  8714. StringBuffer s;
  8715. s.clear().append("extern int ").append(tempName).append("(const void * left, const void * right);");
  8716. if (options.spanMultipleCpp)
  8717. {
  8718. BuildCtx protoctx(*code, mainprototypesAtom);
  8719. protoctx.addQuoted(s);
  8720. }
  8721. else
  8722. {
  8723. BuildCtx protoctx(*code, prototypeAtom);
  8724. protoctx.addQuoted(s);
  8725. }
  8726. BuildCtx declareCtx(*code, declareAtom);
  8727. s.clear().append("int ").append(tempName).append("(const void * left, const void * right)");
  8728. MemberFunction compareFunc(*this, declareCtx, s, MFdynamicproto);
  8729. Owned<ITypeInfo> argType;
  8730. if (isTypePassedByAddress(elementType) && !hasReferenceModifier(elementType))
  8731. argType.setown(makeReferenceModifier(LINK(elementType)));
  8732. else
  8733. argType.setown(makePointerType(LINK(elementType)));
  8734. OwnedHqlExpr leftAddr = createVariable("left", LINK(argType));
  8735. OwnedHqlExpr rightAddr = createVariable("right", LINK(argType));
  8736. IHqlExpression * left = convertAddressToValue(leftAddr, elementType);
  8737. IHqlExpression * right = convertAddressToValue(rightAddr, elementType);
  8738. if (elementType->isReference())
  8739. elementSize = sizeof(char * *);
  8740. left = createTranslatedOwned(left);
  8741. right = createTranslatedOwned(right);
  8742. OwnedHqlExpr compare;
  8743. if (ascending)
  8744. compare.setown(createValue(no_order, LINK(signedType), left, right));
  8745. else
  8746. compare.setown(createValue(no_order, LINK(signedType), right, left));
  8747. CHqlBoundExpr boundCompare;
  8748. buildExpr(compareFunc.ctx, compare, boundCompare);
  8749. compareFunc.ctx.setNextDestructor();
  8750. compareFunc.ctx.addReturn(boundCompare.expr);
  8751. //Allocate an array to store the orders
  8752. unsigned max = list->numChildren();
  8753. Owned<ITypeInfo> t = makeArrayType(LINK(unsignedType), max);
  8754. IHqlExpression * table = ctx.getTempDeclare(t, NULL);
  8755. ctx.associateExpr(expr, table);
  8756. //Generate the call to the function that calculates the orders
  8757. IHqlExpression * castCompare = createValue(no_implicitcast, makePointerType(makeVoidType()), tempCompare);
  8758. HqlExprArray args;
  8759. args.append(*getPointer(table));
  8760. args.append(*getPointer(boundList.expr));
  8761. args.append(*createConstant(unsignedType->castFrom(false, max)));
  8762. args.append(*getSizetConstant(elementSize));
  8763. args.append(*castCompare);
  8764. callProcedure(ctx, createOrderId, args);
  8765. tgt.expr.setown(table);
  8766. }
  8767. //---------------------------------------------------------------------------
  8768. //-- no_rank
  8769. void checkRankRange(IHqlExpression * index, IHqlExpression * list)
  8770. {
  8771. IValue * indexValue = index->queryValue();
  8772. if (indexValue)
  8773. {
  8774. unsigned max = list->numChildren();
  8775. unsigned idx = (unsigned)indexValue->getIntValue();
  8776. //MORE: Should be a warning.....
  8777. if ((idx < 1) || (idx > max))
  8778. throwError(HQLERR_RankOutOfRange);
  8779. }
  8780. //MORE: Could dynamically allocate the array indexes...
  8781. if (list->getOperator() == no_getresult)
  8782. {
  8783. StringBuffer s;
  8784. IHqlExpression * sequence = queryAttributeChild(list, sequenceAtom, 0);
  8785. IHqlExpression * name = queryAttributeChild(list, namedAtom, 0);
  8786. getStoredDescription(s, sequence, name, true);
  8787. throwError1(HQLERR_RankOnNonList, s.str());
  8788. }
  8789. if (list->getOperator() != no_list)
  8790. {
  8791. StringBuffer s;
  8792. getExprECL(list, s);
  8793. throwError1(HQLERR_RankOnNonList, s.str());
  8794. }
  8795. }
  8796. void HqlCppTranslator::createOrderList(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * ascdesc, CHqlBoundExpr & tgt)
  8797. {
  8798. ITypeInfo * orderedType = makeArrayType(LINK(unsignedType), expr->numChildren());
  8799. OwnedHqlExpr ordered = createValue(no_ordered, orderedType, LINK(expr), LINK(ascdesc));
  8800. buildExpr(ctx, ordered, tgt);
  8801. }
  8802. void HqlCppTranslator::doBuildExprRank(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8803. {
  8804. IHqlExpression * index = expr->queryChild(0);
  8805. IHqlExpression * list = expr->queryChild(1);
  8806. if (list->getOperator() == no_alias_scope)
  8807. list = list->queryChild(0);
  8808. checkRankRange(index, list);
  8809. CHqlBoundExpr bound, boundIndex;
  8810. createOrderList(ctx, list, expr->queryChild(2), bound);
  8811. buildExpr(ctx, index, boundIndex);
  8812. HqlExprArray args;
  8813. args.append(*boundIndex.expr.getClear());
  8814. args.append(*createConstant(unsignedType->castFrom(false, list->numChildren())));
  8815. args.append(*getPointer(bound.expr));
  8816. tgt.expr.setown(bindTranslatedFunctionCall(rankFromOrderId, args));
  8817. }
  8818. //---------------------------------------------------------------------------
  8819. //-- no_ranked
  8820. void HqlCppTranslator::doBuildExprRanked(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8821. {
  8822. IHqlExpression * index = expr->queryChild(0);
  8823. IHqlExpression * list = expr->queryChild(1);
  8824. if (list->getOperator() == no_alias_scope)
  8825. list = list->queryChild(0);
  8826. checkRankRange(index, list);
  8827. CHqlBoundExpr bound, boundIndex;
  8828. createOrderList(ctx, list, expr->queryChild(2), bound);
  8829. buildExpr(ctx, index, boundIndex);
  8830. HqlExprArray args;
  8831. args.append(*boundIndex.expr.getClear());
  8832. args.append(*createConstant(unsignedType->castFrom(false, list->numChildren())));
  8833. args.append(*getPointer(bound.expr));
  8834. tgt.expr.setown(bindTranslatedFunctionCall(rankedFromOrderId, args));
  8835. }
  8836. //---------------------------------------------------------------------------
  8837. //-- no_fail
  8838. void HqlCppTranslator::doBuildStmtFail(BuildCtx & ctx, IHqlExpression * expr)
  8839. {
  8840. HqlExprArray args;
  8841. args.append(*getFailCode(expr));
  8842. args.append(*getFailMessage(expr, false));
  8843. IIdAtom * func = expr->hasAttribute(defaultAtom) ? sysFailId : _failId;
  8844. OwnedHqlExpr call = bindFunctionCall(func, args);
  8845. buildStmt(ctx, call);
  8846. }
  8847. void HqlCppTranslator::doBuildExprFailCode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8848. {
  8849. OwnedHqlExpr activeFailMarker = createAttribute(activeFailureAtom);
  8850. HqlExprAssociation * matchedMarker = ctx.queryMatchExpr(activeFailMarker);
  8851. if (!matchedMarker && !ctx.queryMatchExpr(globalContextMarkerExpr))
  8852. {
  8853. if (!buildExprInCorrectContext(ctx, expr, tgt, false))
  8854. throwError1(HQLERR_FailXUsedOutsideFailContext, getOpString(expr->getOperator()));
  8855. return;
  8856. }
  8857. HqlExprArray args;
  8858. if (matchedMarker)
  8859. {
  8860. args.append(*LINK(matchedMarker->queryExpr()));
  8861. tgt.expr.setown(bindTranslatedFunctionCall(queryLocalFailCodeId, args));
  8862. }
  8863. else
  8864. {
  8865. tgt.expr.setown(bindTranslatedFunctionCall(queryFailCodeId, args));
  8866. }
  8867. }
  8868. void HqlCppTranslator::doBuildExprMatchedInJoin(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8869. {
  8870. IHqlExpression *selExpr = expr->queryChild(0);
  8871. assertex(selExpr);
  8872. node_operator op = selExpr->getOperator();
  8873. if (op==no_rows) //denormalize group
  8874. {
  8875. selExpr = selExpr->queryChild(0);
  8876. assertex(selExpr);
  8877. op = selExpr->getOperator();
  8878. if (op!=no_right)
  8879. throwError(HQLERR_InvalidMatchedPatternInJoin);
  8880. }
  8881. OwnedHqlExpr markerExpr = createValue(no_matched_injoin, makeBoolType(), LINK(selExpr));
  8882. if (!ctx.getMatchExpr(markerExpr, tgt))
  8883. {
  8884. if (!buildExprInCorrectContext(ctx, expr, tgt, false))
  8885. throwError(HQLERR_InvalidMatchedPatternInJoin); //to get this far they must be matching on a dataset that is not the current left or right
  8886. return;
  8887. }
  8888. }
  8889. void HqlCppTranslator::doBuildAssignFailMessage(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8890. {
  8891. OwnedHqlExpr activeFailMarker = createAttribute(activeFailureAtom);
  8892. HqlExprAssociation * matchedMarker = ctx.queryMatchExpr(activeFailMarker);
  8893. if (!matchedMarker && !ctx.queryMatchExpr(globalContextMarkerExpr))
  8894. {
  8895. CHqlBoundExpr match;
  8896. if (!buildExprInCorrectContext(ctx, expr, match, false))
  8897. throwError1(HQLERR_FailXUsedOutsideFailContext, getOpString(expr->getOperator()));
  8898. assign(ctx, target, match);
  8899. return;
  8900. }
  8901. IIdAtom * func = getFailMessageId;
  8902. HqlExprArray args;
  8903. if (matchedMarker)
  8904. {
  8905. func = getLocalFailMessageId;
  8906. args.append(*createTranslated(matchedMarker->queryExpr()));
  8907. }
  8908. LinkedHqlExpr tag = expr->queryChild(0);
  8909. if (!tag)
  8910. tag.setown(createQuoted("0", makeConstantModifier(makeReferenceModifier(makeVarStringType(UNKNOWN_LENGTH, 0, 0)))));
  8911. args.append(*LINK(tag));
  8912. OwnedHqlExpr call = bindFunctionCall(func, args);
  8913. buildExprAssign(ctx, target, call);
  8914. }
  8915. void HqlCppTranslator::doBuildAssignEventName(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8916. {
  8917. HqlExprArray args;
  8918. OwnedHqlExpr call = bindFunctionCall(getEventNameId, args);
  8919. buildExprAssign(ctx, target, call);
  8920. }
  8921. void HqlCppTranslator::doBuildAssignEventExtra(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8922. {
  8923. LinkedHqlExpr tag = expr->queryChild(0);
  8924. if (!tag)
  8925. tag.setown(createQuoted("0", makeConstantModifier(makeReferenceModifier(makeVarStringType(UNKNOWN_LENGTH, 0, 0)))));
  8926. HqlExprArray args;
  8927. args.append(*LINK(tag));
  8928. OwnedHqlExpr call = bindFunctionCall(getEventExtraId, args);
  8929. buildExprAssign(ctx, target, call);
  8930. }
  8931. //---------------------------------------------------------------------------
  8932. //-- system call e.g. EXP(), LOG()...
  8933. void HqlCppTranslator::doBuildExprSysFunc(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, IIdAtom * funcName, byte dbz)
  8934. {
  8935. HqlExprArray args;
  8936. ForEachChild(i, expr)
  8937. {
  8938. IHqlExpression * cur = expr->queryChild(i);
  8939. if (!cur->isAttribute())
  8940. args.append(*LINK(cur));
  8941. }
  8942. if (dbz)
  8943. args.append(*createConstant(dbz));
  8944. OwnedHqlExpr call = bindFunctionCall(funcName, args);
  8945. buildExpr(ctx, call, tgt);
  8946. }
  8947. void HqlCppTranslator::doBuildExprOffsetOf(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  8948. {
  8949. if (ctx.getMatchExpr(expr, tgt))
  8950. return;
  8951. IHqlExpression * arg = expr->queryChild(0);
  8952. Owned<IReferenceSelector> selector = buildActiveReference(ctx, arg);
  8953. selector->getOffset(ctx, tgt);
  8954. //cache non-constant values in a temporary variable...
  8955. if (!isSimpleLength(tgt.expr))
  8956. {
  8957. IHqlExpression * temp = ctx.getTempDeclare(expr->queryType(), tgt.expr);
  8958. tgt.expr.setown(temp);
  8959. ctx.associateExpr(expr, tgt);
  8960. }
  8961. }
  8962. //---------------------------------------------------------------------------
  8963. //-- no_subselect --
  8964. void HqlCppTranslator::doBuildAssignSubString(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  8965. {
  8966. if (expr->queryChild(1)->getOperator() == no_rangecommon)
  8967. throwError(HQLERR_StarRangeOnlyInJoinCondition);
  8968. ITypeInfo * resultType = expr->queryType();
  8969. ITypeInfo * targetType = target.queryType();
  8970. type_t rtc = resultType->getTypeCode();
  8971. type_t ttc = targetType->getTypeCode();
  8972. SubStringInfo info(expr);
  8973. CHqlBoundExpr newBound;
  8974. bool doneAssign = false;
  8975. if (info.special)
  8976. doBuildExprSpecialSubString(ctx, info, newBound);
  8977. else if (info.infiniteString)
  8978. doBuildExprInfiniteSubString(ctx, info, newBound);
  8979. if (!newBound.expr)
  8980. {
  8981. IIdAtom * func = NULL;
  8982. type_t stc = info.src->queryType()->getTypeCode();
  8983. if (target.isFixedSize())
  8984. {
  8985. switch (ttc)
  8986. {
  8987. case type_qstring:
  8988. if (stc == type_qstring)
  8989. func = subQStrFTId;
  8990. break;
  8991. case type_data:
  8992. switch (stc)
  8993. {
  8994. case type_data:
  8995. case type_string:
  8996. case type_varstring:
  8997. func = subDataFTId;
  8998. break;
  8999. }
  9000. break;
  9001. case type_string:
  9002. switch (stc)
  9003. {
  9004. case type_data:
  9005. func = subDataFTId;
  9006. break;
  9007. case type_string:
  9008. case type_varstring:
  9009. if (resultType->queryCharset() == info.src->queryType()->queryCharset())
  9010. func = subStrFTId;
  9011. break;
  9012. }
  9013. break;
  9014. }
  9015. if (!func && (queryUnqualifiedType(resultType) != queryUnqualifiedType(targetType)))
  9016. {
  9017. CHqlBoundExpr bound;
  9018. buildTempExpr(ctx, expr, bound);
  9019. assign(ctx, target, bound);
  9020. return;
  9021. }
  9022. }
  9023. CHqlBoundExpr boundSrc;
  9024. buildCachedExpr(ctx, info.src, boundSrc);
  9025. info.bindToFrom(*this, ctx);
  9026. if (!info.boundFrom.expr)
  9027. info.boundFrom.expr.setown(getSizetConstant(1));
  9028. //Some hacks to force the parameters/return values to the same type. It could be solved more cleanly,
  9029. //but with more functions by calling different functions instead.
  9030. CHqlBoundTarget tempTarget;
  9031. tempTarget.set(target);
  9032. switch (rtc)
  9033. {
  9034. case type_string:
  9035. if (resultType->queryCollation()->queryName() != asciiAtom)
  9036. {
  9037. unsigned sourceLen = boundSrc.queryType()->getStringLen();
  9038. boundSrc.expr.setown(createValue(no_typetransfer, makeStringType(sourceLen, NULL, NULL), LINK(boundSrc.expr)));
  9039. OwnedITypeInfo newTargetType = makeStringType(targetType->getStringLen(), NULL, NULL);
  9040. tempTarget.expr.setown(createValue(no_typetransfer, cloneModifiers(targetType, newTargetType), LINK(tempTarget.expr)));
  9041. }
  9042. break;
  9043. }
  9044. HqlExprArray args;
  9045. args.append(*boundSrc.getTranslatedExpr());
  9046. args.append(*info.boundFrom.getTranslatedExpr());
  9047. if (func)
  9048. {
  9049. args.add(*createTranslated(tempTarget.expr), 0);
  9050. if (info.boundTo.expr)
  9051. args.append(*info.boundTo.getTranslatedExpr());
  9052. else
  9053. args.append(*createConstant(unsignedType->castFrom(false, 0x7fffffff)));
  9054. OwnedHqlExpr call = bindFunctionCall(func, args);
  9055. buildStmt(ctx, call);
  9056. }
  9057. else
  9058. {
  9059. if (info.boundTo.expr)
  9060. {
  9061. args.append(*info.boundTo.getTranslatedExpr());
  9062. switch (rtc)
  9063. {
  9064. case type_qstring:
  9065. func = subQStrFTXId;
  9066. break;
  9067. case type_data:
  9068. func = subDataFTXId;
  9069. break;
  9070. case type_unicode:
  9071. case type_varunicode:
  9072. func = unicodeSubStrFTXId;
  9073. break;
  9074. case type_utf8:
  9075. func = utf8SubStrFTXId;
  9076. break;
  9077. default:
  9078. func = subStrFTXId;
  9079. break;
  9080. }
  9081. }
  9082. else
  9083. {
  9084. switch (rtc)
  9085. {
  9086. case type_qstring:
  9087. func = subQStrFXId;
  9088. break;
  9089. case type_data:
  9090. func = subDataFXId;
  9091. break;
  9092. case type_unicode:
  9093. case type_varunicode:
  9094. func = unicodeSubStrFXId;
  9095. break;
  9096. case type_utf8:
  9097. func = utf8SubStrFXId;
  9098. break;
  9099. default:
  9100. func = subStrFXId;
  9101. break;
  9102. }
  9103. }
  9104. OwnedHqlExpr call = bindFunctionCall(func, args);
  9105. buildExprAssign(ctx, tempTarget, call);
  9106. }
  9107. doneAssign = true;
  9108. }
  9109. if (!doneAssign)
  9110. assign(ctx, target, newBound);
  9111. }
  9112. bool HqlCppTranslator::doBuildExprSpecialSubString(BuildCtx & ctx, SubStringInfo & info, CHqlBoundExpr & tgt)
  9113. {
  9114. unsigned size = info.srcType->getStringLen();
  9115. unsigned fromIndex = info.fixedStart;
  9116. unsigned toIndex = info.fixedEnd;
  9117. //If substring is larger than the source use the default processing.
  9118. if (toIndex <= size)
  9119. {
  9120. CHqlBoundExpr boundSrc;
  9121. buildCachedExpr(ctx, info.src, boundSrc);
  9122. boundSrc.expr.setown(getIndexedElementPointer(boundSrc.expr, fromIndex-1));
  9123. unsigned newLength = fromIndex <= toIndex ? toIndex-(fromIndex-1) : 0;
  9124. ITypeInfo * newType = makeReferenceModifier(getStretchedType(newLength, info.srcType));
  9125. tgt.expr.setown(createValue(no_typetransfer, newType, boundSrc.expr.getClear()));
  9126. if (info.expr->queryType()->getStringLen() != newLength)
  9127. tgt.length.setown(getSizetConstant(newLength));
  9128. return true;
  9129. }
  9130. return false;
  9131. }
  9132. bool HqlCppTranslator::doBuildExprInfiniteSubString(BuildCtx & ctx, SubStringInfo & info, CHqlBoundExpr & tgt)
  9133. {
  9134. CHqlBoundExpr boundSrc;
  9135. info.bindToFrom(*this, ctx);
  9136. buildCachedExpr(ctx, info.src, boundSrc);
  9137. IHqlExpression * from = info.from;
  9138. if (info.fixedStart == 1)
  9139. from = NULL;
  9140. IHqlExpression * start = from ? adjustValue(info.boundFrom.expr, -1) : NULL;
  9141. tgt.expr.setown(getIndexedElementPointer(boundSrc.expr, start));
  9142. //ensure type is no longer infinite length, so same optimization does not happen again...
  9143. ITypeInfo * newType = makeReferenceModifier(getStretchedType(UNKNOWN_LENGTH, tgt.expr->queryType()));
  9144. tgt.expr.setown(createValue(no_typetransfer, newType, tgt.expr.getLink()));
  9145. OwnedHqlExpr length;
  9146. if (start && !isZero(start))
  9147. length.setown(createValue(no_sub, info.boundTo.getType(), info.boundTo.expr.getLink(), LINK(start)));
  9148. else
  9149. length.setown(info.boundTo.expr.getLink());
  9150. tgt.length.setown(ensureExprType(length, sizetType));
  9151. ::Release(start);
  9152. return true;
  9153. }
  9154. void HqlCppTranslator::doBuildExprAnySubString(BuildCtx & ctx, SubStringInfo & info, CHqlBoundExpr & tgt)
  9155. {
  9156. CHqlBoundExpr boundSource;
  9157. buildCachedExpr(ctx, info.src, boundSource);
  9158. info.bindToFrom(*this, ctx);
  9159. OwnedHqlExpr from;
  9160. if (info.from)
  9161. {
  9162. OwnedHqlExpr start = adjustValue(info.boundFrom.expr, -1);
  9163. if (!isZero(start))
  9164. {
  9165. HqlExprArray args;
  9166. args.append(*LINK(start));
  9167. args.append(*getBoundLength(boundSource));
  9168. OwnedHqlExpr call = bindTranslatedFunctionCall(rtlMinId, args);
  9169. call.setown(createTranslated(call));
  9170. CHqlBoundExpr fromVar;
  9171. buildTempExpr(ctx, call, fromVar);
  9172. from.set(fromVar.expr);
  9173. }
  9174. }
  9175. OwnedHqlExpr to;
  9176. if (info.to)
  9177. {
  9178. OwnedHqlExpr toExpr = LINK(info.boundTo.expr);
  9179. if (from)
  9180. {
  9181. HqlExprArray args;
  9182. args.append(*LINK(toExpr));
  9183. args.append(*LINK(from));
  9184. toExpr.setown(bindTranslatedFunctionCall(rtlMaxId, args));
  9185. }
  9186. HqlExprArray args;
  9187. args.append(*LINK(toExpr));
  9188. args.append(*getBoundLength(boundSource));
  9189. to.setown(bindTranslatedFunctionCall(rtlMinId, args));
  9190. }
  9191. else
  9192. to.setown(getBoundLength(boundSource));
  9193. boundSource.expr.setown(getIndexedElementPointer(boundSource.expr, from));
  9194. ITypeInfo * newType = makeReferenceModifier(info.expr->getType());
  9195. tgt.expr.setown(createValue(no_typetransfer, newType, boundSource.expr.getClear()));
  9196. if (from && !isZero(from))
  9197. tgt.length.setown(createValue(no_sub, LINK(sizetType), LINK(to), LINK(from)));
  9198. else
  9199. tgt.length.set(to);
  9200. }
  9201. void HqlCppTranslator::doBuildExprSubString(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  9202. {
  9203. if (expr->queryChild(1)->getOperator() == no_rangecommon)
  9204. throwError(HQLERR_StarRangeOnlyInJoinCondition);
  9205. /* Optimize string[start..end] into a type transfer where appropriate */
  9206. SubStringInfo info(expr);
  9207. if (info.special)
  9208. if (doBuildExprSpecialSubString(ctx, info, tgt))
  9209. return;
  9210. if (info.infiniteString)
  9211. if (doBuildExprInfiniteSubString(ctx, info, tgt))
  9212. return;
  9213. if (expr->hasAttribute(quickAtom))
  9214. {
  9215. doBuildExprAnySubString(ctx, info, tgt);
  9216. return;
  9217. }
  9218. buildTempExpr(ctx, expr, tgt);
  9219. }
  9220. //---------------------------------------------------------------------------
  9221. //-- no_trim --
  9222. void HqlCppTranslator::doBuildAssignTrim(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  9223. {
  9224. IHqlExpression * str = expr->queryChild(0);
  9225. IIdAtom * func;
  9226. bool hasAll = expr->hasAttribute(allAtom);
  9227. bool hasLeft = expr->hasAttribute(leftAtom);
  9228. bool hasRight = expr->hasAttribute(rightAtom) || !(hasAll || hasLeft);
  9229. bool hasWS = expr->hasAttribute(whitespaceAtom);
  9230. if (str->queryType()->getTypeCode() == type_varstring)
  9231. {
  9232. if(hasWS)
  9233. func = trimVWSId;
  9234. else if(hasAll)
  9235. func = trimVAllId;
  9236. else if(hasLeft && hasRight)
  9237. func = trimVBothId;
  9238. else if(hasLeft)
  9239. func = trimVLeftId;
  9240. else
  9241. func = trimVRightId;
  9242. }
  9243. else if(str->queryType()->getTypeCode() == type_unicode)
  9244. {
  9245. if(hasWS)
  9246. func = trimUnicodeWSId;
  9247. else if(hasAll)
  9248. func = trimUnicodeAllId;
  9249. else if(hasLeft && hasRight)
  9250. func = trimUnicodeBothId;
  9251. else if(hasLeft)
  9252. func = trimUnicodeLeftId;
  9253. else
  9254. func = trimUnicodeRightId;
  9255. }
  9256. else if(str->queryType()->getTypeCode() == type_varunicode)
  9257. {
  9258. if(hasWS)
  9259. func = trimVUnicodeWSId;
  9260. else if(hasAll)
  9261. func = trimVUnicodeAllId;
  9262. else if(hasLeft && hasRight)
  9263. func = trimVUnicodeBothId;
  9264. else if(hasLeft)
  9265. func = trimVUnicodeLeftId;
  9266. else
  9267. func = trimVUnicodeRightId;
  9268. }
  9269. else if(str->queryType()->getTypeCode() == type_utf8)
  9270. {
  9271. if(hasWS)
  9272. func = trimUtf8WSId;
  9273. else if(hasAll)
  9274. func = trimUtf8AllId;
  9275. else if(hasLeft && hasRight)
  9276. func = trimUtf8BothId;
  9277. else if(hasLeft)
  9278. func = trimUtf8LeftId;
  9279. else
  9280. func = trimUtf8RightId;
  9281. }
  9282. else
  9283. {
  9284. if(hasWS)
  9285. func = trimWSId;
  9286. else if(hasAll)
  9287. func = trimAllId;
  9288. else if(hasLeft && hasRight)
  9289. func = trimBothId;
  9290. else if(hasLeft)
  9291. func = trimLeftId;
  9292. else
  9293. func = trimRightId;
  9294. }
  9295. HqlExprArray args;
  9296. args.append(*LINK(str));
  9297. if (hasWS)
  9298. {
  9299. args.append(*LINK(queryBoolExpr(hasLeft)));
  9300. args.append(*LINK(queryBoolExpr(hasAll)));
  9301. args.append(*LINK(queryBoolExpr(hasRight)));
  9302. }
  9303. OwnedHqlExpr call = bindFunctionCall(func, args);
  9304. buildExprAssign(ctx, target, call);
  9305. }
  9306. void HqlCppTranslator::doBuildExprTrim(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  9307. {
  9308. // MORE - support LEFT,RIGHT,ALL attributes
  9309. CHqlBoundExpr bound;
  9310. buildSimpleExpr(ctx, expr->queryChild(0), bound);
  9311. HqlExprArray args;
  9312. IIdAtom * func;
  9313. OwnedHqlExpr str = getElementPointer(bound.expr);
  9314. bool hasAll = expr->hasAttribute(allAtom);
  9315. bool hasLeft = expr->hasAttribute(leftAtom);
  9316. bool hasRight = expr->hasAttribute(rightAtom) || !(hasAll || hasLeft);
  9317. bool hasWS = expr->hasAttribute(whitespaceAtom);
  9318. type_t btc = bound.expr->queryType()->getTypeCode();
  9319. if(hasAll || hasLeft || hasWS || btc == type_varstring || btc == type_varunicode)
  9320. {
  9321. if (btc == type_varstring)
  9322. {
  9323. if(hasWS) {
  9324. func = trimVWSId;
  9325. }
  9326. else if(hasAll) {
  9327. func = trimVAllId;
  9328. }
  9329. else if(hasLeft && hasRight) {
  9330. func = trimVBothId;
  9331. }
  9332. else if (hasLeft) {
  9333. func = trimVLeftId;
  9334. }
  9335. else {
  9336. func = trimVRightId;
  9337. }
  9338. }
  9339. else if (btc == type_unicode)
  9340. {
  9341. if(hasWS) {
  9342. func = trimUnicodeWSId;
  9343. }
  9344. else if(hasAll) {
  9345. func = trimUnicodeAllId;
  9346. }
  9347. else if(hasLeft && hasRight) {
  9348. func = trimUnicodeBothId;
  9349. }
  9350. else {
  9351. func = trimUnicodeLeftId;
  9352. }
  9353. }
  9354. else if (btc == type_varunicode)
  9355. {
  9356. if(hasWS) {
  9357. func = trimVUnicodeWSId;
  9358. }
  9359. else if(hasAll) {
  9360. func = trimVUnicodeAllId;
  9361. }
  9362. else if(hasLeft && hasRight) {
  9363. func = trimVUnicodeBothId;
  9364. }
  9365. else if(hasLeft) {
  9366. func = trimVUnicodeLeftId;
  9367. }
  9368. else {
  9369. func = trimVUnicodeRightId;
  9370. }
  9371. }
  9372. else if (btc == type_utf8)
  9373. {
  9374. if(hasWS) {
  9375. func = trimUtf8WSId;
  9376. }
  9377. else if(hasAll) {
  9378. func = trimUtf8AllId;
  9379. }
  9380. else if(hasLeft && hasRight) {
  9381. func = trimUtf8BothId;
  9382. }
  9383. else {
  9384. func = trimUtf8LeftId;
  9385. }
  9386. }
  9387. else
  9388. {
  9389. if(hasWS) {
  9390. func = trimWSId;
  9391. }
  9392. else if(hasAll) {
  9393. func = trimAllId;
  9394. }
  9395. else if(hasLeft && hasRight) {
  9396. func = trimBothId;
  9397. }
  9398. else {
  9399. func = trimLeftId;
  9400. }
  9401. }
  9402. args.append(*bound.getTranslatedExpr());
  9403. if (hasWS)
  9404. {
  9405. args.append(*LINK(queryBoolExpr(hasLeft)));
  9406. args.append(*LINK(queryBoolExpr(hasAll)));
  9407. args.append(*LINK(queryBoolExpr(hasRight)));
  9408. }
  9409. OwnedHqlExpr call = bindFunctionCall(func, args);
  9410. buildExpr(ctx, call, tgt);
  9411. }
  9412. else {
  9413. if (btc == type_varstring)
  9414. {
  9415. args.append(*LINK(str));
  9416. func = trimVStrLenId;
  9417. }
  9418. else if (btc == type_unicode)
  9419. {
  9420. args.append(*getBoundLength(bound));
  9421. args.append(*LINK(str));
  9422. func = trimUnicodeStrLenId;
  9423. }
  9424. else if (btc == type_varunicode)
  9425. {
  9426. args.append(*LINK(str));
  9427. func = trimVUnicodeStrLenId;
  9428. }
  9429. else if (btc == type_utf8)
  9430. {
  9431. args.append(*getBoundLength(bound));
  9432. args.append(*LINK(str));
  9433. func = trimUtf8StrLenId;
  9434. }
  9435. else
  9436. {
  9437. args.append(*getBoundLength(bound));
  9438. args.append(*LINK(str));
  9439. func = trimStrLenId;
  9440. }
  9441. tgt.length.setown(bindTranslatedFunctionCall(func, args));
  9442. tgt.expr.set(str);
  9443. }
  9444. }
  9445. //---------------------------------------------------------------------------
  9446. void HqlCppTranslator::doBuildExprIsValid(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  9447. {
  9448. IHqlExpression * const value = expr->queryChild(0);
  9449. HqlExprArray args;
  9450. ITypeInfo * type = value->queryType();
  9451. assertex(type);
  9452. if (type->getTypeCode() == type_alien)
  9453. {
  9454. IHqlAlienTypeInfo * alien = queryAlienType(type);
  9455. IHqlExpression * isValidFunction = alien->queryFunction(getIsValidId);
  9456. if (isValidFunction)
  9457. {
  9458. CHqlBoundExpr bound;
  9459. buildAddress(ctx, value, bound);
  9460. OwnedITypeInfo physicalType = alien->getPhysicalType();
  9461. if (!isTypePassedByAddress(physicalType))
  9462. bound.expr.setown(createValue(no_deref, makeReferenceModifier(LINK(physicalType)), LINK(bound.expr)));
  9463. HqlExprArray args;
  9464. args.append(*bound.getTranslatedExpr());
  9465. OwnedHqlExpr test = createBoundFunction(NULL, isValidFunction, args, NULL, true);
  9466. buildExpr(ctx, test, tgt);
  9467. return;
  9468. }
  9469. else
  9470. type = alien->queryLogicalType();
  9471. }
  9472. CHqlBoundExpr bound;
  9473. buildExpr(ctx, value, bound);
  9474. type_t tc = type->getTypeCode();
  9475. if ((tc == type_decimal) && (bound.expr->getOperator() == no_decimalstack))
  9476. {
  9477. tgt.expr.setown(bindTranslatedFunctionCall(DecValidTosId, args));
  9478. return;
  9479. }
  9480. ensureHasAddress(ctx, bound);
  9481. OwnedHqlExpr address = getPointer(bound.expr);
  9482. switch (tc)
  9483. {
  9484. case type_decimal:
  9485. args.append(*createConstant(type->isSigned()));
  9486. args.append(*getSizetConstant(type->getDigits()));
  9487. args.append(*address.getLink());
  9488. tgt.expr.setown(bindTranslatedFunctionCall(DecValidId, args));
  9489. break;
  9490. case type_real:
  9491. args.append(*getSizetConstant(type->getSize()));
  9492. args.append(*address.getLink());
  9493. tgt.expr.setown(bindTranslatedFunctionCall(validRealId, args));
  9494. break;
  9495. default:
  9496. tgt.expr.set(queryBoolExpr(true));
  9497. break;
  9498. }
  9499. }
  9500. IHqlExpression * HqlCppTranslator::getConstWuid(IHqlExpression * expr)
  9501. {
  9502. OwnedHqlExpr wuid = createConstant(wu()->queryWuid());
  9503. return ensureExprType(wuid, expr->queryType());
  9504. }
  9505. void HqlCppTranslator::doBuildAssignWuid(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  9506. {
  9507. HqlExprArray args;
  9508. OwnedHqlExpr call = bindFunctionCall(getWuidId, args);
  9509. buildExprAssign(ctx, target, call);
  9510. }
  9511. void HqlCppTranslator::doBuildExprWuid(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  9512. {
  9513. HqlExprArray args;
  9514. OwnedHqlExpr call = bindFunctionCall(getWuidId, args);
  9515. buildTempExpr(ctx, call, tgt);
  9516. }
  9517. IHqlExpression * HqlCppTranslator::cvtGetEnvToCall(IHqlExpression * expr)
  9518. {
  9519. IHqlExpression * dft = queryRealChild(expr, 1);
  9520. HqlExprArray args;
  9521. args.append(*LINK(expr->queryChild(0)));
  9522. if (dft)
  9523. args.append(*LINK(dft));
  9524. else
  9525. args.append(*createConstant(createStringValue((const char *)NULL, 0U)));
  9526. return bindFunctionCall(getEnvId, args);
  9527. }
  9528. //---------------------------------------------------------------------------
  9529. void HqlCppTranslator::doBuildAssignToFromUnicode(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  9530. {
  9531. HqlExprArray args;
  9532. if(!target.isFixedSize())
  9533. {
  9534. args.append(*LINK(expr->queryChild(0)));
  9535. args.append(*foldHqlExpression(expr->queryChild(1)));
  9536. OwnedHqlExpr call = bindFunctionCall((expr->getOperator() == no_fromunicode) ? unicode2CodepageXId : codepage2UnicodeXId, args);
  9537. buildExprAssign(ctx, target, call);
  9538. }
  9539. else
  9540. {
  9541. args.append(*createTranslated(target.expr));
  9542. args.append(*LINK(expr->queryChild(0)));
  9543. args.append(*foldHqlExpression(expr->queryChild(1)));
  9544. OwnedHqlExpr call = bindFunctionCall((expr->getOperator() == no_fromunicode) ? unicode2CodepageId : codepage2UnicodeId, args);
  9545. buildStmt(ctx, call);
  9546. }
  9547. }
  9548. void HqlCppTranslator::doBuildExprToFromUnicode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  9549. {
  9550. HqlExprArray args;
  9551. args.append(*LINK(expr->queryChild(0)));
  9552. args.append(*foldHqlExpression(expr->queryChild(1)));
  9553. OwnedHqlExpr call = bindFunctionCall((expr->getOperator() == no_fromunicode) ? unicode2CodepageXId : codepage2UnicodeXId, args);
  9554. buildExpr(ctx, call, tgt);
  9555. }
  9556. //---------------------------------------------------------------------------
  9557. void HqlCppTranslator::doBuildExprKeyUnicode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  9558. {
  9559. HqlExprArray args;
  9560. args.append(*LINK(expr->queryChild(0)));
  9561. args.append(*LINK(expr->queryChild(1)));
  9562. args.append(*LINK(expr->queryChild(2)));
  9563. OwnedHqlExpr call = bindFunctionCall(keyUnicodeStrengthXId, args);
  9564. buildExpr(ctx, call, tgt);
  9565. }
  9566. //---------------------------------------------------------------------------
  9567. void HqlCppTranslator::doBuildAssignWhich(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
  9568. {
  9569. BuildCtx whichCtx(ctx);
  9570. unsigned max = expr->numChildren();
  9571. unsigned idx;
  9572. bool invert = (expr->getOperator() == no_rejected);
  9573. for (idx = 0; idx < max; idx++)
  9574. {
  9575. IHqlExpression * cur = expr->queryChild(idx);
  9576. CHqlBoundExpr bound;
  9577. if (invert)
  9578. {
  9579. OwnedHqlExpr inverse = getInverse(cur);
  9580. buildExpr(whichCtx, inverse, bound);
  9581. }
  9582. else
  9583. buildExpr(whichCtx, cur, bound);
  9584. IHqlStmt * stmt = whichCtx.addFilter(bound.expr);
  9585. OwnedHqlExpr value = createConstant(target.queryType()->castFrom(false, idx+1));
  9586. assignBound(whichCtx, target, value);
  9587. whichCtx.selectElse(stmt);
  9588. }
  9589. assignBound(whichCtx, target, queryZero());
  9590. }
  9591. //---------------------------------------------------------------------------
  9592. void HqlCppTranslator::assignBound(BuildCtx & ctx, const CHqlBoundTarget & lhs, IHqlExpression * rhs)
  9593. {
  9594. CHqlBoundExpr bound;
  9595. bound.expr.set(rhs);
  9596. assign(ctx, lhs, bound);
  9597. }
  9598. void HqlCppTranslator::assignBoundToTemp(BuildCtx & ctx, IHqlExpression * lhs, IHqlExpression * rhs)
  9599. {
  9600. CHqlBoundExpr bound;
  9601. CHqlBoundTarget target;
  9602. bound.expr.set(rhs);
  9603. target.expr.set(lhs);
  9604. assign(ctx, target, bound);
  9605. }
  9606. void HqlCppTranslator::assign(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & rhs)
  9607. {
  9608. IHqlExpression * lhs = target.expr;
  9609. ITypeInfo * lType = lhs->queryType()->queryPromotedType();
  9610. if ((lType->getTypeCode() != type_row) && !target.isFixedSize())
  9611. {
  9612. assignCastUnknownLength(ctx, target, rhs);
  9613. return;
  9614. }
  9615. if (!isSameBasicType(lType, rhs.expr->queryType()->queryPromotedType()))
  9616. assignAndCast(ctx, target, rhs);
  9617. else
  9618. {
  9619. switch (lType->getTypeCode())
  9620. {
  9621. case type_decimal:
  9622. if (isPushed(rhs))
  9623. {
  9624. IIdAtom * funcName = lType->isSigned() ? DecPopDecimalId : DecPopUDecimalId;
  9625. HqlExprArray args;
  9626. args.append(*getPointer(lhs));
  9627. args.append(*getSizetConstant(lType->getSize()));
  9628. args.append(*getSizetConstant(lType->getPrecision()));
  9629. callProcedure(ctx, funcName, args);
  9630. return;
  9631. }
  9632. buildBlockCopy(ctx, lhs, rhs);
  9633. return;
  9634. case type_string:
  9635. {
  9636. if (lType->getSize() == 1 && !options.peephole)
  9637. {
  9638. OwnedHqlExpr l1 = getFirstCharacter(lhs);
  9639. OwnedHqlExpr r1 = getFirstCharacter(rhs.expr);
  9640. ctx.addAssign(l1, r1);
  9641. }
  9642. else
  9643. buildBlockCopy(ctx, lhs, rhs);
  9644. break;
  9645. }
  9646. //fall through...
  9647. case type_unicode:
  9648. case type_data:
  9649. case type_qstring:
  9650. case type_utf8:
  9651. {
  9652. buildBlockCopy(ctx, lhs, rhs);
  9653. break;
  9654. }
  9655. case type_varstring:
  9656. {
  9657. HqlExprArray args;
  9658. args.append(*getElementPointer(lhs));
  9659. args.append(*getElementPointer(rhs.expr));
  9660. callProcedure(ctx, strcpyId, args);
  9661. break;
  9662. }
  9663. case type_varunicode:
  9664. {
  9665. HqlExprArray args;
  9666. args.append(*getElementPointer(lhs));
  9667. args.append(*getElementPointer(rhs.expr));
  9668. callProcedure(ctx, unicodeStrcpyId, args);
  9669. break;
  9670. }
  9671. case type_row:
  9672. {
  9673. if (hasWrapperModifier(target.queryType()))
  9674. {
  9675. //I can't think of any situation where this isn't true....
  9676. assertex(hasLinkCountedModifier(rhs.expr));
  9677. ctx.addAssignLink(lhs, rhs.expr);
  9678. }
  9679. else
  9680. ctx.addAssign(lhs, rhs.expr);
  9681. break;
  9682. }
  9683. default:
  9684. ctx.addAssign(lhs, rhs.expr);
  9685. break;
  9686. }
  9687. }
  9688. }
  9689. void HqlCppTranslator::doStringTranslation(BuildCtx & ctx, ICharsetInfo * tgtset, ICharsetInfo * srcset, unsigned tgtlen, IHqlExpression * srclen, IHqlExpression * target, IHqlExpression * src)
  9690. {
  9691. HqlExprArray args;
  9692. ITranslationInfo * translator = queryDefaultTranslation(tgtset, srcset);
  9693. if (translator)
  9694. {
  9695. IIdAtom * func = createIdAtom(translator->queryRtlFunction());
  9696. args.append(*getSizetConstant(tgtlen));
  9697. args.append(*getElementPointer(target));
  9698. args.append(*LINK(srclen));
  9699. args.append(*getElementPointer(src));
  9700. callProcedure(ctx, func, args);
  9701. }
  9702. }
  9703. void HqlCppTranslator::assignSwapInt(BuildCtx & ctx, ITypeInfo * to, const CHqlBoundTarget & target, CHqlBoundExpr & pure)
  9704. {
  9705. switch (pure.expr->getOperator())
  9706. {
  9707. case no_deref:
  9708. case no_variable:
  9709. break;
  9710. default:
  9711. {
  9712. OwnedHqlExpr translated = pure.getTranslatedExpr();
  9713. pure.clear();
  9714. buildTempExpr(ctx, translated, pure);
  9715. break;
  9716. }
  9717. }
  9718. ITypeInfo * from = pure.expr->queryType();
  9719. unsigned copySize = to->getSize();
  9720. assertex(copySize == from->getSize());
  9721. IHqlExpression * address = getRawAddress(pure.expr);
  9722. switch (copySize)
  9723. {
  9724. case 1:
  9725. ctx.addAssign(target.expr, pure.expr);
  9726. break;
  9727. default:
  9728. {
  9729. HqlExprArray args;
  9730. args.append(*address);
  9731. OwnedHqlExpr call = bindTranslatedFunctionCall(reverseIntId[copySize][to->isSigned()], args);
  9732. ctx.addAssign(target.expr, call);
  9733. break;
  9734. }
  9735. }
  9736. }
  9737. void HqlCppTranslator::throwCannotCast(ITypeInfo * from, ITypeInfo * to)
  9738. {
  9739. StringBuffer fromText, toText;
  9740. getFriendlyTypeStr(from, fromText);
  9741. getFriendlyTypeStr(to, toText);
  9742. throwError2(HQLERR_CastXNotImplemented, fromText.str(), toText.str());
  9743. }
  9744. void HqlCppTranslator::assignAndCast(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & pure)
  9745. {
  9746. if (!target.isFixedSize())
  9747. {
  9748. assignCastUnknownLength(ctx, target, pure);
  9749. return;
  9750. }
  9751. ITypeInfo * to = target.queryType()->queryPromotedType();
  9752. if ((pure.expr->getOperator() == no_constant) && options.foldConstantCast &&
  9753. ((options.inlineStringThreshold == 0) || (to->getSize() <= options.inlineStringThreshold)))
  9754. {
  9755. OwnedHqlExpr cast = getCastExpr(to, pure.expr);
  9756. if (cast)
  9757. {
  9758. assignBound(ctx, target, cast);
  9759. return;
  9760. }
  9761. }
  9762. //NB: Does not include variable length return types....
  9763. ITypeInfo * from = (pure.expr->queryType()->queryPromotedType());
  9764. type_t toType = to->getTypeCode();
  9765. type_t fromType = from->getTypeCode();
  9766. unsigned toSize = to->getSize();
  9767. IHqlExpression * targetVar = target.expr;
  9768. HqlExprArray args;
  9769. assertex(targetVar);
  9770. assertex(toSize != UNKNOWN_LENGTH);
  9771. switch(toType)
  9772. {
  9773. case type_qstring:
  9774. switch (fromType)
  9775. {
  9776. case type_qstring:
  9777. {
  9778. unsigned srcsize = from->getSize();
  9779. if (!pure.length && (srcsize == toSize))
  9780. {
  9781. //memcpy(tgt, src, srclen)
  9782. args.append(*getElementPointer(targetVar));
  9783. args.append(*getElementPointer(pure.expr));
  9784. args.append(*getSizetConstant(toSize));
  9785. callProcedure(ctx, memcpyId, args);
  9786. }
  9787. else
  9788. {
  9789. args.append(*getSizetConstant(to->getStringLen()));
  9790. args.append(*getElementPointer(targetVar));
  9791. args.append(*getBoundLength(pure));
  9792. args.append(*getElementPointer(pure.expr));
  9793. callProcedure(ctx, qstrToQStrId, args);
  9794. }
  9795. break;
  9796. }
  9797. case type_data:
  9798. case type_varstring:
  9799. case type_string:
  9800. {
  9801. if(!queryDefaultTranslation(to->queryCharset(), from->queryCharset()))
  9802. {
  9803. args.append(*getSizetConstant(to->getStringLen()));
  9804. args.append(*getElementPointer(targetVar));
  9805. args.append(*getBoundLength(pure));
  9806. args.append(*getElementPointer(pure.expr));
  9807. callProcedure(ctx, strToQStrId, args);
  9808. break;
  9809. }
  9810. }
  9811. // fallthrough
  9812. default:
  9813. //Need to go via a temporary string.
  9814. OwnedHqlExpr temp = pure.getTranslatedExpr();
  9815. buildExprAssignViaString(ctx, target, temp, to);
  9816. return;
  9817. }
  9818. break;
  9819. case type_data:
  9820. case type_string:
  9821. case type_varstring:
  9822. {
  9823. unsigned srclen = from->getSize();
  9824. ICharsetInfo * srcset = NULL;
  9825. ICharsetInfo * tgtset = to->queryCharset();
  9826. IIdAtom * func = NULL;
  9827. switch (fromType)
  9828. {
  9829. case type_data:
  9830. case type_string:
  9831. case type_varstring:
  9832. {
  9833. srcset = from->queryCharset();
  9834. OwnedHqlExpr boundLen = getBoundLength(pure);
  9835. if ((srcset == tgtset) || (toType == type_data) || (fromType == type_data))
  9836. {
  9837. bool doDefault = true;
  9838. if (boundLen->queryValue())
  9839. {
  9840. unsigned srclen = (unsigned)boundLen->queryValue()->getIntValue();
  9841. if (srclen >= toSize && toType != type_varstring)
  9842. {
  9843. if (srclen > toSize)
  9844. srclen = toSize;
  9845. //memcpy(tgt, src, srclen)
  9846. args.append(*getElementPointer(targetVar));
  9847. args.append(*getElementPointer(pure.expr));
  9848. args.append(*getSizetConstant(srclen));
  9849. callProcedure(ctx, memcpyId, args);
  9850. doDefault = false;
  9851. }
  9852. }
  9853. if (doDefault)
  9854. {
  9855. if (fromType == type_varstring)
  9856. {
  9857. switch (toType)
  9858. {
  9859. case type_varstring: func = vstr2VStrId; break;
  9860. case type_string: func = vstr2StrId; break;
  9861. case type_data: func = vstr2DataId; break;
  9862. default: UNIMPLEMENTED;
  9863. }
  9864. if ((toSize < srclen) || (srclen==UNKNOWN_LENGTH) || (toType != type_varstring))
  9865. {
  9866. args.append(*getSizetConstant(toSize));
  9867. args.append(*getElementPointer(targetVar));
  9868. args.append(*getElementPointer(pure.expr));
  9869. callProcedure(ctx, func, args);
  9870. }
  9871. else
  9872. {
  9873. //strcpy(tgt, src);
  9874. args.append(*getElementPointer(targetVar));
  9875. args.append(*getElementPointer(pure.expr));
  9876. callProcedure(ctx, strcpyId, args);
  9877. }
  9878. }
  9879. else
  9880. {
  9881. switch (toType)
  9882. {
  9883. case type_data:
  9884. func = str2DataId;
  9885. break;
  9886. case type_varstring:
  9887. func = str2VStrId;
  9888. break;
  9889. case type_string:
  9890. func = (srcset->queryName() == ebcdicAtom) ? estr2EStrId : str2StrId;
  9891. break;
  9892. }
  9893. args.append(*getSizetConstant(toSize));
  9894. args.append(*getElementPointer(targetVar));
  9895. args.append(*LINK(boundLen));
  9896. args.append(*getElementPointer(pure.expr));
  9897. callProcedure(ctx, func, args);
  9898. }
  9899. }
  9900. }
  9901. else
  9902. {
  9903. if ((from->getSize() == INFINITE_LENGTH) && !pure.length)
  9904. throwError(HQLERR_CastInfiniteString);
  9905. IHqlExpression * srclen;
  9906. if (toType == type_varstring)
  9907. {
  9908. srclen = getSizetConstant(toSize);
  9909. args.append(*srclen);
  9910. args.append(*getElementPointer(targetVar));
  9911. args.append(*LINK(boundLen));
  9912. args.append(*getElementPointer(pure.expr));
  9913. callProcedure(ctx, estr2VStrId, args);
  9914. }
  9915. else
  9916. doStringTranslation(ctx, tgtset, srcset, toSize, boundLen, targetVar, pure.expr);
  9917. }
  9918. }
  9919. break;
  9920. case type_qstring:
  9921. if (queryDefaultTranslation(tgtset, from->queryCharset()))
  9922. {
  9923. OwnedHqlExpr temp = pure.getTranslatedExpr();
  9924. buildExprAssignViaString(ctx, target, temp, to);
  9925. }
  9926. else
  9927. {
  9928. switch (toType)
  9929. {
  9930. case type_varstring: func = qstr2VStrId; break;
  9931. case type_string: func = qstr2StrId; break;
  9932. case type_data: func = qstr2DataId; break;
  9933. }
  9934. args.append(*getSizetConstant(toSize));
  9935. args.append(*getElementPointer(targetVar));
  9936. args.append(*getBoundLength(pure));
  9937. args.append(*getElementPointer(pure.expr));
  9938. callProcedure(ctx, func, args);
  9939. }
  9940. break;
  9941. case type_unicode:
  9942. case type_varunicode:
  9943. {
  9944. switch(toType)
  9945. {
  9946. case type_data:
  9947. func = (fromType == type_varunicode) ? vunicode2DataId : unicode2DataId;
  9948. break;
  9949. case type_string:
  9950. func = (fromType == type_varunicode) ? vunicode2CodepageId : unicode2CodepageId;
  9951. break;
  9952. case type_varstring:
  9953. func = (fromType == type_varunicode) ? vunicode2VCodepageId : unicode2VCodepageId;
  9954. break;
  9955. }
  9956. args.append(*getSizetConstant(toSize));
  9957. args.append(*getElementPointer(targetVar));
  9958. if(fromType != type_varunicode)
  9959. args.append(*getBoundLength(pure));
  9960. args.append(*getElementPointer(pure.expr));
  9961. if(toType != type_data)
  9962. args.append(*createConstant(to->queryCharset()->queryCodepageName()));
  9963. callProcedure(ctx, func, args);
  9964. }
  9965. break;
  9966. case type_utf8:
  9967. {
  9968. switch(toType)
  9969. {
  9970. case type_data:
  9971. func = utf82DataId;
  9972. break;
  9973. case type_string:
  9974. func = utf82CodepageId;
  9975. break;
  9976. case type_varstring:
  9977. OwnedHqlExpr temp = pure.getTranslatedExpr();
  9978. buildExprAssignViaString(ctx, target, temp, to);
  9979. return;
  9980. }
  9981. args.append(*getSizetConstant(toSize));
  9982. args.append(*getElementPointer(targetVar));
  9983. args.append(*getBoundLength(pure));
  9984. args.append(*getElementPointer(pure.expr));
  9985. if(toType != type_data)
  9986. args.append(*createConstant(to->queryCharset()->queryCodepageName()));
  9987. callProcedure(ctx, func, args);
  9988. }
  9989. break;
  9990. case type_swapint:
  9991. {
  9992. CHqlBoundExpr recast;
  9993. ITypeInfo * tempType = makeIntType(srclen, from->isSigned());
  9994. OwnedHqlExpr translated = createValue(no_implicitcast, tempType, pure.getTranslatedExpr());
  9995. buildExpr(ctx, translated, recast);
  9996. assignAndCast(ctx, target, recast);
  9997. return;
  9998. }
  9999. case type_int:
  10000. case type_packedint:
  10001. {
  10002. //l2an4(toSize, tgt, expr);
  10003. IIdAtom * funcName;
  10004. if (from->isSigned())
  10005. {
  10006. if (toType != type_varstring)
  10007. funcName = (srclen > 4 ? ls82anId : ls42anId);
  10008. else
  10009. funcName = (srclen > 4 ? ls82vnId : ls42vnId);
  10010. }
  10011. else
  10012. {
  10013. if (toType != type_varstring)
  10014. funcName = (srclen > 4 ? l82anId : l42anId);
  10015. else
  10016. funcName = (srclen > 4 ? l82vnId : l42vnId);
  10017. }
  10018. IHqlExpression * strlen = getSizetConstant(toSize);
  10019. args.append(*strlen);
  10020. args.append(*getElementPointer(targetVar));
  10021. args.append(*LINK(pure.expr));
  10022. callProcedure(ctx, funcName, args);
  10023. if (toType != type_data)
  10024. {
  10025. Owned<ICharsetInfo> charset = getCharset(asciiAtom);
  10026. doStringTranslation(ctx, tgtset, charset, toSize, strlen, targetVar, targetVar);
  10027. }
  10028. break;
  10029. }
  10030. case type_void:
  10031. if (pure.expr->getOperator() != no_decimalstack)
  10032. {
  10033. throwCannotCast(from, to);
  10034. break;
  10035. }
  10036. //fall through
  10037. case type_decimal:
  10038. {
  10039. ensurePushed(ctx, pure);
  10040. args.append(*getSizetConstant(toSize));
  10041. OwnedHqlExpr sp = getElementPointer(targetVar);
  10042. args.append(*ensureIndexable(sp));
  10043. switch (toType)
  10044. {
  10045. case type_string: func = DecPopStringId; break;
  10046. case type_data: func = DecPopStringId; break;
  10047. case type_varstring: func = DecPopVStringId; break;
  10048. }
  10049. callProcedure(ctx, func, args);
  10050. break;
  10051. }
  10052. case type_enumerated:
  10053. throwCannotCast(from, to);
  10054. break;
  10055. case type_boolean:
  10056. {
  10057. func = (toType == type_varstring) ? bool2VStrId : (toType == type_data) ? bool2DataId : bool2StrId;
  10058. args.append(*getSizetConstant(toSize));
  10059. args.append(*getElementPointer(targetVar));
  10060. args.append(*pure.expr.getLink());
  10061. callProcedure(ctx, func, args);
  10062. break;
  10063. }
  10064. case type_real:
  10065. {
  10066. IHqlExpression * strlen = getSizetConstant(toSize);
  10067. args.append(*strlen);
  10068. args.append(*getElementPointer(targetVar));
  10069. args.append(*pure.expr.getLink());
  10070. func = (toType == type_varstring) ? f2vnId : f2anId;
  10071. callProcedure(ctx, func, args);
  10072. if (toType != type_data)
  10073. {
  10074. Owned<ICharsetInfo> charset = getCharset(asciiAtom);
  10075. doStringTranslation(ctx, tgtset, charset, toSize, strlen, targetVar, targetVar);
  10076. }
  10077. }
  10078. break;
  10079. default:
  10080. throwCannotCast(from, to);
  10081. break;
  10082. }
  10083. }
  10084. break;
  10085. case type_unicode:
  10086. case type_varunicode:
  10087. switch (fromType)
  10088. {
  10089. case type_unicode:
  10090. case type_varunicode:
  10091. case type_data:
  10092. case type_string:
  10093. case type_varstring:
  10094. case type_utf8:
  10095. {
  10096. IIdAtom * func;
  10097. switch(fromType)
  10098. {
  10099. case type_unicode:
  10100. func = (toType == type_varunicode) ? unicode2VUnicodeId : unicode2UnicodeId;
  10101. break;
  10102. case type_varunicode:
  10103. func = (toType == type_varunicode) ? vunicode2VUnicodeId : vunicode2UnicodeId;
  10104. break;
  10105. case type_data:
  10106. pure.expr.setown(createValue(no_implicitcast, makeReferenceModifier(makeStringType(from->getStringLen(), NULL)), LINK(pure.expr)));
  10107. func = (toType == type_varunicode) ? codepage2VUnicodeId : codepage2UnicodeId;
  10108. break;
  10109. case type_string:
  10110. func = (toType == type_varunicode) ? codepage2VUnicodeId : codepage2UnicodeId;
  10111. break;
  10112. case type_varstring:
  10113. func = (toType == type_varunicode) ? vcodepage2VUnicodeId : vcodepage2UnicodeId;
  10114. break;
  10115. case type_utf8:
  10116. if (toType == type_varunicode)
  10117. {
  10118. OwnedHqlExpr temp = pure.getTranslatedExpr();
  10119. OwnedITypeInfo type = makeUnicodeType(UNKNOWN_LENGTH, NULL);
  10120. buildExprAssignViaType(ctx, target, temp, type);
  10121. return;
  10122. }
  10123. func = utf82UnicodeId;
  10124. break;
  10125. default:
  10126. throwUnexpected();
  10127. }
  10128. args.append(*getSizetConstant(toSize/2));
  10129. args.append(*getElementPointer(targetVar));
  10130. if((fromType != type_varunicode) && (fromType != type_varstring))
  10131. args.append(*getBoundLength(pure));
  10132. args.append(*getElementPointer(pure.expr));
  10133. if((fromType == type_data) || (fromType == type_string) || (fromType == type_varstring))
  10134. args.append(*createConstant(from->queryCharset()->queryCodepageName()));
  10135. callProcedure(ctx, func, args);
  10136. break;
  10137. }
  10138. default:
  10139. OwnedHqlExpr temp = pure.getTranslatedExpr();
  10140. buildExprAssignViaString(ctx, target, temp, to);
  10141. return;
  10142. }
  10143. break;
  10144. case type_utf8:
  10145. switch (fromType)
  10146. {
  10147. case type_unicode:
  10148. case type_varunicode:
  10149. case type_data:
  10150. case type_string:
  10151. case type_varstring:
  10152. case type_utf8:
  10153. {
  10154. IIdAtom * func;
  10155. switch(fromType)
  10156. {
  10157. case type_unicode:
  10158. case type_varunicode:
  10159. func = unicodeToUtf8Id;
  10160. break;
  10161. case type_utf8:
  10162. func = utf8ToUtf8Id;
  10163. break;
  10164. case type_data:
  10165. case type_string:
  10166. case type_varstring:
  10167. func = codepageToUtf8Id;
  10168. break;
  10169. default:
  10170. throwUnexpected();
  10171. }
  10172. args.append(*getSizetConstant(toSize/4));
  10173. args.append(*getElementPointer(targetVar));
  10174. args.append(*getBoundLength(pure));
  10175. args.append(*getElementPointer(pure.expr));
  10176. if((fromType == type_data) || (fromType == type_string) || (fromType == type_varstring))
  10177. args.append(*createConstant(from->queryCharset()->queryCodepageName()));
  10178. callProcedure(ctx, func, args);
  10179. break;
  10180. }
  10181. default:
  10182. OwnedHqlExpr temp = pure.getTranslatedExpr();
  10183. buildExprAssignViaString(ctx, target, temp, to);
  10184. return;
  10185. }
  10186. break;
  10187. case type_decimal:
  10188. {
  10189. CHqlBoundExpr cast;
  10190. doBuildExprCast(ctx, to, pure, cast);
  10191. ensurePushed(ctx, cast);
  10192. IIdAtom * funcName = to->isSigned() ? DecPopDecimalId : DecPopUDecimalId;
  10193. args.append(*getPointer(target.expr));
  10194. args.append(*getSizetConstant(to->getSize()));
  10195. args.append(*getSizetConstant(to->getPrecision()));
  10196. callProcedure(ctx, funcName, args);
  10197. }
  10198. break;
  10199. case type_swapint:
  10200. {
  10201. unsigned fromSize = from->getSize();
  10202. if (fromType == type_int)
  10203. {
  10204. if (fromSize != toSize)
  10205. {
  10206. Owned<ITypeInfo> tempType = makeIntType(toSize, from->isSigned());
  10207. pure.expr.setown(ensureExprType(pure.expr, tempType));
  10208. }
  10209. if (toSize != 1)
  10210. {
  10211. assignSwapInt(ctx, to, target, pure);
  10212. return;
  10213. }
  10214. }
  10215. CHqlBoundExpr cast;
  10216. doBuildExprCast(ctx, to, pure, cast);
  10217. ctx.addAssign(target.expr, cast.expr);
  10218. }
  10219. break;
  10220. case type_int:
  10221. case type_packedint:
  10222. {
  10223. unsigned fromSize = from->getSize();
  10224. if ((fromType == type_swapint || fromType == type_keyedint) && !((fromSize == 1) && (toSize == 1)))
  10225. {
  10226. if (fromSize != toSize)
  10227. {
  10228. CHqlBoundExpr tempInt;
  10229. OwnedITypeInfo tempType = makeIntType(fromSize, from->isSigned());
  10230. doBuildCastViaTemp(ctx, tempType, pure, tempInt);
  10231. CHqlBoundExpr cast;
  10232. doBuildExprCast(ctx, to, tempInt, cast);
  10233. ctx.addAssign(target.expr, cast.expr);
  10234. }
  10235. else
  10236. assignSwapInt(ctx, to, target, pure);
  10237. return;
  10238. }
  10239. }
  10240. //fall through
  10241. case type_boolean:
  10242. case type_real:
  10243. case type_row:
  10244. case type_pointer:
  10245. {
  10246. CHqlBoundExpr cast;
  10247. doBuildExprCast(ctx, to, pure, cast);
  10248. ctx.addAssign(target.expr, cast.expr);
  10249. }
  10250. break;
  10251. default:
  10252. throwCannotCast(from, to);
  10253. break;
  10254. }
  10255. }
  10256. void HqlCppTranslator::assignCastUnknownLength(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & pure)
  10257. {
  10258. assertex(!target.isFixedSize());
  10259. // must be dynamically allocated return type
  10260. ITypeInfo * to = target.queryType();
  10261. ITypeInfo * from = pure.expr->queryType();
  10262. type_t toType = to->getTypeCode();
  10263. type_t fromType = from->getTypeCode();
  10264. IHqlExpression * codepageParam = 0;
  10265. HqlExprArray args;
  10266. IIdAtom * funcName = NULL;
  10267. // assertex(target.length && target.pointer || to->getTypeCode() == type_varstring || to->getTypeCode() == type_varunicode);
  10268. switch (toType)
  10269. {
  10270. case type_qstring:
  10271. {
  10272. switch (fromType)
  10273. {
  10274. case type_qstring:
  10275. funcName = qstrToQStrXId;
  10276. break;
  10277. case type_string:
  10278. case type_data:
  10279. case type_varstring:
  10280. if(!queryDefaultTranslation(to->queryCharset(), from->queryCharset()))
  10281. {
  10282. funcName = strToQStrXId;
  10283. break;
  10284. }
  10285. //fall through
  10286. default:
  10287. CHqlBoundExpr recast;
  10288. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10289. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10290. buildExpr(ctx, translated, recast);
  10291. assignCastUnknownLength(ctx, target, recast);
  10292. return;
  10293. }
  10294. break;
  10295. }
  10296. case type_string:
  10297. case type_data:
  10298. {
  10299. unsigned srclen = from->getSize();
  10300. switch (fromType)
  10301. {
  10302. case type_data:
  10303. case type_string:
  10304. case type_varstring:
  10305. {
  10306. ICharsetInfo * srcset = from->queryCharset();
  10307. ICharsetInfo * tgtset = to->queryCharset();
  10308. if (to->getTypeCode() == type_data)
  10309. funcName = str2DataXId;
  10310. else if ((srcset == tgtset) || (from->getTypeCode() == type_data))
  10311. {
  10312. funcName = str2StrXId;
  10313. }
  10314. else
  10315. {
  10316. if ((from->getSize() == INFINITE_LENGTH) && !pure.length)
  10317. throwError(HQLERR_CastInfiniteString);
  10318. ITranslationInfo * translator = queryDefaultTranslation(tgtset, srcset);
  10319. if (translator)
  10320. funcName = createIdAtom(translator->queryVarRtlFunction());
  10321. else
  10322. funcName = str2StrXId;
  10323. }
  10324. }
  10325. break;
  10326. case type_qstring:
  10327. if(!queryDefaultTranslation(from->queryCharset(), to->queryCharset()))
  10328. {
  10329. funcName = (toType == type_data) ? qstr2DataXId : qstr2StrXId;
  10330. break;
  10331. }
  10332. else
  10333. {
  10334. CHqlBoundExpr recast;
  10335. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10336. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10337. buildExpr(ctx, translated, recast);
  10338. assignCastUnknownLength(ctx, target, recast);
  10339. return;
  10340. }
  10341. case type_unicode:
  10342. {
  10343. if(toType == type_data)
  10344. funcName = unicode2DataXId;
  10345. else
  10346. {
  10347. funcName = unicode2CodepageXId;
  10348. codepageParam = createConstant(to->queryCharset()->queryCodepageName());
  10349. }
  10350. break;
  10351. }
  10352. case type_varunicode:
  10353. {
  10354. if(toType == type_data)
  10355. funcName = vunicode2DataXId;
  10356. else
  10357. {
  10358. funcName = vunicode2CodepageXId;
  10359. codepageParam = createConstant(to->queryCharset()->queryCodepageName());
  10360. }
  10361. break;
  10362. }
  10363. case type_utf8:
  10364. {
  10365. if(toType == type_data)
  10366. funcName = utf82DataXId;
  10367. else
  10368. {
  10369. funcName = utf82CodepageXId;
  10370. codepageParam = createConstant(to->queryCharset()->queryCodepageName());
  10371. }
  10372. break;
  10373. }
  10374. case type_swapint:
  10375. {
  10376. CHqlBoundExpr recast;
  10377. ITypeInfo * type = makeIntType(from->getSize(), from->isSigned());
  10378. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10379. buildExpr(ctx, translated, recast);
  10380. assignCastUnknownLength(ctx, target, recast);
  10381. return;
  10382. }
  10383. case type_int:
  10384. case type_real:
  10385. case type_boolean:
  10386. case type_packedint:
  10387. {
  10388. Owned<ICharsetInfo> asciiCharset = getCharset(asciiAtom);
  10389. if (to->queryCharset() != asciiCharset)
  10390. {
  10391. //This should really be handled by the call processing.
  10392. CHqlBoundExpr recast;
  10393. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10394. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10395. buildExpr(ctx, translated, recast);
  10396. assignCastUnknownLength(ctx, target, recast);
  10397. return;
  10398. }
  10399. if (fromType == type_real)
  10400. funcName = f2axId;
  10401. else if (fromType == type_boolean)
  10402. funcName = bool2StrXId;
  10403. else if (from->isSigned())
  10404. funcName = (srclen > 4 ? ls82axId : ls42axId);
  10405. else
  10406. funcName = (srclen > 4 ? l82axId : l42axId);
  10407. args.append(*pure.getTranslatedExpr());
  10408. OwnedHqlExpr call = bindFunctionCall(funcName, args);
  10409. buildExprAssign(ctx, target, call);
  10410. return;
  10411. }
  10412. case type_void:
  10413. if (pure.expr->getOperator() != no_decimalstack)
  10414. {
  10415. throwCannotCast(from, to);
  10416. break;
  10417. }
  10418. //fall through
  10419. case type_decimal:
  10420. {
  10421. ensurePushed(ctx, pure);
  10422. OwnedHqlExpr call = bindFunctionCall(DecPopStringXId, args);
  10423. buildExprAssign(ctx, target, call);
  10424. return;
  10425. }
  10426. default:
  10427. assertex(!"Unknown copy source type");
  10428. return;
  10429. }
  10430. break;
  10431. }
  10432. case type_varstring:
  10433. {
  10434. unsigned srclen = from->getSize();
  10435. switch (from->getTypeCode())
  10436. {
  10437. case type_data:
  10438. case type_string:
  10439. case type_varstring:
  10440. {
  10441. ICharsetInfo * srcset = from->queryCharset();
  10442. ICharsetInfo * tgtset = to->queryCharset();
  10443. if ((srcset == tgtset) || (to->getTypeCode() == type_data) || (from->getTypeCode() == type_data))
  10444. {
  10445. funcName = str2VStrXId;
  10446. }
  10447. else
  10448. {
  10449. funcName = estr2VStrXId;
  10450. }
  10451. }
  10452. break;
  10453. case type_unicode:
  10454. {
  10455. funcName = unicode2VCodepageXId;
  10456. codepageParam = createConstant(to->queryCharset()->queryCodepageName());
  10457. }
  10458. break;
  10459. case type_varunicode:
  10460. {
  10461. funcName = vunicode2VCodepageXId;
  10462. codepageParam = createConstant(to->queryCharset()->queryCodepageName());
  10463. }
  10464. break;
  10465. case type_qstring:
  10466. case type_utf8:
  10467. {
  10468. CHqlBoundExpr recast;
  10469. ITypeInfo * type = makeStringType(from->getStringLen(), NULL, NULL);
  10470. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10471. buildExpr(ctx, translated, recast);
  10472. assignCastUnknownLength(ctx, target, recast);
  10473. return;
  10474. }
  10475. case type_swapint:
  10476. {
  10477. CHqlBoundExpr recast;
  10478. ITypeInfo * type = makeIntType(from->getSize(), from->isSigned());
  10479. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10480. buildExpr(ctx, translated, recast);
  10481. assignCastUnknownLength(ctx, target, recast);
  10482. return;
  10483. }
  10484. case type_int:
  10485. case type_packedint:
  10486. {
  10487. //l2an4(tgtlen, tgt, expr);
  10488. if (from->isSigned())
  10489. funcName = (srclen > 4 ? ls82vxId : ls42vxId);
  10490. else
  10491. funcName = (srclen > 4 ? l82vxId : l42vxId);
  10492. break;
  10493. }
  10494. case type_boolean:
  10495. {
  10496. funcName = bool2VStrXId;
  10497. break;
  10498. }
  10499. case type_real:
  10500. {
  10501. funcName = f2vxId;;
  10502. break;
  10503. }
  10504. case type_void:
  10505. if (pure.expr->getOperator() != no_decimalstack)
  10506. {
  10507. throwCannotCast(from, to);
  10508. break;
  10509. }
  10510. //fall through
  10511. case type_decimal:
  10512. {
  10513. ensurePushed(ctx, pure);
  10514. OwnedHqlExpr call = bindFunctionCall(DecPopVStringXId, args);
  10515. buildExprAssign(ctx, target, call);
  10516. return;
  10517. }
  10518. default:
  10519. assertex(!"Unknown copy source type");
  10520. return;
  10521. }
  10522. break;
  10523. }
  10524. case type_unicode:
  10525. {
  10526. switch (fromType)
  10527. {
  10528. case type_unicode:
  10529. funcName = unicode2UnicodeXId;
  10530. break;
  10531. case type_varunicode:
  10532. funcName = vunicode2UnicodeXId;
  10533. break;
  10534. case type_utf8:
  10535. funcName = utf82UnicodeXId;
  10536. break;
  10537. case type_data:
  10538. funcName = codepage2UnicodeXId;
  10539. codepageParam = createConstant(from->queryCharset()->queryCodepageName());
  10540. pure.expr.setown(createValue(no_implicitcast, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
  10541. break;
  10542. case type_string:
  10543. funcName = codepage2UnicodeXId;
  10544. codepageParam = createConstant(from->queryCharset()->queryCodepageName());
  10545. pure.expr.setown(createValue(no_typetransfer, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
  10546. break;
  10547. case type_varstring:
  10548. funcName = vcodepage2UnicodeXId;
  10549. codepageParam = createConstant(from->queryCharset()->queryCodepageName());
  10550. pure.expr.setown(createValue(no_typetransfer, makeVarStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
  10551. break;
  10552. default:
  10553. CHqlBoundExpr recast;
  10554. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10555. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10556. buildExpr(ctx, translated, recast);
  10557. assignCastUnknownLength(ctx, target, recast);
  10558. return;
  10559. }
  10560. break;
  10561. }
  10562. case type_varunicode:
  10563. {
  10564. switch (fromType)
  10565. {
  10566. case type_unicode:
  10567. case type_utf8: // go via unicode
  10568. funcName = unicode2VUnicodeXId;
  10569. break;
  10570. case type_varunicode:
  10571. funcName = vunicode2VUnicodeXId;
  10572. break;
  10573. case type_string:
  10574. case type_data:
  10575. funcName = codepage2VUnicodeXId;
  10576. codepageParam = createConstant(from->queryCharset()->queryCodepageName());
  10577. pure.expr.setown(createValue(no_typetransfer, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
  10578. break;
  10579. case type_varstring:
  10580. funcName = vcodepage2VUnicodeXId;
  10581. codepageParam = createConstant(from->queryCharset()->queryCodepageName());
  10582. pure.expr.setown(createValue(no_typetransfer, makeVarStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
  10583. break;
  10584. default:
  10585. CHqlBoundExpr recast;
  10586. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10587. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10588. buildExpr(ctx, translated, recast);
  10589. assignCastUnknownLength(ctx, target, recast);
  10590. return;
  10591. }
  10592. break;
  10593. }
  10594. case type_utf8:
  10595. {
  10596. switch (fromType)
  10597. {
  10598. case type_unicode:
  10599. case type_varunicode:
  10600. funcName = unicodeToUtf8XId;
  10601. break;
  10602. case type_utf8:
  10603. funcName = utf8ToUtf8XId;
  10604. break;
  10605. case type_string:
  10606. case type_data:
  10607. {
  10608. funcName = codepageToUtf8XId;
  10609. codepageParam = createConstant(from->queryCharset()->queryCodepageName());
  10610. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10611. OwnedHqlExpr translated = createValue(no_typetransfer, type, pure.getTranslatedExpr());
  10612. buildExpr(ctx, translated, pure);
  10613. break;
  10614. }
  10615. default:
  10616. CHqlBoundExpr recast;
  10617. ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
  10618. OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
  10619. buildExpr(ctx, translated, recast);
  10620. assignCastUnknownLength(ctx, target, recast);
  10621. return;
  10622. }
  10623. break;
  10624. }
  10625. case type_set:
  10626. if (isSameBasicType(to->queryChildType(), from->queryChildType()))
  10627. {
  10628. if (!target.isAll)
  10629. {
  10630. //Ugly. Create a dummy isAll field to assign to..
  10631. assertex(!pure.isAll || matchesBoolean(pure.isAll, false));
  10632. CHqlBoundTarget tempTarget;
  10633. tempTarget.set(target);
  10634. tempTarget.isAll.setown(ctx.getTempDeclare(queryBoolType(), NULL));
  10635. assignCastUnknownLength(ctx, tempTarget, pure);
  10636. return;
  10637. }
  10638. funcName = set2SetXId;
  10639. }
  10640. else
  10641. {
  10642. OwnedHqlExpr values = pure.getTranslatedExpr();
  10643. buildSetAssignViaBuilder(ctx, target, values);
  10644. return;
  10645. }
  10646. break;
  10647. case type_dictionary:
  10648. case type_table:
  10649. case type_groupedtable:
  10650. {
  10651. OwnedHqlExpr src = pure.getTranslatedExpr();
  10652. buildDatasetAssign(ctx, target, src);
  10653. return;
  10654. }
  10655. default:
  10656. assertex(!"Unexpected target type for variable length");
  10657. break;
  10658. }
  10659. args.append(*pure.getTranslatedExpr());
  10660. if(codepageParam)
  10661. args.append(*codepageParam);
  10662. OwnedHqlExpr call = bindFunctionCall(funcName, args);
  10663. buildExprAssign(ctx, target, call);
  10664. }
  10665. void HqlCppTranslator::expandFunctions(bool expandInline)
  10666. {
  10667. if (expandInline)
  10668. {
  10669. BuildCtx ctx(*code, prototypeAtom);
  10670. ForEachItemIn(idx, code->helpers)
  10671. {
  10672. IHqlExpression & cur = (IHqlExpression &)code->helpers.item(idx);
  10673. StringBuffer init;
  10674. if (getAttribute(cur.queryChild(0), initfunctionAtom, init))
  10675. {
  10676. StringBuffer initproto("extern \"C\" void SERVICE_API ");
  10677. initproto.append(init).append("(const char *);");
  10678. ctx.addQuoted(initproto);
  10679. }
  10680. expandFunctionPrototype(ctx, &cur);
  10681. }
  10682. }
  10683. else
  10684. {
  10685. CIArray includes;
  10686. BuildCtx ctx(*code, includeAtom);
  10687. ForEachItemIn(idx, code->helpers)
  10688. {
  10689. //StringBuffer include;
  10690. //IHqlExpression & cur = (IHqlExpression &)code->helpers.item(idx);
  10691. // getLibraryName(cur, include);
  10692. //MORE!! Get the include name...
  10693. }
  10694. }
  10695. }
  10696. void HqlCppTranslator::bindAndPush(BuildCtx & ctx, IHqlExpression * value)
  10697. {
  10698. CHqlBoundExpr bound;
  10699. buildExpr(ctx, value, bound);
  10700. ensurePushed(ctx, bound);
  10701. }
  10702. bool HqlCppTranslator::ensurePushed(BuildCtx & ctx, const CHqlBoundExpr & pure)
  10703. {
  10704. if (!isPushed(pure))
  10705. {
  10706. //Temporary solution - create a critical block whenever the decimals are used.
  10707. OwnedHqlExpr marker = createAttribute(decimalAtom);
  10708. if (!ctx.queryMatchExpr(marker))
  10709. {
  10710. //If a group with no {} is added, we might get a name clash => make it unique
  10711. StringBuffer s;
  10712. getUniqueId(s.append("BcdCriticalBlock bcd")).append(";");
  10713. ctx.addQuoted(s);
  10714. ctx.associateExpr(marker, NULL);
  10715. }
  10716. ITypeInfo * type = pure.expr->queryType();
  10717. HqlExprArray args;
  10718. IIdAtom * funcName = NULL;
  10719. switch (type->getTypeCode())
  10720. {
  10721. case type_data:
  10722. case type_string:
  10723. case type_varstring:
  10724. funcName = DecPushStringId;
  10725. if (type->queryCharset()->queryName() == ebcdicAtom)
  10726. {
  10727. CHqlBoundExpr temp;
  10728. OwnedHqlExpr translated = pure.getTranslatedExpr();
  10729. OwnedHqlExpr cast = createValue(no_cast, getAsciiType(type), translated.getClear());
  10730. buildExpr(ctx, cast, temp);
  10731. args.append(*getBoundLength(temp));
  10732. args.append(*getElementPointer(temp.expr));
  10733. }
  10734. else
  10735. {
  10736. args.append(*getBoundLength(pure));
  10737. args.append(*getElementPointer(pure.expr));
  10738. }
  10739. break;
  10740. case type_qstring:
  10741. funcName = DecPushQStringId;
  10742. args.append(*getBoundLength(pure));
  10743. args.append(*getElementPointer(pure.expr));
  10744. break;
  10745. case type_unicode:
  10746. case type_varunicode:
  10747. funcName = DecPushUnicodeId;
  10748. args.append(*getBoundLength(pure));
  10749. args.append(*getElementPointer(pure.expr));
  10750. break;
  10751. case type_utf8:
  10752. funcName = DecPushUtf8Id;
  10753. args.append(*getBoundLength(pure));
  10754. args.append(*getElementPointer(pure.expr));
  10755. break;
  10756. case type_decimal:
  10757. funcName = type->isSigned() ? DecPushDecimalId : DecPushUDecimalId;
  10758. args.append(*getPointer(pure.expr));
  10759. args.append(*getSizetConstant(type->getSize()));
  10760. args.append(*getSizetConstant(type->getPrecision()));
  10761. break;
  10762. case type_swapint:
  10763. {
  10764. CHqlBoundExpr copyPure;
  10765. copyPure.set(pure);
  10766. //cast via intermediate int.
  10767. OwnedITypeInfo tempType = makeIntType(type->getSize(), type->isSigned());
  10768. CHqlBoundExpr boundCast;
  10769. doBuildExprCast(ctx, tempType, copyPure, boundCast);
  10770. funcName = type->isSigned() ? DecPushInt64Id : DecPushUInt64Id;
  10771. args.append(*boundCast.expr.getLink());
  10772. break;
  10773. }
  10774. //fall through
  10775. case type_int:
  10776. case type_packedint:
  10777. //more signed/unsigned and optimize the length...
  10778. funcName = type->isSigned() ? DecPushInt64Id : DecPushUInt64Id;
  10779. args.append(*pure.expr.getLink());
  10780. break;
  10781. case type_enumerated:
  10782. throwError2(HQLERR_CastXNotImplemented, "map", "decimal");
  10783. break;
  10784. case type_boolean:
  10785. funcName = DecPushLongId;
  10786. args.append(*pure.expr.getLink());
  10787. break;
  10788. case type_real:
  10789. funcName = DecPushRealId;
  10790. args.append(*pure.expr.getLink());
  10791. break;
  10792. default:
  10793. throwError2(HQLERR_CastXNotImplemented, "unknown", "varstring");
  10794. break;
  10795. }
  10796. if (funcName)
  10797. callProcedure(ctx, funcName, args);
  10798. return true;
  10799. }
  10800. return false;
  10801. }
  10802. static StringBuffer & appendCapital(StringBuffer & s, const char * name)
  10803. {
  10804. if (name && name[0])
  10805. {
  10806. s.append((char)toupper(*name));
  10807. s.append(name+1);
  10808. }
  10809. return s;
  10810. }
  10811. bool HqlCppTranslator::expandFunctionPrototype(StringBuffer & s, IHqlExpression * funcdef)
  10812. {
  10813. return generateFunctionPrototype(s, funcdef, options.targetCompiler);
  10814. }
  10815. void HqlCppTranslator::expandFunctionPrototype(BuildCtx & ctx, IHqlExpression * funcdef)
  10816. {
  10817. StringBuffer s;
  10818. if (expandFunctionPrototype(s, funcdef))
  10819. {
  10820. s.append(";");
  10821. IHqlExpression *body = funcdef->queryChild(0);
  10822. IHqlExpression *namespaceAttr = body->queryAttribute(namespaceAtom);
  10823. if (namespaceAttr)
  10824. {
  10825. StringBuffer ns;
  10826. getStringValue(ns, namespaceAttr->queryChild(0));
  10827. ns.insert(0, "namespace ").appendf(" { %s }", s.str());
  10828. ctx.addQuoted(ns);
  10829. }
  10830. else
  10831. ctx.addQuoted(s);
  10832. }
  10833. }
  10834. //Replace no_param with whatever they will have been bound to
  10835. static IHqlExpression *createActualFromFormal(IHqlExpression *param)
  10836. {
  10837. StringBuffer temp;
  10838. ITypeInfo *paramType = param->queryType();
  10839. CHqlBoundExpr bound;
  10840. //Case is significant if these parameters are use for BEGINC++ sections
  10841. IIdAtom * paramName = param->queryId();
  10842. const char * paramNameText = str(lower(paramName));
  10843. Linked<ITypeInfo> type = paramType;
  10844. switch (paramType->getTypeCode())
  10845. {
  10846. case type_set:
  10847. {
  10848. appendCapital(temp.clear().append("isAll"), paramNameText);
  10849. bound.isAll.setown(createVariable(temp.str(), makeBoolType()));
  10850. }
  10851. //fall through
  10852. case type_string:
  10853. case type_qstring:
  10854. case type_data:
  10855. case type_unicode:
  10856. case type_utf8:
  10857. case type_dictionary:
  10858. case type_table:
  10859. case type_groupedtable:
  10860. if (paramType->getSize() == UNKNOWN_LENGTH)
  10861. {
  10862. if (hasOutOfLineModifier(paramType) || hasLinkCountedModifier(paramType))
  10863. {
  10864. appendCapital(temp.clear().append("count"), paramNameText);
  10865. bound.count.setown(createVariable(temp.str(), LINK(sizetType)));
  10866. }
  10867. else
  10868. {
  10869. appendCapital(temp.clear().append("len"), paramNameText);
  10870. bound.length.setown(createVariable(temp.str(), LINK(sizetType)));
  10871. }
  10872. }
  10873. type.setown(makeReferenceModifier(LINK(type)));
  10874. break;
  10875. }
  10876. bound.expr.setown(createVariable(paramNameText, LINK(type)));
  10877. return bound.getTranslatedExpr();
  10878. }
  10879. IHqlExpression * replaceInlineParameters(IHqlExpression * funcdef, IHqlExpression * expr)
  10880. {
  10881. IHqlExpression * body = funcdef->queryChild(0);
  10882. assertex(!body->hasAttribute(oldSetFormatAtom));
  10883. IHqlExpression * formals = funcdef->queryChild(1);
  10884. HqlMapTransformer simpleTransformer;
  10885. StringBuffer paramNameText, temp;
  10886. ForEachChild(i, formals)
  10887. {
  10888. IHqlExpression * param = formals->queryChild(i);
  10889. OwnedHqlExpr actual = createActualFromFormal(param);
  10890. simpleTransformer.setMapping(param, actual);
  10891. }
  10892. return simpleTransformer.transformRoot(expr);
  10893. }
  10894. void HqlCppTranslator::doBuildUserFunctionReturn(BuildCtx & ctx, ITypeInfo * type, IHqlExpression * value)
  10895. {
  10896. if (!options.spotCSE)
  10897. {
  10898. doBuildFunctionReturn(ctx, type, value);
  10899. return;
  10900. }
  10901. switch (value->getOperator())
  10902. {
  10903. case no_if:
  10904. if (false)///disable for the moment - look at changes in klogermann11 to see why, some v.good, some bad.
  10905. {
  10906. //optimize the way that cses are spotted to minimise unnecessary calculations
  10907. OwnedHqlExpr branches = createComma(LINK(value->queryChild(1)), LINK(value->queryChild(2)));
  10908. OwnedHqlExpr cond = LINK(value->queryChild(0));
  10909. spotScalarCSE(cond, branches, NULL, NULL, queryOptions().spotCseInIfDatasetConditions);
  10910. BuildCtx subctx(ctx);
  10911. IHqlStmt * stmt = buildFilterViaExpr(subctx, cond);
  10912. doBuildUserFunctionReturn(subctx, type, branches->queryChild(0));
  10913. subctx.selectElse(stmt);
  10914. doBuildUserFunctionReturn(subctx, type, branches->queryChild(1));
  10915. break;
  10916. }
  10917. // fallthrough
  10918. default:
  10919. {
  10920. OwnedHqlExpr optimized = spotScalarCSE(value, NULL, queryOptions().spotCseInIfDatasetConditions);
  10921. if (value->isAction())
  10922. buildStmt(ctx, value);
  10923. else
  10924. doBuildFunctionReturn(ctx, type, optimized);
  10925. break;
  10926. }
  10927. }
  10928. }
  10929. void HqlCppTranslator::buildCppFunctionDefinition(BuildCtx & ctx, IHqlExpression * bodyCode, const char *proto)
  10930. {
  10931. processCppBodyDirectives(bodyCode);
  10932. IHqlExpression * location = queryLocation(bodyCode);
  10933. const char * locationFilename = location ? str(location->querySourcePath()) : NULL;
  10934. unsigned startLine = location ? location->getStartLine() : 0;
  10935. IHqlExpression * cppBody = bodyCode->queryChild(0);
  10936. if (cppBody->getOperator() == no_record)
  10937. cppBody = bodyCode->queryChild(1);
  10938. StringBuffer text;
  10939. cppBody->queryValue()->getUTF8Value(text);
  10940. //remove #option, and remove /r so we don't end up with mixed format end of lines.
  10941. text.setLength(cleanupEmbeddedCpp(text.length(), (char*)text.str()));
  10942. const char * start = text.str();
  10943. for (;;)
  10944. {
  10945. char next = *start;
  10946. if (next == '\n')
  10947. startLine++;
  10948. else if (next != '\r')
  10949. break;
  10950. start++;
  10951. }
  10952. const char * body = start;
  10953. const char * cppSeparatorText = "#body";
  10954. const char * separator = strstr(body, cppSeparatorText);
  10955. if (separator)
  10956. {
  10957. if (bodyCode->hasAttribute(inlineAtom))
  10958. throwError(HQLERR_BodyNotAllowedWithInline);
  10959. text.setCharAt(separator-text.str(), 0);
  10960. if (location)
  10961. ctx.addLine(locationFilename, startLine);
  10962. ctx.addQuoted(body);
  10963. if (location)
  10964. ctx.addLine();
  10965. body = separator + strlen(cppSeparatorText);
  10966. if (*body == '\r') body++;
  10967. if (*body == '\n') body++;
  10968. startLine += memcount(body-start, start, '\n');
  10969. }
  10970. bool addPragmas = options.embeddedWarningsAsErrors && !bodyCode->hasAttribute(inlineAtom);
  10971. if (addPragmas)
  10972. {
  10973. ctx.addQuoted("#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))\n"
  10974. "#pragma GCC diagnostic error \"-Wall\"\n"
  10975. "#pragma GCC diagnostic error \"-Wextra\"\n"
  10976. "#pragma GCC diagnostic ignored \"-Wunused-parameter\"\n" // Generated prototype tends to include ctx that is often not used
  10977. "#endif\n");
  10978. }
  10979. MemberFunction userFunc(*this, ctx, proto, MFdynamicproto);
  10980. if (location)
  10981. userFunc.ctx.addLine(locationFilename, startLine);
  10982. userFunc.ctx.addQuoted(body);
  10983. if (location)
  10984. userFunc.ctx.addLine();
  10985. if (addPragmas)
  10986. {
  10987. ctx.addQuoted("\n#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))\n"
  10988. "#pragma GCC diagnostic ignored \"-Wall\"\n"
  10989. "#pragma GCC diagnostic ignored \"-Wextra\"\n"
  10990. "#pragma GCC diagnostic ignored \"-Wunused-variable\"\n" // Some variants of gcc seem to be buggy - this SHOULD be covered by -Wall above but gcc4.8.4 needs it explicit
  10991. "#pragma GCC diagnostic ignored \"-Wparentheses\"\n" // Some variants of gcc seem to be buggy - this SHOULD be covered by -Wall above but gcc4.8.4 needs it explicit
  10992. "#endif\n");
  10993. }
  10994. }
  10995. void HqlCppTranslator::buildScriptFunctionDefinition(BuildCtx &ctx, IHqlExpression * funcdef, const char *proto)
  10996. {
  10997. ITypeInfo * returnType = funcdef->queryType()->queryChildType();
  10998. IHqlExpression * outofline = funcdef->queryChild(0);
  10999. IHqlExpression * formals = funcdef->queryChild(1);
  11000. assertex(outofline->getOperator() == no_outofline);
  11001. IHqlExpression * bodyCode = outofline->queryChild(0);
  11002. IHqlExpression *language = queryAttributeChild(bodyCode, languageAtom, 0);
  11003. bool isImport = bodyCode->hasAttribute(importAtom);
  11004. MemberFunction scriptFunc(*this, ctx, proto, MFdynamicproto);
  11005. BuildCtx & funcctx = scriptFunc.ctx;
  11006. funcctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  11007. funcctx.associateExpr(globalContextMarkerExpr, globalContextMarkerExpr);
  11008. IHqlExpression *optionsParam = nullptr;
  11009. IHqlExpression *queryParam = nullptr;
  11010. unsigned numRealParams = 0;
  11011. ForEachChild(formalIdx, formals)
  11012. {
  11013. IHqlExpression *formal = formals->queryChild(formalIdx);
  11014. if (formal->queryId()==__optionsId)
  11015. optionsParam = formal;
  11016. else if (formal->queryId()==__queryId)
  11017. queryParam = formal; // Query text is being passed in to the function
  11018. else
  11019. numRealParams++;
  11020. }
  11021. OwnedHqlExpr query; // The text of the query (or the name of the import)
  11022. if (queryParam)
  11023. query.setown(createActualFromFormal(queryParam));
  11024. else
  11025. query.set(bodyCode->queryChild(0));
  11026. IValue *queryVal = query->queryValue();
  11027. OwnedHqlExpr embedOptions;
  11028. if (optionsParam)
  11029. embedOptions.setown(createActualFromFormal(optionsParam));
  11030. else
  11031. embedOptions.setown(getEmbedOptionString(bodyCode));
  11032. IValue *optionVal = embedOptions->queryValue();
  11033. bool isActivity = functionBodyIsActivity(bodyCode);
  11034. bool threadlocal = bodyCode->hasAttribute(_threadlocal_Atom) && queryVal != nullptr && optionVal != nullptr && !isActivity;
  11035. bool singletonEmbedContext = bodyCode->hasAttribute(_singletonEmbedContext_Atom);
  11036. HqlExprArray noargs;
  11037. OwnedHqlExpr getPlugin = bindFunctionCall(language, noargs);
  11038. OwnedHqlExpr pluginPtr;
  11039. const char *pluginPtrDef = nullptr;
  11040. if (threadlocal)
  11041. {
  11042. assertex(singletonEmbedContext);
  11043. pluginPtrDef = "static thread_local IEmbedContext *__plugin";
  11044. }
  11045. else if (singletonEmbedContext)
  11046. pluginPtrDef = "IEmbedContext *__plugin";
  11047. else
  11048. pluginPtrDef = "Owned<IEmbedContext> __plugin";
  11049. pluginPtr.setown(createQuoted(pluginPtrDef, getPlugin->getType()));
  11050. buildAssignToTemp(funcctx, pluginPtr, getPlugin);
  11051. StringBuffer createParam;
  11052. if (threadlocal)
  11053. createParam.append("static thread_local IEmbedFunctionContext *__ctx = __plugin->createFunctionContextEx(ctx,");
  11054. else
  11055. createParam.append("Owned<IEmbedFunctionContext> __ctx = __plugin->createFunctionContextEx(ctx,");
  11056. if (isActivity)
  11057. createParam.append("activity,");
  11058. else
  11059. createParam.append("nullptr,");
  11060. createParam.append(isImport ? "EFimport" : "EFembed");
  11061. if (returnType->getTypeCode()==type_void)
  11062. createParam.append("|EFnoreturn");
  11063. if (threadlocal)
  11064. createParam.append("|EFthreadlocal");
  11065. if (!numRealParams)
  11066. createParam.append("|EFnoparams");
  11067. if (embedOptions)
  11068. {
  11069. CHqlBoundExpr bound;
  11070. buildExpr(funcctx, embedOptions, bound);
  11071. createParam.append(",");
  11072. generateExprCpp(createParam, bound.expr);
  11073. }
  11074. else
  11075. createParam.append(",NULL");
  11076. createParam.append(");");
  11077. funcctx.addQuoted(createParam);
  11078. if (threadlocal)
  11079. funcctx.addQuoted("EmbedContextBlock __b(__ctx, ctx);");
  11080. else
  11081. funcctx.addQuoted("EmbedContextBlock __b(__ctx);");
  11082. OwnedHqlExpr ctxVar = createVariable("__ctx", makeBoolType());
  11083. HqlExprArray scriptArgs;
  11084. scriptArgs.append(*LINK(ctxVar));
  11085. if (bodyCode->hasAttribute(projectedAtom))
  11086. {
  11087. assertex(!isImport);
  11088. // Generate the field list from the output record
  11089. StringBuffer fieldlist;
  11090. IHqlExpression *outRec = bodyCode->queryChild(1);
  11091. assertex(outRec->queryRecordType());
  11092. HqlExprArray fields;
  11093. getSimpleFields(fields, outRec);
  11094. ForEachItemIn(idx, fields)
  11095. {
  11096. IIdAtom *fieldName = fields.item(idx).queryId();
  11097. assertex(fieldName);
  11098. fieldlist.append(',').append(fieldName->queryStr());
  11099. }
  11100. assertex(fieldlist.length());
  11101. LinkedHqlExpr substSearch = queryAttributeChild(bodyCode, projectedAtom, 0);
  11102. assertex (substSearch);
  11103. IValue *substValue = substSearch->queryValue();
  11104. if (!queryVal || !substValue)
  11105. {
  11106. // Have to do the substitution at runtime if query or substId are not constant
  11107. HqlExprArray args;
  11108. args.append(*query.getLink());
  11109. args.append(*createConstant(createUtf8Value(fieldlist.length()-1, fieldlist.str()+1, makeUtf8Type(UNKNOWN_LENGTH, NULL))));
  11110. args.append(*LINK(substSearch));
  11111. scriptArgs.append(*bindFunctionCall(substituteEmbeddedScriptId, args,makeUtf8Type(UNKNOWN_LENGTH, NULL)));
  11112. }
  11113. else
  11114. {
  11115. StringBuffer origBody;
  11116. queryVal->getUTF8Value(origBody);
  11117. StringBuffer search;
  11118. substValue->getUTF8Value(search);
  11119. rtlDataAttr result;
  11120. unsigned resultLen;
  11121. rtlSubstituteEmbeddedScript(resultLen, result.refstr(), origBody.lengthUtf8(), origBody.str(), fieldlist.lengthUtf8()-1, fieldlist.str()+1, search.lengthUtf8(), search.str());
  11122. scriptArgs.append(*createConstant(createUtf8Value(resultLen, result.getstr(), makeUtf8Type(resultLen, NULL))));
  11123. }
  11124. }
  11125. else
  11126. {
  11127. scriptArgs.append(*query.getLink());
  11128. }
  11129. IIdAtom *id;
  11130. if (isImport)
  11131. id = importId;
  11132. else if (bodyCode->hasAttribute(_precompile_Atom))
  11133. id = loadCompiledScriptId;
  11134. else
  11135. id = compileEmbeddedScriptId;
  11136. if (!bodyCode->hasAttribute(_prebind_Atom))
  11137. buildFunctionCall(funcctx, id, scriptArgs);
  11138. ForEachChild(i, formals)
  11139. {
  11140. IHqlExpression * param = formals->queryChild(i);
  11141. if (param == optionsParam || param==queryParam)
  11142. continue;
  11143. HqlExprArray args;
  11144. args.append(*LINK(ctxVar));
  11145. ITypeInfo *paramType = param->queryType();
  11146. IIdAtom * paramId = param->queryId();
  11147. const char * paramNameText = str(paramId);
  11148. if (!options.preserveCaseExternalParameter)
  11149. paramNameText = str(lower(paramId));
  11150. args.append(*createConstant(paramNameText));
  11151. IIdAtom * bindFunc;
  11152. switch (paramType->getTypeCode())
  11153. {
  11154. case type_int:
  11155. if (paramType->getSize()<8)
  11156. {
  11157. bindFunc = paramType->isSigned() ? bindSignedSizeParamId : bindUnsignedSizeParamId;
  11158. args.append(*createIntConstant(paramType->getSize()));
  11159. }
  11160. else
  11161. bindFunc = paramType->isSigned() ? bindSignedParamId : bindUnsignedParamId;
  11162. break;
  11163. case type_varstring:
  11164. bindFunc = bindVStringParamId;
  11165. break;
  11166. case type_string:
  11167. bindFunc = bindStringParamId;
  11168. break;
  11169. case type_real:
  11170. if (paramType->getSize()==4)
  11171. bindFunc = bindFloatParamId;
  11172. else
  11173. bindFunc = bindRealParamId;
  11174. break;
  11175. case type_boolean:
  11176. bindFunc = bindBooleanParamId;
  11177. break;
  11178. case type_utf8:
  11179. bindFunc = bindUtf8ParamId;
  11180. break;
  11181. case type_unicode:
  11182. bindFunc = bindUnicodeParamId;
  11183. break;
  11184. case type_data:
  11185. bindFunc = bindDataParamId;
  11186. break;
  11187. case type_row:
  11188. bindFunc = bindRowParamId;
  11189. break;
  11190. case type_table:
  11191. case type_groupedtable:
  11192. bindFunc = bindDatasetParamId;
  11193. break;
  11194. case type_set:
  11195. {
  11196. bindFunc = bindSetParamId;
  11197. ITypeInfo *childType = paramType->queryChildType();
  11198. type_t typeCode = childType->getTypeCode();
  11199. if (childType->isInteger() && !childType->isSigned())
  11200. typeCode = type_unsigned;
  11201. args.append(*createIntConstant(typeCode));
  11202. args.append(*createIntConstant(childType->getSize()));
  11203. break;
  11204. }
  11205. default:
  11206. StringBuffer typeText;
  11207. getFriendlyTypeStr(paramType, typeText);
  11208. throwError1(HQLERR_EmbeddedTypeNotSupported_X, typeText.str());
  11209. return; // Cannot reach here, but previous throw is virtual, so the compiler cannot be sure it does not return
  11210. }
  11211. args.append(*createActualFromFormal(param));
  11212. buildFunctionCall(funcctx, bindFunc, args);
  11213. }
  11214. if (bodyCode->hasAttribute(_prebind_Atom))
  11215. buildFunctionCall(funcctx, id, scriptArgs);
  11216. funcctx.addQuotedLiteral("__ctx->callFunction();");
  11217. IIdAtom * returnFunc;
  11218. HqlExprArray retargs;
  11219. Owned<ITypeInfo> newReturnType;
  11220. retargs.append(*LINK(ctxVar));
  11221. switch (returnType->getTypeCode())
  11222. {
  11223. case type_int:
  11224. returnFunc = returnType->isSigned() ? getSignedResultId : getUnsignedResultId;
  11225. break;
  11226. case type_varstring:
  11227. case type_string:
  11228. returnFunc = getStringResultId;
  11229. break;
  11230. case type_real:
  11231. returnFunc = getRealResultId;
  11232. break;
  11233. case type_boolean:
  11234. returnFunc = getBooleanResultId;
  11235. break;
  11236. case type_unicode:
  11237. returnFunc = getUnicodeResultId;
  11238. break;
  11239. case type_utf8:
  11240. returnFunc = getUTF8ResultId;
  11241. break;
  11242. case type_data:
  11243. returnFunc = getDataResultId;
  11244. break;
  11245. case type_set:
  11246. {
  11247. returnFunc = getSetResultId;
  11248. ITypeInfo *childType = returnType->queryChildType();
  11249. type_t typeCode = childType->getTypeCode();
  11250. if (childType->isInteger() && !childType->isSigned())
  11251. typeCode = type_unsigned;
  11252. retargs.append(*createIntConstant(typeCode));
  11253. retargs.append(*createIntConstant(returnType->queryChildType()->getSize()));
  11254. break;
  11255. }
  11256. case type_row:
  11257. returnFunc = getRowResultId;
  11258. newReturnType.set(returnType);
  11259. break;
  11260. case type_table:
  11261. returnFunc = getDatasetResultId;
  11262. newReturnType.set(returnType);
  11263. break;
  11264. case type_transform:
  11265. returnFunc = getTransformResultId;
  11266. newReturnType.set(returnType);
  11267. break;
  11268. case type_void:
  11269. return;
  11270. default:
  11271. StringBuffer typeText;
  11272. getFriendlyTypeStr(returnType, typeText);
  11273. throwError1(HQLERR_EmbeddedTypeNotSupported_X, typeText.str());
  11274. return; // Cannot reach here, but previous throw is virtual, so the compiler cannot be sure it does not return
  11275. }
  11276. OwnedHqlExpr call = bindFunctionCall(returnFunc, retargs, newReturnType);
  11277. doBuildUserFunctionReturn(funcctx, returnType, call);
  11278. }
  11279. void HqlCppTranslator::buildFunctionDefinition(IHqlExpression * funcdef)
  11280. {
  11281. IHqlExpression * outofline = funcdef->queryChild(0);
  11282. assertex(outofline->getOperator() == no_outofline);
  11283. IHqlExpression * bodyCode = outofline->queryChild(0);
  11284. StringBuffer proto;
  11285. BuildCtx funcctx(*code, helperAtom);
  11286. if (options.spanMultipleCpp)
  11287. {
  11288. const bool inChildActivity = true; // assume the worst
  11289. OwnedHqlExpr pass = getSizetConstant(beginFunctionGetCppIndex(0, inChildActivity));
  11290. funcctx.addGroupPass(pass);
  11291. }
  11292. expandFunctionPrototype(proto, funcdef);
  11293. if (bodyCode->getOperator() == no_embedbody)
  11294. {
  11295. if (bodyCode->hasAttribute(_disallowed_Atom))
  11296. throwError(HQLERR_EmbeddedCppNotAllowed);
  11297. IHqlExpression *languageAttr = bodyCode->queryAttribute(languageAtom);
  11298. if (languageAttr)
  11299. {
  11300. buildScriptFunctionDefinition(funcctx, funcdef, proto);
  11301. }
  11302. else
  11303. {
  11304. bool isInline = bodyCode->hasAttribute(inlineAtom);
  11305. if (isInline)
  11306. {
  11307. if (options.spanMultipleCpp)
  11308. {
  11309. BuildCtx funcctx2(*code, parentHelpersAtom);
  11310. buildCppFunctionDefinition(funcctx2, bodyCode, proto);
  11311. }
  11312. else
  11313. buildCppFunctionDefinition(funcctx, bodyCode, proto);
  11314. }
  11315. else
  11316. {
  11317. BuildCtx funcctx2(*code, userFunctionAtom);
  11318. if (options.spanMultipleCpp)
  11319. {
  11320. OwnedHqlExpr pass = getSizetConstant(beginFunctionGetCppIndex(0, false));
  11321. funcctx2.addGroupPass(pass);
  11322. }
  11323. buildCppFunctionDefinition(funcctx2, bodyCode, proto);
  11324. }
  11325. }
  11326. }
  11327. else
  11328. {
  11329. MemberFunction func(*this, funcctx, proto, MFdynamicproto);
  11330. //MORE: Need to work out how to handle functions that require the context.
  11331. //Need to create a class instead.
  11332. if (functionBodyUsesContext(outofline))
  11333. {
  11334. func.ctx.associateExpr(codeContextMarkerExpr, codeContextMarkerExpr);
  11335. func.ctx.associateExpr(globalContextMarkerExpr, globalContextMarkerExpr);
  11336. }
  11337. OwnedHqlExpr newCode = replaceInlineParameters(funcdef, bodyCode);
  11338. newCode.setown(foldHqlExpression(newCode));
  11339. ITypeInfo * returnType = funcdef->queryType()->queryChildType();
  11340. doBuildUserFunctionReturn(func.ctx, returnType, newCode);
  11341. }
  11342. }
  11343. //---------------------------------------------------------------------------
  11344. void HqlCppTranslator::doBuildPureSubExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
  11345. {
  11346. unsigned max = expr->numChildren();
  11347. if (max == 0)
  11348. tgt.expr.set(expr);
  11349. else
  11350. {
  11351. HqlExprArray args;
  11352. unsigned idx = 0;
  11353. CHqlBoundExpr bound;
  11354. for (idx = 0; idx < max; idx++)
  11355. {
  11356. buildExpr(ctx, expr->queryChild(idx), bound);
  11357. args.append(*bound.expr.getClear());
  11358. }
  11359. tgt.expr.setown(expr->clone(args));
  11360. }
  11361. }
  11362. //---------------------------------------------------------------------------
  11363. IHqlExpression * HqlCppTranslator::getListLength(BuildCtx & ctx, IHqlExpression * expr)
  11364. {
  11365. CHqlBoundExpr bound;
  11366. buildExpr(ctx, expr, bound);
  11367. return getBoundLength(bound);
  11368. }
  11369. IHqlExpression * HqlCppTranslator::getBoundCount(const CHqlBoundExpr & bound)
  11370. {
  11371. if (bound.count)
  11372. return bound.count.getLink();
  11373. ITypeInfo * type = bound.expr->queryType();
  11374. switch (type->getTypeCode())
  11375. {
  11376. case type_array:
  11377. {
  11378. if (bound.length)
  11379. return convertBetweenCountAndSize(bound, true);
  11380. unsigned size = type->getSize();
  11381. if (size != UNKNOWN_LENGTH)
  11382. return getSizetConstant(size / type->queryChildType()->getSize());
  11383. UNIMPLEMENTED;
  11384. }
  11385. case type_dictionary:
  11386. case type_table:
  11387. case type_groupedtable:
  11388. case type_set:
  11389. if (bound.length)
  11390. return convertBetweenCountAndSize(bound, true);
  11391. UNIMPLEMENTED;
  11392. default:
  11393. UNIMPLEMENTED;
  11394. }
  11395. }
  11396. IHqlExpression * HqlCppTranslator::getBoundLength(const CHqlBoundExpr & bound)
  11397. {
  11398. if (bound.length)
  11399. return bound.length.getLink();
  11400. ITypeInfo * type = bound.expr->queryType();
  11401. if (bound.expr->queryValue())
  11402. return getSizetConstant(type->getStringLen());
  11403. switch (type->getTypeCode())
  11404. {
  11405. case type_varstring:
  11406. {
  11407. HqlExprArray args;
  11408. args.append(*getElementPointer(bound.expr));
  11409. return bindTranslatedFunctionCall(strlenId, args);
  11410. }
  11411. case type_varunicode:
  11412. {
  11413. HqlExprArray args;
  11414. args.append(*getElementPointer(bound.expr));
  11415. return bindTranslatedFunctionCall(unicodeStrlenId, args);
  11416. }
  11417. case type_set:
  11418. case type_array:
  11419. case type_dictionary:
  11420. case type_table:
  11421. case type_groupedtable:
  11422. assertex(!isArrayRowset(type));
  11423. if (bound.count)
  11424. return convertBetweenCountAndSize(bound, false);
  11425. UNIMPLEMENTED;
  11426. case type_utf8:
  11427. {
  11428. assertex(type->getSize() != UNKNOWN_LENGTH);
  11429. HqlExprArray args;
  11430. args.append(*getSizetConstant(type->getSize()));
  11431. args.append(*getElementPointer(bound.expr));
  11432. return bindTranslatedFunctionCall(utf8LengthId, args);
  11433. }
  11434. default:
  11435. return getSizetConstant(type->getStringLen());
  11436. }
  11437. }
  11438. IHqlExpression * HqlCppTranslator::getBoundSize(ITypeInfo * type, IHqlExpression * length, IHqlExpression * data)
  11439. {
  11440. type_t tc = type->getTypeCode();
  11441. switch (tc)
  11442. {
  11443. case type_qstring:
  11444. {
  11445. if (length->queryValue())
  11446. return getSizetConstant((size32_t)rtlQStrSize((size32_t)length->queryValue()->getIntValue()));
  11447. HqlExprArray args;
  11448. args.append(*LINK(length));
  11449. return bindTranslatedFunctionCall(qstrSizeId, args);
  11450. }
  11451. case type_varstring:
  11452. return adjustValue(length, 1);
  11453. case type_varunicode:
  11454. {
  11455. OwnedHqlExpr temp = adjustValue(length, 1);
  11456. return multiplyValue(temp, 2);
  11457. }
  11458. case type_unicode:
  11459. return multiplyValue(length, 2);
  11460. case type_utf8:
  11461. {
  11462. assertex(data);
  11463. if (data->queryValue())
  11464. return getSizetConstant(data->queryValue()->getSize());
  11465. HqlExprArray args;
  11466. args.append(*LINK(length));
  11467. args.append(*getElementPointer(data));
  11468. return bindTranslatedFunctionCall(utf8SizeId, args);
  11469. }
  11470. case type_array:
  11471. case type_set:
  11472. return LINK(length);
  11473. default:
  11474. return LINK(length);
  11475. }
  11476. }
  11477. IHqlExpression * HqlCppTranslator::getBoundSize(const CHqlBoundExpr & bound)
  11478. {
  11479. ITypeInfo * type = bound.expr->queryType();
  11480. if (bound.length)
  11481. return getBoundSize(type, bound.length, bound.expr);
  11482. type_t tc = type->getTypeCode();
  11483. if (tc == type_row)
  11484. {
  11485. if (hasReferenceModifier(type))
  11486. return getSizetConstant(sizeof(void*));
  11487. IHqlExpression * record = ::queryRecord(type);
  11488. if (isFixedSizeRecord(record))
  11489. return getSizetConstant(getMinRecordSize(record));
  11490. //call meta function mm.queryRecordSize(&row)
  11491. StringBuffer metaInstance, temp;
  11492. buildMetaForRecord(metaInstance, record);
  11493. temp.append(metaInstance).append(".getRecordSize(");
  11494. OwnedHqlExpr rowAddr = getPointer(bound.expr);
  11495. generateExprCpp(temp, rowAddr);
  11496. temp.append(")");
  11497. return createQuoted(temp.str(), LINK(sizetType));
  11498. }
  11499. if (type->getSize() != UNKNOWN_LENGTH)
  11500. return getSizetConstant(type->getSize());
  11501. OwnedHqlExpr length = getBoundLength(bound);
  11502. return getBoundSize(type, length, bound.expr);
  11503. }
  11504. IHqlExpression * HqlCppTranslator::getFirstCharacter(IHqlExpression * source)
  11505. {
  11506. if (source->getOperator() == no_constant)
  11507. {
  11508. StringBuffer temp;
  11509. source->queryValue()->getStringValue(temp);
  11510. return createUIntConstant((unsigned char)temp.charAt(0));
  11511. }
  11512. return createValue(no_index, makeCharType(), LINK(source), getZero());
  11513. }
  11514. IHqlExpression * HqlCppTranslator::getElementPointer(IHqlExpression * source)
  11515. {
  11516. ITypeInfo * srcType = source->queryType();
  11517. switch (srcType->getTypeCode())
  11518. {
  11519. case type_string:
  11520. case type_data:
  11521. case type_qstring:
  11522. case type_varstring:
  11523. case type_unicode:
  11524. case type_utf8:
  11525. case type_varunicode:
  11526. case type_set:
  11527. case type_array:
  11528. break;
  11529. default:
  11530. throwUnexpectedType(srcType);
  11531. }
  11532. if (source->getOperator() == no_constant)
  11533. return LINK(source);
  11534. OwnedHqlExpr pointer = getPointer(source);
  11535. return ensureIndexable(pointer);
  11536. }
  11537. /* All in params: NOT linked */
  11538. IHqlExpression * HqlCppTranslator::getIndexedElementPointer(IHqlExpression * source, IHqlExpression * index)
  11539. {
  11540. ITypeInfo * srcType = source->queryType();
  11541. switch (srcType->getTypeCode())
  11542. {
  11543. case type_string:
  11544. case type_data:
  11545. case type_qstring:
  11546. case type_varstring:
  11547. case type_unicode:
  11548. case type_utf8:
  11549. case type_varunicode:
  11550. break;
  11551. default:
  11552. throwUnexpectedType(srcType);
  11553. }
  11554. if (!index)
  11555. return getElementPointer(source);
  11556. IValue * value = index->queryValue();
  11557. if (value && value->getIntValue() == 0)
  11558. return getElementPointer(source);
  11559. ITypeInfo * refType = LINK(srcType);
  11560. if (!srcType->isReference())
  11561. refType = makeReferenceModifier(refType);
  11562. OwnedHqlExpr temp;
  11563. if (srcType->getTypeCode() == type_utf8)
  11564. {
  11565. HqlExprArray args;
  11566. args.append(*LINK(index));
  11567. args.append(*getElementPointer(source));
  11568. temp.setown(bindTranslatedFunctionCall(utf8SizeId, args));
  11569. index = temp;
  11570. }
  11571. //special case string indexing
  11572. if (source->getOperator() != no_constant)
  11573. {
  11574. if (!srcType->isReference() && !hasWrapperModifier(srcType))
  11575. return createValue(no_address, refType, createValue(no_index, makeCharType(), ensureIndexable(source), LINK(index)));
  11576. }
  11577. return createValue(no_add, refType, ensureIndexable(source), LINK(index));
  11578. }
  11579. IHqlExpression * HqlCppTranslator::getIndexedElementPointer(IHqlExpression * source, unsigned index)
  11580. {
  11581. if (!index)
  11582. return getElementPointer(source);
  11583. OwnedHqlExpr ival = getSizetConstant(index);
  11584. return getIndexedElementPointer(source, ival);
  11585. }
  11586. IHqlExpression * HqlCppTranslator::needFunction(IIdAtom * name)
  11587. {
  11588. assertex(name);
  11589. HqlDummyLookupContext dummyctx(errorProcessor);
  11590. return internalScope->lookupSymbol(name, LSFsharedOK, dummyctx);
  11591. }
  11592. bool HqlCppTranslator::childrenRequireTemp(BuildCtx & ctx, IHqlExpression * expr, bool includeChildren)
  11593. {
  11594. unsigned numArgs = expr->numChildren();
  11595. for (unsigned index = 0; index < numArgs; index++)
  11596. if (requiresTemp(ctx, expr->queryChild(index), includeChildren))
  11597. return true;
  11598. return false;
  11599. }
  11600. bool HqlCppTranslator::requiresTemp(BuildCtx & ctx, IHqlExpression * expr, bool includeChildren)
  11601. {
  11602. switch (expr->getOperator())
  11603. {
  11604. case no_attr:
  11605. case no_attr_link:
  11606. case no_attr_expr:
  11607. case no_quoted:
  11608. case no_variable:
  11609. case no_constant:
  11610. case no_translated:
  11611. case no_matchtext:
  11612. case no_matchunicode:
  11613. case no_matchlength:
  11614. case no_matchattr:
  11615. case no_matchrow:
  11616. case no_matchutf8:
  11617. case no_libraryinput:
  11618. return false;
  11619. case no_skip:
  11620. case no_fail:
  11621. //This expression does not actually create a temporary variable.
  11622. //Possibly the if code should be checking if the expression has side-effects, in which case this could then return false
  11623. return true;
  11624. case no_getresult:
  11625. case no_getgraphresult:
  11626. case no_workunit_dataset:
  11627. return false; // if in an activity, then will be in setContext, if not then don't really care
  11628. case no_preservemeta:
  11629. return requiresTemp(ctx, expr->queryChild(0), includeChildren);
  11630. case no_alias:
  11631. {
  11632. if (expr->isPure() && ctx.queryMatchExpr(expr->queryChild(0)))
  11633. return false;
  11634. if (!containsActiveDataset(expr)) // generates a earlier temp even if generating within the onCreate() function
  11635. return false;
  11636. return true;
  11637. }
  11638. case no_alias_scope:
  11639. if (includeChildren)
  11640. return true;
  11641. return requiresTemp(ctx, expr->queryChild(0), includeChildren);
  11642. case no_select:
  11643. {
  11644. bool isNew;
  11645. IHqlExpression * ds = querySelectorDataset(expr, isNew);
  11646. if (isNew)
  11647. {
  11648. if (!ds->isPure() || !ds->isDatarow())
  11649. return true;
  11650. if (!ctx.queryAssociation(ds, AssocRow, NULL))
  11651. return true;
  11652. }
  11653. return false;
  11654. }
  11655. case no_field:
  11656. throwUnexpected();
  11657. return false; // more, depends on whether conditional etc.
  11658. case no_sizeof:
  11659. case no_offsetof:
  11660. return false; /// auto creates one anyway.
  11661. case no_typetransfer:
  11662. switch (expr->queryChild(0)->queryType()->getTypeCode())
  11663. {
  11664. case type_qstring:
  11665. case type_string:
  11666. case type_data:
  11667. case type_varstring:
  11668. break;
  11669. default:
  11670. return true;
  11671. }
  11672. break;
  11673. case no_substring:
  11674. {
  11675. SubStringInfo info(expr);
  11676. if (!info.canGenerateInline() && !expr->hasAttribute(quickAtom))
  11677. return true;
  11678. break;
  11679. }
  11680. case no_call:
  11681. case no_externalcall:
  11682. {
  11683. ITypeInfo * type = expr->queryType();
  11684. switch (type->getTypeCode())
  11685. {
  11686. case type_string:
  11687. case type_data:
  11688. case type_qstring:
  11689. case type_varstring:
  11690. case type_unicode:
  11691. case type_varunicode:
  11692. case type_utf8:
  11693. return true;
  11694. }
  11695. if (isTimed(expr))
  11696. return true;
  11697. break;
  11698. }
  11699. case no_cast:
  11700. case no_implicitcast:
  11701. {
  11702. ITypeInfo * type = expr->queryType();
  11703. IHqlExpression * child = expr->queryChild(0);
  11704. switch (type->getTypeCode())
  11705. {
  11706. case type_string:
  11707. case type_data:
  11708. if (!canRemoveStringCast(type, child->queryType()))
  11709. return true;
  11710. break;
  11711. case type_varstring:
  11712. if ((type->getSize() != UNKNOWN_LENGTH) || (child->queryType()->getTypeCode() != type_varstring))
  11713. return true;
  11714. break;
  11715. }
  11716. }
  11717. break;
  11718. case no_eq:
  11719. case no_ne:
  11720. case no_lt:
  11721. case no_le:
  11722. case no_gt:
  11723. case no_ge:
  11724. {
  11725. if (!includeChildren)
  11726. return false;
  11727. unsigned numArgs = expr->numChildren();
  11728. for (unsigned index = 0; index < numArgs; index++)
  11729. {
  11730. OwnedHqlExpr cur = getSimplifyCompareArg(expr->queryChild(index));
  11731. //decimal comparisons can't be short circuited because they might cause a bcd stack overflow.
  11732. if (cur->queryType()->getTypeCode() == type_decimal)
  11733. return true;
  11734. if (requiresTemp(ctx, cur, true))
  11735. return true;
  11736. }
  11737. return false;
  11738. }
  11739. case no_mul:
  11740. case no_div:
  11741. case no_modulus:
  11742. case no_add:
  11743. case no_sub:
  11744. case no_and:
  11745. case no_or:
  11746. case no_xor:
  11747. case no_lshift:
  11748. case no_rshift:
  11749. case no_comma:
  11750. case no_compound:
  11751. case no_band:
  11752. case no_bor:
  11753. case no_bxor:
  11754. case no_pselect:
  11755. case no_index:
  11756. case no_postinc:
  11757. case no_postdec:
  11758. case no_negate:
  11759. case no_not:
  11760. case no_bnot:
  11761. case no_address:
  11762. case no_deref:
  11763. case no_preinc:
  11764. case no_predec:
  11765. case no_if:
  11766. case no_charlen:
  11767. break;
  11768. case no_between:
  11769. //Assume the worse for decimals.
  11770. if (expr->queryChild(0)->queryType()->getTypeCode() == type_decimal)
  11771. return true;
  11772. break;
  11773. case no_order:
  11774. case no_crc:
  11775. case no_hash:
  11776. case no_hash32:
  11777. case no_hash64:
  11778. case no_hashmd5:
  11779. case no_abs:
  11780. return true;
  11781. default:
  11782. return true;
  11783. }
  11784. if (includeChildren)
  11785. return childrenRequireTemp(ctx, expr, includeChildren);
  11786. return false;
  11787. }
  11788. bool HqlCppTranslator::requiresTempAfterFirst(BuildCtx & ctx, IHqlExpression * expr)
  11789. {
  11790. unsigned numArgs = expr->numChildren();
  11791. for (unsigned index = 1; index < numArgs; index++)
  11792. if (requiresTemp(ctx, expr->queryChild(index), true))
  11793. return true;
  11794. return false;
  11795. }
  11796. void HqlCppTranslator::useFunction(IHqlExpression * func)
  11797. {
  11798. code->useFunction(func);
  11799. }
  11800. void HqlCppTranslator::useLibrary(const char * libname)
  11801. {
  11802. code->useLibrary(libname);
  11803. }
  11804. //===========================================================================
  11805. static unique_id_t queryInstance = 0;
  11806. HqlQueryInstance::HqlQueryInstance()
  11807. {
  11808. instance = ++queryInstance;
  11809. }
  11810. StringBuffer & HqlQueryInstance::queryDllName(StringBuffer & out)
  11811. {
  11812. return out.append("query").append(instance);
  11813. }