1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "platform.h"
- #include <algorithm>
- #include "jliball.hpp"
- #include "jlib.hpp"
- #include "jexcept.hpp"
- #include "jmisc.hpp"
- #include "javahash.hpp"
- #include "jmd5.hpp"
- #include "jfile.hpp"
- #include "eclhelper.hpp"
- #include "hql.hpp"
- #include "hqlfunc.hpp"
- #include "hqlattr.hpp"
- #include "hqlcpp.ipp"
- #include "hqlwcpp.hpp"
- #include "hqlcpputil.hpp"
- #include "hqlres.hpp"
- #include "hqlerror.hpp"
- #include "hqlcerrors.hpp"
- #include "hqlcatom.hpp"
- #include "hqlpmap.hpp"
- #include "hqlthql.hpp"
- #include "hqlfold.hpp"
- #include "eclrtl.hpp"
- #include "hqllib.ipp"
- #include "hqlnlp.ipp"
- #include "hqlutil.hpp"
- #include "hqltcppc.ipp"
- #include "hqlttcpp.ipp"
- #include "hqlccommon.hpp"
- #include "hqlopt.hpp"
- #include "hqlpopt.hpp"
- #include "hqlcse.ipp"
- #include "thorplugin.hpp"
- #include "hqlinline.hpp"
- #include "hqlusage.hpp"
- #ifdef _DEBUG
- //#define ADD_ASSIGNMENT_COMMENTS
- //#define ADD_RESOURCE_AS_CPP_COMMENT
- #endif
- //Defaults for various options.
- #define COMPLEXITY_TO_HOIST 2
- #define INLINE_COMPARE_THRESHOLD 2 //7 // above this, a loop is generated
- #define MAX_NESTED_CASES 8
- #define MAX_SIMPLE_VAR_SIZE 99999
- #define MAX_STATIC_ROW_SIZE 10000
- #define MAX_LOCAL_ROW_SIZE 32
- #define DEFAULT_NLP_DETAIL 1
- #define DEFAULT_EXPIRY_PERIOD 7
- #define DEFAULT_PERSIST_EXPIRY_PERIOD 0 // Persists that expire by default have a period defined in sasha
- #ifdef _WIN32
- #define DEFAULT_ACTIVITIES_PER_CPP 800 // windows compiler is fast, linker is slow, but compiler also has quite a small compile limit
- #else
- #define DEFAULT_ACTIVITIES_PER_CPP 500 // gcc assembler is v.slow
- #endif
- //MORE: Simple vars don't work if they are made class members...
- //#define SEARCH_VARIABLE "v211"
- //===========================================================================
- static CriticalSection * systemCS;
- static IHqlScope * cppSystemScope;
- //===========================================================================
- MODULE_INIT(INIT_PRIORITY_STANDARD)
- {
- systemCS = new CriticalSection;
- return true;
- }
- MODULE_EXIT()
- {
- ::Release(cppSystemScope);
- cppSystemScope = NULL;
- delete systemCS;
- }
- //---------------------------------------------------------------------------
- class SubStringInfo : public SubStringHelper
- {
- public:
- SubStringInfo(IHqlExpression * _expr) : SubStringHelper(_expr) { expr = _expr; }
- void bindToFrom(HqlCppTranslator & translator, BuildCtx & ctx);
- public:
- IHqlExpression * expr;
- CHqlBoundExpr boundFrom;
- CHqlBoundExpr boundTo;
- };
- void SubStringInfo::bindToFrom(HqlCppTranslator & translator, BuildCtx & ctx)
- {
- if (to && to->isAttribute())
- throwError(HQLERR_StarRangeOnlyInJoinCondition);
- if (from == to)
- {
- if (from)
- {
- translator.buildSimpleExpr(ctx, from, boundFrom);
- boundTo.expr.set(boundFrom.expr);
- }
- }
- else
- {
- if (from)
- translator.buildCachedExpr(ctx, from, boundFrom);
- if (to)
- translator.buildCachedExpr(ctx, to, boundTo);
- }
- }
- //---------------------------------------------------------------------------
- WorkflowItem::WorkflowItem(IHqlExpression * _function) : wfid(0), function(_function), workflowOp(no_funcdef)
- {
- IHqlExpression * body = function->queryChild(0);
- assertex(body->getOperator() == no_outofline);
- IHqlExpression * ecl = body->queryChild(0);
- exprs.append(*createValue(no_return_stmt, makeVoidType(), LINK(ecl)));
- }
- IHqlExpression * WorkflowItem::getFunction() const
- {
- IHqlExpression * body = function->queryChild(0);
- unsigned max = exprs.ordinality();
- assertex(max);
- LinkedHqlExpr newecl = exprs.item(max-1).queryChild(0);
- for (unsigned i=max-1; i--; )
- {
- IHqlExpression * cur = &exprs.item(i);
- newecl.setown(createCompound(LINK(cur), newecl.getClear()));
- }
- OwnedHqlExpr newBody = replaceChild(body, 0, newecl);
- return replaceChild(function, 0, newBody);
- }
- //---------------------------------------------------------------------------
- IHqlExpression * DatasetReference::querySelector() const
- {
- if (side == no_none)
- return ds->queryNormalizedSelector();
- return selector;
- }
- IHqlExpression * DatasetReference::querySelSeq() const
- {
- if (side == no_none)
- return NULL;
- return selector->queryChild(1);
- }
- IHqlExpression * DatasetReference::mapCompound(IHqlExpression * expr, IHqlExpression * to) const
- {
- return replaceSelector(expr, querySelector(), to);
- }
- IHqlExpression * DatasetReference::mapScalar(IHqlExpression * expr, IHqlExpression * to) const
- {
- return replaceSelector(expr, querySelector(), to);
- }
- //---------------------------------------------------------------------------
- IHqlExpression * createVariable(ITypeInfo * type)
- {
- StringBuffer tempName;
- getUniqueId(tempName.append('v'));
- #ifdef _DEBUG
- #ifdef SEARCH_VARIABLE
- if (stricmp(tempName.str(), SEARCH_VARIABLE)==0)
- type = type;
- #endif
- #endif
- return ::createVariable(tempName.str(), type);
- }
- IHqlExpression * convertWrapperToPointer(IHqlExpression * expr)
- {
- ITypeInfo * type = expr->queryType();
- if (hasWrapperModifier(type))
- return createValue(no_implicitcast, makeReferenceModifier(removeModifier(type, typemod_wrapper)), LINK(expr));
- return LINK(expr);
- }
- IHqlExpression * ensureIndexable(IHqlExpression * expr)
- {
- ITypeInfo * type = expr->queryType();
- if (type->getTypeCode() == type_data)
- {
- IHqlExpression * base = queryStripCasts(expr);
- return createValue(no_implicitcast, makeReferenceModifier(makeStringType(type->getSize(), NULL, NULL)), LINK(base));
- }
- return convertWrapperToPointer(expr);
- }
- void extendConjunctionOwn(HqlExprAttr & cond, IHqlExpression * next)
- {
- if (cond)
- next = createBoolExpr(no_and, cond.getClear(), next);
- cond.setown(next);
- }
- inline bool isPushed(const IHqlExpression * expr)
- {
- return (expr->getOperator() == no_decimalstack);
- }
- inline bool isPushed(const CHqlBoundExpr & bound)
- {
- return isPushed(bound.expr);
- }
- bool isSimpleTranslatedStringExpr(IHqlExpression * expr)
- {
- loop
- {
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_constant:
- case no_variable:
- case no_callback:
- return true;
- case no_cast:
- case no_implicitcast:
- case no_typetransfer:
- case no_deref:
- case no_address:
- expr = expr->queryChild(0);
- break;
- case no_add:
- case no_sub:
- if (!isSimpleTranslatedStringExpr(expr->queryChild(1)))
- return false;
- expr = expr->queryChild(0);
- break;
- default:
- return false;
- }
- }
- }
- bool isSimpleTranslatedExpr(IHqlExpression * expr)
- {
- switch (expr->queryType()->getTypeCode())
- {
- case type_data:
- case type_string:
- case type_qstring:
- case type_varstring:
- case type_decimal:
- case type_unicode:
- case type_varunicode:
- //Less strict rules for strings (and decimal), because string temporaries are more expensive.
- return isSimpleTranslatedStringExpr(expr);
- case type_set:
- //for the moment assume set expressions are always simple once translated.
- return true;
- }
- loop
- {
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_constant:
- case no_variable:
- case no_callback:
- case no_nullptr:
- return true;
- case no_typetransfer:
- expr = expr->queryChild(0);
- break;
- default:
- return false;
- }
- }
- }
- bool isFixedLengthList(IHqlExpression * expr)
- {
- switch (expr->getOperator())
- {
- case no_list:
- case no_datasetlist:
- case no_sortlist:
- return true;
- }
- return false;
- }
- bool needVarStringCompare(ITypeInfo * leftType, ITypeInfo * rightType)
- {
- unsigned lSize = leftType->getSize();
- unsigned rSize = rightType->getSize();
- return (lSize != rSize) || (lSize == UNKNOWN_LENGTH);
- }
- IIdAtom * queryStrCompareFunc(ITypeInfo * realType)
- {
- switch (realType->getTypeCode())
- {
- case type_data:
- return compareDataDataId;
- case type_qstring:
- return compareQStrQStrId;
- }
- ICharsetInfo * charset = realType->queryCharset();
- IAtom * charsetName = charset->queryName();
- if (charsetName == dataAtom)
- return compareDataDataId;
- if (charsetName == asciiAtom)
- return compareStrStrId;
- if (charsetName == ebcdicAtom)
- return compareEStrEStrId;
- assertex(!"Unknown string comparison");
- return compareStrStrId;
- }
- IHqlExpression * getAddress(IHqlExpression * expr)
- {
- if (expr->getOperator() == no_deref)
- {
- IHqlExpression * address = expr->queryChild(0);
- return LINK(address);
- }
- return createValue(no_address, makePointerType(expr->getType()), LINK(expr));
- }
- IHqlExpression * getRawAddress(IHqlExpression * expr)
- {
- OwnedHqlExpr raw = getAddress(expr);
- loop
- {
- switch (raw->getOperator())
- {
- case no_cast:
- case no_implicitcast:
- break;
- default:
- return raw.getClear();
- }
- raw.set(raw->queryChild(0));
- }
- }
- IHqlExpression * getPointer(IHqlExpression * source)
- {
- if (source->getOperator() == no_constant)
- return LINK(source);
- ITypeInfo * type = source->queryType();
- Owned<ITypeInfo> newType;
- switch (type->getTypeCode())
- {
- case type_set:
- if (type->isReference())
- return LINK(source);
- newType.setown(makeReferenceModifier(LINK(queryUnqualifiedType(type))));
- if (hasWrapperModifier(type))
- {
- OwnedHqlExpr cast = createValue(no_implicitcast, LINK(newType), LINK(source));
- return createValue(no_typetransfer, LINK(newType), LINK(cast));
- }
- break;
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- case type_row:
- case type_decimal:
- case type_string:
- case type_data:
- case type_qstring:
- case type_varstring:
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- if (isTypePassedByAddress(type))
- {
- if (type->isReference())
- return LINK(source);
- newType.setown(makeReferenceModifier(LINK(queryUnqualifiedType(type))));
- if (hasLinkCountedModifier(type))
- newType.setown(makeAttributeModifier(newType.getClear(), getLinkCountedAttr()));
- if (hasWrapperModifier(type))
- return createValue(no_implicitcast, LINK(newType), LINK(source));
- //An array of X is implicitly converted to pointer to X so no need to do &a[0]
- return createValue(no_typetransfer, LINK(newType), LINK(source));
- }
- else
- {
- newType.setown(removeModifier(type, typemod_wrapper));
- if (hasWrapperModifier(type))
- return createValue(no_implicitcast, LINK(newType), LINK(source));
- return LINK(source);
- }
- break;
- case type_pointer:
- return LINK(source);
- default:
- newType.setown(makePointerType(LINK(type)));
- break;
- }
- IHqlExpression * cur = source;
- while (cur->getOperator() == no_typetransfer)
- cur = cur->queryChild(0);
- if (cur->getOperator() == no_deref)
- {
- IHqlExpression * address = cur->queryChild(0);
- if (address->queryType() == newType)
- return LINK(address);
- return createValue(no_implicitcast, newType.getClear(), LINK(address));
- }
- else
- return createValue(no_address, newType.getClear(), LINK(source));
- }
- bool isChildOf(IHqlExpression * parent, IHqlExpression * child)
- {
- unsigned max = parent->numChildren();
- unsigned idx;
- for (idx = 0; idx < max; idx++)
- {
- IHqlExpression * cur = parent->queryChild(idx);
- if (cur == child)
- return true;
- }
- return false;
- }
- bool canRemoveStringCast(ITypeInfo * to, ITypeInfo * from)
- {
- unsigned fromSize = from->getSize();
- unsigned toSize = to->getSize();
- //Special case string conversions that don't require us to copy any data.
- if ((toSize == UNKNOWN_LENGTH) || ((fromSize != UNKNOWN_LENGTH) && (toSize <= fromSize)))
- {
- switch (from->getTypeCode())
- {
- case type_varstring:
- if (toSize != UNKNOWN_LENGTH)
- break;
- //fall through
- case type_data:
- case type_string:
- {
- ICharsetInfo * srcset = from->queryCharset();
- ICharsetInfo * tgtset = to->queryCharset();
-
- //Data never calls a conversion function...
- if ((srcset == tgtset) || (to->getTypeCode() == type_data) || (from->getTypeCode() == type_data))
- return true;
- }
- case type_qstring:
- return false;
- }
- }
- return false;
- }
- bool isProjectedInRecord(IHqlExpression * record, IHqlExpression * expr)
- {
- unsigned max = record->numChildren();
- unsigned idx;
- for (idx = 0; idx < max; idx++)
- {
- IHqlExpression * cur = record->queryChild(idx);
- if (cur->queryChild(0) == expr)
- return true;
- }
- return false;
- }
- IHqlExpression * queryStripCasts(IHqlExpression * expr)
- {
- while ((expr->getOperator() == no_cast) || (expr->getOperator() == no_implicitcast))
- expr = expr->queryChild(0);
- return expr;
- }
- // Format the list is stored in doesn't matter, so allow constant strings to be stored by reference
- IHqlExpression * getOptimialListFormat(IHqlExpression * table)
- {
- if (table->isConstant() && table->getOperator() == no_list)
- {
- ITypeInfo * elemType = table->queryType()->queryChildType();
- if (!elemType->isReference())
- {
- switch (elemType->getTypeCode())
- {
- case type_string:
- case type_data:
- {
- HqlExprArray args;
- table->unwindList(args, no_list);
- return createValue(no_list, makeSetType(makeReferenceModifier(LINK(elemType))), args);
- }
- }
- }
- }
- return LINK(table);
- }
- bool canOptimizeAdjust(IHqlExpression * value)
- {
- switch (value->getOperator())
- {
- case no_constant:
- return true;
- case no_add:
- case no_sub:
- return value->queryChild(1)->queryValue() != NULL;
- }
- return false;
- }
- IHqlExpression * adjustValue(IHqlExpression * value, __int64 delta)
- {
- if (delta == 0)
- return LINK(value);
- ITypeInfo * type = value->queryType();
- switch (value->getOperator())
- {
- case no_constant:
- {
- __int64 newValue = value->queryValue()->getIntValue()+delta;
- if (type == sizetType)
- return getSizetConstant((size32_t)newValue);
- return createConstant(type->castFrom(true, newValue));
- }
- case no_add:
- {
- IHqlExpression * lhs = value->queryChild(0);
- IHqlExpression * rhs = value->queryChild(1);
- IValue * rhsValue = rhs->queryValue();
- IValue * lhsValue = lhs->queryValue();
- if (rhsValue)
- {
- delta += rhsValue->getIntValue();
- if (delta == 0)
- return LINK(lhs);
- value = lhs;
- }
- else if (lhsValue)
- {
- delta += lhsValue->getIntValue();
- if (delta == 0)
- return LINK(rhs);
- value = rhs;
- }
- else if (canOptimizeAdjust(rhs))
- return createValue(no_add, value->getType(), LINK(lhs), adjustValue(rhs, delta));
- break;
- }
- case no_sub:
- {
- IValue * rhsValue = value->queryChild(1)->queryValue();
- if (rhsValue)
- {
- IHqlExpression * lhs = value->queryChild(0);
- delta -= rhsValue->getIntValue();
- if (delta == 0)
- return LINK(lhs);
- value = lhs;
- }
- break;
- }
- case no_translated:
- {
- IHqlExpression * arg = value->queryChild(0);
- if (arg->queryValue())
- {
- OwnedHqlExpr newValue = adjustValue(arg, delta);
- return createTranslated(newValue);
- }
- break;
- }
- //optimize no_case because it is generated by a transformation of the dataset no_case
- case no_case:
- case no_mapto:
- {
- HqlExprArray args;
- args.append(*LINK(value->queryChild(0)));
- ForEachChildFrom(i, value, 1)
- {
- IHqlExpression * cur = value->queryChild(i);
- args.append(*adjustValue(cur, delta));
- }
- return value->clone(args);
- }
- }
- IHqlExpression * deltaExpr;
- node_operator op = no_add;
- if (delta < 0)
- {
- op = no_sub;
- delta = -delta;
- }
- if (type == sizetType || !type->isInteger())
- deltaExpr = getSizetConstant((size32_t)delta);
- else
- deltaExpr = createConstant(type->castFrom(true, delta));
- return createValue(op, LINK(type), LINK(value), deltaExpr);
- }
- IHqlExpression * adjustIndexBaseToZero(IHqlExpression * index)
- {
- return adjustValue(index, -1);
- }
- IHqlExpression * adjustIndexBaseToOne(IHqlExpression * index)
- {
- return adjustValue(index, +1);
- }
- IHqlExpression * adjustBoundIntegerValues(IHqlExpression * left, IHqlExpression * right, bool subtract)
- {
- assertex(queryUnqualifiedType(left->queryType()) == queryUnqualifiedType(right->queryType()));
- if (canOptimizeAdjust(left))
- {
- node_operator op = right->getOperator();
- switch (op)
- {
- case no_constant:
- {
- __int64 rhsValue = right->queryValue()->getIntValue();
- if (subtract)
- rhsValue = -rhsValue;
- return adjustValue(left, rhsValue);
- }
- case no_add:
- case no_sub:
- {
- IHqlExpression * rl = right->queryChild(0);
- IHqlExpression * rr = right->queryChild(1);
- if (rr->getOperator() == no_constant)
- {
- if (queryUnqualifiedType(rl->queryType()) == queryUnqualifiedType(rr->queryType()))
- {
- __int64 delta = rr->queryValue()->getIntValue();
- if (op == no_sub)
- delta = -delta;
- if (subtract)
- delta = -delta;
- OwnedHqlExpr newLeft = adjustValue(left, delta);
- return adjustBoundIntegerValues(newLeft, rl, subtract);
- }
- }
- break;
- }
- }
- }
- switch (left->getOperator())
- {
- case no_constant:
- if (!subtract)
- return adjustBoundIntegerValues(right, left, false);
- break;
- case no_add:
- {
- IHqlExpression * lr = left->queryChild(1);
- if (lr->getOperator() == no_constant)
- {
- OwnedHqlExpr newLeft = adjustBoundIntegerValues(left->queryChild(0), right, subtract);
- return adjustBoundIntegerValues(newLeft, lr, false);
- }
- break;
- }
- case no_variable:
- if (!subtract && (right->getOperator() == no_add) && (right->queryChild(1)->getOperator() == no_constant))
- {
- OwnedHqlExpr temp = adjustBoundIntegerValues(left, right->queryChild(0), false);
- return adjustBoundIntegerValues(temp, right->queryChild(1), false);
- }
- break;
- }
- return createValue(subtract ? no_sub : no_add, left->getType(), LINK(left), LINK(right));
- }
-
- IHqlExpression * multiplyValue(IHqlExpression * expr, unsigned __int64 value)
- {
- if (isZero(expr))
- return LINK(expr);
- ITypeInfo * type = expr->queryType();
- IValue * exprValue = expr->queryValue();
- if (exprValue && type->isInteger())
- return createConstant(type->castFrom(false, exprValue->getIntValue() * value));
- if (expr->getOperator() == no_translated)
- {
- IHqlExpression * translated = expr->queryChild(0);
- if (translated->queryValue())
- {
- OwnedHqlExpr newValue = multiplyValue(translated, value);
- return createTranslated(newValue);
- }
- }
- return createValue(no_mul, LINK(type), LINK(expr), createConstant(type->castFrom(false, value)));
- }
- bool matchesConstValue(IHqlExpression * expr, __int64 matchValue)
- {
- IValue * value = expr->queryValue();
- if (value)
- return value->getIntValue() == matchValue;
- if (expr->getOperator() == no_translated)
- return matchesConstValue(expr->queryChild(0), matchValue);
- return false;
- }
- IHqlExpression * createTranslated(IHqlExpression * expr)
- {
- return createValue(no_translated, expr->getType(), LINK(expr));
- }
- IHqlExpression * createTranslatedOwned(IHqlExpression * expr)
- {
- return createValue(no_translated, expr->getType(), expr);
- }
- IHqlExpression * createTranslated(IHqlExpression * expr, IHqlExpression * length)
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_dictionary:
- return createDictionary(no_translated, LINK(expr), LINK(length));
- case type_table:
- case type_groupedtable:
- return createDataset(no_translated, LINK(expr), LINK(length));
- }
- return createValue(no_translated, expr->getType(), LINK(expr), LINK(length));
- }
- static IHqlExpression * querySimplifyCompareArgCast(IHqlExpression * expr)
- {
- if (expr->isConstant())
- return expr;
- while ((expr->getOperator() == no_implicitcast) || (expr->getOperator() == no_cast))
- {
- ITypeInfo * type = expr->queryType()->queryPromotedType();
- switch (type->getTypeCode())
- {
- case type_string:
- case type_data:
- case type_unicode:
- case type_qstring:
- case type_utf8:
- break;
- default:
- return expr;
- }
- IHqlExpression * child = expr->queryChild(0);
- ITypeInfo * childType = child->queryType()->queryPromotedType();
- if (type->getStringLen() < childType->getStringLen())
- break;
- type_t tc = type->getTypeCode();
- if (tc != childType->getTypeCode())
- {
- if (tc == type_string)
- {
- if (childType->getTypeCode() != type_varstring)
- break;
- if (type->queryCharset() != childType->queryCharset())
- break;
- }
- else if (tc == type_unicode)
- {
- if (childType->getTypeCode() != type_varunicode)
- break;
- if (type->queryLocale() != childType->queryLocale())
- break;
- }
- else
- break;
- }
- else
- {
- Owned<ITypeInfo> stretched = getStretchedType(type->getStringLen(), childType);
- if (stretched != type)
- break;
- }
- expr = child;
- }
- return expr;
- }
- IHqlExpression * getSimplifyCompareArg(IHqlExpression * expr)
- {
- IHqlExpression * cast = querySimplifyCompareArgCast(expr);
- if (cast->getOperator() != no_substring)
- return LINK(cast);
- if (cast->queryChild(0)->queryType()->getTypeCode() == type_qstring)
- return LINK(cast);
- HqlExprArray args;
- unwindChildren(args, cast);
- args.append(*createAttribute(quickAtom));
- return cast->clone(args);
- }
- bool isNullAssign(const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- ITypeInfo * targetType = target.expr->queryType();
- //if an assignment to a local variable size temporary object, then it is ok to omit an assignment of null
- //since it won't change its value, and it isn't going to be assigned more than once.
- if ((targetType->getSize() == UNKNOWN_LENGTH) && target.length && hasWrapperModifier(targetType) && !hasModifier(targetType, typemod_member))
- {
- ITypeInfo * exprType = expr->queryType();
- switch (exprType->getTypeCode())
- {
- case type_data:
- case type_string:
- case type_qstring:
- return exprType->getSize() == 0;
- case type_dictionary:
- case type_table:
- return expr->getOperator() == no_null;
- }
- }
- return false;
- }
- ExpressionFormat queryNaturalFormat(ITypeInfo * type)
- {
- if (hasStreamedModifier(type))
- return FormatStreamedDataset;
- if (hasOutOfLineModifier(type))
- return FormatArrayDataset;
- if (hasLinkCountedModifier(type))
- return FormatLinkedDataset;
- return FormatBlockedDataset;
- }
- //===========================================================================
- SubGraphInfo::SubGraphInfo(IPropertyTree * _tree, unsigned _id, unsigned _graphId, IHqlExpression * _graphTag, SubGraphType _type)
- : HqlExprAssociation(subGraphMarker), tree(_tree)
- {
- id = _id;
- graphId = _graphId;
- type = _type;
- graphTag.set(_graphTag);
- }
- //===========================================================================
- IHqlExpression * CHqlBoundExpr::getTranslatedExpr() const
- {
- HqlExprArray args;
- args.append(*LINK(expr));
- if (length) args.append(*LINK(length));
- if (count) args.append(*createAttribute(countAtom, LINK(count)));
- if (isAll) args.append(*createAttribute(allAtom, LINK(isAll)));
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_dictionary:
- return createDictionary(no_translated, args);
- case type_table:
- case type_groupedtable:
- return createDataset(no_translated, args);
- }
- return createValue(no_translated, LINK(type), args);
- }
- IHqlExpression * CHqlBoundExpr::getComplexExpr() const
- {
- assertex(count && expr);
- return createValue(no_complex, expr->getType(), LINK(count), LINK(expr));
- }
- IHqlExpression * CHqlBoundExpr::getIsAll() const
- {
- if (isAll)
- return LINK(isAll);
- return LINK(queryBoolExpr(false));
- }
- void CHqlBoundExpr::setFromTarget(const CHqlBoundTarget & target)
- {
- isAll.set(target.isAll);
- count.set(target.count);
- length.set(target.length);
- expr.setown(convertWrapperToPointer(target.expr));
- }
- void CHqlBoundExpr::setFromTranslated(IHqlExpression * translatedExpr)
- {
- expr.set(translatedExpr->queryChild(0));
- IHqlExpression * arg = translatedExpr->queryChild(1);
- if (arg)
- {
- unsigned i = 2;
- if (arg->getOperator() != no_attr)
- {
- length.set(arg);
- arg = translatedExpr->queryChild(i++);
- }
- while (arg)
- {
- IAtom * name = arg->queryName();
- if (name == countAtom)
- count.set(arg->queryChild(0));
- else if (name == allAtom)
- isAll.set(arg->queryChild(0));
- else
- UNIMPLEMENTED;
- arg = translatedExpr->queryChild(i++);
- }
- }
- }
- bool CHqlBoundTarget::extractFrom(const CHqlBoundExpr & bound)
- {
- ITypeInfo * boundType = bound.queryType();
- if (bound.count)
- {
- if (bound.count->getOperator() != no_variable)
- return false;
- if (!hasLinkCountedModifier(boundType))
- return false;
- }
- if (bound.isAll)
- {
- assertex(bound.isAll->getOperator() == no_variable);
- }
- else if (boundType->getTypeCode() == type_set)
- return false;
- if (bound.length)
- {
- if (bound.length->getOperator() != no_variable)
- return false;
- }
- else if (boundType->getSize() == UNKNOWN_LENGTH)
- {
- type_t btc = boundType->getTypeCode();
- if ((btc != type_varstring) && (btc != type_varunicode) && !hasLinkCountedModifier(boundType))
- return false;
- }
- IHqlExpression * boundExpr = bound.expr;
- if (boundExpr->getOperator() == no_implicitcast)
- {
- IHqlExpression * uncast = boundExpr->queryChild(0);
- if (hasModifier(uncast->queryType(), typemod_member) &&
- (queryUnqualifiedType(boundExpr->queryType()) == queryUnqualifiedType(uncast->queryType())))
- boundExpr = uncast;
- }
- expr.set(boundExpr);
- isAll.set(bound.isAll);
- length.set(bound.length);
- count.set(bound.count);
- return true;
- }
- bool CHqlBoundTarget::isFixedSize() const
- {
- validate();
- return queryType()->getSize() != UNKNOWN_LENGTH;
- }
- void CHqlBoundTarget::validate() const
- {
- if (expr)
- {
- if (queryType()->getSize() != UNKNOWN_LENGTH)
- {
- assertex(!length);
- }
- else if (isArrayRowset(queryType()))
- {
- if (!hasStreamedModifier(queryType()))
- assertex(count != NULL);
- }
- else
- {
- assertex(length || queryType()->getTypeCode() == type_varstring || queryType()->getTypeCode() == type_varunicode || hasStreamedModifier(queryType()));
- }
- }
- }
- ITypeInfo * CHqlBoundTarget::queryType() const
- {
- return expr->queryType();
- }
- IHqlExpression * CHqlBoundTarget::getTranslatedExpr() const
- {
- CHqlBoundExpr temp;
- temp.setFromTarget(*this);
- return temp.getTranslatedExpr();
- }
- //===========================================================================
- CompoundBuilder::CompoundBuilder(node_operator _op)
- {
- op = _op;
- }
- void CompoundBuilder::addOperand(IHqlExpression * arg)
- {
- if (first.get())
- {
- compound.setown(createOpenValue(op, makeBoolType()));
- compound->addOperand(first.getClear());
- }
- if (compound)
- compound->addOperand(arg);
- else
- first.setown(arg);
- }
- IHqlExpression * CompoundBuilder::getCompound()
- {
- if (compound)
- return compound.getClear()->closeExpr();
- return first.getClear();
- }
- //===========================================================================
- void buildClearPointer(BuildCtx & ctx, IHqlExpression * expr, CompilerType compiler)
- {
- StringBuffer s;
- generateExprCpp(s, expr, compiler).append("=NULL;");
- ctx.addQuoted(s);
- }
- void insertUniqueString(StringAttrArray & array, const char * text)
- {
- ForEachItemIn(idx, array)
- {
- StringAttrItem & cur = array.item(idx);
- if (stricmp(cur.text, text) == 0)
- return;
- }
- array.append(* new StringAttrItem(text));
- }
- HqlCppInstance::HqlCppInstance(IWorkUnit *_wu, const char * _wupathname)
- {
- workunit.set(_wu);
- wupathname.set(_wupathname);
- }
- HqlStmts * HqlCppInstance::ensureSection(IAtom * section)
- {
- HqlStmts * match = querySection(section);
- if (match)
- return match;
- HqlCppSection * cur = new HqlCppSection;
- cur->section = section;
- sections.append(*cur);
- return &cur->stmts;
- }
- void HqlCppInstance::processIncludes()
- {
- BuildCtx ctx(*this, includeAtom);
- StringBuffer s;
- ForEachItemIn(idx, includes)
- {
- s.clear().append("#include \"").append(includes.item(idx).text).append("\"");
- ctx.addQuoted(s);
- }
- }
- const char * HqlCppInstance::queryLibrary(unsigned idx)
- {
- if (modules.isItem(idx))
- return modules.item(idx).text;
- return NULL;
- }
- HqlStmts * HqlCppInstance::querySection(IAtom * section)
- {
- ForEachItemIn(idx, sections)
- {
- HqlCppSection & cur = (HqlCppSection &)sections.item(idx);
- if (cur.section == section)
- return &cur.stmts;
- }
- return NULL;
- }
- void HqlCppInstance::addPlugin(const char *plugin, const char *version, bool inThor)
- {
- if (!plugin || !*plugin)
- return;
- StringBuffer dllname(plugin);
- getFileNameOnly(dllname, false); // MORE - shouldn't really need to do this here....
- if (workunit)
- {
- Owned<IWUPlugin> p = workunit->updatePluginByName(dllname.str());
- if (version && *version)
- p->setPluginVersion(version);
- if (inThor)
- p->setPluginThor(true);
- else
- p->setPluginHole(true);
- }
- if (!plugins)
- plugins.setown(createPTree("Plugins"));
- StringBuffer xpath;
- xpath.append("Plugin[@dll='").append(dllname).append("']");
- if (!plugins->hasProp(xpath.str()))
- {
- IPropertyTree * pluginNode = createPTree("Plugin");
- pluginNode->setProp("@dll", dllname.str());
- if (version && *version)
- pluginNode->setProp("@version", version);
- plugins->addPropTree("Plugin", pluginNode);
- }
- }
- void HqlCppInstance::addPluginsAsResource()
- {
- if (!plugins)
- return;
- StringBuffer pluginXML;
- toXML(plugins, pluginXML);
- addResource("PLUGINS", pluginXML.length(), pluginXML.str(), NULL, 1);
- }
- bool HqlCppInstance::useFunction(IHqlExpression * func)
- {
- assertex(func);
- func = func->queryBody();
- if (helpers.contains(*func))
- return false;
- helpers.append(*LINK(func));
- IHqlExpression * funcDef = func->queryChild(0);
- StringBuffer libname, init, include;
- getAttribute(funcDef, libraryAtom, libname);
- getAttribute(funcDef, initfunctionAtom, init);
- getAttribute(funcDef, includeAtom, include);
- if (init.length())
- {
- BuildCtx ctx(*this, initAtom);
- ctx.addQuoted(init.append("(wuid);"));
- }
- IHqlExpression *pluginAttr = funcDef->queryAttribute(pluginAtom);
- if (pluginAttr)
- {
- StringBuffer plugin, version;
- getStringValue(plugin, pluginAttr->queryChild(0));
- getStringValue(version, pluginAttr->queryChild(1));
- addPlugin(plugin.str(), version.str(), false);
- if (!libname.length())
- {
- getStringValue(libname, pluginAttr->queryChild(0));
- getFullFileName(libname, true);
- }
- }
- if (!funcDef->hasAttribute(ctxmethodAtom) && !funcDef->hasAttribute(gctxmethodAtom) && !funcDef->hasAttribute(methodAtom))
- {
- if (libname.length())
- useLibrary(libname.str());
- }
- if (include.length())
- useInclude(include.str());
- return true;
- }
- void HqlCppInstance::useInclude(const char * include)
- {
- insertUniqueString(includes, include);
- }
- void HqlCppInstance::useLibrary(const char * libname)
- {
- insertUniqueString(modules, libname);
- }
- void HqlCppInstance::addHint(const char * hintXml, ICodegenContextCallback * ctxCallback)
- {
- if (!hintFile)
- {
- StringBuffer hintFilename;
- if (wupathname)
- hintFilename.append(wupathname);
- else
- hintFilename.append("wu");
- hintFilename.append("_hints.xml");
- Owned<IFile> file = createIFile(hintFilename);
- Owned<IFileIO> io = file->open(IFOcreate);
- if (!io)
- return;
- hintFile.setown(createIOStream(io));
- appendHintText("<Hints>\n");
- Owned<IWUQuery> query = workunit->updateQuery();
- associateLocalFile(query, FileTypeCpp, hintFilename.str(), "Hints", 0);
- ctxCallback->registerFile(hintFilename.str(), "Hints");
- }
- appendHintText(hintXml);
- }
- void HqlCppInstance::appendHintText(const char * xml)
- {
- hintFile->write(strlen(xml), xml);
- }
- unsigned HqlCppInstance::addStringResource(unsigned len, const char * body)
- {
- return resources.addString(len, body);
- }
- void HqlCppInstance::addResource(const char * type, unsigned len, const void * body, IPropertyTree *manifestEntry, unsigned id)
- {
- resources.addNamed(type, len, body, manifestEntry, id);
- }
- void HqlCppInstance::addCompressResource(const char * type, unsigned len, const void * body, IPropertyTree *manifestEntry, unsigned id)
- {
- #ifdef ADD_RESOURCE_AS_CPP_COMMENT
- BuildCtx ctx(*this, includeAtom);
- StringBuffer s;
- s.append("/* ").append(type).append(".").append(id).append(":\n").append(len,(const char *)data).newline().append("*/");
- ctx.addQuoted(s);
- #endif
- resources.addCompress(type, len, body, manifestEntry, id);
- }
- void HqlCppInstance::flushHints()
- {
- if (hintFile)
- {
- appendHintText("</Hints>\n");
- hintFile.clear();
- }
- }
- void HqlCppInstance::flushResources(const char *filename, ICodegenContextCallback * ctxCallback)
- {
- addPluginsAsResource();
- if (resources.count())
- {
- bool flushText = workunit->getDebugValueBool("flushResourceAsText", false);
- StringBuffer path, trailing;
- splitFilename(filename, &path, &path, &trailing, &trailing);
- StringBuffer ln;
- ln.append(path).append(SharedObjectPrefix).append(trailing).append(LibraryExtension);
- #ifdef __64BIT__
- // ARMFIX: Map all the uses of this property and make sure
- // they're not used to mean x86_64 (it shouldn't, though)
- bool target64bit = workunit->getDebugValueBool("target64bit", true);
- #else
- bool target64bit = workunit->getDebugValueBool("target64bit", false);
- #endif
- resources.flush(ln.str(), flushText, target64bit);
- StringBuffer resTextName;
- if (flushText && resources.queryWriteText(resTextName, ln))
- {
- Owned<IWUQuery> query = workunit->updateQuery();
- associateLocalFile(query, FileTypeHintXml, resTextName, "Workunit resource text", 0);
- ctxCallback->registerFile(resTextName, "Workunit Res.txt");
- }
- useLibrary(filename);
- }
- }
- IHqlCppInstance * createCppInstance(IWorkUnit *wu, const char * wupathname)
- {
- return new HqlCppInstance(wu, wupathname);
- }
- //===========================================================================
- #include "hqlcppsys.ecl"
- HqlCppTranslator::HqlCppTranslator(IErrorReceiver * _errors, const char * _soName, IHqlCppInstance * _code, ClusterType _targetClusterType, ICodegenContextCallback *_ctxCallback) : ctxCallback(_ctxCallback)
- {
- //Insert a couple of warning mapping layers - one for global #onwarnigns, and another for local : onwarning
- globalOnWarnings.setown(new ErrorSeverityMapper(*_errors));
- localOnWarnings.setown(new ErrorSeverityMapper((IErrorReceiver &)*globalOnWarnings)); // horrible: cast required, otherwise copy constructor is called!
- //Ensure that any errors reported within the code generator automatically abort compiling immediately
- errorProcessor.setown(createAbortingErrorReceiver(*localOnWarnings));
- targetClusterType = _targetClusterType;
- {
- CriticalBlock block(*systemCS);
- if (!cppSystemScope)
- {
- StringBuffer systemText;
- unsigned size = 0;
- for (unsigned i1=0; cppSystemText[i1]; i1++)
- size += strlen(cppSystemText[i1]) + 2;
- systemText.ensureCapacity(size);
- for (unsigned i2=0; cppSystemText[i2]; i2++)
- systemText.append(cppSystemText[i2]).newline();
- MultiErrorReceiver errs;
- HqlDummyLookupContext ctx(&errs);
- cppSystemScope = createScope();
- Owned<ISourcePath> sysPath = createSourcePath("<system-definitions>");
- Owned<IFileContents> systemContents = createFileContentsFromText(systemText.str(), sysPath);
- OwnedHqlExpr query = parseQuery(cppSystemScope, systemContents, ctx, NULL, NULL, false);
- if (errs.errCount())
- {
- StringBuffer errtext;
- IECLError *first = errs.firstError();
- first->toString(errtext);
- throw MakeStringException(HQLERR_FailedToLoadSystemModule, "%s @ %d:%d", errtext.str(), first->getColumn(), first->getLine());
- }
- #if 0
- else if (errs.warnCount())
- {
- StringBuffer s;
- errs.toString(s);
- PrintLog("Parsing system scope: ");
- PrintLog(s.str());
- }
- #endif
- }
- }
- hints = 0;
- litno = 0;
- soName.set(_soName);
- HqlDummyLookupContext dummyctx(NULL);
- OwnedHqlExpr internalScopeLookup = cppSystemScope->lookupSymbol(createIdAtom("InternalCppService"), LSFsharedOK, dummyctx);
- internalScope = internalScopeLookup->queryScope();
- _clear(options); // init options is called later, but depends on the workunit.
- startCursorSet = 0;
- requireTable = true;
- activeGraphCtx = NULL;
- maxSequence = 0;
- contextAvailable = true;
- graphSeqNumber = 0;
- nlpParse = NULL;
- outputLibrary = NULL;
- checkedEmbeddedCpp = false;
- cachedAllowEmbeddedCpp = true;
- checkedPipeAllowed = false;
- activitiesThisCpp = 0;
- curCppFile = 0;
- timeReporter.setown(createStdTimeReporter());
- curActivityId = 0;
- holeUniqueSequence = 0;
- nextUid = 0;
- nextTypeId = 0;
- nextFieldId = 0;
- code = (HqlCppInstance*)_code;
- xmlUsesContents = false;
- }
- HqlCppTranslator::~HqlCppTranslator()
- {
- ::Release(nlpParse);
- ::Release(outputLibrary);
- }
- void HqlCppTranslator::setTargetClusterType(ClusterType clusterType)
- {
- targetClusterType = clusterType;
- }
- void HqlCppTranslator::checkAbort()
- {
- if (wu() && wu()->aborting())
- throw MakeStringException(HQLERR_ErrorAlreadyReported, "Aborting");
- }
- // Option: (Name, value, ?overridden, default())
- // problems:
- // default value can depend on another option (e.g., cluster type/supports lcr).
- // don't want code in multiple places - e.g., the values initialized and defaulted, and dependencies calculations duplicated separately.
- // don't want lots of start up costs each time the translator is created -> lightweight classes if any.
- // don't really want two structures, one for the definitions, and another for the values.
- //RESOLVED? want to walk the debug options provided, instead of checking for each possibility in turn.
- // Without this restriction it becomes much easier.
- void HqlCppTranslator::cacheOptions()
- {
- SCMStringBuffer targetText;
- wu()->getDebugValue("targetClusterType", targetText);
- ClusterType clusterType = getClusterType(targetText.s.str());
- if (clusterType != NoCluster)
- setTargetClusterType(clusterType);
- //Some compound flags, which provide defaults for various other options.
- bool paranoid = getDebugFlag("paranoid", false);
- bool releaseMode = getDebugFlag("release", true);
- struct DebugOption
- {
- typedef enum { typeByte, typeUnsigned, typeSigned, typeBool } OptionType;
- DebugOption (bool & _option, const char * name, bool defaultValue) : option(&_option), optName(name)
- {
- _option = defaultValue;
- type = typeBool;
- }
- DebugOption (byte & _option, const char * name, byte defaultValue) : option(&_option), optName(name)
- {
- _option = defaultValue;
- type = typeByte;
- }
- DebugOption (unsigned & _option, const char * name, unsigned defaultValue) : option(&_option), optName(name)
- {
- _option = defaultValue;
- type = typeUnsigned;
- }
- DebugOption (int & _option, const char * name, unsigned defaultValue) : option(&_option), optName(name)
- {
- _option = defaultValue;
- type = typeSigned;
- }
- void setValue(const char * val)
- {
- switch (type)
- {
- case typeBool:
- {
- bool * b = (bool*)option;
- *b = strToBool(val);
- break;
- }
- case typeUnsigned:
- {
- unsigned * u = (unsigned*)option;
- *u = (unsigned)atoi(val);
- break;
- }
- case typeSigned:
- {
- signed * u = (signed*)option;
- *u = (signed)atoi(val);
- break;
- }
- case typeByte:
- {
- byte * b = (byte*)option;
- *b = (byte)atoi(val);
- break;
- }
- }
- }
- void * option;
- const char * optName;
- OptionType type;
- };
- //Note this list cannot have any initial values which are dependent on other options.
- DebugOption debugOptions[] =
- {
- DebugOption(options.peephole,"peephole", true),
- DebugOption(options.foldConstantCast,"foldConstantCast", true),
- DebugOption(options.optimizeBoolReturn,"optimizeBoolReturn", true),
- DebugOption(options.freezePersists,"freezePersists", false),
- DebugOption(options.maxRecordSize, "defaultMaxLengthRecord", MAX_RECORD_SIZE),
- DebugOption(options.subgraphToRegeneate, "subgraphToRegeneate", 0),
- DebugOption(options.checkRoxieRestrictions,"checkRoxieRestrictions", true), // a debug aid for running regression suite
- DebugOption(options.checkThorRestrictions,"checkThorRestrictions", true), // a debug aid for running regression suite
- DebugOption(options.allowCsvWorkunitRead,"allowStoredCsvFormat", false),
- DebugOption(options.evaluateCoLocalRowInvariantInExtract,"evaluateCoLocalRowInvariantInExtract", false),
- DebugOption(options.spanMultipleCpp,"spanMultipleCpp", true),
- DebugOption(options.activitiesPerCpp, "<exception>", 0x7fffffff),
- DebugOption(options.allowInlineSpill,"allowInlineSpill", true),
- DebugOption(options.optimizeGlobalProjects,"optimizeGlobalProjects", false),
- DebugOption(options.optimizeResourcedProjects,"optimizeResourcedProjects", false),
- DebugOption(options.reduceNetworkTraffic,"aggressiveOptimizeProjects", false),
- DebugOption(options.notifyOptimizedProjects, "notifyOptimizedProjects", 0),
- DebugOption(options.optimizeProjectsPreservePersists,"optimizeProjectsPreservePersists", false),
- DebugOption(options.expirePersists, "expirePersists", true),
- DebugOption(options.defaultPersistExpiry, "defaultPersistExpiry", DEFAULT_PERSIST_EXPIRY_PERIOD),
- DebugOption(options.defaultExpiry, "defaultExpiry", DEFAULT_EXPIRY_PERIOD),
- DebugOption(options.checkAsserts,"checkAsserts", true),
- DebugOption(options.assertSortedDistributed,"assertSortedDistributed", false),
- DebugOption(options.optimizeLoopInvariant,"optimizeLoopInvariant", false), // doesn't fully work yet! and has little effect, and messes up the alias dependencies
- DebugOption(options.defaultImplicitKeyedJoinLimit, "defaultImplicitKeyedJoinLimit", 10000),
- DebugOption(options.defaultImplicitIndexReadLimit, "defaultImplicitIndexReadLimit", 0),
- DebugOption(options.commonUpChildGraphs,"commonUpChildGraphs", true),
- DebugOption(options.detectAmbiguousSelector,"detectAmbiguousSelector", false),
- DebugOption(options.allowAmbiguousSelector,"allowAmbiguousSelector", false),
- #ifdef _DEBUG
- DebugOption(options.regressionTest,"regressionTest", true),
- #else
- DebugOption(options.regressionTest,"regressionTest", false),
- #endif
- DebugOption(options.addTimingToWorkunit, "addTimingToWorkunit", true),
- //recreating case can cause duplicate branches in weird situations.
- DebugOption(options.recreateMapFromIf,"recreateMapFromIf", !targetThor()),
- DebugOption(options.showMetaText,"debugShowMetaText", false),
- DebugOption(options.resourceSequential,"resourceSequential", false),
- DebugOption(options.workunitTemporaries,"workunitTemporaries", true),
- DebugOption(options.resourceConditionalActions,"resourceConditionalActions", false), //targetRoxie() ??
- DebugOption(options.actionLinkInNewGraph,"actionLinkInNewGraph", false),
- DebugOption(options.minimizeWorkunitTemporaries, "<exception>", false),
- DebugOption(options.pickBestEngine,"pickBestEngine", true),
- DebugOption(options.groupedChildIterators,"groupedChildIterators", false),
- DebugOption(options.noAllToLookupConversion,"noAllToLookupConversion", false),
- DebugOption(options.notifyWorkflowCse,"notifyWorkflowCse", true),
- DebugOption(options.performWorkflowCse,"performWorkflowCse", false),
- DebugOption(options.warnOnImplicitJoinLimit,"warnOnImplicitJoinLimit", targetRoxie()),
- DebugOption(options.warnOnImplicitReadLimit,"warnOnImplicitReadLimit", targetRoxie()),
- DebugOption(options.convertJoinToLookup,"convertJoinToLookup", true),
- DebugOption(options.convertJoinToLookupIfSorted,"convertJoinToLookupIfSorted", false),
- DebugOption(options.spotCSE,"spotCSE", true),
- DebugOption(options.optimizeNonEmpty,"optimizeNonEmpty", !targetThor()), // not sure that it will be conditional resourced correctly for thor
- DebugOption(options.allowVariableRoxieFilenames,"allowVariableRoxieFilenames", false),
- DebugOption(options.foldConstantDatasets,"foldConstantDatasets", true),
- DebugOption(options.hoistSimpleGlobal,"hoistSimpleGlobal", true),
- DebugOption(options.percolateConstants,"percolateConstants", true),
- DebugOption(options.percolateFilters,"percolateFilters", false),
- DebugOption(options.usePrefetchForAllProjects,"usePrefetchForAllProjects", false),
- DebugOption(options.allFilenamesDynamic,"allFilenamesDynamic", false),
- DebugOption(options.optimizeSteppingPostfilter,"optimizeSteppingPostfilter", true),
- DebugOption(options.moveUnconditionalActions,"moveUnconditionalActions", false),
- DebugOption(options.paranoidCheckNormalized, "paranoidCheckNormalized", paranoid),
- DebugOption(options.paranoidCheckDependencies, "paranoidCheckDependencies", paranoid),
- DebugOption(options.paranoidCheckSelects, "paranoidCheckSelects", paranoid),
- DebugOption(options.preventKeyedSplit,"preventKeyedSplit", true),
- DebugOption(options.preventSteppedSplit,"preventSteppedSplit", true),
- DebugOption(options.canGenerateSimpleAction,"canGenerateSimpleAction", true),
- DebugOption(options.minimizeActivityClasses,"minimizeActivityClasses", true),
- DebugOption(options.maxRootMaybeThorActions, "maxRootMaybeThorActions", 0),
- DebugOption(options.minimizeSkewBeforeSpill,"minimizeSkewBeforeSpill", false),
- DebugOption(options.createSerializeForUnknownSize,"createSerializeForUnknownSize", false),
- DebugOption(options.implicitLinkedChildRows,"implicitLinkedChildRows", false),
- DebugOption(options.mainRowsAreLinkCounted,"mainRowsAreLinkCounted", true),
- DebugOption(options.allowSections,"allowSections", true),
- DebugOption(options.autoPackRecords,"autoPackRecords", false),
- DebugOption(options.commonUniqueNameAttributes,"commonUniqueNameAttributes", true),
- DebugOption(options.sortIndexPayload,"sortIndexPayload", true),
- DebugOption(options.foldFilter,"foldFilter", true),
- DebugOption(options.finalizeAllRows, "finalizeAllRows", false),
- DebugOption(options.maxLocalRowSize , "maxLocalRowSize", MAX_LOCAL_ROW_SIZE),
- DebugOption(options.optimizeGraph,"optimizeGraph", true),
- DebugOption(options.orderDiskFunnel,"orderDiskFunnel", true),
- DebugOption(options.alwaysAllowAllNodes,"alwaysAllowAllNodes", false),
- DebugOption(options.slidingJoins,"slidingJoins", false),
- DebugOption(options.foldOptimized,"foldOptimized", false),
- DebugOption(options.globalOptimize,"globalOptimize", false),
- DebugOption(options.applyInstantEclTransformations,"applyInstantEclTransformations", false), // testing option
- DebugOption(options.calculateComplexity,"calculateComplexity", false),
- DebugOption(options.generateLogicalGraph,"generateLogicalGraph", false),
- DebugOption(options.generateLogicalGraphOnly,"generateLogicalGraphOnly", false),
- DebugOption(options.globalAutoHoist,"globalAutoHoist", true),
- DebugOption(options.applyInstantEclTransformationsLimit, "applyInstantEclTransformationsLimit", 100),
- DebugOption(options.insertProjectCostLevel, "insertProjectCostLevel", (unsigned)-1),
- DebugOption(options.dfaRepeatMax, "dfaRepeatMax", 10),
- DebugOption(options.dfaRepeatMaxScore, "dfaRepeatMaxScore", 100),
- DebugOption(options.debugNlp, "debugNlp", DEFAULT_NLP_DETAIL),
- DebugOption(options.regexVersion, "regexVersion",0),
- DebugOption(options.parseDfaComplexity, "parseDfaComplexity", (unsigned)-1),
- DebugOption(options.expandRepeatAnyAsDfa,"expandRepeatAnyAsDfa", true),
- DebugOption(options.resourceMaxMemory, "resourceMaxMemory", 0),
- DebugOption(options.resourceMaxSockets, "resourceMaxSockets", 0),
- DebugOption(options.resourceMaxActivities, "resourceMaxActivities", 0),
- DebugOption(options.resourceMaxHeavy, "resourceMaxHeavy", 1),
- DebugOption(options.resourceMaxDistribute, "resourceMaxDistribute", 2),
- DebugOption(options.unlimitedResources,"unlimitedResources", false),
- DebugOption(options.filteredReadSpillThreshold, "filteredReadSpillThreshold", 999),
- DebugOption(options.allowThroughSpill,"allowThroughSpill", true),
- DebugOption(options.minimiseSpills,"minimiseSpills", false),
- DebugOption(options.spillMultiCondition,"spillMultiCondition", false),
- DebugOption(options.spotThroughAggregate,"spotThroughAggregate", true),
- DebugOption(options.hoistResourced,"hoistResourced", true),
- DebugOption(options.minimizeSpillSize, "minimizeSpillSize", 0),
- DebugOption(options.maximizeLexer,"maximizeLexer", false),
- DebugOption(options.foldStored,"foldStored", false),
- DebugOption(options.spotTopN,"spotTopN", true),
- DebugOption(options.topnLimit, "topnLimit", 10000),
- DebugOption(options.groupAllDistribute,"groupAllDistribute", false),
- DebugOption(options.spotLocalMerge,"spotLocalMerge", true),
- DebugOption(options.spotPotentialKeyedJoins,"spotPotentialKeyedJoins", false),
- DebugOption(options.combineTrivialStored,"combineTrivialStored", true),
- DebugOption(options.combineAllStored,"combineAllStored", false),
- DebugOption(options.allowStoredDuplicate,"allowStoredDuplicate", false), // only here as a temporary workaround
- DebugOption(options.specifiedClusterSize, "clusterSize", 0),
- DebugOption(options.globalFoldOptions, "globalFoldOptions", (unsigned)-1),
- DebugOption(options.allowScopeMigrate,"allowScopeMigrate", true),
- DebugOption(options.supportFilterProject,"supportFilterProject", true),
- DebugOption(options.normalizeExplicitCasts,"normalizeExplicitCasts", true),
- DebugOption(options.optimizeInlineSource,"optimizeInlineSource", false),
- DebugOption(options.optimizeDiskSource,"optimizeDiskSource", true),
- DebugOption(options.optimizeIndexSource,"optimizeIndexSource", true),
- DebugOption(options.optimizeChildSource,"optimizeChildSource", false),
- DebugOption(options.reportLocations,"reportLocations", true),
- DebugOption(options.debugGeneratedCpp,"debugGeneratedCpp", false),
- DebugOption(options.addFilesnamesToGraph,"addFilesnamesToGraph", true),
- DebugOption(options.normalizeLocations,"normalizeLocations", true),
- DebugOption(options.ensureRecordsHaveSymbols,"ensureRecordsHaveSymbols", true),
- DebugOption(options.constantFoldNormalize,"constantFoldNormalize", true),
- DebugOption(options.constantFoldPostNormalize,"constantFoldPostNormalize", false),
- DebugOption(options.optimizeGrouping,"optimizeGrouping", true),
- DebugOption(options.showMetaInGraph,"showMetaInGraph", false),
- DebugOption(options.spotComplexClasses,"spotComplexClasses", true),
- DebugOption(options.complexClassesThreshold,"complexClassesThreshold", 5000),
- DebugOption(options.complexClassesActivityFilter,"complexClassesActivityFilter", 0),
- DebugOption(options.optimizeString1Compare,"optimizeString1Compare", true),
- DebugOption(options.optimizeSpillProject,"optimizeSpillProject", true),
- DebugOption(options.expressionPeephole,"expressionPeephole", false),
- DebugOption(options.optimizeIncrement,"optimizeIncrement", true),
- DebugOption(options.supportsMergeDistribute,"supportsMergeDistribute", true),
- DebugOption(options.debugNlpAsHint,"debugNlpAsHint", false),
- DebugOption(options.forceVariableWuid,"forceVariableWuid", false),
- DebugOption(options.okToDeclareAndAssign,"okToDeclareAndAssign", false),
- DebugOption(options.noteRecordSizeInGraph,"noteRecordSizeInGraph", true),
- DebugOption(options.convertRealAssignToMemcpy,"convertRealAssignToMemcpy", false),
- DebugOption(options.allowActivityForKeyedJoin,"allowActivityForKeyedJoin", false),
- DebugOption(options.forceActivityForKeyedJoin,"forceActivityForKeyedJoin", false),
- DebugOption(options.addLibraryInputsToGraph,"addLibraryInputsToGraph", false),
- DebugOption(options.showRecordCountInGraph,"showRecordCountInGraph", true),
- DebugOption(options.serializeRowsetInExtract,"serializeRowsetInExtract", false),
- DebugOption(options.testIgnoreMaxLength,"testIgnoreMaxLength", false),
- DebugOption(options.trackDuplicateActivities,"trackDuplicateActivities", false),
- DebugOption(options.showActivitySizeInGraph,"showActivitySizeInGraph", false),
- DebugOption(options.addLocationToCpp,"addLocationToCpp", false),
- DebugOption(options.alwaysCreateRowBuilder,"alwaysCreateRowBuilder", false),
- DebugOption(options.precalculateFieldOffsets,"precalculateFieldOffsets", false),
- DebugOption(options.generateStaticInlineTables,"generateStaticInlineTables", true),
- DebugOption(options.staticRowsUseStringInitializer,"staticRowsUseStringInitializer", true),
- DebugOption(options.convertWhenExecutedToCompound,"convertWhenExecutedToCompound", queryLegacyWhenSemantics()),
- DebugOption(options.standAloneExe,"standAloneExe", false),
- DebugOption(options.enableCompoundCsvRead,"enableCompoundCsvRead", true),
- // The following works 99% of the time, but disabled due to potential problems with the ambiguity of LEFT
- //possibly causing filters on nested records to be incorrectly removed.
- DebugOption(options.optimizeNestedConditional,"optimizeNestedConditional", false),
- DebugOption(options.createImplicitAliases,"createImplicitAliases", false),
- DebugOption(options.combineSiblingGraphs,"combineSiblingGraphs", true),
- DebugOption(options.optimizeSharedGraphInputs,"optimizeSharedGraphInputs", true),
- DebugOption(options.supportsSubSortActivity,"supportsSubSortActivity",false),
- DebugOption(options.implicitSubSort,"implicitSubSort",true),
- DebugOption(options.implicitBuildIndexSubSort,"implicitBuildIndexSubSort",true),
- DebugOption(options.implicitJoinSubSort,"implicitJoinSubSort",true),
- DebugOption(options.implicitGroupSubSort,"implicitGroupSubSort",true),
- DebugOption(options.implicitGroupHashAggregate,"implicitGroupHashAggregate",false),
- DebugOption(options.implicitGroupHashDedup,"implicitGroupHashDedup",false),
- DebugOption(options.reportFieldUsage,"reportFieldUsage",false),
- DebugOption(options.reportFileUsage,"reportFileUsage",false),
- DebugOption(options.subsortLocalJoinConditions,"subsortLocalJoinConditions",false),
- DebugOption(options.projectNestedTables,"projectNestedTables",true),
- DebugOption(options.showSeqInGraph,"showSeqInGraph",false), // For tracking down why projects are not commoned up
- DebugOption(options.normalizeSelectorSequence,"normalizeSelectorSequence",false), // For tracking down why projects are not commoned up
- DebugOption(options.removeXpathFromOutput,"removeXpathFromOutput",false),
- DebugOption(options.canLinkConstantRows,"canLinkConstantRows",true),
- DebugOption(options.checkAmbiguousRollupCondition,"checkAmbiguousRollupCondition",true),
- DebugOption(options.matchExistingDistributionForJoin,"matchExistingDistributionForJoin",true),
- DebugOption(options.expandHashJoin,"expandHashJoin",false),
- DebugOption(options.traceIR,"traceIR",false),
- DebugOption(options.preserveCaseExternalParameter,"preserveCaseExternalParameter",true),
- DebugOption(options.optimizeParentAccess,"optimizeParentAccess",false),
- DebugOption(options.expandPersistInputDependencies,"expandPersistInputDependencies",true),
- DebugOption(options.multiplePersistInstances,"multiplePersistInstances",true),
- DebugOption(options.defaultNumPersistInstances,"defaultNumPersistInstances",-1),
- DebugOption(options.optimizeMax,"optimizeMax",false),
- DebugOption(options.useResultsForChildSpills,"useResultsForChildSpills",false),
- DebugOption(options.alwaysUseGraphResults,"alwaysUseGraphResults",false),
- };
- //get options values from workunit
- const unsigned numDebugOptions = _elements_in(debugOptions);
- Owned<IStringIterator> debugs(&wu()->getDebugValues());
- SCMStringBuffer name, val;
- ForEach(*debugs)
- {
- debugs->str(name);
- wu()->getDebugValue(name.str(),val);
- unsigned x = 0;
- for (; x < numDebugOptions; x++)
- {
- if (0 == stricmp(name.str(), debugOptions[x].optName))
- {
- debugOptions[x].setValue(val.str());
- break;
- }
- }
- }
- //Configure the divide by zero action
- options.divideByZeroAction = DBZzero;
- const char * dbz = wu()->getDebugValue("divideByZero",val).str();
- if (strieq(dbz, "0") || strieq(dbz, "zero"))
- options.divideByZeroAction = DBZzero;
- else if (strieq(dbz, "nan"))
- options.divideByZeroAction = DBZnan;
- else if (strieq(dbz, "fail") || strieq(dbz, "throw"))
- options.divideByZeroAction = DBZfail;
- else if (val.length())
- throwError2(HQLERR_UnexpectedOptionValue_XY, "divideByZero", dbz);
- //The following cases handle options whose default values are dependent on other options.
- //Or where one debug options sets more than one option
- if (options.spanMultipleCpp)
- {
- options.activitiesPerCpp = wu()->getDebugValueInt("activitiesPerCpp", DEFAULT_ACTIVITIES_PER_CPP);
- curCppFile = 1;
- }
- options.targetCompiler = DEFAULT_COMPILER;
- if (wu()->hasDebugValue("targetGcc"))
- options.targetCompiler = wu()->getDebugValueBool("targetGcc", false) ? GccCppCompiler : Vs6CppCompiler;
- SCMStringBuffer compilerText;
- wu()->getDebugValue("targetCompiler", compilerText);
- for (CompilerType iComp = (CompilerType)0; iComp < MaxCompiler; iComp = (CompilerType)(iComp+1))
- {
- if (stricmp(compilerText.s.str(), compilerTypeText[iComp]) == 0)
- options.targetCompiler = iComp;
- }
- if (getDebugFlag("optimizeProjects", true))
- {
- options.optimizeGlobalProjects = true;
- options.optimizeResourcedProjects = true;
- }
- options.minimizeWorkunitTemporaries = !options.workunitTemporaries || getDebugFlag("minimizeWorkunitTemporaries", false);//options.resourceConditionalActions);
- options.inlineStringThreshold = wu()->getDebugValueInt("inlineStringThreshold", (options.targetCompiler != Vs6CppCompiler) ? 0 : 10000);
- options.implicitLinkedChildRows = true;
- options.finalizeAllRows = true; // inline temporary rows should actually be ok.
- postProcessOptions();
- }
- void HqlCppTranslator::postProcessOptions()
- {
- if (options.optimizeMax)
- {
- //Enable any extra potentially expensive optimizations options here...
- options.foldConstantDatasets = true;
- options.percolateConstants = true;
- options.percolateFilters = true;
- }
- //Any post processing - e.g., dependent flags goes here...
- options.optimizeDiskFlag = 0;
- if (options.optimizeInlineSource)
- options.optimizeDiskFlag |= CSFnewinline;
- if (options.optimizeDiskSource)
- options.optimizeDiskFlag |= CSFnewdisk;
- if (options.optimizeIndexSource)
- options.optimizeDiskFlag |= CSFnewindex;
- if (options.optimizeChildSource)
- options.optimizeDiskFlag |= CSFnewchild;
- if (!targetThor())
- {
- //Roxie doesn't gain from additional projects, hthor doesn't support split
- options.optimizeSpillProject = false;
- }
- if (options.resourceSequential)
- options.resourceConditionalActions = true;
- //Probably best to ignore this warning. - possibly configure it based on some other option
- globalOnWarnings->addOnWarning(HQLWRN_FoldRemoveKeyed, ignoreAtom);
- //Ensure the settings for the following options are always present in the workunit
- wu()->setDebugValueInt("expandPersistInputDependencies",options.expandPersistInputDependencies,true);
- if (options.forceVariableWuid)
- wu()->setCloneable(true);
- }
- unsigned HqlCppTranslator::getOptimizeFlags() const
- {
- unsigned optFlags = HOOfold;
- switch (targetClusterType)
- {
- case RoxieCluster:
- optFlags |= HOOnoclonelimit|HOOalwayslocal;
- break;
- case HThorCluster:
- optFlags |= HOOnocloneindexlimit|HOOalwayslocal;
- break;
- case ThorLCRCluster:
- break;
- default:
- UNIMPLEMENTED;
- }
- if ((options.optimizeDiskFlag & CSFnewdisk) && (options.optimizeDiskFlag & CSFnewindex))
- optFlags |= HOOhascompoundaggregate;
- if (options.foldConstantDatasets)
- optFlags |= HOOfoldconstantdatasets;
- if (options.optimizeMax)
- optFlags |= HOOexpensive;
- return optFlags;
- }
- void HqlCppTranslator::overrideOptionsForLibrary()
- {
- options.workunitTemporaries = false;
- options.pickBestEngine = false;
- options.minimizeWorkunitTemporaries = true;
- }
- void HqlCppTranslator::overrideOptionsForQuery()
- {
- options.workunitTemporaries = getDebugFlag("workunitTemporaries", true);
- options.pickBestEngine = getDebugFlag("pickBestEngine", true);
- options.minimizeWorkunitTemporaries = !options.workunitTemporaries || getDebugFlag("minimizeWorkunitTemporaries", false);//options.resourceConditionalActions);
- }
- bool HqlCppTranslator::needToSerializeToSlave(IHqlExpression * expr) const
- {
- if (targetThor())
- return true;
- switch (expr->getOperator())
- {
- case no_getresult:
- case no_workunit_dataset:
- return !matchesConstantValue(queryAttributeChild(expr, sequenceAtom, 0), ResultSequenceOnce);
- default:
- return true;
- }
- }
- IHqlExpression *HqlCppTranslator::addBigLiteral(const char *lit, unsigned litLen)
- {
- unsigned resid = code->addStringResource(litLen, lit);
- HqlExprArray args;
- args.append(*getSizetConstant(resid));
- return bindTranslatedFunctionCall(loadResourceId, args);
- }
- IHqlExpression * HqlCppTranslator::addLiteral(const char * text)
- {
- return createConstant(text);
- }
- IHqlExpression *HqlCppTranslator::addDataLiteral(const char *lit, unsigned litLen)
- {
- if (!canGenerateStringInline(litLen))
- return addBigLiteral(lit, litLen);
- else
- return createConstant(createStringValue(lit, litLen));
- }
- IHqlExpression *HqlCppTranslator::addStringLiteral(const char *lit)
- {
- unsigned litLen = strlen(lit);
- if (!canGenerateStringInline(litLen))
- return addBigLiteral(lit, litLen+1);
- else
- return createConstant(createStringValue(lit, litLen));
- }
- bool HqlCppTranslator::allowEmbeddedCpp()
- {
- if (!checkedEmbeddedCpp)
- {
- cachedAllowEmbeddedCpp = ctxCallback->allowAccess("cpp");
- checkedEmbeddedCpp = true;
- }
- return cachedAllowEmbeddedCpp;
- }
- void HqlCppTranslator::checkPipeAllowed()
- {
- if (!checkedPipeAllowed)
- {
- if (!ctxCallback->allowAccess("pipe"))
- throwError(HQLERR_PipeNotAllowed);
- checkedPipeAllowed = true;
- }
- }
- IHqlExpression * HqlCppTranslator::bindFunctionCall(IIdAtom * name, HqlExprArray & args)
- {
- OwnedHqlExpr function = needFunction(name);
- assertex(function != NULL);
- return bindFunctionCall(function, args);
- }
- IHqlExpression * HqlCppTranslator::bindFunctionCall(IIdAtom * name, IHqlExpression * arg1)
- {
- HqlExprArray args;
- args.append(*arg1);
- return bindFunctionCall(name, args);
- }
- IHqlExpression * HqlCppTranslator::bindFunctionCall(IHqlExpression * function, HqlExprArray & args)
- {
- useFunction(function);
- IHqlExpression * ret = createBoundFunction(NULL, function, args, NULL, false);
- assertex(ret->queryExternalDefinition());
- args.kill();
- return ret;
- }
- IHqlExpression * HqlCppTranslator::bindFunctionCall(IIdAtom * name, HqlExprArray & args, ITypeInfo * newType)
- {
- if (!newType)
- return bindFunctionCall(name, args);
- OwnedHqlExpr function = needFunction(name);
- useFunction(function);
- assertex(function->getOperator() == no_funcdef);
- IHqlExpression * body = function->queryChild(0);
- HqlExprArray bodyArgs;
- unwindChildren(bodyArgs, body);
- HqlExprArray funcArgs;
- funcArgs.append(*createValue(body->getOperator(), LINK(newType), bodyArgs));
- unwindChildren(funcArgs, function, 1);
- ITypeInfo * funcType = makeFunctionType(LINK(newType), LINK(function->queryChild(1)), LINK(function->queryChild(2)));
- OwnedHqlExpr newFunction = createValue(function->getOperator(), funcType, funcArgs);
- return bindFunctionCall(newFunction, args);
- }
- IHqlExpression * HqlCppTranslator::bindTranslatedFunctionCall(IHqlExpression * function, HqlExprArray & args)
- {
- useFunction(function);
- IHqlExpression * ret = createTranslatedExternalCall(NULL, function, args);
- assertex(ret->queryExternalDefinition());
- args.kill();
- return ret;
- }
- IHqlExpression * HqlCppTranslator::bindTranslatedFunctionCall(IIdAtom * name, HqlExprArray & args)
- {
- OwnedHqlExpr function = needFunction(name);
- return bindTranslatedFunctionCall(function, args);
- }
- void HqlCppTranslator::buildTranslatedFunctionCall(BuildCtx & ctx, IIdAtom * name, HqlExprArray & args)
- {
- OwnedHqlExpr call = bindTranslatedFunctionCall(name, args);
- ctx.addExpr(call);
- }
- void HqlCppTranslator::buildFunctionCall(BuildCtx & ctx, IIdAtom * name, HqlExprArray & args)
- {
- OwnedHqlExpr call = bindFunctionCall(name, args);
- buildStmt(ctx, call);
- }
- /* Args: all elements in it are LINKED */
- void HqlCppTranslator::callProcedure(BuildCtx & ctx, IIdAtom * name, HqlExprArray & args)
- {
- OwnedHqlExpr call = bindTranslatedFunctionCall(name, args);
- assertex(call->queryExternalDefinition());
- ctx.addExpr(call);
- }
- bool HqlCppTranslator::getDebugFlag(const char * name, bool defValue)
- {
- return wu()->getDebugValueBool(name, defValue);
- }
- void HqlCppTranslator::doReportWarning(IHqlExpression * location, unsigned id, const char * msg)
- {
- Owned<IECLError> warnError;
- if (!location)
- location = queryActiveActivityLocation();
- if (location)
- warnError.setown(createECLError(SeverityWarning, id, msg, location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0));
- else
- warnError.setown(createECLError(SeverityWarning, id, msg, NULL, 0, 0, 0));
- errorProcessor->report(warnError);
- }
- void HqlCppTranslator::reportWarning(IHqlExpression * location, unsigned id, const char * msg, ...)
- {
- StringBuffer s;
- va_list args;
- va_start(args, msg);
- s.valist_appendf(msg, args);
- va_end(args);
- doReportWarning(location, id, s.str());
- }
- void HqlCppTranslator::reportWarning(unsigned id, const char * msg, ...)
- {
- StringBuffer s;
- va_list args;
- va_start(args, msg);
- s.valist_appendf(msg, args);
- va_end(args);
- doReportWarning(NULL, id, s.str());
- }
- void HqlCppTranslator::addWorkunitException(WUExceptionSeverity severity, unsigned code, const char * text, IHqlExpression * location)
- {
- Owned<IWUException> msg = wu()->createException();
- msg->setExceptionSource("Code Generator");
- if (code)
- msg->setExceptionCode(code);
- msg->setExceptionMessage(text);
- msg->setSeverity(severity);
- msg->setTimeStamp(NULL);
- if (!location)
- location = queryActiveActivityLocation();
- if (location)
- {
- msg->setExceptionFileName(location->querySourcePath()->str());
- msg->setExceptionLineNo(location->getStartLine());
- msg->setExceptionColumn(location->getStartColumn());
- }
- }
- IHqlExpression * HqlCppTranslator::queryActiveNamedActivity()
- {
- ForEachItemInRev(i, activityExprStack)
- {
- IHqlExpression & cur = activityExprStack.item(i);
- IHqlExpression * symbol = queryNamedSymbol(&cur);
- if (symbol && symbol->querySourcePath())
- return symbol;
- if (isCompoundSource(&cur))
- {
- IHqlExpression * child = cur.queryChild(0);
- if (hasNamedSymbol(child))
- return child;
- }
- }
- return NULL;
- }
- IHqlExpression * HqlCppTranslator::queryActiveActivityLocation() const
- {
- ForEachItemInRev(i, activityExprStack)
- {
- IHqlExpression & cur = activityExprStack.item(i);
- IHqlExpression * location = queryLocation(&cur);
- if (location)
- return location;
- if (isCompoundSource(&cur))
- {
- location = queryLocation(cur.queryChild(0));
- if (location)
- return location;
- }
- }
- return NULL;
- }
- void HqlCppTranslator::ThrowStringException(int code,const char *format, ...)
- {
- IHqlExpression * location = queryActiveActivityLocation();
- if (errorProcessor && location)
- {
- StringBuffer errorMsg;
- va_list args;
- va_start(args, format);
- errorMsg.valist_appendf(format, args);
- va_end(args);
- throw createECLError(code, errorMsg.str(), location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0);
- }
- va_list args;
- va_start(args, format);
- IException *ret = MakeStringExceptionVA(code, format, args);
- va_end(args);
- throw ret;
- }
- void HqlCppTranslator::reportErrorDirect(IHqlExpression * location, int code,const char *msg, bool alwaysAbort)
- {
- if (location)
- {
- ECLlocation loc;
- loc.extractLocationAttr(location);
- if (alwaysAbort)
- throw createECLError(code, msg, loc.sourcePath->str(), loc.lineno, loc.column, loc.position);
- errorProcessor->reportError(code, msg, loc.sourcePath->str(), loc.lineno, loc.column, loc.position);
- }
- else
- // errorProcessor->reportError(code, msg, NULL, 0, 0, 0);
- throw MakeStringExceptionDirect(code, msg);
- }
- void HqlCppTranslator::reportError(IHqlExpression * location, int code,const char *format, ...)
- {
- StringBuffer errorMsg;
- va_list args;
- va_start(args, format);
- errorMsg.valist_appendf(format, args);
- va_end(args);
- reportErrorDirect(location, code, errorMsg.str(), true);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildStmtAssign(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * expr)
- {
- buildAssign(ctx, target, expr);
- }
- void HqlCppTranslator::buildAddress(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_address:
- buildExpr(ctx, expr->queryChild(0), tgt);
- break;
- case no_typetransfer:
- buildAddress(ctx, expr->queryChild(0), tgt);
- break;
- default:
- {
- Owned<IReferenceSelector> selector = buildReference(ctx, expr);
- selector->buildAddress(ctx, tgt);
- break;
- }
- }
- }
- bool HqlCppTranslator::hasAddress(BuildCtx & ctx, IHqlExpression * expr)
- {
- switch (expr->getOperator())
- {
- case no_deref:
- case no_variable:
- return true;
- case no_field:
- case no_select:
- {
- Owned<IReferenceSelector> selector = buildReference(ctx, expr);
- return !selector->isConditional();
- }
- case no_typetransfer:
- return hasAddress(ctx, expr->queryChild(0));
- default:
- return false;
- }
- }
- void HqlCppTranslator::buildAssign(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * expr)
- {
- #ifdef ADD_ASSIGNMENT_COMMENTS
- if (target->getOperator() == no_select)
- {
- StringBuffer s;
- ctx.addQuoted(s.append("//Assign to field ").append(target->queryChild(1)->queryName()));
- }
- #endif
- Owned<IReferenceSelector> selector = buildReference(ctx, target);
- if (expr->getOperator() == no_null)
- selector->buildClear(ctx, 0);
- else if (target->isDatarow() && (!hasReferenceModifier(target->queryType()) || !recordTypesMatch(target->queryType(), expr->queryType())))
- buildRowAssign(ctx, selector, expr);
- else
- selector->set(ctx, expr);
- }
- void HqlCppTranslator::doBuildStmtAssignModify(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * expr, node_operator assignOp)
- {
- Owned<IReferenceSelector> selector = buildReference(ctx, target);
- selector->modifyOp(ctx, expr, assignOp);
- }
- void HqlCppTranslator::buildExprAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- /*
- switch (target.queryType().getTypeCode())
- {
- case type_table:
- case type_groupedtable:
- buildDatasetAssign(ctx, target, expr);
- break;
- case type_row:
- buildAssignRow(ctx, target, expr);
- break;
- }
- */
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_constant:
- if (!isNullAssign(target, expr))
- doBuildExprAssign(ctx, target, expr);
- else
- ctx.addAssign(target.length, queryZero());
- break;
- case no_regex_find:
- case no_regex_replace:
- doBuildAssignRegexFindReplace(ctx, target, expr);
- break;
- case no_matched:
- case no_matchtext:
- case no_matchlength:
- case no_matchposition:
- case no_matchunicode:
- case no_matchutf8:
- doBuildMatched(ctx, &target, expr, NULL);
- break;
- case no_matchattr:
- doBuildMatchAttr(ctx, &target, expr, NULL);
- break;
- case no_loopcounter:
- doBuildAssignLoopCounter(ctx, target, expr);
- break;
- case no_evalonce:
- doBuildEvalOnce(ctx, &target, expr, NULL);
- break;
- case no_alias_scope:
- {
- expandAliasScope(ctx, expr);
- buildExprAssign(ctx, target, expr->queryChild(0));
- break;
- }
- case no_case:
- case no_map:
- {
- HqlCppCaseInfo info(*this);
- doBuildCaseInfo(expr, info);
- info.buildAssign(ctx, target);
- break;
- }
- case no_which:
- case no_rejected:
- doBuildAssignWhich(ctx, target, expr);
- break;
- case no_call:
- case no_externalcall:
- doBuildAssignCall(ctx, target, expr);
- break;
- case no_cast:
- case no_implicitcast:
- doBuildAssignCast(ctx, target, expr);
- break;
- case no_choose:
- doBuildAssignChoose(ctx, target, expr);
- break;
- case no_comma:
- case no_compound:
- buildStmt(ctx, expr->queryChild(0));
- buildExprAssign(ctx, target, expr->queryChild(1));
- break;
- case no_concat:
- doBuildAssignConcat(ctx, target, expr);
- break;
- case no_div:
- case no_modulus:
- doBuildAssignDivide(ctx, target, expr);
- break;
- case no_crc:
- case no_hash:
- case no_hash32:
- case no_hash64:
- doBuildAssignHashCrc(ctx, target, expr);
- break;
- case no_hashmd5:
- doBuildAssignHashMd5(ctx, target, expr);
- break;
- case no_if:
- doBuildAssignIf(ctx, target, expr);
- break;
- case no_index:
- doBuildAssignIndex(ctx, target, expr);
- break;
- case no_in:
- case no_notin:
- {
- OwnedHqlExpr optimized = querySimplifyInExpr(expr);
- if (optimized)
- {
- OwnedHqlExpr folded = foldHqlExpression(optimized);
- buildExprAssign(ctx, target, folded);
- }
- else
- doBuildAssignIn(ctx, target, expr);
- break;
- }
- case no_intformat:
- doBuildAssignFormat(intFormatId, ctx, target, expr);
- break;
- case no_nofold:
- case no_nohoist:
- case no_section:
- case no_sectioninput:
- buildExprAssign(ctx, target, expr->queryChild(0));
- break;
- case no_realformat:
- doBuildAssignFormat(realFormatId, ctx, target, expr);
- break;
- case no_order:
- doBuildAssignOrder(ctx, target, expr);
- break;
- case no_unicodeorder:
- doBuildAssignUnicodeOrder(ctx, target, expr);
- break;
- case no_substring:
- doBuildAssignSubString(ctx, target, expr);
- break;
- case no_trim:
- doBuildAssignTrim(ctx, target, expr);
- break;
- case no_field:
- throwUnexpected();
- case no_select:
- {
- OwnedHqlExpr aggregate = convertToSimpleAggregate(expr);
- if (aggregate && canProcessInline(&ctx, aggregate->queryChild(0)))
- {
- buildExprAssign(ctx, target, aggregate);
- return;
- }
- if (shouldEvaluateSelectAsAlias(ctx, expr) && !insideOnStart(ctx))
- {
- CHqlBoundExpr temp;
- doBuildAliasValue(ctx, expr, temp);
- assign(ctx, target, temp);
- return;
- }
- Owned<IReferenceSelector> selector = buildReference(ctx, expr);
- selector->assignTo(ctx, target);
- return;
- }
- break;
- case no_not:
- {
- IHqlExpression * child = expr->queryChild(0);
- node_operator childOp = child->getOperator();
- if (((childOp == no_and) || (childOp == no_or)) && requiresTempAfterFirst(ctx, child))
- {
- if (childOp == no_and)
- doBuildAssignAnd(ctx, target, child, true);
- else
- {
- OwnedHqlExpr inverted = convertOrToAnd(expr);
- buildExprAssign(ctx, target, inverted);
- }
- }
- else
- doBuildExprAssign(ctx, target, expr);
- break;
- }
- case no_or:
- {
- IHqlExpression * left = expr->queryChild(0);
- //in always goes via an assign, so do this first, and then filter on result.
- if (left->getOperator() == no_in)
- {
- BuildCtx subctx(ctx);
- buildExprAssign(subctx, target, left);
- OwnedHqlExpr inverse = getInverse(target.expr);
- subctx.addFilter(inverse);
- buildExprAssign(subctx, target, expr->queryChild(1));
- }
- else if (requiresTempAfterFirst(ctx, expr))
- {
- OwnedHqlExpr inverted = convertOrToAnd(expr);
- buildExprAssign(ctx, target, inverted);
- }
- else
- doBuildExprAssign(ctx, target, expr);
- break;
- }
- case no_and:
- if (requiresTempAfterFirst(ctx, expr))
- doBuildAssignAnd(ctx, target, expr, false);
- else
- doBuildExprAssign(ctx, target, expr);
- break;
- case no_fromunicode:
- case no_tounicode:
- doBuildAssignToFromUnicode(ctx, target, expr);
- break;
- case no_toxml:
- doBuildAssignToXml(ctx, target, expr);
- break;
- case no_wuid:
- doBuildAssignWuid(ctx, target, expr);
- break;
- case no_xmldecode:
- case no_xmlencode:
- doBuildXmlEncode(ctx, &target, expr, NULL);
- break;
- case no_all:
- doBuildAssignAll(ctx, target, expr);
- return;
- case no_list:
- doBuildAssignList(ctx, target, expr);
- return;
- case no_addsets:
- doBuildAssignAddSets(ctx, target, expr);
- return;
- case no_createset:
- buildSetAssignViaBuilder(ctx, target, expr);
- return;
- case no_failmessage:
- doBuildAssignFailMessage(ctx, target, expr);
- return;
- case no_eventname:
- doBuildAssignEventName(ctx, target, expr);
- return;
- case no_eventextra:
- doBuildAssignEventExtra(ctx, target, expr);
- return;
- case no_catch:
- doBuildAssignCatch(ctx, target, expr);
- break;
- case no_id2blob:
- doBuildAssignIdToBlob(ctx, target, expr);
- break;
- case no_getresult:
- case no_workunit_dataset:
- if (isSameFullyUnqualifiedType(expr->queryType(), target.queryType()))
- doBuildAssignGetResult(ctx, target, expr);
- else
- doBuildExprAssign(ctx, target, expr);
- break;
- case no_getgraphresult:
- doBuildAssignGetGraphResult(ctx, target, expr);
- break;
- case no_existslist:
- doBuildAggregateList(ctx, &target, expr, NULL);
- break;
- case no_countlist:
- doBuildAggregateList(ctx, &target, expr, NULL);
- break;
- case no_sumlist:
- doBuildAggregateList(ctx, &target, expr, NULL);
- break;
- case no_minlist:
- doBuildAggregateList(ctx, &target, expr, NULL);
- break;
- case no_maxlist:
- doBuildAggregateList(ctx, &target, expr, NULL);
- break;
- case no_skip:
- {
- bool canReachFollowing = false;
- doBuildStmtSkip(ctx, expr, &canReachFollowing);
- if (canReachFollowing)
- {
- OwnedHqlExpr null = createNullExpr(expr);
- doBuildExprAssign(ctx, target, null);
- }
- break;
- }
- case no_count:
- case no_max:
- case no_min:
- case no_sum:
- case no_exists:
- doBuildAssignAggregate(ctx, target, expr);
- break;
- case no_getenv:
- {
- OwnedHqlExpr mapped = cvtGetEnvToCall(expr);
- buildExprAssign(ctx, target, mapped);
- break;
- }
- default:
- doBuildExprAssign(ctx, target, expr);
- break;
- }
- }
- void HqlCppTranslator::buildExprAssignViaType(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, ITypeInfo * type)
- {
- OwnedHqlExpr temp = createValue(no_implicitcast, LINK(type), LINK(expr));
- buildExprAssign(ctx, target, temp);
- }
- void HqlCppTranslator::buildExprAssignViaString(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, unsigned len)
- {
- OwnedITypeInfo type = makeStringType(len, NULL, NULL);
- buildExprAssignViaType(ctx, target, expr, type);
- }
- void HqlCppTranslator::buildAssignToTemp(BuildCtx & ctx, IHqlExpression * variable, IHqlExpression * expr)
- {
- CHqlBoundTarget boundTarget;
- boundTarget.expr.set(variable);
- buildExprAssign(ctx, boundTarget, expr);
- }
- void HqlCppTranslator::buildAssignViaTemp(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- CHqlBoundExpr temp;
- buildTempExpr(ctx, expr, temp);
- buildExprAssign(ctx, target, temp.expr);
- }
- static bool canOptimizeIncrementAssign(ITypeInfo * type)
- {
- switch (type->getTypeCode())
- {
- case type_real:
- return true;
- case type_int:
- switch (type->getSize())
- {
- case 1:
- case 2:
- case 4:
- case 8:
- return true;
- }
- }
- return false;
- }
- IHqlExpression * HqlCppTranslator::optimizeIncrementAssign(BuildCtx & ctx, IHqlExpression * value)
- {
- //MORE: Could spot x += if(cond, y, 0) and convert to if (cond) x+= y; (especially if y is 1)
- if (value->getOperator() == no_if)
- {
- IHqlExpression * left = value->queryChild(1);
- IHqlExpression * right = value->queryChild(2);
- if (isZero(right))
- {
- buildFilter(ctx, value->queryChild(0));
- return optimizeIncrementAssign(ctx, left);
- }
- if (isZero(left))
- {
- OwnedHqlExpr filter = getInverse(value->queryChild(0));
- buildFilter(ctx, filter);
- return optimizeIncrementAssign(ctx, right);
- }
- }
- if (isCast(value))
- {
- IHqlExpression * uncast = value->queryChild(0);
- OwnedHqlExpr optimizedValue = optimizeIncrementAssign(ctx, uncast);
- if (optimizedValue != uncast)
- return ensureExprType(optimizedValue, value->queryType());
- }
- return LINK(value);
- }
- void HqlCppTranslator::buildIncrementAssign(BuildCtx & ctx, IHqlExpression * target, IHqlExpression * value)
- {
- // CHqlBoundExpr bound;
- // buildExpr(ctx, target, bound);
- ITypeInfo * type = target->queryType();
- OwnedHqlExpr castValue = ensureExprType(value, type);
- BuildCtx condctx(ctx);
- if (options.optimizeIncrement)
- {
- castValue.setown(optimizeIncrementAssign(condctx, castValue));
- if (isZero(castValue))
- return;
- if (canOptimizeIncrementAssign(type))
- {
- CHqlBoundExpr boundTarget;
- buildExpr(condctx, target, boundTarget); // Not very clean!
- CHqlBoundExpr boundValue;
- buildExpr(condctx, castValue, boundValue);
- condctx.addAssignIncrement(boundTarget.expr, boundValue.expr);
- return;
- }
- }
- OwnedHqlExpr plus = createValue(no_add, LINK(target), castValue.getClear());
- buildAssign(condctx, target, plus);
- }
- void HqlCppTranslator::buildIncrementAssign(BuildCtx & ctx, IReferenceSelector * target, IHqlExpression * value)
- {
- buildIncrementAssign(ctx, target->queryExpr(), value);
- // OwnedHqlExpr plus = createValue(no_add, LINK(type), ensureExprType(target->queryExpr(), type), ensureExprType(value, type));
- // target->set(condctx, plus);
- }
- void HqlCppTranslator::buildIncrementAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * value)
- {
- ITypeInfo * type = target.queryType();
- OwnedHqlExpr castValue = ensureExprType(value, type);
- BuildCtx condctx(ctx);
- if (options.optimizeIncrement)
- {
- castValue.setown(optimizeIncrementAssign(condctx, castValue));
- if (isZero(castValue))
- return;
- if (canOptimizeIncrementAssign(type))
- {
- CHqlBoundExpr boundValue;
- buildExpr(ctx, castValue, boundValue);
- ctx.addAssignIncrement(target.expr, boundValue.expr);
- return;
- }
- }
- OwnedHqlExpr plus = createValue(no_add, target.getTranslatedExpr(), castValue.getClear());
- buildExprAssign(ctx, target, plus);
- }
- void HqlCppTranslator::buildClear(BuildCtx & ctx, IHqlExpression * expr)
- {
- OwnedHqlExpr null = createNullExpr(expr);
- buildAssign(ctx, expr, null);
- }
- void HqlCppTranslator::buildClear(BuildCtx & ctx, const CHqlBoundTarget & target)
- {
- if (target.length)
- {
- buildAssignToTemp(ctx, target.length, queryZero());
- //NB: Don't need to clear target.pointer/target.variable if a length is defined......
- return;
- }
- if (target.isFixedSize())
- {
- OwnedHqlExpr null = createNullExpr(target.expr);
- buildExprAssign(ctx, target, null);
- }
- else
- {
- StringBuffer code;
- if (hasWrapperModifier(target.queryType()))
- generateExprCpp(code, target.expr).append(".clear();");
- else
- generateExprCpp(code, target.expr).append(" = 0;");
- ctx.addQuoted(code);
- }
- }
- void HqlCppTranslator::buildFilter(BuildCtx & ctx, IHqlExpression * expr)
- {
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_attr:
- case no_attr_expr:
- case no_attr_link:
- return;
- case no_and:
- doBuildFilterAnd(ctx, expr);
- return;
- case no_not:
- {
- IHqlExpression * child = expr->queryChild(0);
- if ((child->getOperator() == no_or) && requiresTempAfterFirst(ctx, child))
- {
- OwnedHqlExpr inverted = convertOrToAnd(expr);
- buildFilter(ctx,inverted);
- return;
- }
- }
- break;
- case no_or:
- if (!(hints & HintSize) && requiresTempAfterFirst(ctx, expr))
- {
- OwnedHqlExpr inverted = convertOrToAnd(expr);
- buildFilter(ctx, inverted);
- return;
- }
- break;
- case no_between:
- case no_notbetween:
- {
- OwnedHqlExpr between = expandBetween(expr);
- buildFilter(ctx, between);
- return;
- }
- case no_alias_scope:
- {
- expandAliasScope(ctx, expr);
- buildFilter(ctx, expr->queryChild(0));
- return;
- }
- case no_compound:
- {
- buildStmt(ctx, expr->queryChild(0));
- buildFilter(ctx, expr->queryChild(1));
- break;
- }
- }
- buildFilterViaExpr(ctx, expr);
- }
- IHqlStmt * HqlCppTranslator::buildFilterViaExpr(BuildCtx & ctx, IHqlExpression * expr)
- {
- //default action...
- CHqlBoundExpr pure;
- buildExpr(ctx, expr, pure);
- if (pure.length) // check length is non zero
- return ctx.addFilter(pure.length);
- else
- {
- IHqlStmt * stmt = ctx.addFilter(pure.expr);
- ctx.associateExpr(expr, queryBoolExpr(true));
- return stmt;
- }
- }
- void HqlCppTranslator::tidyupExpr(BuildCtx & ctx, CHqlBoundExpr & bound)
- {
- if (isPushed(bound))
- {
- HqlExprArray args;
- callProcedure(ctx, DecPopLongId, args);
- bound.expr.set(NULL);
- }
- }
- void HqlCppTranslator::expandTranslated(IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- tgt.setFromTranslated(expr);
- }
- void HqlCppTranslator::buildCachedExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- buildExpr(ctx, expr, tgt);
- }
- void HqlCppTranslator::buildAnyExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (expr->isDataset())
- buildDataset(ctx, expr, tgt, FormatNatural);
- else if (expr->isDatarow())
- {
- Owned<IReferenceSelector> selector = buildNewRow(ctx, expr);
- selector->buildAddress(ctx, tgt);
- }
- else
- buildExpr(ctx, expr, tgt);
- }
- bool HqlCppTranslator::shouldEvaluateSelectAsAlias(BuildCtx & ctx, IHqlExpression * expr)
- {
- //If we're inside an activity that serializes onStart data, then the code to serialize fields
- //selected from a row is generally simpler than the code to serialize the row itself.
- if (insideActivityRemoteSerialize(ctx) && !expr->isList())
- {
- bool isNew;
- IHqlExpression * ds = querySelectorDataset(expr, isNew);
- if (isNew && ds->getOperator() == no_getgraphresult)
- {
- IHqlExpression * graphId = ds->queryChild(1);
- if (isCurrentActiveGraph(ctx, graphId))
- return true;
- }
- }
- return false;
- }
- void HqlCppTranslator::buildExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_counter:
- doBuildExprCounter(ctx, expr, tgt);
- return;
- case no_evaluate:
- doBuildExprEvaluate(ctx, expr, tgt);
- return;
- case no_thor:
- throwUnexpected();
- // assertex(expr->queryType()->isScalar());
- // buildExpr(ctx, expr->queryChild(0), tgt);
- return;
- case no_count:
- if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
- doBuildExprCount(ctx, expr, tgt);
- return;
- case no_max:
- case no_min:
- case no_sum:
- if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
- doBuildExprAggregate(ctx, expr, tgt);
- return;
- case no_exists:
- if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
- doBuildExprExists(ctx, expr, tgt);
- return;
- case no_countdict:
- if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
- doBuildExprCountDict(ctx, expr, tgt);
- return;
- case no_existsdict:
- if (!(expr->isPure() && ctx.getMatchExpr(expr, tgt)))
- doBuildExprExistsDict(ctx, expr, tgt);
- return;
- case no_existslist:
- doBuildAggregateList(ctx, NULL, expr, &tgt);
- return;
- case no_countlist:
- doBuildAggregateList(ctx, NULL, expr, &tgt);
- return;
- case no_sumlist:
- doBuildAggregateList(ctx, NULL, expr, &tgt);
- return;
- case no_minlist:
- doBuildAggregateList(ctx, NULL, expr, &tgt);
- return;
- case no_maxlist:
- doBuildAggregateList(ctx, NULL, expr, &tgt);
- return;
- case no_sizeof:
- doBuildExprSizeof(ctx, expr, tgt);
- return;
- case no_filepos:
- doBuildExprFilepos(ctx, expr, tgt);
- return;
- case no_file_logicalname:
- doBuildExprFileLogicalName(ctx, expr, tgt);
- return;
- case no_getresult:
- case no_workunit_dataset:
- doBuildExprGetResult(ctx, expr, tgt);
- return;
- case no_getgraphresult:
- doBuildExprGetGraphResult(ctx, expr, tgt, FormatNatural);
- return;
- case no_regex_find:
- case no_regex_replace:
- doBuildExprRegexFindReplace(ctx, expr, tgt);
- return;
- case no_skip:
- case no_assert:
- {
- buildStmt(ctx, expr);
- OwnedHqlExpr null = createNullExpr(expr);
- buildExpr(ctx, null, tgt);
- return;
- }
- case no_matched:
- case no_matchtext:
- case no_matchlength:
- case no_matchposition:
- case no_matchunicode:
- case no_matchutf8:
- doBuildMatched(ctx, NULL, expr, &tgt);
- return;
- case no_matchattr:
- doBuildMatchAttr(ctx, NULL, expr, &tgt);
- return;
- case no_rowdiff:
- doBuildExprRowDiff(ctx, expr, tgt);
- return;
- case no_xmltext:
- doBuildExprXmlText(ctx, expr, tgt);
- return;
- case no_xmlunicode:
- doBuildExprXmlUnicode(ctx, expr, tgt);
- return;
- case no_evalonce:
- doBuildEvalOnce(ctx, NULL, expr, &tgt);
- return;
- case no_alias:
- doBuildExprAlias(ctx, expr, &tgt);
- return;
- case no_alias_scope:
- {
- expandAliasScope(ctx, expr);
- buildExpr(ctx, expr->queryChild(0), tgt);
- return;
- }
- case no_between:
- case no_notbetween:
- {
- OwnedHqlExpr between = expandBetween(expr);
- buildExpr(ctx, between, tgt);
- return;
- }
- case no_libraryinput:
- doBuildAliasValue(ctx, expr, tgt);
- return;
- case no_externalcall:
- case no_call:
- doBuildExprCall(ctx, expr, tgt);
- return;
- case no_comma:
- case no_compound:
- buildStmt(ctx, expr->queryChild(0));
- buildExpr(ctx, expr->queryChild(1), tgt);
- return;
- case no_cast:
- case no_implicitcast:
- doBuildExprCast(ctx, expr, tgt);
- return;
- case no_charlen:
- tgt.expr.setown(doBuildCharLength(ctx, expr->queryChild(0)));
- return;
- case no_add:
- doBuildExprAdd(ctx, expr, tgt);
- return;
- case no_mul:
- case no_sub:
- doBuildExprArith(ctx, expr, tgt);
- return;
- case no_abs:
- doBuildExprAbs(ctx, expr, tgt);
- return;
- case no_negate:
- doBuildExprNegate(ctx, expr, tgt);
- return;
- case no_div:
- case no_modulus:
- doBuildExprDivide(ctx, expr, tgt);
- return;
- case no_if:
- doBuildExprIf(ctx, expr, tgt);
- return;
- case no_index:
- doBuildExprIndex(ctx, expr, tgt);
- return;
- case no_list:
- doBuildExprList(ctx, expr, tgt);
- return;
- case no_all:
- doBuildExprAll(ctx, expr, tgt);
- return;
- case no_trim:
- doBuildExprTrim(ctx, expr, tgt);
- return;
- case no_intformat:
- doBuildExprFormat(intFormatId, ctx, expr, tgt);
- return;
- case no_realformat:
- doBuildExprFormat(realFormatId, ctx, expr, tgt);
- return;
- case no_exp:
- doBuildExprSysFunc(ctx, expr, tgt, clibExpId);
- return;
- case no_ln:
- doBuildExprSysFunc(ctx, expr, tgt, lnId);
- return;
- case no_sin:
- doBuildExprSysFunc(ctx, expr, tgt, sinId);
- return;
- case no_cos:
- doBuildExprSysFunc(ctx, expr, tgt, cosId);
- return;
- case no_tan:
- doBuildExprSysFunc(ctx, expr, tgt, tanId);
- return;
- case no_asin:
- doBuildExprSysFunc(ctx, expr, tgt, asinId);
- return;
- case no_acos:
- doBuildExprSysFunc(ctx, expr, tgt, acosId);
- return;
- case no_atan:
- doBuildExprSysFunc(ctx, expr, tgt, atanId);
- return;
- case no_atan2:
- doBuildExprSysFunc(ctx, expr, tgt, atan2Id);
- return;
- case no_sinh:
- doBuildExprSysFunc(ctx, expr, tgt, sinhId);
- return;
- case no_cosh:
- doBuildExprSysFunc(ctx, expr, tgt, coshId);
- return;
- case no_tanh:
- doBuildExprSysFunc(ctx, expr, tgt, tanhId);
- return;
- case no_log10:
- doBuildExprSysFunc(ctx, expr, tgt, log10Id);
- return;
- case no_power:
- doBuildExprSysFunc(ctx, expr, tgt, powerId);
- return;
- case no_fail:
- doBuildStmtFail(ctx, expr);
- tgt.expr.setown(createConstant(0));
- return;
- case no_failcode:
- doBuildExprFailCode(ctx, expr, tgt);
- return;
- case no_ordered:
- doBuildExprOrdered(ctx, expr, tgt);
- return;
- case no_random:
- doBuildExprSysFunc(ctx, expr, tgt, rtlRandomId);
- return;
- case no_rank:
- doBuildExprRank(ctx, expr, tgt);
- return;
- case no_ranked:
- doBuildExprRanked(ctx, expr, tgt);
- return;
- case no_round:
- case no_roundup:
- doBuildExprRound(ctx, expr, tgt);
- return;
- case no_sqrt:
- doBuildExprSysFunc(ctx, expr, tgt, sqrtId);
- return;
- case no_truncate:
- doBuildExprTrunc(ctx, expr, tgt);
- return;
- case no_offsetof:
- doBuildExprOffsetOf(ctx, expr, tgt);
- return;
- case no_substring:
- doBuildExprSubString(ctx, expr, tgt);
- return;
- case no_in:
- case no_notin:
- {
- if (expr->queryChild(1)->getOperator() == no_all)
- tgt.expr.setown(createConstant(op == no_in));
- else
- {
- OwnedHqlExpr optimized = querySimplifyInExpr(expr);
- if (optimized)
- {
- OwnedHqlExpr folded = foldHqlExpression(optimized);
- buildExpr(ctx, folded, tgt);
- }
- else
- buildTempExpr(ctx, expr, tgt);
- }
- return;
- }
- case no_indict:
- doBuildExprInDict(ctx, expr, tgt);
- return;
- case no_case:
- case no_choose:
- case no_concat:
- case no_crc:
- case no_hash:
- case no_hash32:
- case no_hash64:
- case no_hashmd5:
- case no_map:
- case no_order:
- case no_unicodeorder:
- case no_rejected:
- case no_which:
- case no_addsets:
- case no_createset:
- case no_catch:
- case no_failmessage:
- case no_eventname:
- case no_eventextra:
- case no_loopcounter:
- case no_toxml:
- buildTempExpr(ctx, expr, tgt);
- return;
- case no_asstring:
- case no_typetransfer:
- doBuildExprTransfer(ctx, expr, tgt);
- return;
- case no_translated:
- {
- expandTranslated(expr, tgt);
- return;
- }
- case no_eq:
- case no_ne:
- case no_le:
- case no_lt:
- case no_ge:
- case no_gt:
- if (options.expressionPeephole)
- {
- OwnedHqlExpr optimized = peepholeOptimize(ctx, expr);
- if (optimized != expr)
- {
- buildExpr(ctx, optimized, tgt);
- return;
- }
- }
- doBuildExprCompare(ctx, expr, tgt);
- return;
- case no_wuid:
- doBuildExprWuid(ctx, expr, tgt);
- return;
- case no_getenv:
- {
- OwnedHqlExpr mapped = cvtGetEnvToCall(expr);
- buildExpr(ctx, mapped, tgt);
- return;
- }
- case no_notnot:
- {
- OwnedHqlExpr castChild = ensureExprType(expr->queryChild(0), queryBoolType());
- buildExpr(ctx, castChild, tgt);
- }
- return;
- case no_not:
- {
- IHqlExpression * child = expr->queryChild(0);
- node_operator childOp = child->getOperator();
- if (((childOp == no_and) || (childOp == no_or)) && requiresTempAfterFirst(ctx, child))
- buildTempExpr(ctx, expr, tgt);
- else
- doBuildExprNot(ctx, expr, tgt);
- return;
- }
- case no_constant:
- {
- ITypeInfo * type = expr->queryType();
- if ((options.inlineStringThreshold > 0) && (type->getSize() > options.inlineStringThreshold) && (type->getSize() != UNKNOWN_LENGTH))
- {
- IHqlExpression * literal = addBigLiteral((const char *)expr->queryValue()->queryValue(), type->getSize());
- Owned<ITypeInfo> retType = makeReferenceModifier(LINK(type));
- switch (type->getTypeCode())
- {
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- literal = createValue(no_implicitcast, LINK(retType), literal);
- break;
- }
- if (literal->queryType() != retType)
- literal = createValue(no_typetransfer, LINK(retType), literal);
- tgt.expr.setown(literal);
- }
- else
- tgt.expr.set(expr);
- return;
- }
- case no_quoted:
- case no_variable:
- tgt.expr.set(expr);
- return;
- case no_globalscope:
- if (options.regressionTest)
- throwUnexpected();
- buildExpr(ctx, expr->queryChild(0), tgt);
- return;
- case no_nothor:
- case no_nofold:
- case no_nohoist:
- case no_section:
- case no_sectioninput:
- case no_pure:
- buildExpr(ctx, expr->queryChild(0), tgt);
- return;
- case no_band:
- case no_bor:
- case no_bnot:
- case no_bxor:
- case no_lshift:
- case no_rshift:
- doBuildPureSubExpr(ctx, expr, tgt);
- return;
- //MORE: Shouldn't these be special cased?
- case no_xor:
- doBuildPureSubExpr(ctx, expr, tgt);
- return;
- case no_select:
- {
- OwnedHqlExpr aggregate = convertToSimpleAggregate(expr);
- if (aggregate && canProcessInline(&ctx, aggregate->queryChild(0)))
- {
- buildExpr(ctx, aggregate, tgt);
- return;
- }
- if (shouldEvaluateSelectAsAlias(ctx, expr))
- {
- doBuildAliasValue(ctx, expr, tgt);
- return;
- }
- Owned<IReferenceSelector> selector = buildReference(ctx, expr);
- selector->get(ctx, tgt);
- return;
- }
- case no_field:
- throwUnexpected();
- case no_is_null:
- {
- //Until we have something better in place isNull is the inverse of isValid().
- IHqlExpression * child = expr->queryChild(0);
- OwnedHqlExpr null = createValue(no_not, makeBoolType(), createValue(no_is_valid, makeBoolType(), LINK(child)));
- buildExpr(ctx, null, tgt);
- }
- return;
- case no_is_valid:
- doBuildExprIsValid(ctx, expr, tgt);
- return;
- case no_fromunicode:
- case no_tounicode:
- doBuildExprToFromUnicode(ctx, expr, tgt);
- return;
- case no_keyunicode:
- doBuildExprKeyUnicode(ctx, expr, tgt);
- return;
- case no_xmldecode:
- case no_xmlencode:
- buildTempExpr(ctx, expr, tgt);
- return;
- case no_and:
- case no_or:
- if (requiresTempAfterFirst(ctx, expr))
- buildTempExpr(ctx, expr, tgt);
- else
- doBuildPureSubExpr(ctx, expr, tgt);
- return;
- case no_assertkeyed:
- case no_assertwild:
- {
- StringBuffer s;
- throwError1(HQLERR_KeyedWildNoIndex, getExprECL(expr, s).str());
- }
- case no_assertstepped:
- {
- StringBuffer s;
- throwError1(HQLERR_SteppedNoJoin, getExprECL(expr, s).str());
- }
- case no_id2blob:
- doBuildExprIdToBlob(ctx, expr, tgt);
- return;
- case no_blob2id:
- doBuildExprBlobToId(ctx, expr, tgt);
- return;
- case no_embedbody:
- doBuildExprEmbedBody(ctx, expr, &tgt);
- return;
- case no_null:
- tgt.length.setown(getSizetConstant(0));
- tgt.expr.setown(createValue(no_nullptr, makeReferenceModifier(expr->getType())));
- return;
- case no_clustersize:
- doBuildExprSysFunc(ctx, expr, tgt, getClusterSizeId);
- return;
- case no_deref:
- //Untested
- buildExpr(ctx, expr->queryChild(0), tgt);
- if (tgt.expr->getOperator() == no_address)
- tgt.expr.setown(createValue(no_typetransfer, expr->getType(), LINK(tgt.expr->queryChild(0))));
- else
- tgt.expr.setown(createValue(no_deref, expr->getType(), LINK(tgt.expr)));
- return;
- case no_funcdef:
- tgt.expr.setown(doBuildInternalFunction(expr));
- useFunction(tgt.expr);
- return;
- case no_purevirtual:
- case no_internalselect:
- {
- //This shouldn't happen we should have an no_checkconcrete wrapper inserted into the tree like checkconstant,
- //but it currently can in obscure library contexts (e.g., library3ie2.xhql)
- IAtom * name = expr->queryName();
- throwError1(HQLERR_ConcreteMemberRequired, name ? name->str() : "");
- }
- case NO_AGGREGATEGROUP:
- throwError1(HQLERR_OutsideGroupAggregate, getOpString(op));
- default:
- break;
- }
- EclIR::dbglogIR(expr);
- StringBuffer msg;
- msg.append("Unexpected operator '").append(getOpString(op)).append("' in: HqlCppTranslator::buildExpr(");
- toECL(expr, msg, true);
- // expr->toString(msg);
- msg.append(")");
- throw MakeStringException(HQLERR_UnexpectedOperator, "%s", msg.str());
- doBuildPureSubExpr(ctx, expr, tgt);
- }
- void HqlCppTranslator::buildExprOrAssign(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * tgt)
- {
- if (target)
- buildExprAssign(ctx, *target, expr);
- else if (tgt)
- buildExpr(ctx, expr, *tgt);
- else
- buildStmt(ctx, expr);
- }
- bool HqlCppTranslator::specialCaseBoolReturn(BuildCtx & ctx, IHqlExpression * expr)
- {
- if (!options.optimizeBoolReturn)
- return false;
- if ((expr->getOperator() == no_and) && (unwoundCount(expr, no_and) <= MAX_NESTED_CASES))
- return true;
- if (expr->getOperator() == no_not)
- expr = expr->queryChild(0);
- if (!requiresTemp(ctx, expr, true))
- return false;
- if (expr->getOperator() == no_alias_scope)
- expr = expr->queryChild(0);
- if (expr->getOperator() == no_compound)
- expr = expr->queryChild(1);
- if ((expr->getOperator() == no_and) || (expr->getOperator() == no_or))
- return true;
- return false;
- }
- void HqlCppTranslator::buildReturn(BuildCtx & ctx, IHqlExpression * expr, ITypeInfo * retType)
- {
- ITypeInfo * exprType = expr->queryType();
- if (!retType) retType = exprType;
- expr = queryExpandAliasScope(ctx, expr);
- node_operator op = expr->getOperator();
- type_t returntc = retType->getTypeCode();
- if ((retType->getSize() == UNKNOWN_LENGTH) && (returntc == type_varstring))
- {
- if (hasConstModifier(retType) && (hasConstModifier(exprType) || expr->queryValue()))
- {
- OwnedHqlExpr cast = ensureExprType(expr, retType);
- CHqlBoundExpr ret;
- buildCachedExpr(ctx, cast, ret);
- ctx.setNextDestructor();
- ctx.addReturn(ret.expr);
- }
- else
- {
- if (hasConstModifier(retType))
- {
- IIdAtom * funcAtom;
- if (expr->queryType()->getTypeCode()==type_varstring)
- funcAtom = cloneVStringId;
- else
- funcAtom = cloneVStringXId;
- HqlExprArray args;
- args.append(*LINK(expr));
- OwnedHqlExpr call = bindFunctionCall(funcAtom, args);
- CHqlBoundExpr ret;
- buildExpr(ctx, call, ret);
- ctx.addReturn(ret.expr);
- return;
- }
- CHqlBoundTarget retVar;
- retVar.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
- buildExprAssign(ctx, retVar, expr);
- ctx.setNextDestructor();
- StringBuffer s;
- retVar.expr->toString(s);
- switch (retType->getTypeCode())
- {
- case type_varstring:
- s.append(".detachstr()");
- break;
- case type_varunicode:
- s.append(".detachustr()");
- break;
- default:
- UNIMPLEMENTED;
- }
- OwnedHqlExpr temp = createQuoted(s.str(), LINK(exprType));
- ctx.addReturn(temp);
- }
- }
- else if ((returntc == type_row) && hasLinkCountedModifier(retType))
- {
- CHqlBoundTarget result;
- buildTempExpr(ctx, ctx, result, expr, FormatNatural, false);
- //MORE: There should be a cleaner way of doing this
- StringBuffer s;
- result.expr->toString(s);
- s.append(".getClear()");
- OwnedHqlExpr temp = createQuoted(s.str(), LINK(exprType));
- ctx.addReturn(temp);
- }
- else if ((returntc == type_table) && hasStreamedModifier(retType))
- {
- CHqlBoundTarget result;
- buildTempExpr(ctx, ctx, result, expr, FormatStreamedDataset, false);
- //MORE: There should be a cleaner way of doing this
- StringBuffer s;
- result.expr->toString(s);
- s.append(".getClear()");
- OwnedHqlExpr temp = createQuoted(s.str(), LINK(exprType));
- ctx.addReturn(temp);
- }
- else if ((returntc == type_boolean) && specialCaseBoolReturn(ctx, expr))
- {
- bool successValue = true;
- if (op == no_not)
- {
- //!(a and b) is converted into !a || !b. Otherwise just invert the test condition.
- IHqlExpression * child = expr->queryChild(0);
- if (child->getOperator() == no_alias_scope)
- child = child->queryChild(0);
- if (child->getOperator() != no_and)
- {
- successValue = false;
- expr = expr->queryChild(0);
- }
- }
- BuildCtx condctx(ctx);
- buildFilteredReturn(condctx, expr, queryBoolExpr(successValue));
- buildReturn(ctx, queryBoolExpr(!successValue));
- }
- else if (op == no_if)
- {
- OwnedHqlExpr castTrue = ensureExprType(expr->queryChild(1), retType);
- OwnedHqlExpr castFalse = ensureExprType(expr->queryChild(2), retType);
- BuildCtx condctx(ctx);
- buildFilter(condctx, expr->queryChild(0));
- buildReturn(condctx, castTrue);
- buildReturn(ctx, castFalse);
- }
- else if (op == no_map || op == no_case)
- {
- HqlCppCaseInfo info(*this);
- doBuildCaseInfo(expr, info);
- info.buildReturn(ctx);
- }
- else
- {
- CHqlBoundExpr ret;
- OwnedHqlExpr castExpr = ensureExprType(expr, retType);
- buildExpr(ctx, castExpr, ret);
- ctx.addReturn(ret.expr);
- }
- }
- //Assumes that the value being returned is simple.
- //for (a || b || c) gen if (a) return x; if (b) return x; if (c) return x;
- //and !(a && b && c) -> !a || !b || !c
- void HqlCppTranslator::buildFilteredReturn(BuildCtx & ctx, IHqlExpression * filter, IHqlExpression * value)
- {
- filter = queryExpandAliasScope(ctx, filter);
- HqlExprArray conds;
- node_operator op = filter->getOperator();
- if (op == no_or)
- {
- buildFilteredReturn(ctx, filter->queryChild(0), value);
- buildFilteredReturn(ctx, filter->queryChild(1), value);
- return;
- }
- if (op == no_not)
- {
- IHqlExpression * child = filter->queryChild(0);
- node_operator childOp = child->getOperator();
- if (childOp == no_and)
- {
- child->unwindList(conds, no_and);
- ForEachItemIn(i, conds)
- {
- IHqlExpression & cur = conds.item(i);
- OwnedHqlExpr inverse = getInverse(&cur);
- buildFilteredReturn(ctx, inverse, value);
- }
- return;
- }
- if (childOp == no_alias_scope)
- {
- expandAliasScope(ctx, child);
- OwnedHqlExpr inverse = getInverse(child->queryChild(0));
- buildFilteredReturn(ctx, inverse, value);
- return;
- }
- }
- BuildCtx condctx(ctx);
- buildFilter(condctx, filter);
- if (value)
- buildReturn(condctx, value);
- else
- condctx.addReturn(NULL);
- }
- void HqlCppTranslator::buildStmt(BuildCtx & _ctx, IHqlExpression * expr)
- {
- BuildCtx ctx(_ctx);
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_assign:
- doBuildStmtAssign(ctx, expr->queryChild(0), expr->queryChild(1));
- return;
- case no_assign_addfiles:
- doBuildStmtAssignModify(ctx, expr->queryChild(0), expr->queryChild(1), op);
- return;
- case no_alias:
- doBuildExprAlias(ctx, expr, NULL);
- return;
- case no_alias_scope:
- {
- expandAliasScope(ctx, expr);
- buildStmt(ctx, expr->queryChild(0));
- return;
- }
- case no_assignall:
- {
- unsigned idx;
- unsigned kids = expr->numChildren();
- for (idx = 0; idx < kids; idx++)
- buildStmt(ctx, expr->queryChild(idx));
- return;
- }
- case no_comma:
- case no_compound:
- buildStmt(ctx, expr->queryChild(0));
- buildStmt(ctx, expr->queryChild(1));
- return;
- case no_if:
- doBuildStmtIf(ctx, expr);
- return;
- case no_call:
- case no_externalcall:
- doBuildStmtCall(ctx, expr);
- return;
- case no_nofold:
- case no_nohoist:
- case no_nothor:
- case no_section:
- case no_sectioninput:
- buildStmt(ctx, expr->queryChild(0));
- return;
- case no_null:
- return;
- case no_fail:
- doBuildStmtFail(ctx, expr);
- return;
- case no_setmeta:
- return;
- case no_update:
- doBuildStmtUpdate(ctx, expr);
- return;
- case no_output:
- if (queryRealChild(expr, 1))
- throwError1(HQLERR_NotSupportedInsideNoThor, "OUTPUT to file");
- doBuildStmtOutput(ctx, expr);
- return;
- case no_subgraph:
- doBuildThorChildSubGraph(ctx, expr, SubGraphRoot);
- return;
- case no_thor:
- doBuildThorGraph(ctx, expr);
- return;
- case no_workflow_action:
- return;
- case no_ensureresult:
- doBuildStmtEnsureResult(ctx, expr);
- return;
- case no_extractresult:
- case no_setresult:
- doBuildStmtSetResult(ctx, expr);
- return;
- case no_parallel:
- case no_sequential:
- case no_actionlist:
- case no_orderedactionlist:
- {
- ForEachChild(idx, expr)
- {
- BuildCtx subctx(ctx);
- //Add a group for each branch of a sequential to ensure all branches are independent
- if (op == no_sequential)
- subctx.addGroup();
- buildStmt(subctx, expr->queryChild(idx));
- }
- return;
- }
- case no_wait:
- doBuildStmtWait(ctx, expr);
- return;
- case no_notify:
- doBuildStmtNotify(ctx, expr);
- return;
- case no_skip:
- doBuildStmtSkip(ctx, expr, NULL);
- return;
- case no_assert:
- doBuildStmtAssert(ctx, expr);
- return;
- case no_embedbody:
- doBuildExprEmbedBody(ctx, expr, NULL);
- return;
- case no_setworkflow_cond:
- {
- HqlExprArray args;
- args.append(*LINK(expr->queryChild(0)));
- buildFunctionCall(ctx, setWorkflowConditionId, args);
- return;
- }
- case no_apply:
- doBuildStmtApply(ctx, expr);
- return;
- case no_cluster:
- doBuildStmtCluster(ctx, expr);
- return;
- case no_choose:
- doBuildChoose(ctx, NULL, expr);
- return;
- case no_persist_check:
- buildWorkflowPersistCheck(ctx, expr);
- return;
- case no_childquery:
- buildChildGraph(ctx, expr);
- return;
- case no_evaluate_stmt:
- expr = expr->queryChild(0);
- if (expr->queryValue())
- return;
- break; // evaluate default behaviour.
- }
- CHqlBoundExpr tgt;
- buildAnyExpr(ctx, expr, tgt);
- ctx.addExpr(tgt.expr);
- tidyupExpr(ctx, tgt);
- }
- class AliasExpansionInfo
- {
- public:
- void pushCondition(IHqlExpression * expr, unsigned branch) { conditions.append(*createAttribute(branchAtom, LINK(expr), getSizetConstant(branch))); }
- void popCondition() { conditions.pop(); }
- void popConditions(unsigned num) { conditions.popn(num); }
- bool isConditional() { return conditions.ordinality() != 0; }
- IHqlExpression * createConditionIntersection(IHqlExpression * prev)
- {
- if (conditions.ordinality() == 0)
- return NULL;
- if (!prev)
- return createValueSafe(no_sortlist, makeSortListType(NULL), conditions);
- unsigned maxPrev = prev->numChildren();
- unsigned max = maxPrev;
- if (max > conditions.ordinality())
- max = conditions.ordinality();
- for (unsigned i=0; i < max; i++)
- {
- if (&conditions.item(i) != prev->queryChild(i))
- {
- if (i == 0)
- return NULL;
- return createValueSafe(no_sortlist, makeSortListType(NULL), conditions, 0, i);
- }
- }
- if (max == maxPrev)
- return LINK(prev);
- return createValueSafe(no_sortlist, makeSortListType(NULL), conditions);
- }
- HqlExprArray conditions;
- };
- void HqlCppTranslator::doExpandAliases(BuildCtx & ctx, IHqlExpression * expr, AliasExpansionInfo & info)
- {
- IHqlExpression * prev = static_cast<IHqlExpression *>(expr->queryTransformExtra());
- if (prev == expr)
- return;
- #ifdef USE_NEW_ALIAS_CODE
- OwnedHqlExpr commonPath = info.createConditionIntersection(prev);
- if (prev == commonPath)
- return;
- if (commonPath)
- expr->setTransformExtra(commonPath);
- else
- expr->setTransformExtraUnlinked(expr);
- node_operator op = expr->getOperator();
- switch (op)
- {
- //MORE: Anything that creates a child query shouldn't be included here...
- case no_select:
- case NO_AGGREGATE:
- case no_alias_scope:
- break;
- case no_alias:
- {
- IHqlExpression * value = expr->queryChild(0);
- if ((commonPath == NULL) && !ctx.queryMatchExpr(value))
- {
- if (containsAliasLocally(value) && !expr->hasAttribute(globalAtom))
- doExpandAliases(ctx, value, info);
- doBuildExprAlias(ctx, expr, NULL);
- }
- break;
- }
- case no_and:
- case no_or:
- {
- HqlExprArray args;
- expr->unwindList(args, op);
- doExpandAliases(ctx, &args.item(0), info);
- unsigned max = args.ordinality();
- for (unsigned i=1; i < max; i++)
- {
- info.pushCondition(expr, i);
- doExpandAliases(ctx, &args.item(i), info);
- }
- info.popConditions(max-1);
- break;
- }
- case no_if:
- {
- doExpandAliases(ctx, expr->queryChild(0), info);
- info.pushCondition(expr, 1);
- doExpandAliases(ctx, expr->queryChild(1), info);
- info.popCondition();
- info.pushCondition(expr, 2);
- doExpandAliases(ctx, expr->queryChild(2), info);
- info.popCondition();
- break;
- }
- case no_case:
- {
- doExpandAliases(ctx, expr->queryChild(0), info);
- unsigned max = expr->numChildren();
- for (unsigned i=1; i < max-1; i++)
- {
- info.pushCondition(expr, i*2);
- doExpandAliases(ctx, expr->queryChild(i)->queryChild(0), info);
- info.popCondition();
- info.pushCondition(expr, i*2+1);
- doExpandAliases(ctx, expr->queryChild(i)->queryChild(1), info);
- info.popCondition();
- }
- info.pushCondition(expr, (max-1)*2);
- doExpandAliases(ctx, expr->queryChild(max-1), info);
- info.popCondition();
- break;
- }
- case no_map:
- {
- //The following is equivalent to old, code; I'm not sure it is the best implementation
- unsigned max = expr->numChildren();
- for (unsigned i=0; i < max-1; i++)
- {
- info.pushCondition(expr, i*2);
- doExpandAliases(ctx, expr->queryChild(i)->queryChild(0), info);
- info.popCondition();
- info.pushCondition(expr, i*2+1);
- doExpandAliases(ctx, expr->queryChild(i)->queryChild(1), info);
- info.popCondition();
- }
- info.pushCondition(expr, (max-1)*2);
- doExpandAliases(ctx, expr->queryChild(max-1), info);
- info.popCondition();
- break;
- }
- default:
- if (containsAliasLocally(expr))
- {
- ForEachChild(i, expr)
- doExpandAliases(ctx, expr->queryChild(i), info);
- }
- break;
- }
- #else
- expr->setTransformExtraUnlinked(expr);
- node_operator op = expr->getOperator();
- switch (op)
- {
- //MORE: Anything that creates a child query shouldn't be included here...
- case no_select:
- case NO_AGGREGATE:
- case no_alias_scope:
- break;
- case no_alias:
- {
- doBuildExprAlias(ctx, expr, NULL);
- break;
- }
- default:
- if (containsAliasLocally(expr))
- {
- ForEachChild(i, expr)
- doExpandAliases(ctx, expr->queryChild(i), info);
- }
- break;
- }
- #endif
- }
- void HqlCppTranslator::expandAliases(BuildCtx & ctx, IHqlExpression * expr)
- {
- if (containsAliasLocally(expr))
- {
- TransformMutexBlock block;
- AliasExpansionInfo info;
- doExpandAliases(ctx, expr, info);
- }
- }
- void HqlCppTranslator::expandAliasScope(BuildCtx & ctx, IHqlExpression * expr)
- {
- TransformMutexBlock block;
- AliasExpansionInfo info;
- unsigned max = expr->numChildren();
- for (unsigned idx = 1; idx < max; idx++)
- {
- IHqlExpression * child = expr->queryChild(idx);
- if (containsAliasLocally(child))
- doExpandAliases(ctx, child, info);
- }
- }
- //------------------------------------------------------------------------------
- void HqlCppTranslator::gatherActiveCursors(BuildCtx & ctx, HqlExprCopyArray & activeRows)
- {
- AssociationIterator iter(ctx);
- ForEach(iter)
- {
- HqlExprAssociation & cur = iter.get();
- if (cur.isRowAssociation())
- {
- BoundRow & curRow = static_cast<BoundRow &>(cur);
- if ((curRow.querySide() != no_self) && !curRow.isBuilder())
- activeRows.append(*curRow.querySelector());
- }
- else if (cur.represents->getOperator() == no_counter)
- activeRows.append(*cur.represents);
- }
- }
- bool HqlCppTranslator::canEvaluateInContext(BuildCtx & ctx, IHqlExpression * expr)
- {
- HqlExprCopyArray cursors;
- gatherActiveCursors(ctx, cursors);
- return ::canEvaluateInScope(cursors, expr);
- }
- bool mustEvaluateInContext(BuildCtx & ctx, IHqlExpression * expr)
- {
- HqlExprCopyArray required;
- expr->gatherTablesUsed(NULL, &required);
- if (required.ordinality() == 0)
- return false;
- HqlExprCopyArray activeRows;
- HqlExprCopyArray inheritedRows;
- RowAssociationIterator iter(ctx);
- ForEach(iter)
- {
- BoundRow & cur = iter.get();
- if ((cur.querySide() != no_self) && !cur.isBuilder())
- {
- IHqlExpression * selector = cur.querySelector();
- if (cur.isInherited())
- inheritedRows.append(*selector);
- else
- activeRows.append(*selector);
- }
- }
- //Ensure all instances of activeRows which match the inherited rows are removed
- ForEachItemInRev(i, activeRows)
- {
- if (inheritedRows.find(activeRows.item(i)))
- activeRows.remove(i);
- }
- return canEvaluateInScope(activeRows, required);
- }
- bool filterIsTableInvariant(IHqlExpression * expr)
- {
- IHqlExpression * dsSelector = expr->queryChild(0)->queryNormalizedSelector();
- ForEachChildFrom(i, expr, 1)
- {
- IHqlExpression * cur = expr->queryChild(i);
- if (containsSelector(cur, dsSelector))
- return false;
- }
- return true;
- }
- //-----------------------------------------------------------------------------
- bool LoopInvariantHelper::getBestContext(BuildCtx & ctx, IHqlExpression * expr)
- {
- finished();
- active = ctx.selectBestContext(expr);
- return (active != NULL);
- }
- void LoopInvariantHelper::finished()
- {
- if (active)
- {
- active->mergeScopeWithContainer();
- active = NULL;
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::buildBlockCopy(BuildCtx & ctx, IHqlExpression * tgt, CHqlBoundExpr & src)
- {
- OwnedHqlExpr size = getBoundSize(src);
- if (!size->queryValue() || size->queryValue()->getIntValue() != 0)
- {
- HqlExprArray args;
- args.append(*getPointer(tgt));
- args.append(*getPointer(src.expr));
- args.append(*size.getClear());
- callProcedure(ctx, memcpyId, args);
- }
- }
- void HqlCppTranslator::buildSimpleExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- node_operator op = expr->getOperator();
- bool simple = false;
- switch (op)
- {
- case no_alias_scope:
- {
- expandAliasScope(ctx, expr);
- buildSimpleExpr(ctx, expr->queryChild(0), tgt);
- return;
- }
- case no_preservemeta:
- buildSimpleExpr(ctx, expr->queryChild(0), tgt);
- return;
- case no_constant:
- case no_variable:
- case no_getresult: // gets forced into a variable.
- case no_workunit_dataset: // gets forced into a variable.
- case no_getgraphresult: // gets forced into a variable.
- case no_alias:
- case no_list:
- case no_all:
- case no_null:
- case no_id2blob:
- case no_rows:
- case no_libraryinput:
- simple = true;
- break;
- case no_compound:
- buildStmt(ctx, expr->queryChild(0));
- buildSimpleExpr(ctx, expr->queryChild(1), tgt);
- return;
- case no_field:
- throwUnexpected();
- case no_select:
- {
- CHqlBoundExpr bound;
- buildCachedExpr(ctx, expr, bound);
- if (isSimpleTranslatedExpr(bound.expr))
- tgt.set(bound);
- else
- {
- OwnedHqlExpr trans = bound.getTranslatedExpr();
- buildTempExpr(ctx, trans, tgt);
- }
- return;
- }
- break; // should depend on whether conditional etc....
- case no_translated:
- simple = isSimpleTranslatedExpr(expr->queryChild(0));
- break;
- case no_substring:
- {
- SubStringInfo info(expr);
- if (info.canGenerateInline() || expr->hasAttribute(quickAtom))
- simple = true;
- break;
- }
- case no_cast:
- case no_implicitcast:
- {
- //special case casting a string to (string) - saves lots of temporaries.
- ITypeInfo * exprType = expr->queryType();
- IHqlExpression * child = expr->queryChild(0);
- ITypeInfo * childType = child->queryType();
- if ((exprType->getTypeCode() == type_string) && (exprType->getSize() == UNKNOWN_LENGTH))
- {
- if ((childType->getTypeCode() == type_string) && (exprType->queryCharset() == childType->queryCharset()))
- {
- buildSimpleExpr(ctx, child, tgt);
- return;
- }
- }
- if (options.foldConstantCast && (child->getOperator() == no_constant))
- simple = true;
- break;
- }
- case no_sizeof:
- case no_offsetof:
- simple = true;
- break;
- case no_regex_find:
- simple = expr->isBoolean();
- break;
- case no_call:
- case no_externalcall:
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_set:
- simple = true;
- break;
- case type_string:
- case type_data:
- case type_qstring:
- if (type->getSize() == UNKNOWN_LENGTH)
- simple = true;
- break;
- }
- }
- }
- if (simple)
- buildCachedExpr(ctx, expr, tgt);
- else
- buildTempExpr(ctx, expr, tgt);
- }
- IHqlExpression * HqlCppTranslator::buildSimplifyExpr(BuildCtx & ctx, IHqlExpression * expr)
- {
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_constant:
- case no_all:
- case no_null:
- return LINK(expr);
- case no_list:
- if (expr->isConstant())
- return LINK(expr);
- break;
- }
- CHqlBoundExpr bound;
- buildSimpleExpr(ctx, expr, bound);
- return bound.getTranslatedExpr();
- }
- /* In type: not linked. Return: linked */
- IHqlExpression * HqlCppTranslator::createWrapperTemp(BuildCtx & ctx, ITypeInfo * type, typemod_t modifier)
- {
- Linked<ITypeInfo> rawType = queryUnqualifiedType(type);
- if (hasStreamedModifier(type))
- rawType.setown(setStreamedAttr(rawType, true));
- else if (hasLinkCountedModifier(type))
- rawType.setown(makeAttributeModifier(rawType.getClear(), getLinkCountedAttr()));
- Owned<ITypeInfo> declType = makeWrapperModifier(rawType.getClear());
- declType.setown(makeModifier(declType.getClear(), modifier));
- switch (declType->getTypeCode())
- {
- case type_set: //needed if we have sets with link counted elements
- case type_row:
- case type_array:
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- //Ensure row and dataset temporaries are active throughout a function, so pointers to the row
- //or rows within a dataset remain valid (e.g., outside conditions).
- if ((modifier != typemod_member) && ctx.queryMatchExpr(queryConditionalRowMarker()))
- ctx.setNextPriority(BuildCtx::OutermostScopePrio);
- break;
- }
- return ctx.getTempDeclare(declType, NULL);
- }
- void HqlCppTranslator::createTempFor(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundTarget & target)
- {
- createTempFor(ctx, expr->queryType(), target, typemod_none, FormatNatural);
- }
- void HqlCppTranslator::createTempFor(BuildCtx & ctx, ITypeInfo * _exprType, CHqlBoundTarget & target, typemod_t modifier, ExpressionFormat format)
- {
- Owned<ITypeInfo> exprType = makeModifier(LINK(_exprType->queryPromotedType()), modifier);
- type_t tc = exprType->getTypeCode();
- switch (tc)
- {
- case type_array:
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- {
- if (format == FormatStreamedDataset || hasStreamedModifier(exprType))
- {
- }
- else
- {
- if (recordRequiresLinkCount(::queryRecord(exprType)) || hasLinkCountedModifier(_exprType))
- {
- assertex(format != FormatBlockedDataset);
- format = FormatLinkedDataset;
- }
- else if (format == FormatNatural)
- format = FormatLinkedDataset;
- }
- break;
- }
- }
- switch (format)
- {
- case FormatBlockedDataset:
- exprType.setown(setLinkCountedAttr(exprType, false));
- break;
- case FormatLinkedDataset:
- case FormatArrayDataset:
- exprType.setown(setLinkCountedAttr(exprType, true));
- break;
- case FormatStreamedDataset:
- exprType.setown(setStreamedAttr(exprType, true));
- break;
- case FormatNatural:
- if (hasStreamedModifier(exprType))
- format = FormatStreamedDataset;
- else if (hasLinkCountedModifier(exprType))
- format = FormatLinkedDataset;
- else
- format = FormatBlockedDataset;
- break;
- }
- size32_t size = exprType->getSize();
- if (size == UNKNOWN_LENGTH)
- {
- switch (tc)
- {
- case type_string:
- case type_data:
- case type_qstring:
- case type_unicode:
- case type_utf8:
- {
- OwnedITypeInfo lenType = makeModifier(LINK(sizetType), modifier);
- target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
- target.length.setown(ctx.getTempDeclare(lenType, NULL));
- break;
- }
- case type_varstring:
- case type_varunicode:
- {
- target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
- break;
- }
- case type_set:
- case type_array:
- case type_table:
- case type_groupedtable:
- case type_dictionary:
- break;
- default:
- {
- UNIMPLEMENTED;
- break;
- }
- }
- }
- else if (size > MAX_SIMPLE_VAR_SIZE)
- {
- switch (tc)
- {
- case type_string:
- case type_data:
- case type_qstring:
- case type_unicode:
- case type_varstring:
- case type_varunicode:
- case type_utf8:
- {
- target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
- break;
- }
- }
- }
- switch (tc)
- {
- case type_set:
- {
- OwnedITypeInfo isAllType = makeModifier(LINK(boolType), modifier);
- target.isAll.setown(ctx.getTempDeclare(isAllType, NULL));
- }
- //fall through
- case type_array:
- case type_table:
- case type_groupedtable:
- case type_dictionary:
- {
- OwnedITypeInfo lenType = makeModifier(LINK(sizetType), modifier);
- target.expr.setown(createWrapperTemp(ctx, exprType, modifier));
- if (!hasStreamedModifier(exprType))
- {
- if (isArrayRowset(exprType))
- {
- //A bit of a hack, but the cleanest I could come up with... really access to the count member should be wrapped in
- //member functions, but getting them created needs a whole new level of complication (probably moving out out of hqlwcpp)
- StringBuffer name;
- target.expr->toString(name).append(".count");
- target.count.setown(createVariable(name, LINK(lenType)));
- }
- else
- target.length.setown(ctx.getTempDeclare(lenType, NULL));
- break;
- }
- }
- }
- if (!target.expr)
- {
- target.expr.setown(ctx.getTempDeclare(exprType, NULL));
- }
- }
- void HqlCppTranslator::buildTempExpr(BuildCtx & ctx, BuildCtx & declareCtx, CHqlBoundTarget & tempTarget, IHqlExpression * expr, ExpressionFormat format, bool ignoreSetAll)
- {
- if (options.addLocationToCpp)
- {
- IHqlExpression * location = queryLocation(expr);
- if (location)
- {
- StringBuffer s;
- s.append("// ").append(location->querySourcePath()->str()).append("(").append(location->getStartLine()).append(",").append(location->getStartColumn()).append(") ").append(expr->queryName());
- ctx.addQuoted(s);
- }
- else if (expr->queryName())
- {
- StringBuffer s;
- s.append("// ").append(expr->queryName());
- ctx.addQuoted(s);
- }
- }
- typemod_t modifier = (&ctx != &declareCtx) ? typemod_member : typemod_none;
- OwnedITypeInfo type = makeModifier(expr->getType(), modifier);
- BuildCtx subctx(ctx);
- switch (type->getTypeCode())
- {
- case type_row:
- {
- Owned<BoundRow> tempRow = declareTempRow(declareCtx, subctx, expr);
- buildRowAssign(subctx, tempRow, expr);
- tempTarget.expr.set(tempRow->queryBound());
- ctx.associate(*tempRow);
- break;
- }
- break;
- case type_table:
- case type_groupedtable:
- case type_dictionary:
- {
- createTempFor(declareCtx, type, tempTarget, modifier, format);
- IHqlStmt * stmt = subctx.addGroup();
- stmt->setIncomplete(true);
- buildDatasetAssign(subctx, tempTarget, expr);
- stmt->setIncomplete(false);
- stmt->mergeScopeWithContainer();
- break;
- }
- default:
- {
- createTempFor(declareCtx, type, tempTarget, modifier, format);
- if (ignoreSetAll)
- tempTarget.isAll.clear();
- IHqlStmt * stmt = subctx.addGroup();
- stmt->setIncomplete(true);
- buildExprAssign(subctx, tempTarget, expr);
- stmt->setIncomplete(false);
- stmt->mergeScopeWithContainer();
- break;
- }
- }
- }
- void HqlCppTranslator::buildTempExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ExpressionFormat format)
- {
- node_operator op = expr->getOperator();
- if (op == no_alias)
- {
- doBuildExprAlias(ctx, expr, &tgt);
- return;
- }
- if (isCast(expr))
- {
- ITypeInfo * exprType = expr->queryType();
- if (exprType->getStringLen() == UNKNOWN_LENGTH)
- {
- unsigned bestLen = getBestLengthEstimate(expr);
- if (bestLen != UNKNOWN_LENGTH)
- {
- IHqlExpression * uncast = expr->queryChild(0);
- Owned<ITypeInfo> stretchedType = getStretchedType(bestLen, exprType);
- OwnedHqlExpr castExpr = ensureExprType(uncast, stretchedType);
- buildTempExpr(ctx, castExpr, tgt, format);
- ctx.associateExpr(expr, tgt);
- return;
- }
- }
- }
- BuildCtx bestctx(ctx);
- if (expr->isPure() && ctx.getMatchExpr(expr, tgt))
- return;
- switch (expr->getOperator())
- {
- case no_variable:
- tgt.expr.set(expr);
- return;
- case no_translated:
- {
- if (!expr->queryChild(1))
- {
- IHqlExpression * value = expr->queryChild(0);
- if (value->getOperator() == no_variable)
- {
- tgt.expr.set(value);
- return;
- }
- }
- break;
- }
- case no_id2blob:
- buildExpr(ctx, expr, tgt);
- return;
- case no_call:
- if (!isEmbedCall(expr))
- break;
- //fall through
- case no_externalcall:
- if (format == FormatNatural && expr->isDataset())
- {
- ITypeInfo * exprType = expr->queryType();
- if (hasStreamedModifier(exprType))
- format = FormatStreamedDataset;
- else if (hasLinkCountedModifier(exprType) || hasOutOfLineModifier(exprType))
- format = FormatLinkedDataset;
- else
- format = FormatBlockedDataset;
- }
- break;
- }
- LoopInvariantHelper helper;
- if (options.optimizeLoopInvariant)
- helper.getBestContext(bestctx, expr);
- bool canBeAll = canSetBeAll(expr);
- CHqlBoundTarget tempTarget;
- buildTempExpr(bestctx, bestctx, tempTarget, expr, format, !canBeAll);
- tgt.setFromTarget(tempTarget);
- bestctx.associateExpr(expr, tgt);
- }
- void HqlCppTranslator::buildExprViaTypedTemp(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ITypeInfo * type)
- {
- OwnedHqlExpr cast = createValue(no_implicitcast, LINK(type), LINK(expr));
- if (cast->isPure() && ctx.getMatchExpr(cast, tgt))
- return;
- LoopInvariantHelper helper;
- BuildCtx bestctx(ctx);
- if (options.optimizeLoopInvariant)
- helper.getBestContext(bestctx, expr);
- CHqlBoundTarget tempTarget;
- createTempFor(bestctx, type, tempTarget, typemod_none, FormatNatural);
- buildExprAssign(bestctx, tempTarget, expr);
- tgt.setFromTarget(tempTarget);
- if (cast->isPure())
- bestctx.associateExpr(cast, tgt);
- }
- void HqlCppTranslator::buildExprEnsureType(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, ITypeInfo * type)
- {
- if (queryUnqualifiedType(expr->queryType()) != queryUnqualifiedType(type))
- buildExprViaTypedTemp(ctx, expr, tgt, type);
- else
- buildExpr(ctx, expr, tgt);
- }
- AliasKind HqlCppTranslator::doBuildAliasValue(BuildCtx & ctx, IHqlExpression * value, CHqlBoundExpr & tgt)
- {
- //can happen when this is called for non no_alias arguments
- if (value->getOperator() == no_alias)
- value = value->queryChild(0);
- EvalContext * instance = queryEvalContext(ctx);
- if (instance)
- return instance->evaluateExpression(ctx, value, tgt, true);
- expandAliases(ctx, value);
- buildTempExpr(ctx, value, tgt);
- return RuntimeAlias;
- }
- void HqlCppTranslator::doBuildExprAlias(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * tgt)
- {
- //MORE These will be declared in a different context later.
- IHqlExpression * value = expr->queryChild(0);
- while (value->getOperator() == no_alias)
- value = value->queryChild(0);
- CHqlBoundExpr bound;
- if (!tgt)
- tgt = &bound;
- //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.
- //so far on my examples it does the latter, but doesn't seem to cause the former
- if (expr->hasAttribute(localAtom) || (insideOnCreate(ctx) && !expr->hasAttribute(globalAtom)))
- {
- expandAliases(ctx, value);
- switch (value->getOperator())
- {
- // these operations generate temporaries anyway, and the row versions are inefficient via a buildTempExpr
- case no_getresult:
- case no_getgraphresult:
- case no_getgraphloopresult:
- buildAnyExpr(ctx, value, *tgt);
- break;
- default:
- buildTempExpr(ctx, value, *tgt);
- break;
- }
- }
- else
- {
- doBuildAliasValue(ctx, value, *tgt);
- }
- }
- void HqlCppTranslator::doBuildBoolAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- if (requiresTemp(ctx, expr, true))
- {
- BuildCtx subctx(ctx);
- assignBound(subctx, target, queryBoolExpr(false));
- buildFilter(subctx, expr);
- assignBound(subctx, target, queryBoolExpr(true));
- }
- else
- {
- CHqlBoundExpr temp;
- buildCachedExpr(ctx, expr, temp);
- assign(ctx, target, temp);
- }
- }
- void HqlCppTranslator::doBuildExprAssign(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- CHqlBoundExpr temp;
- buildExpr(ctx, expr, temp);
- assign(ctx, target, temp);
- }
- void HqlCppTranslator::ensureSimpleExpr(BuildCtx & ctx, CHqlBoundExpr & tgt)
- {
- if (!isSimpleTranslatedExpr(tgt.expr))
- {
- OwnedHqlExpr bound = tgt.getTranslatedExpr();
- buildTempExpr(ctx, bound, tgt);
- }
- }
- IHqlExpression * HqlCppTranslator::ensureSimpleTranslatedExpr(BuildCtx & ctx, IHqlExpression * expr)
- {
- if (isSimpleTranslatedExpr(expr))
- return LINK(expr);
- OwnedHqlExpr translated = createTranslated(expr);
- CHqlBoundExpr bound;
- buildTempExpr(ctx, translated, bound);
- return LINK(bound.expr);
- }
- void HqlCppTranslator::ensureHasAddress(BuildCtx & ctx, CHqlBoundExpr & tgt)
- {
- IHqlExpression * expr = tgt.expr;
- node_operator op = expr->getOperator();
- switch (op)
- {
- case no_deref:
- case no_variable:
- break;
- default:
- if (!isTypePassedByAddress(expr->queryType()))
- {
- OwnedHqlExpr bound = tgt.getTranslatedExpr();
- buildTempExpr(ctx, bound, tgt);
- }
- break;
- }
- }
- //---------------------------------------------------------------------------
- bool optimizeVarStringCompare(node_operator op, const CHqlBoundExpr & lhs, const CHqlBoundExpr & rhs, CHqlBoundExpr & tgt)
- {
- IHqlExpression * rhsExpr = rhs.expr;
- if ((rhsExpr->getOperator() == no_constant) && (rhsExpr->queryType()->getStringLen() == 0))
- {
- if ((op == no_eq) || (op == no_ne))
- {
- tgt.expr.setown(createValue(op, LINK(boolType), createValue(no_deref, makeCharType(), lhs.expr.getLink()), getZero()));
- return true;
- }
- }
- return false;
- }
- void HqlCppTranslator::doBuildExprSetCompareAll(BuildCtx & ctx, IHqlExpression * set, CHqlBoundExpr & tgt, bool invert)
- {
- Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, set);
- cursor->buildIsAll(ctx, tgt);
- if (invert)
- tgt.expr.setown(getInverse(tgt.expr));
- }
- void HqlCppTranslator::doBuildExprSetCompareNone(BuildCtx & ctx, IHqlExpression * set, CHqlBoundExpr & tgt, bool invert)
- {
- Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, set);
- cursor->buildExists(ctx, tgt);
- if (!invert)
- tgt.expr.setown(getInverse(tgt.expr));
- }
- bool HqlCppTranslator::doBuildExprSetCompare(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- //Special case comparison against all and null set. All other work goes through a the order code.
- node_operator exprOp = expr->getOperator();
- if ((exprOp == no_eq) || (exprOp == no_ne))
- {
- OwnedHqlExpr left = normalizeListCasts(expr->queryChild(0));
- OwnedHqlExpr right = normalizeListCasts(expr->queryChild(1));
- if (right->getOperator() == no_all)
- doBuildExprSetCompareAll(ctx, left, tgt, exprOp==no_ne);
- else if (left->getOperator() == no_all)
- doBuildExprSetCompareAll(ctx, right, tgt, exprOp==no_ne);
- else if (isNullList(right))
- doBuildExprSetCompareNone(ctx, left, tgt, exprOp==no_ne);
- else if (isNullList(left))
- doBuildExprSetCompareNone(ctx, right, tgt, exprOp==no_ne);
- else
- return false;
- return true;
- }
- return false;
- }
- IHqlExpression * HqlCppTranslator::convertBoundStringToChar(const CHqlBoundExpr & bound)
- {
- OwnedHqlExpr element = getElementPointer(bound.expr);
- Owned<ITypeInfo> charType = makeCharType(true);
- switch (element->getOperator())
- {
- case no_constant:
- {
- IValue * value = element->queryValue();
- return createConstant(value->castTo(charType));
- }
- case no_address:
- return LINK(element->queryChild(0));
- }
- return createValue(no_deref, charType.getClear(), element.getClear());
- }
- void HqlCppTranslator::doBuildExprCompare(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * left = expr->queryChild(0);
- IHqlExpression * right = expr->queryChild(1);
- ITypeInfo * leftType = left->queryType()->queryPromotedType();
- ITypeInfo * rightType = right->queryType()->queryPromotedType();
- assertex(areTypesComparable(leftType,rightType));
- OwnedHqlExpr orderExpr;
- CHqlBoundExpr lhs, rhs;
- node_operator compareOp = expr->getOperator();
- type_t tc = leftType->getTypeCode();
- switch (tc)
- {
- case type_string:
- case type_data:
- case type_qstring:
- {
- OwnedHqlExpr simpleLeft = getSimplifyCompareArg(left);
- OwnedHqlExpr simpleRight = getSimplifyCompareArg(right);
- HqlExprArray args;
- buildCachedExpr(ctx, simpleLeft, lhs);
- buildCachedExpr(ctx, simpleRight, rhs);
- //update types - lengths may be constant by now..
- leftType = lhs.queryType();
- rightType = rhs.queryType();
- IIdAtom * func = queryStrCompareFunc(leftType);
- //MORE: Move blank string compare here?
- if (lhs.length || rhs.length || needVarStringCompare(leftType, rightType))
- {
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- if (func == compareStrStrId && isBlankString(rhs.expr))
- {
- func = compareStrBlankId;
- }
- else
- {
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- }
- orderExpr.setown(bindTranslatedFunctionCall(func, args));
- }
- else if (options.optimizeString1Compare &&
- ((tc == type_string && isAscii(leftType)) || tc == type_data) &&
- (leftType->getSize() == 1) && (rightType->getSize() == 1) &&
- ((compareOp == no_eq) || (compareOp == no_ne)))
- {
- //Optimize equality/non equality of a single character string.
- //Not done for > etc because of potential issues with signed/unsigned chars
- args.append(*convertBoundStringToChar(lhs));
- args.append(*convertBoundStringToChar(rhs));
- tgt.expr.setown(createValue(compareOp, makeBoolType(), args));
- return;
- }
- else
- {
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
- args.append(*getSizetConstant(leftType->getSize()));
-
- orderExpr.setown(bindTranslatedFunctionCall(memcmpId, args));
- }
- break;
- }
- case type_unicode:
- {
- OwnedHqlExpr simpleLeft = LINK(left);//getSimplifyCompareArg(left);
- OwnedHqlExpr simpleRight = LINK(right);//getSimplifyCompareArg(right);
- HqlExprArray args;
- buildCachedExpr(ctx, simpleLeft, lhs);
- buildCachedExpr(ctx, simpleRight, rhs);
- assertex(haveCommonLocale(leftType, rightType));
- char const * locale = getCommonLocale(leftType, rightType)->str();
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- args.append(*createConstant(locale));
- orderExpr.setown(bindTranslatedFunctionCall(compareUnicodeUnicodeId, args));
- break;
- }
- case type_varunicode:
- {
- HqlExprArray args;
- buildCachedExpr(ctx, left, lhs);
- buildCachedExpr(ctx, right, rhs);
- assertex(haveCommonLocale(leftType, rightType));
- char const * locale = getCommonLocale(leftType, rightType)->str();
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
- args.append(*createConstant(locale));
- orderExpr.setown(bindTranslatedFunctionCall(compareVUnicodeVUnicodeId, args));
- break;
- }
- case type_utf8:
- {
- OwnedHqlExpr simpleLeft = LINK(left);//getSimplifyCompareArg(left);
- OwnedHqlExpr simpleRight = LINK(right);//getSimplifyCompareArg(right);
- HqlExprArray args;
- buildCachedExpr(ctx, simpleLeft, lhs);
- buildCachedExpr(ctx, simpleRight, rhs);
- assertex(haveCommonLocale(leftType, rightType));
- char const * locale = getCommonLocale(leftType, rightType)->str();
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- args.append(*createConstant(locale));
- orderExpr.setown(bindTranslatedFunctionCall(compareUtf8Utf8Id, args));
- break;
- }
- case type_varstring:
- {
- HqlExprArray args;
- buildCachedExpr(ctx, left, lhs);
- buildCachedExpr(ctx, right, rhs);
- //optimize comparison against null string.
- if (optimizeVarStringCompare(compareOp, lhs, rhs, tgt) || optimizeVarStringCompare(compareOp, rhs, lhs, tgt))
- return;
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
-
- orderExpr.setown(bindTranslatedFunctionCall(compareVStrVStrId, args));
- break;
- }
- case type_decimal:
- {
- HqlExprArray args;
- buildCachedExpr(ctx, left, lhs);
- buildCachedExpr(ctx, right, rhs);
- if (!isPushed(lhs) && !isPushed(rhs) && isSameBasicType(lhs.queryType(), rhs.queryType()))
- {
- args.append(*getSizetConstant(leftType->getSize()));
- args.append(*getPointer(lhs.expr));
- args.append(*getPointer(rhs.expr));
- orderExpr.setown(bindTranslatedFunctionCall(leftType->isSigned() ? DecCompareDecimalId : DecCompareUDecimalId, args));
- }
- else
- {
- bool pushedLhs = ensurePushed(ctx, lhs);
- bool pushedRhs = ensurePushed(ctx, rhs);
- //NB: Arguments could be pushed in opposite order 1 <=> x *2
- if (pushedLhs && !pushedRhs)
- orderExpr.setown(bindTranslatedFunctionCall(DecDistinctRId, args));
- else
- orderExpr.setown(bindTranslatedFunctionCall(DecDistinctId, args));
- }
- break;
- }
- case type_set:
- case type_array:
- {
- if (doBuildExprSetCompare(ctx, expr, tgt))
- return;
- //fallthrough....
- }
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- case type_row:
- case type_record:
- {
- IHqlExpression * orderExpr = createValue(no_order, LINK(signedType), LINK(left), LINK(right));
- OwnedHqlExpr cmpExpr = createBoolExpr(compareOp, orderExpr, createConstant(signedType->castFrom(true, 0)));
- buildExpr(ctx, cmpExpr, tgt);
- return;
- }
- case type_swapint:
- case type_packedint:
- {
- Owned<ITypeInfo> type = makeIntType(leftType->getSize(), leftType->isSigned());
- IHqlExpression * intLeft = createValue(no_implicitcast, type.getLink(), LINK(left));
- IHqlExpression * intRight = createValue(no_implicitcast, type.getLink(), LINK(right));
- OwnedHqlExpr transformed = createValue(compareOp, makeBoolType(), intLeft, intRight);
- doBuildPureSubExpr(ctx, transformed, tgt);
- return;
- }
- default:
- doBuildPureSubExpr(ctx, expr, tgt);
- return;
- }
- tgt.expr.setown(createValue(compareOp, LINK(boolType), LINK(orderExpr), createConstant(orderExpr->queryType()->castFrom(true, 0))));
- }
- //---------------------------------------------------------------------------
- //-- no_and --
- void HqlCppTranslator::doBuildFilterToTarget(BuildCtx & ctx, const CHqlBoundTarget & isOk, HqlExprArray & conds, bool invert)
- {
- LinkedHqlExpr test = isOk.expr;
- if (invert)
- test.setown(getInverse(test));
- unsigned max = conds.ordinality();
- unsigned curIndex = 0;
- for (unsigned outer =0; curIndex < max; outer += MAX_NESTED_CASES)
- {
- BuildCtx subctx(ctx);
- if (outer != 0)
- subctx.addFilter(test);
- buildExprAssign(subctx, isOk, queryBoolExpr(invert)); // if(!invert,false,true) => invert
- doBuildFilterNextAndRange(subctx, curIndex, MAX_NESTED_CASES, conds);
- buildExprAssign(subctx, isOk, queryBoolExpr(!invert)); // if(!invert,true,false) => !invert
- }
- }
- void HqlCppTranslator::doBuildFilterAnd(BuildCtx & ctx, IHqlExpression * expr)
- {
- HqlExprArray conds;
- expr->unwindList(conds, no_and);
- //Estimate the depth generated by the conditions - it may be wrong because
- //aliases generated in outer levels can stop temporaries being required later.
- unsigned numConds = conds.ordinality();
- unsigned depthEstimate = 1;
- for (unsigned i=1; i < numConds; i++)
- if (requiresTemp(ctx, &conds.item(i), true))
- depthEstimate++;
- if (depthEstimate < MAX_NESTED_CASES)
- {
- unsigned curIndex = 0;
- doBuildFilterNextAndRange(ctx, curIndex, numConds, conds);
- }
- else
- {
- CHqlBoundTarget isOk;
- createTempFor(ctx, expr, isOk);
- doBuildFilterToTarget(ctx, isOk, conds, false);
- ctx.addFilter(isOk.expr);
- }
- }
- void HqlCppTranslator::doBuildFilterNextAndRange(BuildCtx & ctx, unsigned & curIndex, unsigned maxIterations, HqlExprArray & conds)
- {
- unsigned max = conds.ordinality();
- for (unsigned i=0; (i < maxIterations) && (curIndex != max); i++)
- {
- unsigned last;
- expandAliases(ctx, &conds.item(curIndex));
- for (last = curIndex+1; last < max; last++)
- if (requiresTemp(ctx, &conds.item(last), true))
- break;
- doBuildFilterAndRange(ctx, curIndex, last, conds);
- curIndex = last;
- }
- }
- void HqlCppTranslator::doBuildFilterAndRange(BuildCtx & ctx, unsigned first, unsigned last, HqlExprArray & conds)
- {
- if (first+1 == last)
- buildFilter(ctx, &conds.item(first));
- else
- {
- HqlExprArray args;
- for (unsigned k = first; k < last; k++)
- args.append(OLINK(conds.item(k)));
- OwnedHqlExpr test = createValue(no_and, makeBoolType(), args);
- buildFilterViaExpr(ctx, test);
- }
- }
- void HqlCppTranslator::doBuildAssignAnd(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, bool invert)
- {
- HqlExprArray conds;
- expr->unwindList(conds, no_and);
- doBuildFilterToTarget(ctx, target, conds, invert);
- }
- void HqlCppTranslator::doBuildAssignOr(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- BuildCtx subctx(ctx);
- HqlExprArray conds;
- expr->unwindList(conds, no_or);
- unsigned first = 0;
- unsigned max = conds.ordinality();
- while (first < max)
- {
- unsigned last = first+1;
- //special case no_in because it always creates a temporary, so may as well assign on its own
- if (conds.item(first).getOperator() != no_in)
- {
- for (; last < max; last++)
- {
- IHqlExpression & cur = conds.item(last);
- if ((cur.getOperator() == no_in) || requiresTemp(subctx, &cur, true))
- break;
- }
- }
- if (first != 0 || last != max)
- {
- if (last != first+1)
- {
- OwnedHqlExpr left = createBalanced(no_or, queryBoolType(), conds, first, last);
- doBuildExprAssign(subctx, target, left);
- }
- else
- buildExprAssign(subctx, target, &conds.item(first));
- if (last != max)
- {
- OwnedHqlExpr inverse = getInverse(target.expr);
- subctx.addFilter(inverse);
- }
- }
- else
- {
- doBuildExprAssign(subctx, target, expr);
- }
- first = last;
- }
- }
- //---------------------------------------------------------------------------
- //-- no_case --
- void HqlCppTranslator::doBuildCaseInfo(IHqlExpression * expr, HqlCppCaseInfo & info)
- {
- unsigned maxMaps = expr->numChildren()-1;
- unsigned index = 0;
- if (expr->getOperator() == no_case)
- {
- info.setCond(expr->queryChild(0));
- index++;
- }
-
- for (;index<maxMaps;index++)
- info.addPair(expr->queryChild(index));
- info.setDefault(expr->queryChild(maxMaps));
- }
- void HqlCppTranslator::doBuildInCaseInfo(IHqlExpression * expr, HqlCppCaseInfo & info, IHqlExpression * normalized)
- {
- bool valueIfMatch = (expr->getOperator() == no_in);
- HqlExprArray args;
- LinkedHqlExpr values = normalized;
- if (!normalized)
- values.setown(normalizeListCasts(expr->queryChild(1)));
- info.setCond(expr->queryChild(0));
- cvtInListToPairs(args, values, valueIfMatch);
- info.addPairs(args);
- info.setDefault(queryBoolExpr(!valueIfMatch));
- }
- void HqlCppTranslator::doBuildAssignInStored(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- OwnedHqlExpr values = normalizeListCasts(expr->queryChild(1));
- CHqlBoundExpr bound;
- if (values->isPure())
- ctx.getMatchExpr(values, bound);
- if (options.optimizeLoopInvariant && !bound.expr)
- {
- if (values->getOperator() == no_createset)
- {
- IHqlExpression * ds = values->queryChild(0);
- //MORE: This is a special case - it should check if the dataset can be iterated without any projection
- switch (ds->getOperator())
- {
- case no_select:
- case no_rows:
- break;
- default:
- {
- //Evaluate the dataset into a temporary - the iterator will match it up later
- //Evaluating the dataset instead of the set since this is likely to avoid a memcpy with link counted rows enabled.
- LoopInvariantHelper helper;
- BuildCtx bestctx(ctx);
- if (helper.getBestContext(bestctx, ds))
- {
- CHqlBoundExpr temp;
- buildTempExpr(ctx, ds, temp);
- }
- break;
- }
- }
- }
- else
- {
- LoopInvariantHelper helper;
- BuildCtx bestctx(ctx);
- if (helper.getBestContext(bestctx, values))
- {
- //Unfortunately this will do strength reduction again, but shouldn't take too long.
- buildTempExpr(bestctx, values, bound);
- }
- }
- }
- if (bound.expr)
- values.setown(bound.getTranslatedExpr());
- bool valueIfMatch = (expr->getOperator() == no_in);
- ITypeInfo * elementType = values->queryType()->queryChildType();
- Owned<ITypeInfo> compareType = getPromotedECLCompareType(expr->queryChild(0)->queryType(), elementType);
- CHqlBoundExpr boundSearch;
- OwnedHqlExpr castSearch = ensureExprType(expr->queryChild(0), compareType);
- BuildCtx subctx(ctx);
- Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, values);
- CHqlBoundExpr isAll;
- cursor->buildIsAll(ctx, isAll);
- if (isAll.expr->queryValue())
- {
- if (isAll.expr->queryValue()->getBoolValue())
- {
- buildExprAssign(subctx, target, queryBoolExpr(valueIfMatch));
- //If this inverted the test we would need to do more.
- return;
- }
- }
- else
- {
- IHqlStmt * stmt = subctx.addFilter(isAll.expr);
- buildExprAssign(subctx, target, queryBoolExpr(valueIfMatch));
- subctx.selectElse(stmt);
- }
- //result = false/true
- buildSimpleExpr(subctx, castSearch, boundSearch);
- buildExprAssign(subctx, target, queryBoolExpr(!valueIfMatch));
-
- //iterate through the set
- bool needToBreak = !cursor->isSingleValued();
- CHqlBoundExpr boundCurElement;
- cursor->buildIterateLoop(subctx, boundCurElement, needToBreak);
- OwnedHqlExpr curElement = boundCurElement.getTranslatedExpr();
- OwnedHqlExpr castCurElement = ensureExprType(curElement, compareType);
- //if match then
- OwnedHqlExpr matchTest = createValue(no_eq, makeBoolType(), boundSearch.getTranslatedExpr(), LINK(castCurElement));
- buildFilter(subctx, matchTest);
- //result = true/false + break loop.
- buildExprAssign(subctx, target, queryBoolExpr(valueIfMatch));
- if (needToBreak)
- subctx.addBreak();
- }
- void HqlCppTranslator::doBuildAssignInCreateSet(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- IHqlExpression * setExpr = expr->queryChild(1);
- IHqlExpression * dataset = setExpr->queryChild(0);
- IHqlExpression * selected = setExpr->queryChild(1);
- bool valueIfMatch = (expr->getOperator() == no_in);
- ITypeInfo * elementType = setExpr->queryType()->queryChildType();
- Owned<ITypeInfo> compareType = getPromotedECLCompareType(expr->queryChild(0)->queryType(), elementType);
- CHqlBoundExpr boundSearch;
- OwnedHqlExpr castSearch = ensureExprType(expr->queryChild(0), compareType);
- //result = false/true
- buildSimpleExpr(ctx, castSearch, boundSearch);
- buildExprAssign(ctx, target, queryBoolExpr(!valueIfMatch));
-
- //iterate through the set
- bool needToBreak = !hasNoMoreRowsThan(dataset, 1);
- BuildCtx loopctx(ctx);
- buildDatasetIterate(loopctx, dataset, needToBreak);
- //if match then
- OwnedHqlExpr matchTest = createValue(no_eq, makeBoolType(), boundSearch.getTranslatedExpr(), ensureExprType(selected, compareType));
- buildFilter(loopctx, matchTest);
- //result = true/false + break loop.
- buildExprAssign(loopctx, target, queryBoolExpr(valueIfMatch));
- if (needToBreak)
- loopctx.addBreak();
- }
- void HqlCppTranslator::doBuildAssignIn(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- OwnedHqlExpr values = normalizeListCasts(expr->queryChild(1));
- node_operator op = expr->getOperator();
- bool valueIfMatch = (op == no_in);
- switch (values->getOperator())
- {
- case no_all:
- buildExprAssign(ctx, target, queryBoolExpr(valueIfMatch));
- break;
- case no_null:
- buildExprAssign(ctx, target, queryBoolExpr(!valueIfMatch));
- break;
- case no_list:
- {
- HqlCppCaseInfo info(*this);
- doBuildInCaseInfo(expr, info, values);
- info.buildAssign(ctx, target);
- break;
- }
- case no_createset:
- {
- //Look further at bug #52745.eclxml and what causes the poor code.
- //if (canIterateInline(&ctx, values->queryChild(0)))
- // doBuildAssignInCreateSet(ctx, target, expr);
- //else
- doBuildAssignInStored(ctx, target, expr);
- break;
- }
- #if 0
- //Possible optimizations, but I don't have any examples that would trigger them, so don't enable
- case no_if:
- {
- BuildCtx subctx(ctx);
- OwnedHqlExpr inLhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(1)));
- OwnedHqlExpr inRhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(2)));
- IHqlStmt * stmt = buildFilterViaExpr(subctx, values->queryChild(0));
- buildExprAssign(subctx, target, inLhs);
- subctx.selectElse(stmt);
- buildExprAssign(subctx, target, inRhs);
- break;
- }
- case no_addsets:
- if (op == no_in)
- {
- BuildCtx subctx(ctx);
- OwnedHqlExpr inLhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(0)));
- OwnedHqlExpr inRhs = createValue(expr->getOperator(), LINK(expr->queryChild(0)), LINK(values->queryChild(1)));
- buildExprAssign(ctx, target, inLhs);
- OwnedHqlExpr test = getInverse(target.expr);
- subctx.addFilter(test);
- buildExprAssign(subctx, target, inRhs);
- break;
- }
- #endif
- //fall through
- default:
- doBuildAssignInStored(ctx, target, expr);
- break;
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprInDict(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression *dict = expr->queryChild(1);
- Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dict);
- cursor->buildInDataset(ctx, expr, tgt);
- }
- void HqlCppTranslator::doBuildExprCountDict(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression *dict = expr->queryChild(0);
- Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dict);
- cursor->buildCountDict(ctx, tgt); // not the same as buildCount - that is the size of the table, we want the number of populated entries
- }
- void HqlCppTranslator::doBuildExprExistsDict(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression *dict = expr->queryChild(0);
- Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(ctx, dict);
- cursor->buildExistsDict(ctx, tgt);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprArith(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_decimal:
- {
- bindAndPush(ctx, expr->queryChild(0));
- bindAndPush(ctx, expr->queryChild(1));
-
- HqlExprArray args;
- IIdAtom * func;
- switch (expr->getOperator())
- {
- case no_add:
- func = DecAddId;
- break;
- case no_div:
- func = DecDivideId;
- args.append(*getSizetConstant(options.divideByZeroAction));
- break;
- case no_modulus:
- func = DecModulusId;
- args.append(*getSizetConstant(options.divideByZeroAction));
- break;
- case no_mul:
- func = DecMulId;
- break;
- case no_sub:
- func = DecSubId;
- break;
- default: UNIMPLEMENTED;
- }
- callProcedure(ctx, func, args);
- tgt.expr.setown(createValue(no_decimalstack, LINK(type)));
- }
- break;
- case type_swapint:
- case type_packedint:
- {
- //someone is being deliberately perverse....
- ITypeInfo * type = expr->queryType();
- ITypeInfo * intType = makeIntType(type->getSize(), type->isSigned());
- IHqlExpression * lhs = expr->queryChild(0);
- IHqlExpression * rhs = expr->queryChild(1);
- assertex(isSameBasicType(type, lhs->queryType()));
- assertex(isSameBasicType(type, rhs->queryType()));
- lhs = createValue(no_implicitcast, LINK(intType), LINK(lhs));
- rhs = createValue(no_implicitcast, LINK(intType), LINK(rhs));
- IHqlExpression * newExpr = createValue(expr->getOperator(), intType, lhs, rhs);
- OwnedHqlExpr castNewExpr = createValue(no_implicitcast, LINK(type), newExpr);
- buildExpr(ctx, castNewExpr, tgt);
- break;
- }
- default:
- doBuildPureSubExpr(ctx, expr, tgt);
- break;
- }
- }
- void HqlCppTranslator::doBuildExprAdd(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (expr->queryType()->getTypeCode() != type_int)
- {
- doBuildExprArith(ctx, expr, tgt);
- return;
- }
- CHqlBoundExpr boundL, boundR;
- buildExpr(ctx, expr->queryChild(0), boundL);
- bool WORK_AROUND_GCC_CONDITION_BUG = (options.targetCompiler == GccCppCompiler);
- if (WORK_AROUND_GCC_CONDITION_BUG && expr->queryChild(1)->getOperator() == no_if)
- buildTempExpr(ctx, expr->queryChild(1), boundR);
- else
- buildExpr(ctx, expr->queryChild(1), boundR);
- tgt.expr.setown(adjustBoundIntegerValues(boundL.expr, boundR.expr, false));
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprNegate(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_decimal:
- {
- bindAndPush(ctx, expr->queryChild(0));
- HqlExprArray args;
- callProcedure(ctx, DecNegateId, args);
- tgt.expr.setown(createValue(no_decimalstack, LINK(type)));
- }
- break;
- case type_data:
- case type_qstring:
- case type_string:
- case type_varstring:
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- throwError(HQLERR_MinusOnString);
- default:
- doBuildPureSubExpr(ctx, expr, tgt);
- break;
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprRound(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * arg = expr->queryChild(0);
- node_operator op = expr->getOperator();
- switch (arg->queryType()->getTypeCode())
- {
- case type_decimal:
- {
- bindAndPush(ctx, arg);
- HqlExprArray args;
- if (op == no_round)
- {
- IHqlExpression * places = queryRealChild(expr, 1);
- if (places)
- {
- args.append(*LINK(places));
- callProcedure(ctx, DecRoundToId, args);
- }
- else
- callProcedure(ctx, DecRoundId, args);
- }
- else
- callProcedure(ctx, DecRoundUpId, args);
- assertex(expr->queryType()->getTypeCode() == type_decimal);
- tgt.expr.setown(createValue(no_decimalstack, expr->getType()));
- }
- break;
- default:
- {
- if (op == no_round)
- {
- if (queryRealChild(expr, 1))
- doBuildExprSysFunc(ctx, expr, tgt, roundToId);
- else
- doBuildExprSysFunc(ctx, expr, tgt, roundId);
- }
- else
- doBuildExprSysFunc(ctx, expr, tgt, roundupId);
- break;
- }
- }
- }
- void HqlCppTranslator::doBuildExprTrunc(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * arg = expr->queryChild(0);
- switch (arg->queryType()->getTypeCode())
- {
- case type_decimal:
- {
- bindAndPush(ctx, arg);
- HqlExprArray args;
- callProcedure(ctx, DecTruncateId, args);
- assertex(expr->queryType()->getTypeCode() == type_decimal);
- tgt.expr.setown(createValue(no_decimalstack, expr->getType()));
- }
- break;
- default:
- {
- doBuildExprSysFunc(ctx, expr, tgt, truncateId);
- break;
- }
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprAbs(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_decimal:
- {
- bindAndPush(ctx, expr->queryChild(0));
-
- HqlExprArray args;
- IIdAtom * func = DecAbsId;
- callProcedure(ctx, func, args);
- tgt.expr.setown(createValue(no_decimalstack, LINK(type)));
- }
- break;
- case type_int:
- case type_swapint:
- case type_packedint:
- case type_real:
- {
- CHqlBoundExpr temp;
- buildTempExpr(ctx, expr->queryChild(0), temp);
- ITypeInfo * type = expr->getType();
- IHqlExpression * cond = createValue(no_ge, makeBoolType(), temp.expr.getLink(), createConstant(type->castFrom(true, 0)));
- tgt.expr.setown(createValue(no_if, type, cond, temp.expr.getLink(), createValue(no_negate, LINK(type), temp.expr.getLink())));
- }
- break;
- default:
- buildExpr(ctx, expr->queryChild(0), tgt);
- break;
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildAssignCatch(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- BuildCtx subctx(ctx);
- subctx.addGroup();
- BuildCtx tryctx(subctx);
- tryctx.addQuotedCompound("try");
- buildExprAssign(tryctx, target, expr->queryChild(0));
- BuildCtx catchctx(subctx);
- catchctx.addQuotedCompound("catch (IException * e)");
- IHqlExpression * exceptVar = associateLocalFailure(catchctx, "e");
- buildExprAssign(catchctx, target, expr->queryChild(1));
- HqlExprArray args;
- args.append(*LINK(exceptVar));
- callProcedure(catchctx, freeExceptionId, args);
- }
- //---------------------------------------------------------------------------
- //-- no_externalcall --
- IHqlExpression * getCastParameter(IHqlExpression * curParam, ITypeInfo * argType)
- {
- type_t atc = argType->getTypeCode();
- //Remove a few unnecessary casts which clutter up the code/or make it less efficient
- if (isCast(curParam) && (curParam->queryType() == argType))
- {
- //If the following code is incorrect, the casts should get added back by the code that follows
- IHqlExpression * uncast = curParam->queryChild(0);
- //casts to larger size integers
- if (atc == type_int)
- curParam = uncast;
- else if ((atc == type_unicode) && (uncast->queryType()->getTypeCode() == type_varunicode))
- curParam = uncast;
- else if ((atc == type_string) && (uncast->queryType()->getTypeCode() == type_varstring))
- curParam = uncast;
- }
- ITypeInfo * paramType = curParam->queryType();
- type_t ptc = paramType->getTypeCode();
- if ((atc != ptc) && !(atc == type_row && ptc == type_table))
- {
- switch (atc)
- {
- case type_unicode:
- if ((argType->getSize() == UNKNOWN_LENGTH) && (ptc == type_varunicode))
- return LINK(curParam);
- break;
- case type_string:
- if ((argType->getSize() == UNKNOWN_LENGTH) &&
- ((ptc == type_varstring) && (argType->queryCharset() == paramType->queryCharset())))
- return LINK(curParam);
- break;
- case type_dictionary:
- case type_row:
- case type_table:
- case type_groupedtable:
- {
- IHqlExpression * record = queryRecord(argType);
- if (record && (record->numChildren() != 0))
- {
- //really need to project instead.
- //return ensureExprType(curParam, argType);
- }
- return LINK(curParam);
- }
- }
- return ensureExprType(curParam, argType);
- }
- ITypeInfo * childType = argType->queryChildType();
- if (paramType->queryTypeBase() != argType)
- {
- size32_t argSize = argType->getSize();
- switch (atc)
- {
- case type_int:
- case type_real:
- if (argSize <= paramType->getSize())
- return ensureExprType(curParam, argType);
- break;
- case type_decimal:
- //Don't need explicit cast to cast between different sizes of these types...
- //Will be done automatically by the compiler.
- break;
- case type_unicode:
- //Don't need cast between different locales
- if ((argSize != paramType->getSize()) && (argSize != UNKNOWN_LENGTH))
- {
- Owned<ITypeInfo> modArgType = makeUnicodeType(argType->getStringLen(), curParam->queryType()->queryLocale());
- return ensureExprType(curParam, modArgType);
- }
- break;
- case type_varunicode:
- //Don't need cast between different locales
- if(argSize != paramType->getSize())
- {
- Owned<ITypeInfo> modArgType = makeVarUnicodeType(argType->getStringLen(), curParam->queryType()->queryLocale());
- return ensureExprType(curParam, modArgType);
- }
- break;
- case type_utf8:
- //Don't need cast between different locales
- if(argSize != paramType->getSize())
- {
- Owned<ITypeInfo> modArgType = makeUtf8Type(argType->getStringLen(), curParam->queryType()->queryLocale());
- return ensureExprType(curParam, modArgType);
- }
- break;
- case type_set:
- if (childType)
- return ensureExprType(curParam, argType);
- break;
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- case type_row:
- {
- IHqlExpression * record = queryRecord(argType);
- if (record && (record->numChildren() != 0))
- {
- //really need to project instead.
- //return ensureExprType(curParam, argType);
- }
- break;
- }
- default:
- return ensureExprType(curParam, argType);
- }
- }
- // if (argType->queryCharset() != paramType->queryCharset())
- // return ensureExprType(curParam, argType);
- return LINK(curParam);
- }
- void HqlCppTranslator::normalizeBoundExpr(BuildCtx & ctx, CHqlBoundExpr & bound)
- {
- bound.expr.setown(convertWrapperToPointer(bound.expr));
- }
- IHqlExpression * HqlCppTranslator::doBuildInternalFunction(IHqlExpression * funcdef)
- {
- unsigned match = internalFunctions.find(*funcdef);
- if (match != NotFound)
- return LINK(&internalFunctionExternals.item(match));
- OwnedHqlExpr externalFuncdef = createExternalFuncdefFromInternal(funcdef);
- internalFunctions.append(*LINK(funcdef));
- internalFunctionExternals.append(*LINK(externalFuncdef));
- buildFunctionDefinition(funcdef);
- return LINK(externalFuncdef);
- }
- void HqlCppTranslator::doBuildCall(BuildCtx & ctx, const CHqlBoundTarget * tgt, IHqlExpression * expr, CHqlBoundExpr * result)
- {
- if (result && expr->isPure() && ctx.getMatchExpr(expr, *result))
- return;
- LinkedHqlExpr funcdef;
- if (expr->getOperator() == no_externalcall)
- {
- funcdef.set(expr->queryExternalDefinition());
- assertex(funcdef != NULL);
- useFunction(funcdef);
- }
- else
- {
- IHqlExpression * def = expr->queryBody()->queryFunctionDefinition();
- assertex(def && def->getOperator() == no_funcdef);
- funcdef.setown(doBuildInternalFunction(def));
- }
- IHqlExpression * external = funcdef->queryChild(0);
- IHqlExpression * formals = funcdef->queryChild(1);
- if (external->hasAttribute(ctxmethodAtom))
- ensureContextAvailable(ctx);
- if (external->hasAttribute(gctxmethodAtom) || external->hasAttribute(globalContextAtom))
- {
- if (!ctx.queryMatchExpr(globalContextMarkerExpr))
- throwError1(HQLERR_FuncNotInGlobalContext, external->queryName()->str());
- }
- unsigned maxArg = formals->numChildren();
- unsigned maxParam = expr->numChildren();
- bool returnByReference = false;
- bool returnMustAssign = false;
- HqlExprArray args;
- unsigned arg = 0;
- unsigned param;
- unsigned firstParam = 0;
- bool isMethod = external->hasAttribute(methodAtom) || external->hasAttribute(omethodAtom) ;
- bool newFormatSet = !external->hasAttribute(oldSetFormatAtom);
- bool translateSetReturn = false;
- if (isMethod)
- {
- CHqlBoundExpr bound;
- buildExpr(ctx, expr->queryChild(firstParam++), bound);
- args.append(*bound.expr.getClear());
- }
- if (external->hasAttribute(userMatchFunctionAtom))
- {
- //MORE: Test valid in this location...
- args.append(*createVariable("walker", makeBoolType()));
- }
- IHqlExpression * extendAttr = external->queryAttribute(extendAtom);
- bool doneAssign = false;
- CHqlBoundExpr localBound;
- CHqlBoundTarget localTarget;
- Linked<BoundRow> resultRow;
- Linked<BoundRow> resultRowBuilder;
- Owned<ITypeInfo> targetType = tgt ? LINK(tgt->queryType()) : makeVoidType();
- ITypeInfo * retType = funcdef->queryType()->queryChildType();
- BoundRow * resultSelfCursor = NULL;
- switch (retType->getTypeCode())
- {
- case type_varstring:
- case type_varunicode:
- if (retType->getSize() == UNKNOWN_LENGTH)
- {
- if (hasConstModifier(retType))
- break;
- returnMustAssign = true;
- if (tgt && !tgt->isFixedSize())
- {
- doneAssign = true;
- localBound.expr.set(tgt->expr);
- }
- else
- localBound.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
- break;
- }
- else
- {
- //fixed size strings => just pass pointer
- IHqlExpression * resultVar = ctx.getTempDeclare(retType, NULL);
- args.append(*getElementPointer(resultVar));
- localBound.expr.setown(resultVar);
- }
- returnByReference = true;
- break;
- case type_string:
- case type_data:
- case type_qstring:
- case type_unicode:
- case type_utf8:
- if (retType->getSize() == UNKNOWN_LENGTH)
- {
- OwnedHqlExpr lenVar;
- OwnedHqlExpr strVar;
- if (tgt && !tgt->isFixedSize())
- {
- doneAssign = true;
- strVar.set(tgt->expr);
- lenVar.set(tgt->length);
- }
- else
- {
- strVar.setown(createWrapperTemp(ctx, retType, typemod_none));
- lenVar.setown(ctx.getTempDeclare(sizetType, NULL));
- }
- args.append(*LINK(lenVar));
- args.append(*createValue(no_reference, strVar->getType(), LINK(strVar), LINK(extendAttr)));
- localBound.length.set(lenVar);
- localBound.expr.set(strVar);
- }
- else
- {
- //fixed size strings => just pass pointer
- if (tgt && tgt->isFixedSize() && targetType->queryPromotedType() == retType)
- {
- doneAssign = true;
- args.append(*getElementPointer(tgt->expr));
- localBound.expr.set(tgt->expr);
- }
- else
- {
- IHqlExpression * resultVar = ctx.getTempDeclare(retType, NULL);
- args.append(*getElementPointer(resultVar));
- localBound.expr.setown(resultVar);
- }
- }
- returnByReference = true;
- break;
- case type_set:
- {
- translateSetReturn = !newFormatSet;
- OwnedHqlExpr lenVar;
- OwnedHqlExpr strVar;
- OwnedHqlExpr isAll;
- if (tgt && !tgt->isFixedSize())
- {
- doneAssign = true;
- strVar.set(tgt->expr);
- if (translateSetReturn)
- lenVar.setown(ctx.getTempDeclare(unsignedType, NULL));
- else
- lenVar.set(tgt->length);
- assertex(tgt->isAll != NULL);
- isAll.set(tgt->isAll);
- }
- else
- {
- Owned<ITypeInfo> dataType = makeDataType(UNKNOWN_LENGTH);
- strVar.setown(createWrapperTemp(ctx, dataType, typemod_none));
- if (translateSetReturn)
- {
- lenVar.setown(ctx.getTempDeclare(unsignedType, NULL));
- }
- else
- {
- lenVar.setown(ctx.getTempDeclare(sizetType, NULL));
- isAll.setown(ctx.getTempDeclare(boolType, NULL));
- }
- }
- if (newFormatSet)
- args.append(*LINK(isAll));
- args.append(*LINK(lenVar));
- args.append(*createValue(no_reference, strVar->getType(), LINK(strVar)));
- if (newFormatSet)
- {
- localBound.length.set(lenVar);
- }
- else
- {
- localBound.count.set(lenVar);
- if (isAll && !isAll->queryValue())
- ctx.addAssign(isAll, queryBoolExpr(false));
- }
- localBound.isAll.set(isAll);
- localBound.expr.setown(createValue(no_implicitcast, makeReferenceModifier(LINK(retType)), LINK(strVar)));
- returnByReference = true;
- break;
- }
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- {
- if (hasStreamedModifier(retType))
- {
- if (getBoolAttribute(external, allocatorAtom, true))
- args.append(*createRowAllocator(ctx, ::queryRecord(retType)));
- returnMustAssign = true;
- if (tgt && hasStreamedModifier(targetType) && recordTypesMatch(targetType, retType))
- {
- doneAssign = true;
- localBound.expr.set(tgt->expr);
- }
- else
- localBound.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
- break;
- }
- const CHqlBoundTarget * curTarget;
- if (tgt && !tgt->isFixedSize() &&
- (hasLinkCountedModifier(targetType) == hasLinkCountedModifier(retType)))
- {
- doneAssign = true;
- curTarget = tgt;
- }
- else
- {
- curTarget = &localTarget;
- ExpressionFormat format = (hasLinkCountedModifier(retType) ? FormatLinkedDataset : FormatBlockedDataset);
- createTempFor(ctx, retType, localTarget, typemod_none, format);
- }
- if (curTarget->count)
- args.append(*LINK(curTarget->count));
- if (curTarget->length)
- args.append(*LINK(curTarget->length));
- args.append(*createValue(no_reference, curTarget->expr->getType(), LINK(curTarget->expr)));
- if (hasLinkCountedModifier(retType) && hasNonNullRecord(retType) && getBoolAttribute(external, allocatorAtom, true))
- args.append(*createRowAllocator(ctx, ::queryRecord(retType)));
- localBound.setFromTarget(*curTarget);
- // localBound.expr.setown(createValue(no_implicitcast, makeReferenceModifier(LINK(retType)), LINK(strVar)));
- returnByReference = true;
- break;
- }
- case type_row:
- {
- if (hasLinkCountedModifier(retType))
- {
- if (hasNonNullRecord(retType) && getBoolAttribute(external, allocatorAtom, true))
- args.append(*createRowAllocator(ctx, ::queryRecord(retType)));
- //Always assign link counted rows to a temporary (or the target) to ensure the are not leaked.
- returnMustAssign = true;
- if (tgt && hasLinkCountedModifier(targetType) && recordTypesMatch(targetType, retType))
- {
- doneAssign = true;
- localBound.expr.set(tgt->expr);
- }
- else
- localBound.expr.setown(createWrapperTemp(ctx, retType, typemod_none));
- }
- else
- {
- //row, just pass pointer
- if (tgt && recordTypesMatch(targetType, retType) && !hasLinkCountedModifier(targetType))
- {
- doneAssign = true;
- args.append(*getPointer(tgt->expr));
- localBound.expr.set(tgt->expr);
- }
- else
- {
- if (isVariableSizeRecord(expr->queryRecord()))
- {
- const char * name = expr->queryName()->str();
- throwError1(HQLERR_VariableRowMustBeLinked, name ? name : "");
- }
- resultRow.setown(declareTempRow(ctx, ctx, expr));
- resultRowBuilder.setown(createRowBuilder(ctx, resultRow));
- IHqlExpression * bound = resultRowBuilder->queryBound();
- args.append(*getPointer(bound));
- localBound.expr.setown(getPointer(resultRow->queryBound()));
- }
- returnByReference = true;
- }
- break;
- }
- case type_transform:
- {
- //Ugly, but target selector is passed in as the target
- assertex(tgt && tgt->expr);
- resultSelfCursor = resolveSelectorDataset(ctx, tgt->expr);
- assertex(resultSelfCursor);
- if (resultSelfCursor->queryBuilder())
- args.append(*LINK(resultSelfCursor->queryBuilder()));
- else
- throwUnexpectedX("Expected a dynamic target for a transform - legacy not supported");
- returnByReference = true;
- doneAssign = true;
- break;
- }
- case type_array:
- UNIMPLEMENTED;
- }
- for (param = firstParam; param < maxParam; param++)
- {
- IHqlExpression * curParam = expr->queryChild(param);
- if (curParam->isAttribute())
- continue;
- if (arg >= maxArg)
- {
- PrintLog("Too many parameters passed to function '%s'", expr->queryName()->str());
- throwError1(HQLERR_TooManyParameters, expr->queryName()->str());
- }
- CHqlBoundExpr bound;
- IHqlExpression * curArg = formals->queryChild(arg);
- ITypeInfo * argType = curArg->queryType();
- OwnedHqlExpr castParam = getCastParameter(curParam, argType);
- type_t atc = argType->getTypeCode();
- switch (atc)
- {
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- {
- if (getBoolAttribute(external, passParameterMetaAtom, false))
- args.append(*buildMetaParameter(curParam));
- ExpressionFormat format = queryNaturalFormat(argType);
- buildDataset(ctx, castParam, bound, format);
- break;
- }
- case type_row:
- {
- if (getBoolAttribute(external, passParameterMetaAtom, false))
- args.append(*buildMetaParameter(curParam));
- Owned<IReferenceSelector> selector = buildNewRow(ctx, castParam);
- if (hasLinkCountedModifier(argType))
- selector.setown(ensureLinkCountedRow(ctx, selector));
- selector->buildAddress(ctx, bound);
- break;
- }
- case type_set:
- {
- ITypeInfo * elemType = argType->queryChildType();
- if (newFormatSet && elemType && (elemType->getTypeCode() != type_any) && (elemType != castParam->queryType()->queryChildType()))
- buildExprEnsureType(ctx, castParam, bound, argType);
- else
- buildExpr(ctx, castParam, bound);
- if (isUnknownSize(elemType))
- {
- ITypeInfo * boundElemType = bound.queryType()->queryChildType();
- assertex(!boundElemType || isUnknownSize(boundElemType));
- }
- normalizeBoundExpr(ctx, bound);
- break;
- }
- case type_decimal:
- {
- buildSimpleExpr(ctx, castParam, bound);
- normalizeBoundExpr(ctx, bound);
- break;
- }
- default:
- {
- buildExpr(ctx, castParam, bound);
- normalizeBoundExpr(ctx, bound);
- break;
- }
- }
- bool done = false;
- switch (atc)
- {
- case type_string:
- case type_data:
- case type_qstring:
- case type_unicode:
- case type_utf8:
- if (argType->getSize() == UNKNOWN_LENGTH)
- args.append(*getBoundLength(bound));
- /*
- Ensure parameter is passed as non-const if the argument does not have const.
- if (!curArg->hasAttribute(constAtom))//!argType->isConstantType())// && bound.queryType()->isConstantType())
- bound.expr.setown(createValue(no_cast, LINK(argType), LINK(bound.expr)));
- */
- break;
- case type_varstring:
- case type_varunicode:
- //MORE: pass length only if an out parameter
- break;
- case type_set:
- {
- if (newFormatSet)
- {
- args.append(*bound.getIsAll());
- args.append(*getBoundSize(bound));
- }
- else
- {
- if (castParam->getOperator() == no_all)
- throwError(HQLERR_AllPassedExternal);
- args.append(*getBoundCount(bound));
- }
- break;
- }
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- {
- if (!hasStreamedModifier(argType))
- {
- if (isArrayRowset(argType))
- args.append(*getBoundCount(bound));
- else
- args.append(*getBoundSize(bound));
- }
- bound.expr.setown(getPointer(bound.expr));
- break;
- }
- case type_array:
- UNIMPLEMENTED;
- }
- if (!done)
- args.append(*bound.expr.getClear());
- arg++;
- }
- if (arg < maxArg)
- {
- //MORE: Process default parameters...
- PrintLog("Not enough parameters passed to function '%s'", expr->queryName()->str());
- throwError1(HQLERR_TooFewParameters, expr->queryName()->str());
- }
- OwnedHqlExpr call = bindTranslatedFunctionCall(funcdef, args);
- //either copy the integral value across, or a var string to fixed string
- if (returnMustAssign)
- {
- ctx.addAssign(localBound.expr, call);
- }
- else if (resultSelfCursor)
- {
- OwnedHqlExpr sizeVar = ctx.getTempDeclare(unsignedType, call);
- OwnedHqlExpr sizeOfExpr = createSizeof(resultSelfCursor->querySelector());
- ctx.associateExpr(sizeOfExpr, sizeVar);
- }
- else if (returnByReference || (!tgt && !result))
- {
- ctx.addExpr(call);
- if (translateSetReturn && tgt)
- {
- CHqlBoundTarget targetLength;
- CHqlBoundExpr boundLength;
- boundLength.expr.setown(getBoundLength(localBound));
- targetLength.expr.set(tgt->length);
- assign(ctx, targetLength, boundLength);
- }
- }
- else
- localBound.expr.set(call);
- if (localBound.expr)
- localBound.expr.setown(convertWrapperToPointer(localBound.expr));
- if (tgt && !doneAssign)
- assign(ctx, *tgt, localBound);
- else if (result)
- result->set(localBound);
- //Old style row target where the row is passed in as a parameter
- if (resultRow)
- finalizeTempRow(ctx, resultRow, resultRowBuilder);
- if (returnByReference)
- ctx.associateExpr(expr, localBound);
- }
- void HqlCppTranslator::doBuildExprCall(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- doBuildCall(ctx, NULL, expr, &tgt);
- }
- void HqlCppTranslator::doBuildAssignCall(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- ITypeInfo * exprType = expr->queryType()->queryPromotedType();
- if ((exprType->getSize() == UNKNOWN_LENGTH) && target.isFixedSize())
- {
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- ITypeInfo * targetType = target.queryType()->queryPromotedType();
- if ((isStringType(exprType) || isUnicodeType(exprType) || isStringType(targetType) || isUnicodeType(targetType)) && exprType->getTypeCode() != targetType->getTypeCode())
- {
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- if ((exprType->getTypeCode() == type_set) && (queryUnqualifiedType(targetType) != queryUnqualifiedType(exprType)))
- {
- if (exprType->queryChildType()) // allow direct assignment of generic set functions. (e.g., internal)
- {
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- }
- doBuildCall(ctx, &target, expr, NULL);
- }
- void HqlCppTranslator::doBuildStmtCall(BuildCtx & ctx, IHqlExpression * expr)
- {
- doBuildCall(ctx, NULL, expr, NULL);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildXmlEncode(BuildCtx & ctx, const CHqlBoundTarget * tgt, IHqlExpression * expr, CHqlBoundExpr * result)
- {
- node_operator op = expr->getOperator();
- bool isUnicode = isUnicodeType(expr->queryType());
- HqlExprArray args;
- IIdAtom * func;
- args.append(*LINK(expr->queryChild(0)));
- if (op == no_xmldecode)
- func = isUnicode ? xmlDecodeUStrId : xmlDecodeStrId;
- else
- {
- func = isUnicode ? xmlEncodeUStrId : xmlEncodeStrId;
- __int64 flags = 0;
- if (expr->hasAttribute(allAtom))
- flags = ENCODE_WHITESPACE;
- args.append(*createConstant(flags));
- }
- OwnedHqlExpr call = bindFunctionCall(func, args);
- if (tgt)
- buildExprAssign(ctx, *tgt, call);
- else
- buildExpr(ctx, call, *result);
- }
- //---------------------------------------------------------------------------
- //-- no_cast --
- //-- no_implicitcast --
- IValue * getCastValue(ITypeInfo * cast, IHqlExpression * arg)
- {
- Owned<IValue> value;
- switch (arg->getOperator())
- {
- case no_constant:
- value.set(arg->queryValue());
- break;
- case no_cast: case no_implicitcast:
- value.setown(getCastValue(arg->queryType(), arg->queryChild(0)));
- break;
- default:
- return NULL;
- }
- if (!value)
- return NULL;
- return value->castTo(cast);
- }
- inline IHqlExpression * getCastExpr(ITypeInfo * cast, IHqlExpression * arg)
- {
- IValue * value = getCastValue(cast, arg);
- if (value)
- return createConstant(value);
- return NULL;
- }
- void HqlCppTranslator::doBuildAssignCast(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- IHqlExpression * left = expr->queryChild(0);
- if (options.foldConstantCast)
- {
- //remove when we have constant folding installed...
- OwnedHqlExpr cast = getCastExpr(expr->queryType(), left);
- if (cast)
- {
- buildExprAssign(ctx, target, cast);
- return;
- }
- }
- #if 0
- StringBuffer s;
- s.append("assign cast from=");
- left->queryType()->getECLType(s);
- target.queryType()->getECLType(s.append(" target="));
- expr->queryType()->getECLType(s.append(" expr="));
- PrintLog(s.str());
- #endif
- ITypeInfo * targetType = target.queryType();
- ITypeInfo * exprType = expr->queryType();
- if ((targetType->queryPromotedType() == exprType->queryPromotedType()))
- {
- CHqlBoundExpr bound;
- if (ctx.getMatchExpr(left, bound))
- assignAndCast(ctx, target, bound);
- else
- {
- OwnedHqlExpr values = normalizeListCasts(expr);
- if (values != expr)
- {
- buildExprAssign(ctx, target, values);
- return;
- }
-
- node_operator leftOp = left->getOperator();
- bool useTemp = requiresTemp(ctx, left, false) && (leftOp != no_concat) && (leftOp != no_createset);
- if (useTemp && target.isFixedSize())
- {
- bool ignoreStretched = false;
- switch (leftOp)
- {
- case no_case:
- case no_map:
- //MORE: If the length of the bulk of the branches match then it is worth ignoring.
- //would be worthwhile if isStringType(targetType) || isUnicodeType(targetType);
- break;
- case no_substring:
- //don't do this if the target type is unicode at the moment
- ignoreStretched = isStringType(targetType);
- break;
- }
- if (ignoreStretched)
- {
- Owned<ITypeInfo> stretchedType = getStretchedType(targetType->getStringLen(), exprType);
- if (isSameBasicType(stretchedType, targetType->queryPromotedType()))
- useTemp = false;
- }
- }
- if (useTemp)
- {
- buildExpr(ctx, left, bound);
- assignAndCast(ctx, target, bound);
- }
- else
- {
- buildExprAssign(ctx, target, left);
- }
- }
- return;
- }
- ITypeInfo * leftType = left->queryType();
- if ((targetType->queryPromotedType() == left->queryType()->queryPromotedType()))
- {
- if (preservesValue(exprType, leftType))
- {
- buildExprAssign(ctx, target, left);
- return;
- }
- }
- CHqlBoundExpr pure;
- bool assignDirect = false;
- if ((exprType->getSize() == UNKNOWN_LENGTH) && (targetType->getTypeCode() == exprType->getTypeCode()) &&
- (isStringType(exprType) || isUnicodeType(exprType)))
- {
- OwnedITypeInfo stretched = getStretchedType(UNKNOWN_LENGTH, targetType->queryPromotedType());
- if (stretched == exprType->queryPromotedType())
- assignDirect = true;
- }
- if (assignDirect)
- buildExpr(ctx, left, pure);
- else
- buildExpr(ctx, expr, pure);
- assignAndCast(ctx, target, pure);
- }
- void HqlCppTranslator::doBuildExprCast(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * arg = expr->queryChild(0);
- ITypeInfo * exprType = expr->queryType();
- if (exprType->getTypeCode() == type_set)
- {
- OwnedHqlExpr castArg = ensureExprType(arg, exprType);
- if ((castArg->getOperator() != no_cast) && (castArg->getOperator() != no_implicitcast))
- {
- buildExpr(ctx, castArg, tgt);
- return;
- }
-
- //The case is almost certainly going to go via a temporary anyway, better code is generated if we can avoid an extra assign
- buildTempExpr(ctx, expr, tgt);
- return;
- }
- if (options.foldConstantCast)
- {
- //remove when we have constant folding installed...
- IHqlExpression * cast = getCastExpr(exprType, arg);
- if (cast)
- {
- tgt.expr.setown(cast);
- return;
- }
- }
- // weird special case.... (int4)(swapint4)int4_x - remove both casts...
- switch (arg->getOperator())
- {
- case no_cast:
- case no_implicitcast:
- {
- IHqlExpression * child = arg->queryChild(0);
- if (child->queryType() == exprType)
- {
- if ((exprType->getTypeCode() == type_int) || (exprType->getTypeCode() == type_swapint) || (exprType->getTypeCode() == type_packedint))
- {
- ITypeInfo * argType = arg->queryType();
- if ((argType->getTypeCode() == type_int) || (argType->getTypeCode() == type_swapint) || (argType->getTypeCode() == type_packedint))
- {
- if (argType->getSize() == exprType->getSize())
- {
- buildExpr(ctx, child, tgt);
- return;
- }
- }
- }
- }
- break;
- }
- #if 0
- case no_if:
- {
- //optimize cast of an if where one of the arguments is already the correct type
- //this doesn't really improve things
- IHqlExpression * lhs = arg->queryChild(1);
- IHqlExpression * rhs = arg->queryChild(2);
- if (lhs->queryType() == exprType || lhs->getOperator() == no_constant ||
- rhs->queryType() == exprType || rhs->getOperator() == no_constant)
- {
- HqlExprArray args;
- args.append(*LINK(arg->queryChild(0)));
- args.append(*ensureExprType(lhs, exprType));
- args.append(*ensureExprType(rhs, exprType));
- unwindChildren(args, arg, 3);
- OwnedHqlExpr next = createValue(no_if, LINK(exprType), args);
- buildExpr(ctx, next, tgt);
- return;
- }
- break;
- }
- #endif
- case no_substring:
- {
- ITypeInfo * argType = arg->queryType();
- if ((exprType->getSize() != UNKNOWN_LENGTH) && (argType->getSize() == UNKNOWN_LENGTH) && (exprType->getTypeCode() == argType->getTypeCode()))
- {
- OwnedITypeInfo stretched = getStretchedType(exprType->getStringLen(), argType);
- if (stretched == exprType)
- {
- buildTempExpr(ctx, expr, tgt);
- return;
- }
- }
- break;
- }
- }
- CHqlBoundExpr pure;
- buildExpr(ctx, arg, pure);
- doBuildExprCast(ctx, exprType, pure, tgt);
- if ((arg->queryType()->getTypeCode() == type_decimal) && !isTypePassedByAddress(exprType))
- {
- OwnedHqlExpr translated = tgt.getTranslatedExpr();
- buildTempExpr(ctx, translated, tgt);
- }
- }
- void HqlCppTranslator::doBuildCastViaTemp(BuildCtx & ctx, ITypeInfo * to, CHqlBoundExpr & pure, CHqlBoundExpr & tgt)
- {
- CHqlBoundTarget boundTarget;
- Linked<ITypeInfo> targetType = to;
- //If the temporary size can be deduced, then use a fixed length temporary to save a heap operation.
- ITypeInfo * fromType = pure.expr->queryType();
- if (isStringType(to) && to->getSize() == UNKNOWN_LENGTH && isStringType(fromType) && !pure.length)
- {
- assertex(fromType->getSize() != UNKNOWN_LENGTH);
- targetType.setown(getStretchedType(fromType->getStringLen(), to));
- }
- OwnedHqlExpr translated = pure.getTranslatedExpr();
- OwnedHqlExpr cast = ensureExprType(translated, targetType);
- buildTempExpr(ctx, cast, tgt);
- }
- void HqlCppTranslator::doBuildCastViaString(BuildCtx & ctx, ITypeInfo * to, const CHqlBoundExpr & pure, CHqlBoundExpr & tgt)
- {
- ITypeInfo * from = pure.expr->queryType();
- Owned<ITypeInfo> tempType = makeStringType(from->getStringLen(), NULL, NULL);
- OwnedHqlExpr temp = createValue(no_implicitcast, LINK(to),
- createValue(no_implicitcast, tempType.getLink(), pure.getTranslatedExpr()));
- buildExpr(ctx, temp, tgt);
- }
- void HqlCppTranslator::doBuildExprCast(BuildCtx & ctx, ITypeInfo * to, CHqlBoundExpr & pure, CHqlBoundExpr & tgt)
- {
- ITypeInfo * from = pure.expr->queryType();
- HqlExprArray args;
- IIdAtom * funcName = NULL;
- OwnedHqlExpr op;
- switch (to->getTypeCode())
- {
- case type_boolean:
- {
- switch (from->getTypeCode())
- {
- case type_string:
- funcName = an2bId;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_data:
- funcName = data2BoolId;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_qstring:
- funcName = qstr2BoolId;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_varstring:
- funcName = vn2bId;
- args.append(*getElementPointer(pure.expr));
- break;
- case type_decimal:
- ensurePushed(ctx, pure);
- funcName = DecCompareNullId;
- break;
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- doBuildCastViaString(ctx, to, pure, tgt);
- return;
- case type_real:
- default:
- //default action
- break;
- }
- break;
- }
- case type_packedint:
- {
- ITypeInfo * logicalType = to->queryPromotedType();
- size32_t toSize = logicalType->getSize();
- if ((from->getTypeCode() != type_int) || (toSize != from->getSize()))
- {
- OwnedHqlExpr translated = pure.getTranslatedExpr();
- OwnedHqlExpr castTranslated = createValue(no_implicitcast, LINK(logicalType), LINK(translated));
- buildExpr(ctx, castTranslated, tgt);
- return;
- }
- tgt.set(pure);
- return;
- }
- case type_swapint:
- {
- if ((from->getTypeCode() == type_swapint) && (to->getSize() == from->getSize()))
- {
- break; // default behaviour
- //MORE: Could special case cast between diff size swapints, but a bit too complicated.
- }
- if (from->getTypeCode() != type_int)
- {
- ITypeInfo * tempType = makeIntType(to->getSize(), to->isSigned());
- IHqlExpression * translated = pure.getTranslatedExpr();
- translated = createValue(no_implicitcast, tempType, translated);
- OwnedHqlExpr castTranslated = createValue(no_implicitcast, LINK(to), translated);
- buildExpr(ctx, castTranslated, tgt);
- return;
- }
-
- unsigned toSize = to->getSize();
- unsigned fromSize = from->getSize();
- if ((toSize == 1) && (fromSize == 1))
- {
- if (to->isSigned() != from->isSigned())
- break;
- tgt.expr.setown(createValue(no_typetransfer, LINK(to), LINK(pure.expr)));
- return;
- }
- if (toSize != fromSize)
- {
- Owned<ITypeInfo> tempType = makeIntType(toSize, from->isSigned());
- CHqlBoundExpr tempInt;
- tempInt.expr.setown(ensureExprType(pure.expr, tempType));
- doBuildCastViaTemp(ctx, to, tempInt, tgt);
- }
- else
- doBuildCastViaTemp(ctx, to, pure, tgt);
- return;
- }
- case type_int:
- {
- switch (from->getTypeCode())
- {
- case type_qstring:
- {
- //Need to go via a temporary string.
- Owned<ITypeInfo> tempType = makeStringType(from->getStringLen(), NULL, NULL);
- OwnedHqlExpr temp = createValue(no_implicitcast, LINK(to),
- createValue(no_implicitcast, tempType.getLink(), pure.getTranslatedExpr()));
- buildExpr(ctx, temp, tgt);
- return;
- }
- case type_string:
- case type_data:
- {
- IAtom * charset = from->queryCharset()->queryName();
- if (charset == ebcdicAtom)
- {
- if (to->isSigned())
- funcName = (to->getSize() > 4 ? en2ls8Id : en2ls4Id);
- else
- funcName = (to->getSize() > 4 ? en2l8Id : en2l4Id);
- }
- else if ((charset == asciiAtom) || (charset == dataAtom))
- {
- if (to->isSigned())
- funcName = (to->getSize() > 4 ? an2ls8Id : an2ls4Id);
- else
- funcName = (to->getSize() > 4 ? an2l8Id : an2l4Id);
- }
- else
- assertex(!"Unknown character set");
- //MORE: This should really cast the result to the real width to remove extra bytes.
- //e.g. (unsigned3)-1 should be 0xffffff, not 0xffffffff
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- }
- case type_varstring:
- if (to->isSigned())
- funcName = (to->getSize() > 4 ? vn2ls8Id : vn2ls4Id);
- else
- funcName = (to->getSize() > 4 ? vn2l8Id : vn2l4Id);
- args.append(*getElementPointer(pure.expr));
- break;
- case type_decimal:
- ensurePushed(ctx, pure);
- if (to->getSize() > 4)
- funcName = DecPopInt64Id;
- else
- funcName = DecPopLongId;
- break;
- case type_packedint:
- {
- if (to->getSize() < from->getSize())
- {
- funcName = castIntId[to->getSize()][to->isSigned()];
- args.append(*LINK(pure.expr));
- }
- else
- tgt.set(pure);
- break;
- }
- case type_swapint:
- {
- unsigned toSize = to->getSize();
- unsigned fromSize = from->getSize();
- if ((toSize == 1) && (fromSize == 1))
- {
- if (to->isSigned() != from->isSigned())
- break;
- tgt.expr.setown(createValue(no_typetransfer, LINK(to), LINK(pure.expr)));
- return;
- }
- if (toSize != fromSize)
- {
- Owned<ITypeInfo> tempType = makeIntType(fromSize, from->isSigned());
- CHqlBoundExpr tempInt;
- doBuildCastViaTemp(ctx, tempType, pure, tempInt);
- funcName = castIntId[to->getSize()][to->isSigned()];
- if (funcName && toSize < fromSize)
- {
- args.append(*LINK(tempInt.expr));
- tgt.expr.setown(bindTranslatedFunctionCall(funcName, args));
- }
- else
- tgt.expr.setown(ensureExprType(tempInt.expr, to));
- }
- else
- doBuildCastViaTemp(ctx, to, pure, tgt);
- return;
- }
- case type_int:
- if (to->getSize() < from->getSize())
- {
- IIdAtom * name = castIntId[to->getSize()][to->isSigned()];
- if (name)
- {
- args.append(*LINK(pure.expr));
- IHqlExpression * call = bindTranslatedFunctionCall(name, args);
- op.setown(createValue(no_typetransfer, LINK(to), call));
- }
- }
- break;
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- doBuildCastViaString(ctx, to, pure, tgt);
- return;
- case type_real:
- default:
- //default action
- break;
- }
- break;
- }
- case type_real:
- switch (from->getTypeCode())
- {
- case type_qstring:
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- doBuildCastViaString(ctx, to, pure, tgt);
- return;
- case type_data:
- case type_string:
- funcName = from->queryCharset()->queryName() != ebcdicAtom ? an2fId : en2fId;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_varstring:
- funcName = from->queryCharset()->queryName() != ebcdicAtom ? vn2fId : ex2fId;
- args.append(*getElementPointer(pure.expr));
- break;
- case type_decimal:
- ensurePushed(ctx, pure);
- funcName = DecPopRealId;
- break;
- case type_swapint:
- {
- //cast via intermediate int.
- ITypeInfo * type = makeIntType(from->getSize(), from->isSigned());
- IHqlExpression * translated = pure.getTranslatedExpr();
- OwnedHqlExpr castTranslated = createValue(no_implicitcast, type, translated);
- pure.clear();
- buildExpr(ctx, castTranslated, pure);
- from = type;
- }
- //fallthrough
- case type_int:
- case type_boolean:
- case type_packedint:
- default:
- //default action
- break;
- }
- break;
- case type_decimal:
- {
- ensurePushed(ctx, pure);
- bool needToSetPrecision = true;
- unsigned toDigits = to->getDigits();
- unsigned toPrecision = to->getPrecision();
- switch (from->getTypeCode())
- {
- case type_int:
- case type_swapint:
- if (toDigits >= from->getDigits())
- needToSetPrecision = false;
- break;
- case type_decimal:
- {
- unsigned fromDigits = from->getDigits();
- unsigned fromPrecision = from->getPrecision();
- if (((toDigits - toPrecision) >= (fromDigits - fromPrecision)) &&
- (toPrecision >= fromPrecision))
- needToSetPrecision = false;
- break;
- }
- }
- if ((toDigits == MAX_DECIMAL_DIGITS) && (toPrecision == MAX_DECIMAL_PRECISION))
- needToSetPrecision = false;
- if (needToSetPrecision)
- {
- args.append(*createConstant(createIntValue(to->getDigits(), 1, false)));
- args.append(*createConstant(createIntValue(to->getPrecision(), 1, false)));
- callProcedure(ctx, DecSetPrecisionId, args);
- }
- op.setown(createValue(no_decimalstack, LINK(to)));
- }
- break;
- case type_set:
- {
- //MORE: Shouldn't have to create this node...
- OwnedHqlExpr cast = createValue(no_implicitcast, LINK(to), pure.getTranslatedExpr());
- buildTempExpr(ctx, cast, tgt);
- return;
- }
- case type_pointer:
- case type_row:
- break;
- case type_varstring:
- if ((to->getSize() == UNKNOWN_LENGTH) && (from->getTypeCode() == type_varstring))
- tgt.set(pure);
- else
- doBuildCastViaTemp(ctx, to, pure, tgt);
- return;
- case type_string:
- case type_data:
- {
- if (canRemoveStringCast(to, from))
- {
- ICharsetInfo * srcset = from->queryCharset();
- ICharsetInfo * tgtset = to->queryCharset();
-
- //Data never calls a conversion function... but does add a cast
- if ((srcset == tgtset) || (to->getTypeCode() == type_data) || (from->getTypeCode() == type_data))
- {
- if (from->getTypeCode() == type_varstring)
- tgt.length.setown(getBoundLength(pure));
- else
- tgt.length.set(pure.length);
- Owned<ITypeInfo> newType;
- if (to->getSize() == UNKNOWN_LENGTH)
- newType.setown(getStretchedType(from->getSize(), to));
- else
- newType.set(to);
- if (from->getTypeCode() != type_data)
- {
- newType.setown(cloneModifiers(from, newType));
- tgt.expr.setown(createValue(no_typetransfer, newType.getClear(), pure.expr.getLink()));
- }
- else
- {
- IHqlExpression * base = queryStripCasts(pure.expr);
- newType.setown(makeReferenceModifier(newType.getClear()));
- tgt.expr.setown(createValue(no_cast, newType.getClear(), LINK(base)));
- }
- return;
- }
- }
- }
- doBuildCastViaTemp(ctx, to, pure, tgt);
- return;
- case type_unicode:
- case type_varunicode:
- if ((from->getTypeCode() == to->getTypeCode()) && (to->getSize() == UNKNOWN_LENGTH))
- {
- tgt.set(pure);
- return;
- }
- doBuildCastViaTemp(ctx, to, pure, tgt);
- return;
- default:
- doBuildCastViaTemp(ctx, to, pure, tgt);
- return;
- }
- if (funcName)
- op.setown(bindTranslatedFunctionCall(funcName, args));
- if (!op)
- op.setown(ensureExprType(pure.expr, to));
- if (queryUnqualifiedType(op->queryType()) != queryUnqualifiedType(to))
- {
- OwnedHqlExpr translated = createTranslated(op);
- OwnedHqlExpr cast = ensureExprType(translated, to);
- buildExpr(ctx, cast, tgt);
- }
- else
- tgt.expr.setown(op.getClear());
- }
- //---------------------------------------------------------------------------
- //-- no_char_length --
- //NB: parameter is expression to take length of - not the length node.
- IHqlExpression * HqlCppTranslator::doBuildCharLength(BuildCtx & ctx, IHqlExpression * expr)
- {
- CHqlBoundExpr bound;
- buildCachedExpr(ctx, expr, bound);
- return getBoundLength(bound);
- }
- //---------------------------------------------------------------------------
- //-- no_choose
- void HqlCppTranslator::doBuildChoose(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr)
- {
- CHqlBoundExpr test;
-
- BuildCtx subctx(ctx);
- buildExpr(subctx, expr->queryChild(0), test);
- IHqlStmt * stmt = subctx.addSwitch(test.expr);
-
- unsigned max = expr->numChildren()-1;
- unsigned idx;
- for (idx = 1; idx < max; idx++)
- {
- OwnedHqlExpr branch = getSizetConstant(idx);
- subctx.addCase(stmt, branch);
- buildExprOrAssign(subctx, target, expr->queryChild(idx), NULL);
- }
- IHqlExpression * defaultExpr = expr->queryChild(max);
- if (target || !isNullAction(defaultExpr))
- {
- subctx.addDefault(stmt);
- buildExprOrAssign(subctx, target, defaultExpr, NULL);
- }
- }
- void HqlCppTranslator::doBuildAssignChoose(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- unsigned max = expr->numChildren()-1;
- unsigned idx;
- bool allConstant = true;
- for (idx = 1; idx < max; idx++)
- {
- if (!expr->queryChild(idx)->queryValue())
- allConstant = false;
- }
- if (allConstant)
- {
- //MORE: Need to calculate the correct type.
- HqlExprArray args;
- args.append(*LINK(expr->queryChild(0)));
- for (idx = 1; idx < max; idx++)
- {
- IHqlExpression * v1 = createConstant(createIntValue(idx, LINK(unsignedType)));
- IHqlExpression * v2 = expr->queryChild(idx);
- ITypeInfo * type = v2->queryType();
- args.append(* createValue(no_mapto, LINK(type), v1, LINK(v2)));
- }
- args.append(*LINK(expr->queryChild(max)));
- OwnedHqlExpr caseExpr = createValue(no_case, expr->getType(), args);
- buildExprAssign(ctx, target, caseExpr);
- }
- else
- {
- doBuildChoose(ctx, &target, expr);
- }
- }
- //---------------------------------------------------------------------------
- //-- compare (no_eq,no_ne,no_lt,no_gt,no_le,no_ge) --
- //Are the arguments scalar? If so return the scalar arguments.
- static bool getIsScalarCompare(IHqlExpression * expr, SharedHqlExpr & left, SharedHqlExpr & right)
- {
- left.set(expr->queryChild(0));
- right.set(expr->queryChild(1));
- ITypeInfo * lType = left->queryType();
- ITypeInfo * rType = right->queryType();
- type_t leftTypeCode = lType ? lType->getTypeCode() : type_row;
- type_t rightTypeCode = rType ? rType->getTypeCode() : type_row;
- assertex(leftTypeCode == rightTypeCode);
- switch (leftTypeCode)
- {
- case type_row:
- case type_set:
- return false;
- default:
- return true;
- }
- }
- void HqlCppTranslator::doBuildAssignCompare(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- OwnedHqlExpr left;
- OwnedHqlExpr right;
- if (getIsScalarCompare(expr, left, right))
- {
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- //Comparing a row - calculate the ordering and then compare against zero...
- IHqlExpression * compare = createValue(no_order, LINK(signedType), LINK(left), LINK(right));
- OwnedHqlExpr temp = createBoolExpr(expr->getOperator(), compare, getZero());
- buildExprAssign(ctx, target, temp);
- }
- //---------------------------------------------------------------------------
- //-- no_concat --
- void HqlCppTranslator::buildConcatFArgs(HqlExprArray & args, BuildCtx & ctx, const HqlExprArray & values, ITypeInfo * argType)
- {
- ForEachItemIn(idx, values)
- {
- IHqlExpression * cur = &values.item(idx);
- OwnedHqlExpr value = getCastParameter(cur, argType);
- CHqlBoundExpr bound;
- buildCachedExpr(ctx, value, bound);
- //The function takes ... so the length must be 4 bytes or the stack
- //gets out of sync...
- OwnedHqlExpr length = getBoundLength(bound);
- args.append(*ensureExprType(length, unsignedType));
- args.append(*getElementPointer(bound.expr));
- }
- args.append(*createConstant(signedType->castFrom(true, -1))); // correct size terminator
- }
- void HqlCppTranslator::doBuildVarLengthConcatF(BuildCtx & ctx, const CHqlBoundTarget & target, const HqlExprArray & values)
- {
- ITypeInfo * targetType = target.queryType();
- Linked<ITypeInfo> argType = targetType;
- type_t ttc = targetType->getTypeCode();
- HqlExprArray args;
- IIdAtom * func;
- if (ttc == type_varstring)
- {
- func = concatVStrId;
- argType.setown(makeStringType(UNKNOWN_LENGTH, LINK(targetType->queryCharset()), LINK(targetType->queryCollation())));
- }
- else if (ttc == type_unicode)
- {
- args.append(*target.length.getLink());
- func = concatUnicodeId;
- }
- else if (ttc == type_utf8)
- {
- args.append(*target.length.getLink());
- func = concatUtf8Id;
- }
- else if (ttc == type_varunicode)
- {
- func = concatVUnicodeId;
- argType.setown(makeUnicodeType(UNKNOWN_LENGTH, targetType->queryLocale()));
- }
- else
- {
- args.append(*target.length.getLink());
- func = concatId;
- }
- IHqlExpression * tgt = createValue(no_address, makeVoidType(), LINK(target.expr));
- if (ttc == type_data)
- tgt = createValue(no_implicitcast, makePointerType(makeStringType(UNKNOWN_LENGTH, NULL, NULL)), tgt);
- args.append(*tgt);
- buildConcatFArgs(args, ctx, values, argType);
- callProcedure(ctx, func, args);
- }
- bool HqlCppTranslator::doBuildFixedLengthConcatF(BuildCtx & ctx, const CHqlBoundTarget & target, const HqlExprArray & values)
- {
- ITypeInfo * targetType = target.queryType();
- Owned<ITypeInfo> argType = getStretchedType(UNKNOWN_LENGTH, targetType);
- type_t ttc = targetType->getTypeCode();
- HqlExprArray args;
- IIdAtom * func = NULL;
- OwnedHqlExpr fill;
- switch (ttc)
- {
- case type_varstring:
- func = concatVStrFId;
- argType.setown(makeStringType(UNKNOWN_LENGTH, LINK(targetType->queryCharset()), LINK(targetType->queryCollation())));
- break;
- case type_varunicode:
- func = concatVUnicodeFId;
- argType.setown(makeUnicodeType(UNKNOWN_LENGTH, targetType->queryLocale()));
- break;
- case type_unicode:
- func = concatUnicodeFId;
- break;
- case type_string:
- func = concatStrFId;
- if (targetType->queryCharset()->queryName() == ebcdicAtom)
- fill.setown(getSizetConstant('@'));
- else
- fill.setown(getSizetConstant(' '));
- break;
- case type_data:
- func = concatStrFId;
- fill.setown(getSizetConstant(0));
- break;
- }
- if (func)
- {
- args.append(*getSizetConstant(targetType->getStringLen()));
- args.append(*getPointer(target.expr));
- if (fill)
- args.append(*LINK(fill));
- buildConcatFArgs(args, ctx, values, argType);
- callProcedure(ctx, func, args);
- return true;
- }
- return false;
- }
- void HqlCppTranslator::doBuildAssignConcat(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- ITypeInfo * targetType = target.queryType();
- ICharsetInfo * targetCharset = targetType->queryCharset();
- type_t ttc = targetType->getTypeCode();
- switch (ttc)
- {
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- break;
- case type_string:
- case type_varstring:
- case type_data:
- if (!queryDefaultTranslation(targetCharset, expr->queryType()->queryCharset()))
- break;
- //fallthrough
- default:
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- HqlExprArray values;
- expr->unwindList(values, no_concat);
- //Combine adjacent constants (not folded previously because of the tree structure)
- //Not optimized in the folder since it can mess up cse evaluation
- for (unsigned i=0; i < values.ordinality()-1; i++)
- {
- IValue * firstValue = values.item(i).queryValue();
- if (firstValue)
- {
- Linked<IValue> combinedValue = firstValue;
- while (i+1 < values.ordinality())
- {
- IValue * nextValue = values.item(i+1).queryValue();
- if (!nextValue)
- break;
- combinedValue.setown(concatValues(combinedValue, nextValue));
- values.remove(i+1);
- }
- if (combinedValue->queryType()->getStringLen() == 0)
- {
- values.remove(i);
- i--; // not nice, but will be incremented before comparison so safe
- }
- else if (combinedValue != firstValue)
- values.replace(*createConstant(combinedValue.getClear()), i);
- }
- }
- if (!target.isFixedSize())
- {
- doBuildVarLengthConcatF(ctx, target, values);
- }
- else if (!doBuildFixedLengthConcatF(ctx, target, values))
- {
- Owned<ITypeInfo> varType = getStretchedType(UNKNOWN_LENGTH, targetType);
- OwnedHqlExpr castValue = createValue(no_concat, LINK(varType), values);
- doBuildExprAssign(ctx, target, castValue);
- }
- }
- //---------------------------------------------------------------------------
- //-- no_div --
- // also used for no_modulus
- void HqlCppTranslator::doBuildExprDivide(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (expr->queryType()->getTypeCode() == type_decimal)
- {
- doBuildExprArith(ctx, expr, tgt);
- return;
- }
- IHqlExpression * left = expr->queryChild(0);
- IHqlExpression * right = expr->queryChild(1);
- assertex(left->queryType() == right->queryType());
- IValue * value = right->queryValue();
- if (value)
- {
- Owned<IValue> zero = right->queryType()->castFrom(false, 0);
- int cmp = value->compare(zero);
- if (cmp == 0)
- {
- OwnedHqlExpr eZero = createConstant(LINK(zero));
- doBuildDivideByZero(ctx, NULL, eZero, &tgt);
- }
- else
- doBuildPureSubExpr(ctx, expr, tgt);
- }
- else
- {
- buildTempExpr(ctx, expr, tgt);
- }
- }
- void HqlCppTranslator::doBuildDivideByZero(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * zero, CHqlBoundExpr * bound)
- {
- //Always assign something to bound - even if it is replaced further down.
- if (bound)
- buildExpr(ctx, zero, *bound);
- switch (options.divideByZeroAction)
- {
- case DBZzero:
- if (target)
- assignBound(ctx, *target, zero);
- break;
- case DBZfail:
- {
- HqlExprArray noArgs;
- buildFunctionCall(ctx, failDivideByZeroId, noArgs);
- break;
- }
- case DBZnan:
- {
- LinkedHqlExpr nan = zero;
- if (zero->queryType()->getTypeCode() == type_real)
- {
- HqlExprArray noArgs;
- nan.setown(bindFunctionCall(createRealNullId, noArgs));
- }
- if (target)
- assignBound(ctx, *target, nan);
- else
- buildExpr(ctx, nan, *bound);
- break;
- }
- default:
- throwUnexpected();
- }
- }
- void HqlCppTranslator::doBuildAssignDivide(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- if (expr->queryType()->getTypeCode() == type_decimal)
- {
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- IHqlExpression * left = expr->queryChild(0);
- IHqlExpression * right = expr->queryChild(1);
- assertex(left->queryType() == right->queryType());
- CHqlBoundExpr lhs,rhs;
- buildExpr(ctx, left, lhs);
- buildSimpleExpr(ctx, right, rhs);
- IHqlExpression * divisor = rhs.expr.get();
- OwnedHqlExpr pureExpr = createValue(expr->getOperator(), left->getType(), lhs.expr.getClear(), LINK(divisor));
- IValue * zero = pureExpr->queryType()->castFrom(false, 0);
- OwnedHqlExpr eZero = createConstant(zero);
- IValue * value = rhs.expr->queryValue();
- if (value)
- {
- int cmp = value->compare(eZero->queryValue());
- if (cmp == 0)
- doBuildDivideByZero(ctx, &target, eZero, NULL);
- else
- assignBound(ctx, target, pureExpr);
- }
- else
- {
- BuildCtx subctx(ctx);
- IHqlStmt * stmt = subctx.addFilter(divisor);
- assignBound(subctx, target, pureExpr);
- subctx.selectElse(stmt);
- doBuildDivideByZero(subctx, &target, eZero, NULL);
- }
- }
- //---------------------------------------------------------------------------
- //-- no_if --
- bool HqlCppTranslator::ifRequiresAssignment(BuildCtx & ctx, IHqlExpression * expr)
- {
- IHqlExpression * trueExpr = expr->queryChild(1);
- IHqlExpression * falseExpr = expr->queryChild(2);
- if (requiresTemp(ctx, trueExpr, true) || requiresTemp(ctx, falseExpr, true) || expr->queryType()->getSize() == UNKNOWN_LENGTH)
- return true;
- if (trueExpr->queryType() != falseExpr->queryType() && isStringType(expr->queryType()))
- return true;
- if (expr->queryType()->getTypeCode() == type_decimal)
- return true;
- return false;
- }
- void HqlCppTranslator::doBuildAssignIf(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- if (!ifRequiresAssignment(ctx, expr))
- {
- doBuildExprAssign(ctx, target, expr);
- return;
- }
- IHqlExpression * trueExpr = expr->queryChild(1);
- IHqlExpression * falseExpr = expr->queryChild(2);
- BuildCtx subctx(ctx);
- CHqlBoundExpr cond;
- buildCachedExpr(subctx, expr->queryChild(0), cond);
- IHqlStmt * test = subctx.addFilter(cond.expr);
- buildExprAssign(subctx, target, trueExpr);
- subctx.selectElse(test);
- buildExprAssign(subctx, target, falseExpr);
- }
- void HqlCppTranslator::doBuildExprIf(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (ifRequiresAssignment(ctx, expr))
- {
- buildTempExpr(ctx, expr, tgt);
- return;
- }
- IHqlExpression * trueExpr = expr->queryChild(1);
- IHqlExpression * falseExpr = expr->queryChild(2);
- //Length should not be conditional...
- CHqlBoundExpr cond;
- CHqlBoundExpr boundTrue;
- CHqlBoundExpr boundFalse;
- buildCachedExpr(ctx, expr->queryChild(0), cond);
- buildCachedExpr(ctx, trueExpr, boundTrue);
- buildCachedExpr(ctx, falseExpr, boundFalse);
- //true and false should have same type...
- tgt.expr.setown(createValue(no_if, expr->getType(), cond.expr.getClear(), boundTrue.expr.getClear(), boundFalse.expr.getClear()));
- }
- void HqlCppTranslator::doBuildStmtIf(BuildCtx & ctx, IHqlExpression * expr)
- {
- BuildCtx subctx(ctx);
- CHqlBoundExpr cond;
- buildCachedExpr(subctx, expr->queryChild(0), cond);
- IHqlStmt * test = subctx.addFilter(cond.expr);
- optimizeBuildActionList(subctx, expr->queryChild(1));
- IHqlExpression * elseExpr = queryRealChild(expr, 2);
- if (elseExpr && elseExpr->getOperator() != no_null)
- {
- subctx.selectElse(test);
- optimizeBuildActionList(subctx, elseExpr);
- }
- }
- //---------------------------------------------------------------------------
- //-- no_intformat --
- IHqlExpression * HqlCppTranslator::createFormatCall(IIdAtom * func, IHqlExpression * expr)
- {
- HqlExprArray args;
- unsigned max = expr->numChildren();
- unsigned idx;
- for (idx=0; idx < max; idx++)
- {
- IHqlExpression * cur = expr->queryChild(idx);;
- args.append(*LINK(cur));
- }
- return bindFunctionCall(func, args);
- }
- void HqlCppTranslator::doBuildExprFormat(IIdAtom * func, BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- OwnedHqlExpr call = createFormatCall(func, expr);
- buildExpr(ctx, call, tgt);
- }
- void HqlCppTranslator::doBuildAssignFormat(IIdAtom * func, BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- OwnedHqlExpr call = createFormatCall(func, expr);
- buildExprAssign(ctx, target, call);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildAssignToXml(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- IHqlExpression * row = expr->queryChild(0);
- HqlExprArray args;
- args.append(*buildMetaParameter(row));
- args.append(*LINK(row));
- args.append(*getSizetConstant(XWFtrim|XWFopt|XWFnoindent));
- OwnedHqlExpr call = bindFunctionCall(ctxGetRowXmlId, args);
- buildExprAssign(ctx, target, call);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::processCppBodyDirectives(IHqlExpression * expr)
- {
- ForEachChild(i, expr)
- {
- IHqlExpression * cur = expr->queryChild(i);
- if (cur->isAttribute())
- {
- IAtom * name = cur->queryName();
- if (name == linkAtom)
- {
- //MORE: Add code to add the argument to the linker options.
- }
- else if (name == libraryAtom)
- {
- StringBuffer libraryName;
- getStringValue(libraryName, cur->queryChild(0));
- if (libraryName.length())
- useLibrary(libraryName.str());
- }
- }
- }
- }
- void HqlCppTranslator::doBuildExprEmbedBody(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr * tgt)
- {
- if (!allowEmbeddedCpp())
- throwError(HQLERR_EmbeddedCppNotAllowed);
- processCppBodyDirectives(expr);
- IHqlExpression *languageAttr = expr->queryAttribute(languageAtom);
- if (languageAttr)
- {
- UNIMPLEMENTED; // It's not clear if this can ever happen - perhaps a parameterless function that used EMBED ?
- }
- StringBuffer text;
- expr->queryChild(0)->queryValue()->getUTF8Value(text);
- text.setLength(cleanupEmbeddedCpp(text.length(), (char*)text.str()));
- OwnedHqlExpr quoted = createQuoted(text.str(), expr->getType());
- if (tgt)
- {
- ITypeInfo * type = expr->queryType();
- assertex(type->getTypeCode() == type_varstring || type->getSize() != UNKNOWN_LENGTH);
- tgt->expr.set(quoted);
- }
- else
- ctx.addExpr(quoted);
- }
- //---------------------------------------------------------------------------
- //-- no_index --
- IHqlExpression * getSimpleListIndex(BuildCtx & ctx, IHqlExpression * expr)
- {
- IHqlExpression * index = expr->queryChild(1);
- if (!index->isConstant())
- return NULL;
- OwnedHqlExpr set = normalizeListCasts(expr->queryChild(0));
- switch (set->getOperator())
- {
- case no_null:
- case no_list:
- break;
- default:
- return NULL;
- }
- OwnedHqlExpr folded = foldHqlExpression(index);
- __int64 which = folded->queryValue()->getIntValue();
- if ((which > 0) && (which <= set->numChildren()))
- return LINK(set->queryChild((unsigned)which-1));
- return createNullExpr(expr);
- }
- void HqlCppTranslator::doBuildExprIndex(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- OwnedHqlExpr simple = getSimpleListIndex(ctx, expr);
- if (simple)
- buildExpr(ctx, simple, tgt);
- else
- {
- OwnedHqlExpr simpleList = simplifyFixedLengthList(expr->queryChild(0));
- Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, simpleList);
- cursor->buildExprSelect(ctx, expr, tgt);
- }
- }
- void HqlCppTranslator::doBuildAssignIndex(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- OwnedHqlExpr simple = getSimpleListIndex(ctx, expr);
- if (simple)
- buildExprAssign(ctx, target, simple);
- else
- {
- OwnedHqlExpr simpleList = simplifyFixedLengthList(expr->queryChild(0));
- Owned<IHqlCppSetCursor> cursor = createSetSelector(ctx, simpleList);
- cursor->buildAssignSelect(ctx, target, expr);
- }
- }
- //---------------------------------------------------------------------------
- //-- no_list --
- bool isComplexSet(ITypeInfo * type, bool isConstant)
- {
- ITypeInfo * childType = type->queryChildType();
- if (!childType)
- return false;
- switch (childType->getTypeCode())
- {
- case type_alien:
- return true;
- case type_string:
- case type_qstring:
- case type_data:
- case type_unicode:
- case type_varstring:
- case type_varunicode:
- return isUnknownSize(childType) && !isConstant;
- case type_utf8:
- case type_swapint:
- case type_packedint:
- return true;
- case type_int:
- switch (childType->getSize())
- {
- case 3: case 5: case 6: case 7:
- return true;
- }
- return false;
- }
- return false;
- }
- bool isComplexSet(IHqlExpression * expr)
- {
- return isComplexSet(expr->queryType(), isConstantSet(expr));
- }
- bool isConstantSet(IHqlExpression * expr)
- {
- unsigned max = expr->numChildren();
- unsigned idx;
- for (idx = 0; idx < max; idx++)
- {
- IHqlExpression * child = expr->queryChild(idx);
- if (!child->queryValue())
- return false;
- }
- return true;
- }
- bool createUnknownLengthStringSet(MemoryBuffer & target, IHqlExpression * set)
- {
- ITypeInfo * elemType = set->queryType()->queryChildType();
- type_t tc = elemType->getTypeCode();
- ForEachChild(i, set)
- {
- IHqlExpression * cur = set->queryChild(i);
- IValue * curValue = cur->queryValue();
- if (!curValue)
- return false;
- size32_t sizeValue = curValue->getSize();
- if ((tc != type_varstring) && (tc != type_varunicode))
- {
- size32_t lenValue = curValue->queryType()->getStringLen();
- rtlWriteInt4(target.reserve(sizeof(size32_t)), lenValue);
- }
- curValue->toMem(target.reserve(sizeValue));
- }
- return true;
- }
- void HqlCppTranslator::doBuildExprConstList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- BuildCtx declareCtx(*code, literalAtom);
- if (!declareCtx.getMatchExpr(expr, tgt))
- {
- ITypeInfo * type = expr->queryType();
- Linked<ITypeInfo> elementType = type->queryChildType();
- if (!elementType)
- throwError(HQLERR_NullSetCannotGenerate);
- Owned<ITypeInfo> transferType;
- OwnedHqlExpr table;
- OwnedHqlExpr declare;
- unsigned numElements = expr->numChildren();
- LinkedHqlExpr values = expr;
- if ((isTypePassedByAddress(elementType) && ((elementType->getTypeCode() != type_varstring) || isUnknownSize(elementType))))
- {
- if (isUnknownSize(elementType))
- {
- MemoryBuffer serialized;
- bool ok = createUnknownLengthStringSet(serialized, values);
- assertex(ok);
- Owned<IValue> value = createDataValue(serialized.toByteArray(), serialized.length());
- OwnedHqlExpr constValue = createConstant(LINK(value));
- OwnedHqlExpr initializer = createValue(no_create_initializer, constValue->getType(), LINK(constValue));
- Owned<ITypeInfo> declareType = makeConstantModifier(constValue->getType());
- declare.setown(declareCtx.getTempDeclare(declareType, initializer));
- ITypeInfo * arrayType = makeReferenceModifier(makeSetType(LINK(elementType)));
- table.setown(createValue(no_typetransfer, arrayType, LINK(declare)));
- tgt.length.setown(getSizetConstant(serialized.length()));
- }
- else if (elementType->isReference())
- {
- // use a var string type to get better C++ generated...
- transferType.set(elementType);
- elementType.setown(makeVarStringType(UNKNOWN_LENGTH));
- }
- else
- {
- // for string, data and qstring we need to initialize the array with a list of characters instead of
- // a cstring e.g., char[][2] = { { 'a','b' }, { 'c', 'd' } };
- HqlExprArray newValues;
- ForEachChild(idx, expr)
- {
- IHqlExpression * next = expr->queryChild(idx);
- newValues.append(*createValue(no_create_initializer, next->getType(), LINK(next)));
- }
- values.setown(createValue(no_list, makeSetType(LINK(elementType)), newValues));
- }
- }
- if (!declare)
- {
- Owned<ITypeInfo> t = makeConstantModifier(makeArrayType(LINK(elementType), numElements));
- declare.setown(declareCtx.getTempDeclare(t, values));
- if (transferType)
- {
- ITypeInfo * arrayType = makeArrayType(LINK(transferType), numElements);
- table.setown(createValue(no_typetransfer, arrayType, LINK(declare)));
- }
- }
- tgt.count.setown(getSizetConstant(numElements));
- tgt.expr.set(table ? table : declare);
- //make sure tables get added before any global functions
- declareCtx.associateExpr(expr, tgt);
- if (options.spanMultipleCpp)
- {
- BuildCtx protoctx(*code, mainprototypesAtom);
- protoctx.addDeclareExternal(declare);
- }
- }
- }
- void HqlCppTranslator::doBuildExprDynList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (!ctx.getMatchExpr(expr, tgt))
- {
- ITypeInfo * type = expr->queryType();
- ITypeInfo * elementType = type->queryChildType();
- unsigned max = expr->numChildren();
- //MORE: What if this is an array of variable length strings?
- Owned<ITypeInfo> t = makeArrayType(LINK(elementType), max);
- IHqlExpression * table = ctx.getTempDeclare(t, NULL);
- // new code - should really use a selector...
- unsigned idx;
- CHqlBoundTarget boundTarget;
- for (idx = 0; idx < max; idx++)
- {
- IHqlExpression * child = expr->queryChild(idx);
- boundTarget.expr.setown(createValue(no_index, LINK(elementType), LINK(table), createConstant((int)idx)));
- buildExprAssign(ctx, boundTarget, child);
- }
- tgt.count.setown(getSizetConstant(max));
- tgt.expr.setown(table);
- ctx.associateExpr(expr, tgt);
- }
- }
- void HqlCppTranslator::doBuildExprList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_set:
- case type_array:
- {
- LinkedHqlExpr values = expr;
- //MORE: Also alien data types and other weird things...
- //if (childType->getSize() == UNKNOWN_LENGTH)
- if (expr->numChildren() == 0)
- {
- tgt.length.setown(getSizetConstant(0));
- tgt.expr.setown(createValue(no_nullptr, makeReferenceModifier(LINK(type))));
- return;
- }
- else if (isComplexSet(expr))
- {
- buildTempExpr(ctx, expr, tgt);
- return;
- }
- if (isConstantSet(expr))
- doBuildExprConstList(ctx, values, tgt);
- else
- doBuildExprDynList(ctx, values, tgt);
- tgt.isAll.set(queryBoolExpr(false));
- }
- break;
- default:
- throwUnexpectedX("This type of list not supported yet");
- }
- }
- void HqlCppTranslator::doBuildAssignList(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * _expr)
- {
- OwnedHqlExpr expr = simplifyFixedLengthList(_expr);
- node_operator op = expr->getOperator();
- assertex(op == no_list);
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_set:
- case type_array:
- break;
- default:
- throwUnexpectedX("This type of list not supported yet");
- }
- //This is an assignment, a non-constant set would end up creating two temporaries.
- unsigned numItems = expr->numChildren();
- if (((numItems > 0) && (numItems < 3)) || isComplexSet(expr) || !isConstantSet(expr))
- {
- Owned<IHqlCppSetBuilder> builder = createTempSetBuilder(target.queryType()->queryChildType(), target.isAll);
- builder->buildDeclare(ctx);
- buildSetAssign(ctx, builder, expr);
- builder->buildFinish(ctx, target);
- }
- else if (numItems == 0)
- {
- CHqlBoundExpr temp;
- buildExpr(ctx, expr, temp);
- if (target.isAll)
- {
- if (temp.isAll)
- ctx.addAssign(target.isAll, temp.isAll);
- else
- ctx.addAssign(target.isAll, queryBoolExpr(false));
- }
- ctx.addAssign(target.length, temp.length);
- ctx.addAssign(target.expr, temp.expr);
- }
- else
- {
- OwnedHqlExpr cast = ensureExprType(expr, target.queryType());
- OwnedHqlExpr simpleCast = simplifyFixedLengthList(cast);
- // can do a direct assignment without any casts
- doBuildExprAssign(ctx, target, simpleCast);
- }
- }
- void HqlCppTranslator::doBuildExprAll(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- tgt.isAll.set(queryBoolExpr(true));
- tgt.length.setown(getSizetConstant(0));
- tgt.expr.setown(createQuoted("0", makeSetType(NULL)));
- }
- void HqlCppTranslator::doBuildAssignAll(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- CHqlBoundExpr temp;
- buildExpr(ctx, expr, temp);
- ctx.addAssign(target.isAll, temp.isAll);
- ctx.addAssign(target.length, temp.length);
- ctx.addAssign(target.expr, temp.expr);
- }
- //---------------------------------------------------------------------------
- //-- no_not --
- void HqlCppTranslator::doBuildExprNot(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- assertex(expr->queryChild(0)->isBoolean());
- CHqlBoundExpr bound;
- buildExpr(ctx, expr->queryChild(0), bound);
- tgt.expr.setown(getInverse(bound.expr));
- }
- //---------------------------------------------------------------------------
- //-- no_or --
- IHqlExpression * HqlCppTranslator::convertOrToAnd(IHqlExpression * expr)
- {
- bool invert = true;
- if (expr->getOperator() == no_not)
- {
- invert = false;
- expr = expr->queryChild(0);
- }
- assertex(expr->getOperator() == no_or);
- HqlExprArray original, inverted;
- expr->unwindList(original, no_or);
- ForEachItemIn(idx, original)
- inverted.append(*getInverse(&original.item(idx)));
- IHqlExpression * ret = createValue(no_and, makeBoolType(), inverted);
- if (invert)
- ret = createValue(no_not, makeBoolType(), ret);
- return ret;
- }
- //---------------------------------------------------------------------------
- // no_unicodeorder
- void HqlCppTranslator::doBuildAssignUnicodeOrder(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- CHqlBoundExpr lhs, rhs, locale, strength;
- buildCachedExpr(ctx, expr->queryChild(0), lhs);
- buildCachedExpr(ctx, expr->queryChild(1), rhs);
- buildCachedExpr(ctx, expr->queryChild(2), locale);
- buildCachedExpr(ctx, expr->queryChild(3), strength);
- Owned<IHqlExpression> op;
- HqlExprArray args;
- ITypeInfo * realType = lhs.expr->queryType()->queryPromotedType();
- switch(realType->getTypeCode())
- {
- case type_unicode:
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- args.append(*getElementPointer(locale.expr));
- args.append(*strength.expr.getLink());
- op.setown(bindTranslatedFunctionCall(compareUnicodeUnicodeStrengthId, args));
- break;
- case type_varunicode:
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
- args.append(*getElementPointer(locale.expr));
- args.append(*strength.expr.getLink());
- op.setown(bindTranslatedFunctionCall(compareVUnicodeVUnicodeStrengthId, args));
- break;
- case type_utf8:
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- args.append(*getElementPointer(locale.expr));
- args.append(*strength.expr.getLink());
- op.setown(bindTranslatedFunctionCall(compareUtf8Utf8StrengthId, args));
- break;
- default:
- UNIMPLEMENTED;
- }
- assignBound(ctx, target, op);
- }
- //---------------------------------------------------------------------------
- //-- no_order --
- static void buildIteratorFirst(HqlCppTranslator & translator, BuildCtx & ctx, IHqlExpression * iter, IHqlExpression * row)
- {
- StringBuffer s;
- translator.generateExprCpp(s, row).append(" = (byte*)");
- translator.generateExprCpp(s, iter).append(".first();");
- ctx.addQuoted(s);
- }
- static void buildIteratorNext(HqlCppTranslator & translator, BuildCtx & ctx, IHqlExpression * iter, IHqlExpression * row)
- {
- StringBuffer s;
- translator.generateExprCpp(s, row).append(" = (byte*)");
- translator.generateExprCpp(s, iter).append(".next();");
- ctx.addQuoted(s);
- }
- static void buildIteratorIsValid(BuildCtx & ctx, IHqlExpression * iter, IHqlExpression * row, CHqlBoundExpr & bound)
- {
- bound.expr.set(row);
- }
- void HqlCppTranslator::doBuildAssignCompareRow(BuildCtx & ctx, EvaluateCompareInfo & info, IHqlExpression * left, IHqlExpression * right)
- {
- HqlExprArray leftValues, rightValues;
- IHqlExpression * record = left->queryRecord();
- expandRowOrder(left->queryNormalizedSelector(), record, leftValues, false);
- expandRowOrder(right->queryNormalizedSelector(), record, rightValues, false);
- optimizeOrderValues(leftValues, rightValues, false);
- doBuildAssignCompare(ctx, info, leftValues, rightValues, true, false); //MORE: ,no_break,true
- }
- void HqlCppTranslator::doBuildAssignCompareTable(BuildCtx & ctx, EvaluateCompareInfo & info, IHqlExpression * left, IHqlExpression * right)
- {
- ITypeInfo * targetType = info.target.queryType();
- OwnedHqlExpr zeroTarget = createConstant(targetType->castFrom(true, 0));
- OwnedHqlExpr plusOne = createConstant(targetType->castFrom(true, +1));
- OwnedHqlExpr minusOne = createConstant(targetType->castFrom(true, -1));
- // cmp = 0;
- assignBound(ctx, info.target, zeroTarget);
- BuildCtx subctx(ctx);
- subctx.addGroup(); // stop bound cursors leaking outside the testing block.
- // i1 iter1; i1.first();
- HqlExprAttr leftIter, leftRow;
- Owned<IHqlCppDatasetCursor> cursor = createDatasetSelector(subctx, left);
- cursor->buildIterateClass(subctx, leftIter, leftRow);
- buildIteratorFirst(*this, subctx, leftIter, leftRow);
- // i2; forEachIn(i2); {
- CHqlBoundExpr isValid;
- BuildCtx loopctx(subctx);
- buildDatasetIterate(loopctx, right, true);
- bindTableCursor(loopctx, left, leftRow);
-
- // if (!i1.isValid()) { cmp = -1; break; }
- buildIteratorIsValid(loopctx, leftIter, leftRow, isValid);
- OwnedHqlExpr test = createValue(no_not, makeBoolType(), isValid.expr.getClear());
- BuildCtx moreRightCtx(loopctx);
- moreRightCtx.addFilter(test);
- if (info.actionIfDiffer == return_stmt)
- {
- if (info.isEqualityCompare())
- {
- OwnedHqlExpr returnValue = info.getEqualityReturnValue();
- moreRightCtx.addReturn(returnValue);
- }
- else
- moreRightCtx.addReturn(minusOne);
- }
- else
- {
- buildExprAssign(moreRightCtx, info.target, minusOne);
- moreRightCtx.addBreak();
- }
- //Now do the comparison....
- {
- EvaluateCompareInfo childInfo(info);
- if (childInfo.actionIfDiffer == break_stmt)
- childInfo.actionIfDiffer = null_stmt;
- //***childInfo??
- doBuildAssignCompareRow(loopctx, info, left, right);
- }
- if (info.actionIfDiffer != return_stmt)
- {
- // if (cmp != 0) break;
- BuildCtx donectx(loopctx);
- donectx.addFilter(info.target.expr);
- donectx.addQuoted("break;");
- }
- // i1.next();
- buildIteratorNext(*this, loopctx, leftIter, leftRow);
- buildIteratorIsValid(subctx, leftIter, leftRow, isValid);
- if (info.actionIfDiffer == return_stmt)
- {
- //if (i1.isValid) return +1;
- BuildCtx moreLeftCtx(subctx);
- moreLeftCtx.addFilter(isValid.expr);
- if (info.isEqualityCompare())
- {
- OwnedHqlExpr returnValue = info.getEqualityReturnValue();
- moreLeftCtx.addReturn(returnValue);
- }
- else
- moreLeftCtx.addReturn(plusOne);
- }
- else
- {
- //if (cmp == 0 && i1.isValid) cmp = +1;
- OwnedHqlExpr cmp = createBoolExpr(no_and, createBoolExpr(no_eq, LINK(info.target.expr), LINK(zeroTarget)), LINK(isValid.expr));
- BuildCtx moreLeftCtx(subctx);
- moreLeftCtx.addFilter(cmp);
- buildExprAssign(moreLeftCtx, info.target, plusOne);
- BuildCtx tailctx(ctx);
- if (info.actionIfDiffer == break_stmt)
- {
- tailctx.addFilter(info.target.expr);
- tailctx.addBreak();
- }
- }
- }
- void HqlCppTranslator::expandRowOrder(IHqlExpression * selector, IHqlExpression * record, HqlExprArray & values, bool isRow)
- {
- ForEachChild(idx, record)
- {
- IHqlExpression * field = record->queryChild(idx);
- switch (field->getOperator())
- {
- case no_ifblock:
- expandRowOrder(selector, field->queryChild(1), values, isRow);
- break;
- case no_record:
- expandRowOrder(selector, field, values, isRow);
- break;
- case no_field:
- {
- OwnedHqlExpr selected;
- if (isRow)
- selected.setown(createNewSelectExpr(LINK(selector), LINK(field)));
- else
- selected.setown(createSelectExpr(LINK(selector), LINK(field)));
- if (field->isDatarow())
- expandRowOrder(selected, field->queryRecord(), values, false);
- else
- values.append(*LINK(selected));
- break;
- }
- }
- }
- }
- void HqlCppTranslator::expandSimpleOrder(IHqlExpression * left, IHqlExpression * right, HqlExprArray & leftValues, HqlExprArray & rightValues)
- {
- while ((left->getOperator() == no_negate) && (right->getOperator() == no_negate))
- {
- IHqlExpression * temp = right->queryChild(0);
- right = left->queryChild(0);
- left = temp;
- }
- if (left == right)
- {
- //Weird code is here just so I can force some strange exceptions in the regression suite.
- IHqlExpression * cur = left;
- if (cur->getOperator() == no_alias)
- cur = cur->queryChild(0);
- if (cur->getOperator() != no_nofold)
- return;
- }
- if (left->isDatarow())
- {
- IHqlExpression * record = left->queryRecord();
- assertex(right->isDatarow() && (record == right->queryRecord()));
- expandRowOrder(left, record, leftValues, !isActiveRow(left));
- expandRowOrder(right, record, rightValues, !isActiveRow(right));
- }
- else
- {
- leftValues.append(*LINK(left));
- rightValues.append(*LINK(right));
- }
- }
- void HqlCppTranslator::expandOrder(IHqlExpression * expr, HqlExprArray & leftValues, HqlExprArray & rightValues, SharedHqlExpr & defaultValue)
- {
- OwnedHqlExpr left = normalizeListCasts(expr->queryChild(0));
- OwnedHqlExpr right = normalizeListCasts(expr->queryChild(1));
- if ((isFixedLengthList(left) || isNullList(left)) && (isFixedLengthList(right) || isNullList(right)))
- {
- unsigned maxLeft = left->numChildren();
- unsigned maxRight = right->numChildren();
- unsigned max = std::min(maxLeft, maxRight);
- for (unsigned i=0; i < max; i++)
- expandSimpleOrder(left->queryChild(i), right->queryChild(i), leftValues, rightValues);
- if (maxLeft != maxRight)
- defaultValue.setown(createConstant(signedType->castFrom(true, ((maxLeft > maxRight) ? +1 : -1))));
- }
- else
- expandSimpleOrder(left, right, leftValues, rightValues);
- }
- IHqlExpression * HqlCppTranslator::querySimpleOrderSelector(IHqlExpression * expr)
- {
- if (expr->getOperator() != no_select)
- return NULL;
- return queryDatasetCursor(expr);
- }
- static unsigned getMemcmpSize(IHqlExpression * left, IHqlExpression * right, bool isEqualityCompare)
- {
- ITypeInfo * leftType = left->queryType();
- if (!leftType)
- return 0;
- if (!isSameBasicType(leftType, right->queryType()))
- return 0;
- unsigned size = leftType->getSize();
- switch (leftType->getTypeCode())
- {
- case type_bigendianint:
- case type_boolean:
- return size;
- case type_littleendianint:
- if ((size == 1) && !leftType->isSigned())
- return 1;
- if (isEqualityCompare)
- return size;
- break;
- case type_string:
- case type_data:
- case type_qstring:
- if (size != UNKNOWN_LENGTH)
- return size;
- break;
- }
- return 0;
- }
- void HqlCppTranslator::optimizeOrderValues(HqlExprArray & leftValues, HqlExprArray & rightValues, bool isEqualityCompare)
- {
- unsigned max = leftValues.ordinality();
- if (max <= 1)
- return;
- for (unsigned i=0; i < max-1; i++)
- {
- IHqlExpression * curFirstLeft = &leftValues.item(i);
- IHqlExpression * curFirstRight = &rightValues.item(i);
- IHqlExpression * leftSel = querySimpleOrderSelector(curFirstLeft);
- IHqlExpression * rightSel = querySimpleOrderSelector(curFirstRight);
- if (!leftSel || !rightSel)
- continue;
- unsigned compareSize = getMemcmpSize(curFirstLeft, curFirstRight, isEqualityCompare);
- if (!compareSize)
- continue;
- IHqlExpression * nextLeft = &leftValues.item(i+1);
- IHqlExpression * nextRight = &rightValues.item(i+1);
- if (querySimpleOrderSelector(nextLeft) != leftSel || querySimpleOrderSelector(nextRight) != rightSel ||
- (getMemcmpSize(nextLeft, nextRight, isEqualityCompare) == 0))
- continue;
- //Worth iterating the selectors...
- RecordSelectIterator leftIter(leftSel->queryRecord(), leftSel);
- ForEach(leftIter)
- if (leftIter.query() == curFirstLeft)
- break;
- if (!leftIter.isValid() || leftIter.isInsideIfBlock())
- continue;
- RecordSelectIterator rightIter(rightSel->queryRecord(), rightSel);
- ForEach(rightIter)
- if (rightIter.query() == curFirstRight)
- break;
- if (!rightIter.isValid() || rightIter.isInsideIfBlock())
- continue;
- unsigned j; // linux wants it declared outside of 'for'
- for (j=i+1; j < max; j++)
- {
- if (!leftIter.next() || leftIter.isInsideIfBlock())
- break;
- if (!rightIter.next() || rightIter.isInsideIfBlock())
- break;
- IHqlExpression * nextLeft = &leftValues.item(j);
- IHqlExpression * nextRight = &rightValues.item(j);
- if (leftIter.query() != nextLeft || rightIter.query() != nextRight)
- break;
- unsigned thisSize = getMemcmpSize(nextLeft, nextRight, isEqualityCompare);
- if (!thisSize)
- break;
- compareSize += thisSize;
- }
- if (j != i+1)
- {
- IHqlExpression * newLeft = createValue(no_typetransfer, makeStringType(compareSize), LINK(curFirstLeft));
- IHqlExpression * newRight = createValue(no_typetransfer, makeStringType(compareSize), LINK(curFirstRight));
- leftValues.replace(*newLeft, i);
- rightValues.replace(*newRight, i);
- leftValues.removen(i+1, j-(i+1));
- rightValues.removen(i+1, j-(i+1));
- max -= (j - (i+1));
- }
- }
- }
- inline IHqlExpression * createSignedConstant(__int64 value)
- {
- return createConstant(signedType->castFrom(true, value));
- }
- static IHqlExpression * convertAllToInteger(IHqlExpression * allExpr)
- {
- IValue * allValue = allExpr->queryValue();
- if (allValue)
- return createSignedConstant(allValue->getBoolValue() ? 1 : 0);
- return createValue(no_if, LINK(signedType), LINK(allExpr), createSignedConstant(1), createSignedConstant(0));
- }
- void HqlCppTranslator::doBuildAssignCompareElement(BuildCtx & ctx, EvaluateCompareInfo & info, IHqlExpression * left, IHqlExpression * right, bool isFirst, bool isLast)
- {
- if (left->getOperator() == no_if && right->getOperator() == no_if && left->queryChild(0) == right->queryChild(0))
- {
- BuildCtx subctx(ctx);
- IHqlStmt * filter = buildFilterViaExpr(subctx, left->queryChild(0));
- doBuildAssignCompareElement(subctx, info, left->queryChild(1), right->queryChild(1), isFirst, false);
- if ((isFirst && (info.actionIfDiffer != return_stmt)) || left->queryChild(2) != right->queryChild(2))
- {
- subctx.selectElse(filter);
- doBuildAssignCompareElement(subctx, info, left->queryChild(2), right->queryChild(2), isFirst, false);
- }
- return;
- }
- if (left == right)
- {
- //Can happen from conditions expanded above
- if (isFirst)
- {
- if (info.actionIfDiffer != return_stmt)
- buildExprAssign(ctx, info.target, queryZero());
- }
- return;
- }
- ITypeInfo * leftType = left->queryType();
- type_t tc;
- if (leftType)
- tc = leftType->getTypeCode();
- else
- tc = type_set;
- CHqlBoundExpr lhs,rhs;
- bool useMemCmp = false;
- switch (tc)
- {
- case type_dictionary:
- {
- //You can't iterate dictionaries, so convert to datasets first. A bit of a silly comparison anyway
- OwnedHqlExpr dsLeft = createDataset(no_datasetfromdictionary, LINK(left));
- OwnedHqlExpr dsRight = createDataset(no_datasetfromdictionary, LINK(right));
- doBuildAssignCompareTable(ctx, info, dsLeft, dsRight);
- return;
- }
- case type_table:
- case type_groupedtable:
- doBuildAssignCompareTable(ctx, info, left, right);
- return;
- case type_row:
- doBuildAssignCompareRow(ctx, info, left, right);
- return;
- case type_bigendianint:
- {
- //MORE: Compare big endian integers with a memcmp
- if (hasAddress(ctx, left) && hasAddress(ctx, right) && isSameBasicType(leftType, right->queryType()))
- {
- buildAddress(ctx, left, lhs);
- buildAddress(ctx, right, rhs);
- useMemCmp = true;
- break;
- }
- Owned<ITypeInfo> type = makeIntType(leftType->getSize(), leftType->isSigned());
- OwnedHqlExpr intLeft = createValue(no_implicitcast, type.getLink(), LINK(left));
- OwnedHqlExpr intRight = createValue(no_implicitcast, type.getLink(), LINK(right));
- buildCachedExpr(ctx, intLeft, lhs);
- buildCachedExpr(ctx, intRight, rhs);
- break;
- }
- case type_string:
- case type_data:
- case type_qstring:
- {
- OwnedHqlExpr simpleLeft = getSimplifyCompareArg(left);
- OwnedHqlExpr simpleRight = getSimplifyCompareArg(right);
- buildCachedExpr(ctx, simpleLeft, lhs);
- buildCachedExpr(ctx, simpleRight, rhs);
- break;
- }
- default:
- buildCachedExpr(ctx, left, lhs);
- buildCachedExpr(ctx, right, rhs);
- break;
- }
- ITypeInfo * realType = lhs.queryType()->queryPromotedType();
- tc = realType->getTypeCode();
- IHqlExpression * op = NULL;
- switch (tc)
- {
- //MORE: Should common up with comparison code...
- case type_string:
- case type_data:
- case type_qstring:
- {
- HqlExprArray args;
- IIdAtom * func;
- if (lhs.length || rhs.length || needVarStringCompare(realType, rhs.queryType()->queryPromotedType()))
- {
- //MORE: This does not cope with different padding characters...
- func = queryStrCompareFunc(realType);
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- }
- else
- {
- func = memcmpId;
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
- args.append(*getSizetConstant(realType->getSize()));
- }
-
- op = bindTranslatedFunctionCall(func, args);
- break;
- }
- case type_unicode:
- {
- HqlExprArray args;
- assertex(haveCommonLocale(leftType, right->queryType()));
- char const * locale = getCommonLocale(leftType, right->queryType())->str();
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- args.append(*createConstant(locale));
- op = bindTranslatedFunctionCall(compareUnicodeUnicodeId, args);
- break;
- }
- case type_varunicode:
- {
- HqlExprArray args;
- assertex(haveCommonLocale(leftType, right->queryType()));
- char const * locale = getCommonLocale(leftType, right->queryType())->str();
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
- args.append(*createConstant(locale));
- op = bindTranslatedFunctionCall(compareVUnicodeVUnicodeId, args);
- break;
- }
- case type_utf8:
- {
- HqlExprArray args;
- assertex(haveCommonLocale(leftType, right->queryType()));
- char const * locale = getCommonLocale(leftType, right->queryType())->str();
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- args.append(*createConstant(locale));
- op = bindTranslatedFunctionCall(compareUtf8Utf8Id, args);
- break;
- }
- case type_varstring:
- {
- HqlExprArray args;
- args.append(*getElementPointer(lhs.expr));
- args.append(*getElementPointer(rhs.expr));
-
- op = bindTranslatedFunctionCall(compareVStrVStrId, args);
- break;
- }
- case type_decimal:
- {
- HqlExprArray args;
- if (!isPushed(lhs) && !isPushed(rhs) && (leftType->queryPromotedType() == right->queryType()->queryPromotedType()))
- {
- args.append(*getSizetConstant(leftType->queryPromotedType()->getSize()));
- args.append(*getPointer(lhs.expr));
- args.append(*getPointer(rhs.expr));
- op = bindTranslatedFunctionCall(leftType->isSigned() ? DecCompareDecimalId : DecCompareUDecimalId, args);
- }
- else
- {
- bool pushedLhs = ensurePushed(ctx, lhs);
- bool pushedRhs = ensurePushed(ctx, rhs);
- //NB: Arguments could be pushed in opposite order 1 <=> x *2
- if (pushedLhs && !pushedRhs)
- op = bindTranslatedFunctionCall(DecDistinctRId, args);
- else
- op = bindTranslatedFunctionCall(DecDistinctId, args);
- }
- break;
- }
- case type_set:
- case type_array:
- {
- //compare all
- OwnedHqlExpr leftAll = lhs.getIsAll();
- OwnedHqlExpr rightAll = rhs.getIsAll();
- assertex(leftAll && rightAll);
- if (leftAll != rightAll)
- {
- if (leftAll->queryValue() && rightAll->queryValue())
- {
- op = createConstant(leftAll->queryValue()->getIntValue() - rightAll->queryValue()->getIntValue());
- break;
- }
- if (getIntValue(leftAll, false) || getIntValue(rightAll, false))
- {
- op = createValue(no_sub, LINK(signedType), convertAllToInteger(leftAll), convertAllToInteger(rightAll));
- break;
- }
- }
- if (lhs.expr != rhs.expr)
- {
- HqlExprArray args;
- args.append(*getBoundLength(lhs));
- args.append(*getElementPointer(lhs.expr));
- args.append(*getBoundLength(rhs));
- args.append(*getElementPointer(rhs.expr));
- op = bindTranslatedFunctionCall(compareDataDataId, args);
- }
- if (leftAll != rightAll)
- {
- IHqlExpression * orderAll = createValue(no_sub, LINK(signedType), convertAllToInteger(leftAll), convertAllToInteger(rightAll));
- if (op)
- {
- IHqlExpression * cond = NULL;
- if (!getIntValue(leftAll, true))
- {
- if (!getIntValue(rightAll, true))
- cond = NULL;
- else
- cond = LINK(rightAll);
- }
- else
- {
- if (!getIntValue(rightAll, true))
- cond = LINK(leftAll);
- else
- cond = createBoolExpr(no_or, LINK(leftAll), LINK(rightAll));
- }
- if (cond)
- op = createValue(no_if, LINK(signedType), cond, orderAll, op);
- else
- orderAll->Release();
- }
- else
- op = orderAll;
- }
- if (!op)
- op = getZero();
- break;
- }
- case type_boolean:
- case type_swapint:
- case type_packedint:
- case type_int:
- if (!useMemCmp && !info.isEqualityCompare() && (realType->getSize() < signedType->getSize()))
- {
- op = createValue(no_sub, LINK(signedType),
- createValue(no_implicitcast, LINK(signedType), lhs.expr.getLink()),
- createValue(no_implicitcast, LINK(signedType), rhs.expr.getLink()));
- break;
- }
- //fall through
- default:
- if (useMemCmp)
- {
- HqlExprArray args;
- args.append(*lhs.expr.getLink());
- args.append(*rhs.expr.getLink());
- args.append(*getSizetConstant(leftType->getSize()));
- op = bindTranslatedFunctionCall(memcmpId, args);
- }
- else
- {
- if (info.isEqualityCompare())
- {
- op = createBoolExpr(no_ne, LINK(lhs.expr), LINK(rhs.expr));
- }
- else
- {
- ensureSimpleExpr(ctx, lhs);
- ensureSimpleExpr(ctx, rhs);
- OwnedHqlExpr testlt = createBoolExpr(no_lt, lhs.expr.getLink(), rhs.expr.getLink());
- OwnedHqlExpr retlt = createIntConstant(-1);
- OwnedHqlExpr testgt = createBoolExpr(no_gt, lhs.expr.getLink(), rhs.expr.getLink());
- OwnedHqlExpr retgt = createIntConstant(+1);
- if (info.actionIfDiffer == return_stmt)
- {
- BuildCtx subctx1(ctx);
- subctx1.addFilter(testlt);
- subctx1.addReturn(retlt);
- BuildCtx subctx2(ctx);
- subctx2.addFilter(testgt);
- subctx2.addReturn(retgt);
- return;
- }
- else
- {
- // generate (a < b ? -1 : (a > b ? +1 : 0))
- op = createValue(no_if, LINK(signedType),
- LINK(testlt), LINK(retlt),
- createValue(no_if, LINK(signedType), LINK(testgt), LINK(retgt), getZero()));
- }
- }
- }
- break;
- }
- OwnedHqlExpr safeReleaseOp = op;
- assertex(op);
- BuildCtx subctx(ctx);
- if (info.isEqualityCompare() && (info.actionIfDiffer == return_stmt))
- {
- subctx.addFilter(op);
- OwnedHqlExpr returnValue = info.getEqualityReturnValue();
- subctx.addReturn(returnValue);
- }
- else
- {
- assignBound(subctx, info.target, op);
- switch (info.actionIfDiffer)
- {
- case break_stmt:
- subctx.addFilter(info.target.expr);
- subctx.addBreak();
- break;
- case return_stmt:
- if (!isLast || info.hasDefault)
- subctx.addFilter(info.target.expr);
- else
- info.alwaysReturns = true;
- subctx.addReturn(info.target.expr);
- break;
- }
- }
- }
- void HqlCppTranslator::doBuildAssignCompare(BuildCtx & ctx, EvaluateCompareInfo & info, HqlExprArray & leftValues, HqlExprArray & rightValues, bool isFirst, bool isOuter)
- {
- assertex(leftValues.ordinality() == rightValues.ordinality());
- Owned<BuildCtx> subctx = new BuildCtx(ctx);
- OwnedHqlExpr compare = createBoolExpr(no_not, LINK(info.target.expr));
- unsigned idx;
- unsigned max = leftValues.ordinality();
- for (idx = 0; idx < max; idx++)
- {
- if ((idx & 7) == 0)
- subctx.setown(new BuildCtx(ctx));
- if (!info.actionIfDiffer && !isFirst)
- subctx->addFilter(compare);
- doBuildAssignCompareElement(*subctx, info, &leftValues.item(idx), &rightValues.item(idx), isFirst, isOuter && (idx == max-1));
- isFirst = false;
- }
- }
- void HqlCppTranslator::doBuildAssignOrder(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- HqlExprArray leftValues, rightValues;
- OwnedHqlExpr defaultValue;
- expandOrder(expr, leftValues, rightValues, defaultValue);
- optimizeOrderValues(leftValues, rightValues, false);
- EvaluateCompareInfo info(no_order);
- info.target.set(target);
- doBuildAssignCompare(ctx, info, leftValues, rightValues, true, false);
- unsigned maxLeft = leftValues.ordinality();
- if (defaultValue)
- {
- if (maxLeft != 0)
- {
- OwnedHqlExpr compare = createBoolExpr(no_not, LINK(target.expr));
- ctx.addFilter(compare);
- }
- buildExprAssign(ctx, target, defaultValue);
- }
- else if (maxLeft == 0)
- buildExprAssign(ctx, target, queryZero());
- }
- void HqlCppTranslator::doBuildReturnCompare(BuildCtx & ctx, IHqlExpression * expr, node_operator op, bool isBoolEquality)
- {
- HqlExprArray leftValues, rightValues;
- OwnedHqlExpr defaultValue;
- expandOrder(expr, leftValues, rightValues, defaultValue);
- optimizeOrderValues(leftValues, rightValues, (op == no_eq));
- EvaluateCompareInfo info(op);
- info.actionIfDiffer = return_stmt;
- info.isBoolEquality = isBoolEquality;
- info.hasDefault = (defaultValue != NULL);
- createTempFor(ctx, expr, info.target);
- doBuildAssignCompare(ctx, info, leftValues, rightValues, true, true);
- if (!info.alwaysReturns)
- {
- if (info.isBoolEquality)
- {
- OwnedHqlExpr returnValue = createConstant(defaultValue == NULL);
- buildReturn(ctx, returnValue);
- }
- else
- {
- if (defaultValue)
- buildReturn(ctx, defaultValue);
- else
- buildReturn(ctx, queryZero());
- }
- }
- }
- //---------------------------------------------------------------------------
- //-- no_hash --
- class HashCodeCreator
- {
- public:
- HashCodeCreator(HqlCppTranslator & _translator, const CHqlBoundTarget & _target, node_operator _hashKind, bool _optimizeInternal)
- : translator(_translator), target(_target), hashKind(_hashKind), optimizeInternal(_optimizeInternal)
- {
- prevFunc = NULL;
- }
- //Combine calls to the hash function on adjacent memory to minimise the number of calls
- //and the generated code size.
- void buildHash(BuildCtx & ctx, IIdAtom * func, IHqlExpression * length, IHqlExpression * ptr)
- {
- if ((func == hash32DataId) || (func == hash64DataId))
- {
- ptr = stripTranslatedCasts(ptr);
- if (prevFunc)
- {
- if ((prevFunc == func) && rightFollowsLeft(prevPtr, prevLength, ptr))
- {
- prevLength.setown(peepholeAddExpr(prevLength, length));
- return;
- }
- flush(ctx);
- }
- prevFunc = func;
- prevLength.set(length);
- prevPtr.set(ptr);
- return;
- }
- flush(ctx);
- buildCall(ctx, func, length, ptr);
- }
- void beginCondition(BuildCtx & ctx)
- {
- ensureInitialAssigned(ctx);
- flush(ctx);
- }
- void endCondition(BuildCtx & ctx)
- {
- flush(ctx);
- }
- void finish(BuildCtx & ctx)
- {
- flush(ctx);
- ensureInitialAssigned(ctx);
- }
- void setInitialValue(IHqlExpression * expr)
- {
- initialValue.set(expr);
- }
- inline node_operator kind() const { return hashKind; }
- inline bool optimize() const { return optimizeInternal; }
- protected:
- void buildCall(BuildCtx & ctx, IIdAtom * func, IHqlExpression * length, IHqlExpression * ptr)
- {
- if (func == hash32DataId)
- {
- unsigned fixedSize = (unsigned)getIntValue(length, 0);
- switch (fixedSize)
- {
- case 1: func = hash32Data1Id; break;
- case 2: func = hash32Data2Id; break;
- case 3: func = hash32Data3Id; break;
- case 4: func = hash32Data4Id; break;
- case 5: func = hash32Data5Id; break;
- case 6: func = hash32Data6Id; break;
- case 7: func = hash32Data7Id; break;
- case 8: func = hash32Data8Id; break;
- }
- if (func != hash32DataId)
- length = NULL;
- }
- HqlExprArray args;
- if (length)
- args.append(*LINK(length));
- args.append(*LINK(ptr));
- if (initialValue)
- args.append(*initialValue.getClear());
- else
- args.append(*LINK(target.expr));
- CHqlBoundExpr boundHash;
- boundHash.expr.setown(translator.bindTranslatedFunctionCall(func, args));
- translator.assign(ctx, target, boundHash);
- }
- void ensureInitialAssigned(BuildCtx & ctx)
- {
- if (initialValue)
- {
- translator.assignBound(ctx, target, initialValue);
- initialValue.clear();
- }
- }
- void flush(BuildCtx & ctx)
- {
- if (prevFunc)
- {
- buildCall(ctx, prevFunc, prevLength, prevPtr);
- prevFunc = NULL;
- }
- }
- protected:
- HqlCppTranslator & translator;
- const CHqlBoundTarget & target;
- LinkedHqlExpr initialValue;
- node_operator hashKind;
- bool optimizeInternal;
- IIdAtom * prevFunc;
- OwnedHqlExpr prevLength;
- OwnedHqlExpr prevPtr;
- };
- void HqlCppTranslator::doBuildAssignHashCrc(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- IHqlExpression * child = expr->queryChild(0);
- LinkedHqlExpr initialValue = queryZero();
- node_operator op = expr->getOperator();
- if (op == no_hash32)
- initialValue.setown(createConstant(createIntValue(HASH32_INIT, 4, false)));
- else if (op == no_hash64)
- initialValue.setown(createConstant(createIntValue(HASH64_INIT, 8, false)));
- HashCodeCreator creator(*this, target, op, expr->hasAttribute(internalAtom));
- creator.setInitialValue(initialValue);
- if (child->getOperator() != no_sortlist)
- doBuildAssignHashElement(ctx, creator, child);
- else
- {
- unsigned max = child->numChildren();
- unsigned idx;
- for (idx = 0; idx < max; idx++)
- doBuildAssignHashElement(ctx, creator, child->queryChild(idx));
- }
- creator.finish(ctx);
- }
- void HqlCppTranslator::doBuildAssignHashElement(BuildCtx & ctx, HashCodeCreator & creator, IHqlExpression * elem, IHqlExpression * record)
- {
- bool useNewSelector = elem->isDatarow() && ((elem->getOperator() != no_select) || isNewSelector(elem));
- ForEachChild(i, record)
- {
- IHqlExpression * cur = record->queryChild(i);
- switch (cur->getOperator())
- {
- case no_field:
- {
- OwnedHqlExpr selected = useNewSelector ? createNewSelectExpr(LINK(elem), LINK(cur)) : createSelectExpr(LINK(elem), LINK(cur));
- doBuildAssignHashElement(ctx, creator, selected);
- break;
- }
- case no_record:
- doBuildAssignHashElement(ctx, creator, elem, cur);
- break;
- case no_ifblock:
- doBuildAssignHashElement(ctx, creator, elem, cur->queryChild(1));
- break;
- }
- }
- }
- void HqlCppTranslator::doBuildAssignHashElement(BuildCtx & ctx, HashCodeCreator & creator, IHqlExpression * elem)
- {
- if (creator.optimize())
- {
- switch (elem->getOperator())
- {
- case no_if:
- {
- BuildCtx subctx(ctx);
- creator.beginCondition(subctx);
- IHqlStmt * cond = buildFilterViaExpr(subctx, elem->queryChild(0));
- doBuildAssignHashElement(subctx, creator, elem->queryChild(1));
- creator.endCondition(subctx);
- IHqlExpression * elseValue = elem->queryChild(2);
- if (elseValue && elseValue->getOperator() != no_constant)
- {
- subctx.selectElse(cond);
- creator.beginCondition(subctx);
- doBuildAssignHashElement(subctx, creator, elseValue);
- creator.endCondition(subctx);
- }
- return;
- }
- case no_constant:
- return;
- }
- }
- Linked<ITypeInfo> type = elem->queryType()->queryPromotedType(); // skip alien data types, to logical type.
- if (type->getTypeCode() == type_row)
- {
- doBuildAssignHashElement(ctx, creator, elem, elem->queryRecord());
- return;
- }
- IIdAtom * func=NULL;
- switch (creator.kind())
- {
- case no_hash: func = hashDataId; break;
- case no_hash32: func = hash32DataId; break;
- case no_hash64: func = hash64DataId; break;
- case no_crc: func = crcDataId; break;
- }
- CHqlBoundExpr bound;
- OwnedHqlExpr length;
- OwnedHqlExpr ptr;
- bool alreadyTrimmedRight = (elem->getOperator() == no_trim) && (elem->hasAttribute(rightAtom) || !elem->hasAttribute(leftAtom));
- //If this hash is generated internally (e.g., for a dedup) and fixed length, then can simplify the hash calculation
- bool canOptimizeHash = (creator.optimize() && isFixedSize(type));
- bool optimizeTrim = alreadyTrimmedRight || canOptimizeHash;
- switch (type->getTypeCode())
- {
- case type_string:
- {
- if (!optimizeTrim)
- {
- OwnedHqlExpr trimmed = createValue(no_trim, getStretchedType(UNKNOWN_LENGTH, type), LINK(elem));
- buildCachedExpr(ctx, trimmed, bound);
- }
- else
- buildCachedExpr(ctx, elem, bound);
- length.setown(getBoundLength(bound));
- ptr.setown(getElementPointer(bound.expr));
- }
- break;
- case type_unicode:
- {
- if (!optimizeTrim)
- {
- OwnedHqlExpr trimmed = createValue(no_trim, getStretchedType(UNKNOWN_LENGTH, type), LINK(elem));
- buildCachedExpr(ctx, trimmed, bound);
- }
- else
- buildCachedExpr(ctx, elem, bound);
- length.setown(getBoundLength(bound));
- ptr.setown(getElementPointer(bound.expr));
- switch (creator.kind())
- {
- case no_hash: func = hashUnicodeId; break;
- case no_hash32: func = hash32UnicodeId; break;
- case no_hash64: func = hash64UnicodeId; break;
- case no_crc: func = crcUnicodeId; break;
- }
- }
- break;
- case type_utf8:
- {
- if (!optimizeTrim)
- {
- OwnedHqlExpr trimmed = createValue(no_trim, getStretchedType(UNKNOWN_LENGTH, type), LINK(elem));
- buildCachedExpr(ctx, trimmed, bound);
- }
- else
- buildCachedExpr(ctx, elem, bound);
- length.setown(getBoundLength(bound));
- ptr.setown(getElementPointer(bound.expr));
- switch (creator.kind())
- {
- case no_hash: func = hashUtf8Id; break;
- case no_hash32: func = hash32Utf8Id; break;
- case no_hash64: func = hash64Utf8Id; break;
- case no_crc: func = crcUtf8Id; break;
- }
- }
- break;
- case type_data:
- {
- buildCachedExpr(ctx, elem, bound);
- length.setown(getBoundLength(bound));
- ptr.setown(getElementPointer(bound.expr));
- break;
- }
- case type_qstring:
- {
- LinkedHqlExpr exprToHash = elem;
- if (!canOptimizeHash)
- {
- //Always convert to a string so the hash is compatible with a string.
- OwnedHqlExpr cast = ensureExprType(elem, unknownStringType);
- if (alreadyTrimmedRight)
- {
- exprToHash.set(cast);
- }
- else
- {
- OwnedHqlExpr trimmed = createValue(no_trim, LINK(unknownStringType), LINK(cast));
- exprToHash.setown(foldHqlExpression(trimmed));
- }
- }
- buildCachedExpr(ctx, exprToHash, bound);
- length.setown(getBoundSize(bound));
- ptr.setown(getElementPointer(bound.expr));
- break;
- }
- case type_varstring:
- buildCachedExpr(ctx, elem, bound);
- ptr.setown(getElementPointer(bound.expr));
- switch (creator.kind())
- {
- case no_hash: func = hashVStrId; break;
- case no_hash32: func = hash32VStrId; break;
- case no_hash64: func = hash64VStrId; break;
- case no_crc: func = crcVStrId; break;
- }
- break;
- case type_varunicode:
- buildCachedExpr(ctx, elem, bound);
- ptr.setown(getElementPointer(bound.expr));
- switch (creator.kind())
- {
- case no_hash: func = hashVUnicodeId; break;
- case no_hash32: func = hash32VUnicodeId; break;
- case no_hash64: func = hash64VUnicodeId; break;
- case no_crc: func = crcVUnicodeId; break;
- }
- break;
- case type_boolean:
- case type_int:
- case type_swapint:
- case type_real:
- if (creator.optimize() && hasAddress(ctx, elem))
- {
- buildAddress(ctx, elem, bound);
- length.setown(getSizetConstant(type->getSize()));
- ptr.setown(LINK(bound.expr));
- }
- else
- {
- if (!creator.optimize())
- type.setown(makeIntType(8, true));
- OwnedHqlExpr castElem = ensureExprType(elem, type);
- buildTempExpr(ctx, castElem, bound);
- length.setown(getSizetConstant(type->getSize()));
- ptr.setown(getPointer(bound.expr));
- }
- break;
- case type_row:
- throwUnexpected();
- break;
- case type_dictionary:
- case type_groupedtable:
- case type_table:
- //MORE: Should be handle this differently, with an iterator for the link counted rows case?
- //Not sure if that is a good idea - we need to be certain we get the same values with
- //LCR rows enabled and disabled. But this won't be very efficient with lcr rows.
- //fallthrough
- if (creator.optimize() && hasOutOfLineRows(elem->queryType()))
- {
- creator.beginCondition(ctx);
- BuildCtx iterctx(ctx);
- buildDatasetIterate(iterctx, elem, false);
- doBuildAssignHashElement(iterctx, creator, elem->queryNormalizedSelector(), elem->queryRecord());
- creator.endCondition(iterctx);
- return;
- }
- else
- {
- OwnedHqlExpr serialized = ::ensureSerialized(elem, diskAtom);
- buildDataset(ctx, serialized, bound, FormatBlockedDataset);
- length.setown(getBoundSize(bound));
- ptr.setown(getPointer(bound.expr));
- }
- break;
- default:
- buildTempExpr(ctx, elem, bound, FormatBlockedDataset);
- length.setown(getBoundSize(bound));
- ptr.setown(getPointer(bound.expr));
- break;
- }
- creator.buildHash(ctx, func, length, ptr);
- }
- //---------------------------------------------------------------------------
- //-- no_hash --
- void HqlCppTranslator::doBuildAssignHashMd5(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- IHqlExpression * child = expr->queryChild(0);
- Owned<ITypeInfo> stateType = makeDataType(sizeof(md5_state_s));
- //initialize the state object
- CHqlBoundTarget stateTemp;
- CHqlBoundExpr state;
- createTempFor(ctx, stateType, stateTemp, typemod_none, FormatNatural);
- state.setFromTarget(stateTemp);
- OwnedHqlExpr stateExpr = state.getTranslatedExpr();
- HqlExprArray args;
- args.append(*LINK(stateExpr));
- OwnedHqlExpr callInit = bindFunctionCall(hashMd5InitId, args);
- buildStmt(ctx, callInit);
- //Now hash each of the elements in turn.
- if (child->getOperator() != no_sortlist)
- doBuildHashMd5Element(ctx, child, state);
- else
- {
- unsigned max = child->numChildren();
- for (unsigned idx = 0; idx < max; idx++)
- doBuildHashMd5Element(ctx, child->queryChild(idx), state);
- }
- //finalise the md5, and get the result.
- args.append(*LINK(stateExpr));
- OwnedHqlExpr callFinish = bindFunctionCall(hashMd5FinishId, args);
- buildExprAssign(ctx, target, callFinish);
- }
- void HqlCppTranslator::doBuildHashMd5Element(BuildCtx & ctx, IHqlExpression * elem, CHqlBoundExpr & state)
- {
- CHqlBoundExpr bound;
- Linked<ITypeInfo> type = elem->queryType()->queryPromotedType(); // skip alien data types, to logical type.
- HqlExprArray args;
- switch (type->getTypeCode())
- {
- case type_string:
- case type_unicode:
- case type_data:
- case type_qstring:
- case type_varstring:
- case type_varunicode:
- case type_utf8:
- buildExpr(ctx, elem, bound);
- args.append(*getBoundSize(bound));
- args.append(*getElementPointer(bound.expr));
- break;
- case type_int:
- case type_swapint:
- case type_packedint:
- {
- type.setown(makeIntType(8, true));
- OwnedHqlExpr castElem = ensureExprType(elem, type);
- buildTempExpr(ctx, castElem, bound);
- args.append(*getSizetConstant(type->getSize()));
- args.append(*getPointer(bound.expr));
- break;
- }
- default:
- buildTempExpr(ctx, elem, bound);
- args.append(*getSizetConstant(type->getSize()));
- args.append(*getPointer(bound.expr));
- break;
- }
- args.append(*getBoundSize(state));
- args.append(*LINK(state.expr));
- OwnedHqlExpr call = bindTranslatedFunctionCall(hashMd5DataId, args);
- ctx.addExpr(call);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprTransfer(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- CHqlBoundExpr bound;
- //Ensure the bound result has an address
- IHqlExpression * src = expr->queryChild(0);
- bool gotAddress = false;
- if (src->isDataset())
- {
- buildDataset(ctx, src, bound, FormatBlockedDataset);
- bound.expr.setown(getPointer(bound.expr));
- }
- else if (src->isDatarow())
- {
- Owned<IReferenceSelector> ref = buildNewRow(ctx, src);
- ref->get(ctx, bound);
- bound.expr.setown(getPointer(bound.expr));
- }
- else if (isTypePassedByAddress(src->queryType()))
- buildCachedExpr(ctx, src, bound);
- else if (hasAddress(ctx, src))
- {
- buildAddress(ctx, src, bound);
- gotAddress = true;
- }
- else
- buildTempExpr(ctx, src, bound);
- OwnedITypeInfo from = bound.expr->getType();
- ITypeInfo * to = expr->queryType();
- //Must calculate the size of the bound value before we start messing about with stripping casts etc.
- OwnedHqlExpr size;
- if (to->getSize() == UNKNOWN_LENGTH)
- {
- if (from->getSize() == UNKNOWN_LENGTH)
- size.setown(getBoundSize(bound));
- else
- size.setown(getSizetConstant(from->getSize()));
- }
- if (!isTypePassedByAddress(from) && !gotAddress)
- bound.expr.setown(getAddress(bound.expr));
- //strip unnecessary casts...
- while (bound.expr->getOperator() == no_implicitcast)
- bound.expr.set(bound.expr->queryChild(0));
- if (isTypePassedByAddress(to))
- {
- to->Link();
- if (!to->isReference())
- to = makeReferenceModifier(to);
- tgt.expr.setown(createValue(no_implicitcast, to, LINK(bound.expr)));
- if (to->getSize() == UNKNOWN_LENGTH)
- {
- switch (to->getTypeCode())
- {
- case type_unicode:
- if (size->isConstant())
- tgt.length.setown(getSizetConstant((size32_t)getIntValue(size)/sizeof(UChar)));
- else
- tgt.length.setown(createValue(no_div, LINK(sizetType), LINK(size), getSizetConstant(2)));
- break;
- case type_qstring:
- if (size->isConstant())
- tgt.length.setown(getSizetConstant(rtlQStrLength((size32_t)getIntValue(size))));
- else
- tgt.length.setown(createValue(no_div, LINK(sizetType), multiplyValue(size, 4), getSizetConstant(3)));
- break;
- case type_varstring:
- case type_varunicode:
- break;
- default:
- tgt.length.set(size);
- break;
- }
- }
- }
- else
- {
- tgt.length.clear();
- tgt.expr.set(bound.expr);
- if (hasWrapperModifier(tgt.expr->queryType()))
- tgt.expr.setown(createValue(no_implicitcast, makeReferenceModifier(LINK(queryUnqualifiedType(from))), LINK(tgt.expr)));
- tgt.expr.setown(createValue(no_implicitcast, makePointerType(LINK(to)), tgt.expr.getClear()));
- tgt.expr.setown(createValue(no_deref, LINK(to), tgt.expr.getClear()));
- }
- }
- //---------------------------------------------------------------------------
- //-- no_ordered
- void HqlCppTranslator::doBuildExprOrdered(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (ctx.getMatchExpr(expr, tgt))
- return;
- bool ascending = true;
- OwnedHqlExpr list = simplifyFixedLengthList(expr->queryChild(0));
- IHqlExpression * attr = expr->queryChild(1);
- if (attr && attr->isAttribute() && (attr->queryName() == descAtom))
- ascending = false;
- if (list->numChildren() == 0)
- throwError(HQLERR_RankOnNull);
- //create the list that is going to be sorted
- CHqlBoundExpr boundList;
- OwnedHqlExpr optimalList = getOptimialListFormat(list);
- buildExpr(ctx, optimalList, boundList);
- //create a compare function....
- ITypeInfo * elementType = boundList.expr->queryType()->queryChildType();
- unsigned elementSize = elementType->getSize();
- if (elementSize == UNKNOWN_LENGTH)
- throwError(HQLERR_OrderOnVarlengthStrings);
- StringBuffer tempName;
- getUniqueId(tempName.append('v'));
- IHqlExpression * tempCompare = createVariable(tempName.str(), makeVoidType());
- StringBuffer s;
- s.clear().append("extern int ").append(tempName).append("(const void * left, const void * right);");
- if (options.spanMultipleCpp)
- {
- BuildCtx protoctx(*code, mainprototypesAtom);
- protoctx.addQuoted(s);
- }
- else
- {
- BuildCtx protoctx(*code, prototypeAtom);
- protoctx.addQuoted(s);
- }
- BuildCtx declareCtx(*code, declareAtom);
- s.clear().append("int ").append(tempName).append("(const void * left, const void * right)");
- declareCtx.addQuotedCompound(s);
- Owned<ITypeInfo> argType;
- if (isTypePassedByAddress(elementType) && !hasReferenceModifier(elementType))
- argType.setown(makeReferenceModifier(LINK(elementType)));
- else
- argType.setown(makePointerType(LINK(elementType)));
- OwnedHqlExpr leftAddr = createVariable("left", LINK(argType));
- OwnedHqlExpr rightAddr = createVariable("right", LINK(argType));
- IHqlExpression * left = convertAddressToValue(leftAddr, elementType);
- IHqlExpression * right = convertAddressToValue(rightAddr, elementType);
- if (elementType->isReference())
- elementSize = sizeof(char * *);
- left = createTranslatedOwned(left);
- right = createTranslatedOwned(right);
- OwnedHqlExpr compare;
- if (ascending)
- compare.setown(createValue(no_order, LINK(signedType), left, right));
- else
- compare.setown(createValue(no_order, LINK(signedType), right, left));
- CHqlBoundExpr boundCompare;
- buildExpr(declareCtx, compare, boundCompare);
- declareCtx.setNextDestructor();
- declareCtx.addReturn(boundCompare.expr);
- //Allocate an array to store the orders
- unsigned max = list->numChildren();
- Owned<ITypeInfo> t = makeArrayType(LINK(unsignedType), max);
- IHqlExpression * table = ctx.getTempDeclare(t, NULL);
- ctx.associateExpr(expr, table);
- //Generate the call to the function that calculates the orders
- IHqlExpression * castCompare = createValue(no_implicitcast, makePointerType(makeVoidType()), tempCompare);
- HqlExprArray args;
- args.append(*getPointer(table));
- args.append(*getPointer(boundList.expr));
- args.append(*createConstant(unsignedType->castFrom(false, max)));
- args.append(*getSizetConstant(elementSize));
- args.append(*castCompare);
- callProcedure(ctx, createOrderId, args);
- tgt.expr.setown(table);
- }
- //---------------------------------------------------------------------------
- //-- no_rank
- void checkRankRange(IHqlExpression * index, IHqlExpression * list)
- {
- IValue * indexValue = index->queryValue();
- if (indexValue)
- {
- unsigned max = list->numChildren();
- unsigned idx = (unsigned)indexValue->getIntValue();
- //MORE: Should be a warning.....
- if ((idx < 1) || (idx > max))
- throwError(HQLERR_RankOutOfRange);
- }
- //MORE: Could dynamically allocate the array indexes...
- if (list->getOperator() == no_getresult)
- {
- StringBuffer s;
- IHqlExpression * sequence = queryAttributeChild(list, sequenceAtom, 0);
- IHqlExpression * name = queryAttributeChild(list, namedAtom, 0);
- getStoredDescription(s, sequence, name, true);
- throwError1(HQLERR_RankOnStored, s.str());
- }
- }
- void HqlCppTranslator::createOrderList(BuildCtx & ctx, IHqlExpression * expr, IHqlExpression * ascdesc, CHqlBoundExpr & tgt)
- {
- ITypeInfo * orderedType = makeArrayType(LINK(unsignedType), expr->numChildren());
- OwnedHqlExpr ordered = createValue(no_ordered, orderedType, LINK(expr), LINK(ascdesc));
- buildExpr(ctx, ordered, tgt);
- }
- void HqlCppTranslator::doBuildExprRank(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * index = expr->queryChild(0);
- IHqlExpression * list = expr->queryChild(1);
- checkRankRange(index, list);
- CHqlBoundExpr bound, boundIndex;
- createOrderList(ctx, list, expr->queryChild(2), bound);
- buildExpr(ctx, index, boundIndex);
- HqlExprArray args;
- args.append(*boundIndex.expr.getClear());
- args.append(*createConstant(unsignedType->castFrom(false, list->numChildren())));
- args.append(*getPointer(bound.expr));
- tgt.expr.setown(bindTranslatedFunctionCall(rankFromOrderId, args));
- }
- //---------------------------------------------------------------------------
- //-- no_ranked
- void HqlCppTranslator::doBuildExprRanked(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * index = expr->queryChild(0);
- IHqlExpression * list = expr->queryChild(1);
- checkRankRange(index, list);
- CHqlBoundExpr bound, boundIndex;
- createOrderList(ctx, list, expr->queryChild(2), bound);
- buildExpr(ctx, index, boundIndex);
- HqlExprArray args;
- args.append(*boundIndex.expr.getClear());
- args.append(*createConstant(unsignedType->castFrom(false, list->numChildren())));
- args.append(*getPointer(bound.expr));
- tgt.expr.setown(bindTranslatedFunctionCall(rankedFromOrderId, args));
- }
- //---------------------------------------------------------------------------
- //-- no_fail
- void HqlCppTranslator::doBuildStmtFail(BuildCtx & ctx, IHqlExpression * expr)
- {
- HqlExprArray args;
- args.append(*getFailCode(expr));
- args.append(*getFailMessage(expr, false));
- IIdAtom * func = expr->hasAttribute(defaultAtom) ? sysFailId : _failId;
- OwnedHqlExpr call = bindFunctionCall(func, args);
- buildStmt(ctx, call);
- }
- void HqlCppTranslator::doBuildExprFailCode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- OwnedHqlExpr activeFailMarker = createAttribute(activeFailureAtom);
- HqlExprAssociation * matchedMarker = ctx.queryMatchExpr(activeFailMarker);
- if (!matchedMarker && !ctx.queryMatchExpr(globalContextMarkerExpr))
- {
- if (!buildExprInCorrectContext(ctx, expr, tgt, false))
- throwError1(HQLERR_FailXUsedOutsideFailContext, getOpString(expr->getOperator()));
- return;
- }
- HqlExprArray args;
- if (matchedMarker)
- {
- args.append(*LINK(matchedMarker->queryExpr()));
- tgt.expr.setown(bindTranslatedFunctionCall(queryLocalFailCodeId, args));
- }
- else
- {
- tgt.expr.setown(bindTranslatedFunctionCall(queryFailCodeId, args));
- }
- }
- void HqlCppTranslator::doBuildAssignFailMessage(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- OwnedHqlExpr activeFailMarker = createAttribute(activeFailureAtom);
- HqlExprAssociation * matchedMarker = ctx.queryMatchExpr(activeFailMarker);
- if (!matchedMarker && !ctx.queryMatchExpr(globalContextMarkerExpr))
- {
- CHqlBoundExpr match;
- if (!buildExprInCorrectContext(ctx, expr, match, false))
- throwError1(HQLERR_FailXUsedOutsideFailContext, getOpString(expr->getOperator()));
- assign(ctx, target, match);
- return;
- }
- IIdAtom * func = getFailMessageId;
- HqlExprArray args;
- if (matchedMarker)
- {
- func = getLocalFailMessageId;
- args.append(*createTranslated(matchedMarker->queryExpr()));
- }
- LinkedHqlExpr tag = expr->queryChild(0);
- if (!tag)
- tag.setown(createQuoted("0", makeConstantModifier(makeReferenceModifier(makeVarStringType(UNKNOWN_LENGTH, 0, 0)))));
- args.append(*LINK(tag));
- OwnedHqlExpr call = bindFunctionCall(func, args);
- buildExprAssign(ctx, target, call);
- }
- void HqlCppTranslator::doBuildAssignEventName(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- HqlExprArray args;
- OwnedHqlExpr call = bindFunctionCall(getEventNameId, args);
- buildExprAssign(ctx, target, call);
- }
- void HqlCppTranslator::doBuildAssignEventExtra(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- LinkedHqlExpr tag = expr->queryChild(0);
- if (!tag)
- tag.setown(createQuoted("0", makeConstantModifier(makeReferenceModifier(makeVarStringType(UNKNOWN_LENGTH, 0, 0)))));
- HqlExprArray args;
- args.append(*LINK(tag));
- OwnedHqlExpr call = bindFunctionCall(getEventExtraId, args);
- buildExprAssign(ctx, target, call);
- }
- //---------------------------------------------------------------------------
- //-- system call e.g. EXP(), LOG()...
- void HqlCppTranslator::doBuildExprSysFunc(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt, IIdAtom * funcName)
- {
- HqlExprArray args;
- ForEachChild(i, expr)
- {
- IHqlExpression * cur = expr->queryChild(i);
- if (!cur->isAttribute())
- args.append(*LINK(cur));
- }
- OwnedHqlExpr call = bindFunctionCall(funcName, args);
- buildExpr(ctx, call, tgt);
- }
- void HqlCppTranslator::doBuildExprOffsetOf(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (ctx.getMatchExpr(expr, tgt))
- return;
- IHqlExpression * arg = expr->queryChild(0);
- Owned<IReferenceSelector> selector = buildActiveReference(ctx, arg);
- selector->getOffset(ctx, tgt);
- //cache non-constant values in a temporary variable...
- if (!isSimpleLength(tgt.expr))
- {
- IHqlExpression * temp = ctx.getTempDeclare(expr->queryType(), tgt.expr);
- tgt.expr.setown(temp);
- ctx.associateExpr(expr, tgt);
- }
- }
- //---------------------------------------------------------------------------
- //-- no_subselect --
- void HqlCppTranslator::doBuildAssignSubString(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- if (expr->queryChild(1)->getOperator() == no_rangecommon)
- throwError(HQLERR_StarRangeOnlyInJoinCondition);
- ITypeInfo * resultType = expr->queryType();
- ITypeInfo * targetType = target.queryType();
- type_t rtc = resultType->getTypeCode();
- type_t ttc = targetType->getTypeCode();
- SubStringInfo info(expr);
- CHqlBoundExpr newBound;
- bool doneAssign = false;
- if (info.special)
- doBuildExprSpecialSubString(ctx, info, newBound);
- else if (info.infiniteString)
- doBuildExprInfiniteSubString(ctx, info, newBound);
- if (!newBound.expr)
- {
- IIdAtom * func = NULL;
- type_t stc = info.src->queryType()->getTypeCode();
- if (target.isFixedSize())
- {
- switch (ttc)
- {
- case type_qstring:
- if (stc == type_qstring)
- func = subQStrFTId;
- break;
- case type_data:
- switch (stc)
- {
- case type_data:
- case type_string:
- case type_varstring:
- func = subDataFTId;
- break;
- }
- break;
- case type_string:
- switch (stc)
- {
- case type_data:
- func = subDataFTId;
- break;
- case type_string:
- case type_varstring:
- if (resultType->queryCharset() == info.src->queryType()->queryCharset())
- func = subStrFTId;
- break;
- }
- break;
- }
- if (!func && (queryUnqualifiedType(resultType) != queryUnqualifiedType(targetType)))
- {
- CHqlBoundExpr bound;
- buildTempExpr(ctx, expr, bound);
- assign(ctx, target, bound);
- return;
- }
- }
- CHqlBoundExpr boundSrc;
- buildCachedExpr(ctx, info.src, boundSrc);
- info.bindToFrom(*this, ctx);
- if (!info.boundFrom.expr)
- info.boundFrom.expr.setown(getSizetConstant(1));
- //Some hacks to force the parameters/return values to the same type. It could be solved more cleanly,
- //but with more functions by calling different functions instead.
- CHqlBoundTarget tempTarget;
- tempTarget.set(target);
- switch (rtc)
- {
- case type_string:
- if (resultType->queryCollation()->queryName() != asciiAtom)
- {
- unsigned sourceLen = boundSrc.queryType()->getStringLen();
- boundSrc.expr.setown(createValue(no_typetransfer, makeStringType(sourceLen, NULL, NULL), LINK(boundSrc.expr)));
- OwnedITypeInfo newTargetType = makeStringType(targetType->getStringLen(), NULL, NULL);
- tempTarget.expr.setown(createValue(no_typetransfer, cloneModifiers(targetType, newTargetType), LINK(tempTarget.expr)));
- }
- break;
- }
- HqlExprArray args;
- args.append(*boundSrc.getTranslatedExpr());
- args.append(*info.boundFrom.getTranslatedExpr());
- if (func)
- {
- args.add(*createTranslated(tempTarget.expr), 0);
- if (info.boundTo.expr)
- args.append(*info.boundTo.getTranslatedExpr());
- else
- args.append(*createConstant(unsignedType->castFrom(false, 0x7fffffff)));
- OwnedHqlExpr call = bindFunctionCall(func, args);
- buildStmt(ctx, call);
- }
- else
- {
- if (info.boundTo.expr)
- {
- args.append(*info.boundTo.getTranslatedExpr());
- switch (rtc)
- {
- case type_qstring:
- func = subQStrFTXId;
- break;
- case type_data:
- func = subDataFTXId;
- break;
- case type_unicode:
- case type_varunicode:
- func = unicodeSubStrFTXId;
- break;
- case type_utf8:
- func = utf8SubStrFTXId;
- break;
- default:
- func = subStrFTXId;
- break;
- }
- }
- else
- {
- switch (rtc)
- {
- case type_qstring:
- func = subQStrFXId;
- break;
- case type_data:
- func = subDataFXId;
- break;
- case type_unicode:
- case type_varunicode:
- func = unicodeSubStrFXId;
- break;
- case type_utf8:
- func = utf8SubStrFXId;
- break;
- default:
- func = subStrFXId;
- break;
- }
- }
- OwnedHqlExpr call = bindFunctionCall(func, args);
- buildExprAssign(ctx, tempTarget, call);
- }
- doneAssign = true;
- }
- if (!doneAssign)
- assign(ctx, target, newBound);
- }
- bool HqlCppTranslator::doBuildExprSpecialSubString(BuildCtx & ctx, SubStringInfo & info, CHqlBoundExpr & tgt)
- {
- unsigned size = info.srcType->getStringLen();
- unsigned fromIndex = info.fixedStart;
- unsigned toIndex = info.fixedEnd;
- //If substring is larger than the source use the default processing.
- if (toIndex <= size)
- {
- CHqlBoundExpr boundSrc;
- buildCachedExpr(ctx, info.src, boundSrc);
- boundSrc.expr.setown(getIndexedElementPointer(boundSrc.expr, fromIndex-1));
- unsigned newLength = fromIndex <= toIndex ? toIndex-(fromIndex-1) : 0;
- ITypeInfo * newType = makeReferenceModifier(getStretchedType(newLength, info.srcType));
- tgt.expr.setown(createValue(no_typetransfer, newType, boundSrc.expr.getClear()));
- if (info.expr->queryType()->getStringLen() != newLength)
- tgt.length.setown(getSizetConstant(newLength));
- return true;
- }
- return false;
- }
- bool HqlCppTranslator::doBuildExprInfiniteSubString(BuildCtx & ctx, SubStringInfo & info, CHqlBoundExpr & tgt)
- {
- CHqlBoundExpr boundSrc;
- info.bindToFrom(*this, ctx);
- buildCachedExpr(ctx, info.src, boundSrc);
- IHqlExpression * from = info.from;
- if (info.fixedStart == 1)
- from = NULL;
- IHqlExpression * start = from ? adjustValue(info.boundFrom.expr, -1) : NULL;
- tgt.expr.setown(getIndexedElementPointer(boundSrc.expr, start));
- //ensure type is no longer infinite length, so same optimization does not happen again...
- ITypeInfo * newType = makeReferenceModifier(getStretchedType(UNKNOWN_LENGTH, tgt.expr->queryType()));
- tgt.expr.setown(createValue(no_typetransfer, newType, tgt.expr.getLink()));
- OwnedHqlExpr length;
- if (start && !isZero(start))
- length.setown(createValue(no_sub, info.boundTo.expr.getLink(), LINK(start)));
- else
- length.setown(info.boundTo.expr.getLink());
- tgt.length.setown(ensureExprType(length, sizetType));
- ::Release(start);
- return true;
- }
- void HqlCppTranslator::doBuildExprAnySubString(BuildCtx & ctx, SubStringInfo & info, CHqlBoundExpr & tgt)
- {
- CHqlBoundExpr boundSource;
- buildCachedExpr(ctx, info.src, boundSource);
- info.bindToFrom(*this, ctx);
- OwnedHqlExpr from;
- if (info.from)
- {
- OwnedHqlExpr start = adjustValue(info.boundFrom.expr, -1);
- if (!isZero(start))
- {
- HqlExprArray args;
- args.append(*LINK(start));
- args.append(*getBoundLength(boundSource));
- OwnedHqlExpr call = bindTranslatedFunctionCall(rtlMinId, args);
- call.setown(createTranslated(call));
- CHqlBoundExpr fromVar;
- buildTempExpr(ctx, call, fromVar);
- from.set(fromVar.expr);
- }
- }
- OwnedHqlExpr to;
- if (info.to)
- {
- OwnedHqlExpr toExpr = LINK(info.boundTo.expr);
- if (from)
- {
- HqlExprArray args;
- args.append(*LINK(toExpr));
- args.append(*LINK(from));
- toExpr.setown(bindTranslatedFunctionCall(rtlMaxId, args));
- }
- HqlExprArray args;
- args.append(*LINK(toExpr));
- args.append(*getBoundLength(boundSource));
- to.setown(bindTranslatedFunctionCall(rtlMinId, args));
- }
- else
- to.setown(getBoundLength(boundSource));
- boundSource.expr.setown(getIndexedElementPointer(boundSource.expr, from));
- ITypeInfo * newType = makeReferenceModifier(info.expr->getType());
- tgt.expr.setown(createValue(no_typetransfer, newType, boundSource.expr.getClear()));
- if (from && !isZero(from))
- tgt.length.setown(createValue(no_sub, LINK(sizetType), LINK(to), LINK(from)));
- else
- tgt.length.set(to);
- }
- void HqlCppTranslator::doBuildExprSubString(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- if (expr->queryChild(1)->getOperator() == no_rangecommon)
- throwError(HQLERR_StarRangeOnlyInJoinCondition);
- /* Optimize string[start..end] into a type transfer where appropriate */
- SubStringInfo info(expr);
-
- if (info.special)
- if (doBuildExprSpecialSubString(ctx, info, tgt))
- return;
-
- if (info.infiniteString)
- if (doBuildExprInfiniteSubString(ctx, info, tgt))
- return;
- if (expr->hasAttribute(quickAtom))
- {
- doBuildExprAnySubString(ctx, info, tgt);
- return;
- }
- buildTempExpr(ctx, expr, tgt);
- }
- //---------------------------------------------------------------------------
- //-- no_trim --
- void HqlCppTranslator::doBuildAssignTrim(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- IHqlExpression * str = expr->queryChild(0);
- IIdAtom * func;
- bool hasAll = expr->hasAttribute(allAtom);
- bool hasLeft = expr->hasAttribute(leftAtom);
- bool hasRight = expr->hasAttribute(rightAtom);
- if (str->queryType()->getTypeCode() == type_varstring)
- {
- if(hasAll)
- func = trimVAllId;
- else if(hasLeft && hasRight)
- func = trimVBothId;
- else if(hasLeft)
- func = trimVLeftId;
- else
- func = trimVRightId;
- }
- else if(str->queryType()->getTypeCode() == type_unicode)
- {
- if(hasAll)
- func = trimUnicodeAllId;
- else if(hasLeft && hasRight)
- func = trimUnicodeBothId;
- else if(hasLeft)
- func = trimUnicodeLeftId;
- else
- func = trimUnicodeRightId;
- }
- else if(str->queryType()->getTypeCode() == type_varunicode)
- {
- if(hasAll)
- func = trimVUnicodeAllId;
- else if(hasLeft && hasRight)
- func = trimVUnicodeBothId;
- else if(hasLeft)
- func = trimVUnicodeLeftId;
- else
- func = trimVUnicodeRightId;
- }
- else if(str->queryType()->getTypeCode() == type_utf8)
- {
- if(hasAll)
- func = trimUtf8AllId;
- else if(hasLeft && hasRight)
- func = trimUtf8BothId;
- else if(hasLeft)
- func = trimUtf8LeftId;
- else
- func = trimUtf8RightId;
- }
- else
- {
- if(hasAll)
- func = trimAllId;
- else if(hasLeft && hasRight)
- func = trimBothId;
- else if(hasLeft)
- func = trimLeftId;
- else
- func = trimRightId;
- }
- HqlExprArray args;
- args.append(*LINK(str));
- OwnedHqlExpr call = bindFunctionCall(func, args);
- buildExprAssign(ctx, target, call);
- }
- void HqlCppTranslator::doBuildExprTrim(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- // MORE - support LEFT,RIGHT,ALL attributes
- CHqlBoundExpr bound;
- buildSimpleExpr(ctx, expr->queryChild(0), bound);
- HqlExprArray args;
- IIdAtom * func;
- OwnedHqlExpr str = getElementPointer(bound.expr);
-
- bool hasAll = expr->hasAttribute(allAtom);
- bool hasLeft = expr->hasAttribute(leftAtom);
- bool hasRight = expr->hasAttribute(rightAtom);
-
- type_t btc = bound.expr->queryType()->getTypeCode();
- if(hasAll || hasLeft)
- {
- if (btc == type_varstring)
- {
- if(hasAll) {
- func = trimVAllId;
- }
- else if(hasLeft && hasRight) {
- func = trimVBothId;
- }
- else {
- func = trimVLeftId;
- }
- }
- else if (btc == type_unicode)
- {
- if(hasAll) {
- func = trimUnicodeAllId;
- }
- else if(hasLeft && hasRight) {
- func = trimUnicodeBothId;
- }
- else {
- func = trimUnicodeLeftId;
- }
- }
- else if (btc == type_varunicode)
- {
- if(hasAll) {
- func = trimVUnicodeAllId;
- }
- else if(hasLeft && hasRight) {
- func = trimVUnicodeBothId;
- }
- else {
- func = trimVUnicodeLeftId;
- }
- }
- else if (btc == type_utf8)
- {
- if(hasAll) {
- func = trimUtf8AllId;
- }
- else if(hasLeft && hasRight) {
- func = trimUtf8BothId;
- }
- else {
- func = trimUtf8LeftId;
- }
- }
- else
- {
- if(hasAll) {
- func = trimAllId;
- }
- else if(hasLeft && hasRight) {
- func = trimBothId;
- }
- else {
- func = trimLeftId;
- }
- }
- args.append(*bound.getTranslatedExpr());
- OwnedHqlExpr call = bindFunctionCall(func, args);
- buildExpr(ctx, call, tgt);
- }
- else {
- if (btc == type_varstring)
- {
- args.append(*LINK(str));
- func = trimVStrLenId;
- }
- else if (btc == type_unicode)
- {
- args.append(*getBoundLength(bound));
- args.append(*LINK(str));
- func = trimUnicodeStrLenId;
- }
- else if (btc == type_varunicode)
- {
- args.append(*LINK(str));
- func = trimVUnicodeStrLenId;
- }
- else if (btc == type_utf8)
- {
- args.append(*getBoundLength(bound));
- args.append(*LINK(str));
- func = trimUtf8StrLenId;
- }
- else
- {
- args.append(*getBoundLength(bound));
- args.append(*LINK(str));
- func = trimStrLenId;
- }
- tgt.length.setown(bindTranslatedFunctionCall(func, args));
- tgt.expr.set(str);
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprIsValid(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- IHqlExpression * const value = expr->queryChild(0);
- HqlExprArray args;
- ITypeInfo * type = value->queryType();
- assertex(type);
- if (type->getTypeCode() == type_alien)
- {
- IHqlAlienTypeInfo * alien = queryAlienType(type);
- IHqlExpression * isValidFunction = alien->queryFunction(getIsValidId);
- if (isValidFunction)
- {
- CHqlBoundExpr bound;
- buildAddress(ctx, value, bound);
-
- OwnedITypeInfo physicalType = alien->getPhysicalType();
- if (!isTypePassedByAddress(physicalType))
- bound.expr.setown(createValue(no_deref, makeReferenceModifier(LINK(physicalType)), LINK(bound.expr)));
- HqlExprArray args;
- args.append(*bound.getTranslatedExpr());
- OwnedHqlExpr test = createBoundFunction(NULL, isValidFunction, args, NULL, true);
- buildExpr(ctx, test, tgt);
- return;
- }
- else
- type = alien->queryLogicalType();
- }
- CHqlBoundExpr bound;
- buildExpr(ctx, value, bound);
- type_t tc = type->getTypeCode();
- if ((tc == type_decimal) && (bound.expr->getOperator() == no_decimalstack))
- {
- tgt.expr.setown(bindTranslatedFunctionCall(DecValidTosId, args));
- return;
- }
- ensureHasAddress(ctx, bound);
- OwnedHqlExpr address = getPointer(bound.expr);
- switch (tc)
- {
- case type_decimal:
- args.append(*createConstant(type->isSigned()));
- args.append(*getSizetConstant(type->getDigits()));
- args.append(*address.getLink());
- tgt.expr.setown(bindTranslatedFunctionCall(DecValidId, args));
- break;
- case type_real:
- args.append(*getSizetConstant(type->getSize()));
- args.append(*address.getLink());
- tgt.expr.setown(bindTranslatedFunctionCall(validRealId, args));
- break;
- default:
- tgt.expr.set(queryBoolExpr(true));
- break;
- }
- }
- IHqlExpression * HqlCppTranslator::getConstWuid(IHqlExpression * expr)
- {
- SCMStringBuffer out;
- wu()->getWuid(out);
- OwnedHqlExpr wuid = createConstant(out.str());
- return ensureExprType(wuid, expr->queryType());
- }
- void HqlCppTranslator::doBuildAssignWuid(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- HqlExprArray args;
- OwnedHqlExpr call = bindFunctionCall(getWuidId, args);
- buildExprAssign(ctx, target, call);
- }
- void HqlCppTranslator::doBuildExprWuid(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- HqlExprArray args;
- OwnedHqlExpr call = bindFunctionCall(getWuidId, args);
- buildTempExpr(ctx, call, tgt);
- }
- IHqlExpression * HqlCppTranslator::cvtGetEnvToCall(IHqlExpression * expr)
- {
- IHqlExpression * dft = queryRealChild(expr, 1);
- HqlExprArray args;
- args.append(*LINK(expr->queryChild(0)));
- if (dft)
- args.append(*LINK(dft));
- else
- args.append(*createConstant(createStringValue((const char *)NULL, 0U)));
- return bindFunctionCall(getEnvId, args);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildAssignToFromUnicode(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- HqlExprArray args;
- if(!target.isFixedSize())
- {
- args.append(*LINK(expr->queryChild(0)));
- args.append(*foldHqlExpression(expr->queryChild(1)));
- OwnedHqlExpr call = bindFunctionCall((expr->getOperator() == no_fromunicode) ? unicode2CodepageXId : codepage2UnicodeXId, args);
- buildExprAssign(ctx, target, call);
- }
- else
- {
- args.append(*createTranslated(target.expr));
- args.append(*LINK(expr->queryChild(0)));
- args.append(*foldHqlExpression(expr->queryChild(1)));
- OwnedHqlExpr call = bindFunctionCall((expr->getOperator() == no_fromunicode) ? unicode2CodepageId : codepage2UnicodeId, args);
- buildStmt(ctx, call);
- }
- }
- void HqlCppTranslator::doBuildExprToFromUnicode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- HqlExprArray args;
- args.append(*LINK(expr->queryChild(0)));
- args.append(*foldHqlExpression(expr->queryChild(1)));
- OwnedHqlExpr call = bindFunctionCall((expr->getOperator() == no_fromunicode) ? unicode2CodepageXId : codepage2UnicodeXId, args);
- buildExpr(ctx, call, tgt);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildExprKeyUnicode(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- HqlExprArray args;
- args.append(*LINK(expr->queryChild(0)));
- args.append(*LINK(expr->queryChild(1)));
- args.append(*LINK(expr->queryChild(2)));
- OwnedHqlExpr call = bindFunctionCall(keyUnicodeStrengthXId, args);
- buildExpr(ctx, call, tgt);
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildAssignWhich(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
- {
- BuildCtx whichCtx(ctx);
- unsigned max = expr->numChildren();
- unsigned idx;
- bool invert = (expr->getOperator() == no_rejected);
- for (idx = 0; idx < max; idx++)
- {
- IHqlExpression * cur = expr->queryChild(idx);
- CHqlBoundExpr bound;
- if (invert)
- {
- OwnedHqlExpr inverse = getInverse(cur);
- buildExpr(whichCtx, inverse, bound);
- }
- else
- buildExpr(whichCtx, cur, bound);
- IHqlStmt * stmt = whichCtx.addFilter(bound.expr);
- OwnedHqlExpr value = createConstant(target.queryType()->castFrom(false, idx+1));
- assignBound(whichCtx, target, value);
- whichCtx.selectElse(stmt);
- }
- assignBound(whichCtx, target, queryZero());
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::assignBound(BuildCtx & ctx, const CHqlBoundTarget & lhs, IHqlExpression * rhs)
- {
- CHqlBoundExpr bound;
- bound.expr.set(rhs);
- assign(ctx, lhs, bound);
- }
- void HqlCppTranslator::assignBoundToTemp(BuildCtx & ctx, IHqlExpression * lhs, IHqlExpression * rhs)
- {
- CHqlBoundExpr bound;
- CHqlBoundTarget target;
- bound.expr.set(rhs);
- target.expr.set(lhs);
- assign(ctx, target, bound);
- }
- void HqlCppTranslator::assign(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & rhs)
- {
- if (!target.isFixedSize())
- {
- assignCastUnknownLength(ctx, target, rhs);
- return;
- }
- IHqlExpression * lhs = target.expr;
- ITypeInfo * lType = lhs->queryType()->queryPromotedType();
- if (!isSameBasicType(lType, rhs.expr->queryType()->queryPromotedType()))
- assignAndCast(ctx, target, rhs);
- else
- {
- switch (lType->getTypeCode())
- {
- case type_decimal:
- if (isPushed(rhs))
- {
- IIdAtom * funcName = lType->isSigned() ? DecPopDecimalId : DecPopUDecimalId;
- HqlExprArray args;
- args.append(*getPointer(lhs));
- args.append(*getSizetConstant(lType->getSize()));
- args.append(*getSizetConstant(lType->getPrecision()));
- callProcedure(ctx, funcName, args);
- return;
- }
- buildBlockCopy(ctx, lhs, rhs);
- return;
- case type_string:
- {
- if (lType->getSize() == 1 && !options.peephole)
- {
- OwnedHqlExpr l1 = getFirstCharacter(lhs);
- OwnedHqlExpr r1 = getFirstCharacter(rhs.expr);
- ctx.addAssign(l1, r1);
- }
- else
- buildBlockCopy(ctx, lhs, rhs);
- break;
- }
- //fall through...
- case type_unicode:
- case type_data:
- case type_qstring:
- case type_utf8:
- {
- buildBlockCopy(ctx, lhs, rhs);
- break;
- }
- case type_varstring:
- {
- HqlExprArray args;
- args.append(*getElementPointer(lhs));
- args.append(*getElementPointer(rhs.expr));
-
- callProcedure(ctx, strcpyId, args);
- break;
- }
- case type_varunicode:
- {
- HqlExprArray args;
- args.append(*getElementPointer(lhs));
- args.append(*getElementPointer(rhs.expr));
-
- callProcedure(ctx, unicodeStrcpyId, args);
- break;
- }
- case type_row:
- {
- if (hasWrapperModifier(target.queryType()))
- {
- //I can't think of any situation where this isn't true....
- assertex(hasLinkCountedModifier(rhs.expr));
- StringBuffer assignText;
- generateExprCpp(assignText, lhs).append(".set(");
- generateExprCpp(assignText, rhs.expr).append(");");
- ctx.addQuoted(assignText);
- //Could generate the following instead
- //ctx.addAssign(lhs, no_link(rhs.expr));
- //And post-optimize to the above.
- }
- else
- ctx.addAssign(lhs, rhs.expr);
- break;
- }
- default:
- ctx.addAssign(lhs, rhs.expr);
- break;
- }
- }
- }
- void HqlCppTranslator::doStringTranslation(BuildCtx & ctx, ICharsetInfo * tgtset, ICharsetInfo * srcset, unsigned tgtlen, IHqlExpression * srclen, IHqlExpression * target, IHqlExpression * src)
- {
- HqlExprArray args;
- ITranslationInfo * translator = queryDefaultTranslation(tgtset, srcset);
- if (translator)
- {
- IIdAtom * func = createIdAtom(translator->queryRtlFunction());
- args.append(*getSizetConstant(tgtlen));
- args.append(*getElementPointer(target));
- args.append(*LINK(srclen));
- args.append(*getElementPointer(src));
- callProcedure(ctx, func, args);
- }
- }
- void HqlCppTranslator::assignSwapInt(BuildCtx & ctx, ITypeInfo * to, const CHqlBoundTarget & target, CHqlBoundExpr & pure)
- {
- switch (pure.expr->getOperator())
- {
- case no_deref:
- case no_variable:
- break;
- default:
- {
- OwnedHqlExpr translated = pure.getTranslatedExpr();
- pure.clear();
- buildTempExpr(ctx, translated, pure);
- break;
- }
- }
- ITypeInfo * from = pure.expr->queryType();
- unsigned copySize = to->getSize();
- assertex(copySize == from->getSize());
- IHqlExpression * address = getRawAddress(pure.expr);
- switch (copySize)
- {
- case 1:
- ctx.addAssign(target.expr, pure.expr);
- break;
- default:
- {
- HqlExprArray args;
- args.append(*address);
- OwnedHqlExpr call = bindTranslatedFunctionCall(reverseIntId[copySize][to->isSigned()], args);
- ctx.addAssign(target.expr, call);
- break;
- }
- }
- }
- void HqlCppTranslator::throwCannotCast(ITypeInfo * from, ITypeInfo * to)
- {
- StringBuffer fromText, toText;
- getFriendlyTypeStr(from, fromText);
- getFriendlyTypeStr(to, toText);
- throwError2(HQLERR_CastXNotImplemented, fromText.str(), toText.str());
- }
- void HqlCppTranslator::assignAndCast(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & pure)
- {
- if (!target.isFixedSize())
- {
- assignCastUnknownLength(ctx, target, pure);
- return;
- }
- ITypeInfo * to = target.queryType()->queryPromotedType();
- if ((pure.expr->getOperator() == no_constant) && options.foldConstantCast &&
- ((options.inlineStringThreshold == 0) || (to->getSize() <= options.inlineStringThreshold)))
- {
- OwnedHqlExpr cast = getCastExpr(to, pure.expr);
- if (cast)
- {
- assignBound(ctx, target, cast);
- return;
- }
- }
- //NB: Does not include variable length return types....
- ITypeInfo * from = (pure.expr->queryType()->queryPromotedType());
- type_t toType = to->getTypeCode();
- type_t fromType = from->getTypeCode();
- unsigned toSize = to->getSize();
- IHqlExpression * targetVar = target.expr;
- HqlExprArray args;
- assertex(targetVar);
- assertex(toSize != UNKNOWN_LENGTH);
- switch(toType)
- {
- case type_qstring:
- switch (fromType)
- {
- case type_qstring:
- {
- unsigned srcsize = from->getSize();
- if (!pure.length && (srcsize == toSize))
- {
- //memcpy(tgt, src, srclen)
- args.append(*getElementPointer(targetVar));
- args.append(*getElementPointer(pure.expr));
- args.append(*getSizetConstant(toSize));
- callProcedure(ctx, memcpyId, args);
- }
- else
- {
- args.append(*getSizetConstant(to->getStringLen()));
- args.append(*getElementPointer(targetVar));
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, qstrToQStrId, args);
- }
- break;
- }
- case type_data:
- case type_varstring:
- case type_string:
- {
- if(!queryDefaultTranslation(to->queryCharset(), from->queryCharset()))
- {
- args.append(*getSizetConstant(to->getStringLen()));
- args.append(*getElementPointer(targetVar));
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, strToQStrId, args);
- break;
- }
- //fall through
- }
- default:
- //Need to go via a temporary string.
- OwnedHqlExpr temp = pure.getTranslatedExpr();
- buildExprAssignViaString(ctx, target, temp, to->getStringLen());
- return;
- }
- break;
- case type_data:
- case type_string:
- case type_varstring:
- {
- unsigned srclen = from->getSize();
- ICharsetInfo * srcset = NULL;
- ICharsetInfo * tgtset = to->queryCharset();
- IIdAtom * func = NULL;
- switch (fromType)
- {
- case type_data:
- case type_string:
- case type_varstring:
- {
- srcset = from->queryCharset();
- OwnedHqlExpr boundLen = getBoundLength(pure);
- if ((srcset == tgtset) || (toType == type_data) || (fromType == type_data))
- {
- bool doDefault = true;
- if (boundLen->queryValue())
- {
- unsigned srclen = (unsigned)boundLen->queryValue()->getIntValue();
- if (srclen >= toSize && toType != type_varstring)
- {
- if (srclen > toSize)
- srclen = toSize;
- //memcpy(tgt, src, srclen)
- args.append(*getElementPointer(targetVar));
- args.append(*getElementPointer(pure.expr));
- args.append(*getSizetConstant(srclen));
- callProcedure(ctx, memcpyId, args);
- doDefault = false;
- }
- }
- if (doDefault)
- {
- if (fromType == type_varstring)
- {
- switch (toType)
- {
- case type_varstring: func = vstr2VStrId; break;
- case type_string: func = vstr2StrId; break;
- case type_data: func = vstr2DataId; break;
- default: UNIMPLEMENTED;
- }
- if ((toSize < srclen) || (srclen==UNKNOWN_LENGTH) || (toType != type_varstring))
- {
- args.append(*getSizetConstant(toSize));
- args.append(*getElementPointer(targetVar));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, func, args);
- }
- else
- {
- //strcpy(tgt, src);
- args.append(*getElementPointer(targetVar));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, strcpyId, args);
- }
- }
- else
- {
- switch (toType)
- {
- case type_data:
- func = str2DataId;
- break;
- case type_varstring:
- func = str2VStrId;
- break;
- case type_string:
- func = (srcset->queryName() == ebcdicAtom) ? estr2EStrId : str2StrId;
- break;
- }
- args.append(*getSizetConstant(toSize));
- args.append(*getElementPointer(targetVar));
- args.append(*LINK(boundLen));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, func, args);
- }
- }
- }
- else
- {
- if ((from->getSize() == INFINITE_LENGTH) && !pure.length)
- throwError(HQLERR_CastInfiniteString);
-
- IHqlExpression * srclen;
- if (toType == type_varstring)
- {
- srclen = getSizetConstant(toSize);
- args.append(*srclen);
- args.append(*getElementPointer(targetVar));
- args.append(*LINK(boundLen));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, estr2VStrId, args);
- }
- else
- doStringTranslation(ctx, tgtset, srcset, toSize, boundLen, targetVar, pure.expr);
- }
- }
- break;
- case type_qstring:
- if (queryDefaultTranslation(tgtset, from->queryCharset()))
- {
- OwnedHqlExpr temp = pure.getTranslatedExpr();
- buildExprAssignViaString(ctx, target, temp, to->getStringLen());
- }
- else
- {
- switch (toType)
- {
- case type_varstring: func = qstr2VStrId; break;
- case type_string: func = qstr2StrId; break;
- case type_data: func = qstr2DataId; break;
- }
- args.append(*getSizetConstant(toSize));
- args.append(*getElementPointer(targetVar));
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- callProcedure(ctx, func, args);
- }
- break;
- case type_unicode:
- case type_varunicode:
- {
- switch(toType)
- {
- case type_data:
- func = (fromType == type_varunicode) ? vunicode2DataId : unicode2DataId;
- break;
- case type_string:
- func = (fromType == type_varunicode) ? vunicode2CodepageId : unicode2CodepageId;
- break;
- case type_varstring:
- func = (fromType == type_varunicode) ? vunicode2VCodepageId : unicode2VCodepageId;
- break;
- }
- args.append(*getSizetConstant(toSize));
- args.append(*getElementPointer(targetVar));
- if(fromType != type_varunicode)
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- if(toType != type_data)
- args.append(*createConstant(to->queryCharset()->queryCodepageName()));
- callProcedure(ctx, func, args);
- }
- break;
- case type_utf8:
- {
- switch(toType)
- {
- case type_data:
- func = utf82DataId;
- break;
- case type_string:
- func = utf82CodepageId;
- break;
- case type_varstring:
- OwnedHqlExpr temp = pure.getTranslatedExpr();
- buildExprAssignViaString(ctx, target, temp, to->getStringLen());
- return;
- }
- args.append(*getSizetConstant(toSize));
- args.append(*getElementPointer(targetVar));
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- if(toType != type_data)
- args.append(*createConstant(to->queryCharset()->queryCodepageName()));
- callProcedure(ctx, func, args);
- }
- break;
- case type_swapint:
- {
- CHqlBoundExpr recast;
- ITypeInfo * tempType = makeIntType(srclen, from->isSigned());
- OwnedHqlExpr translated = createValue(no_implicitcast, tempType, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignAndCast(ctx, target, recast);
- return;
- }
- case type_int:
- case type_packedint:
- {
- //l2an4(toSize, tgt, expr);
- IIdAtom * funcName;
- if (from->isSigned())
- {
- if (toType != type_varstring)
- funcName = (srclen > 4 ? ls82anId : ls42anId);
- else
- funcName = (srclen > 4 ? ls82vnId : ls42vnId);
- }
- else
- {
- if (toType != type_varstring)
- funcName = (srclen > 4 ? l82anId : l42anId);
- else
- funcName = (srclen > 4 ? l82vnId : l42vnId);
- }
- IHqlExpression * strlen = getSizetConstant(toSize);
- args.append(*strlen);
- args.append(*getElementPointer(targetVar));
- args.append(*LINK(pure.expr));
- callProcedure(ctx, funcName, args);
- if (toType != type_data)
- {
- Owned<ICharsetInfo> charset = getCharset(asciiAtom);
- doStringTranslation(ctx, tgtset, charset, toSize, strlen, targetVar, targetVar);
- }
- break;
- }
- case type_void:
- if (pure.expr->getOperator() != no_decimalstack)
- {
- throwCannotCast(from, to);
- break;
- }
- //fall through
- case type_decimal:
- {
- ensurePushed(ctx, pure);
- args.append(*getSizetConstant(toSize));
- OwnedHqlExpr sp = getElementPointer(targetVar);
- args.append(*ensureIndexable(sp));
- switch (toType)
- {
- case type_string: func = DecPopStringId; break;
- case type_data: func = DecPopStringId; break;
- case type_varstring: func = DecPopVStringId; break;
- }
- callProcedure(ctx, func, args);
- break;
- }
- case type_enumerated:
- throwCannotCast(from, to);
- break;
- case type_boolean:
- {
- func = (toType == type_varstring) ? bool2VStrId : (toType == type_data) ? bool2DataId : bool2StrId;
- args.append(*getSizetConstant(toSize));
- args.append(*getElementPointer(targetVar));
- args.append(*pure.expr.getLink());
- callProcedure(ctx, func, args);
- break;
- }
- case type_real:
- {
- IHqlExpression * strlen = getSizetConstant(toSize);
- args.append(*strlen);
- args.append(*getElementPointer(targetVar));
- args.append(*pure.expr.getLink());
- func = (toType == type_varstring) ? f2vnId : f2anId;
- callProcedure(ctx, func, args);
- if (toType != type_data)
- {
- Owned<ICharsetInfo> charset = getCharset(asciiAtom);
- doStringTranslation(ctx, tgtset, charset, toSize, strlen, targetVar, targetVar);
- }
- }
- break;
- default:
- throwCannotCast(from, to);
- break;
- }
- }
- break;
- case type_unicode:
- case type_varunicode:
- switch (fromType)
- {
- case type_unicode:
- case type_varunicode:
- case type_data:
- case type_string:
- case type_varstring:
- case type_utf8:
- {
- IIdAtom * func;
- switch(fromType)
- {
- case type_unicode:
- func = (toType == type_varunicode) ? unicode2VUnicodeId : unicode2UnicodeId;
- break;
- case type_varunicode:
- func = (toType == type_varunicode) ? vunicode2VUnicodeId : vunicode2UnicodeId;
- break;
- case type_data:
- pure.expr.setown(createValue(no_implicitcast, makeReferenceModifier(makeStringType(from->getStringLen(), NULL)), LINK(pure.expr)));
- func = (toType == type_varunicode) ? codepage2VUnicodeId : codepage2UnicodeId;
- break;
- case type_string:
- func = (toType == type_varunicode) ? codepage2VUnicodeId : codepage2UnicodeId;
- break;
- case type_varstring:
- func = (toType == type_varunicode) ? vcodepage2VUnicodeId : vcodepage2UnicodeId;
- break;
- case type_utf8:
- if (toType == type_varunicode)
- {
- OwnedHqlExpr temp = pure.getTranslatedExpr();
- OwnedITypeInfo type = makeUnicodeType(to->getStringLen(), NULL);
- buildExprAssignViaType(ctx, target, temp, type);
- return;
- }
- func = utf82UnicodeId;
- break;
- default:
- throwUnexpected();
- }
- args.append(*getSizetConstant(toSize/2));
- args.append(*getElementPointer(targetVar));
- if((fromType != type_varunicode) && (fromType != type_varstring))
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- if((fromType == type_data) || (fromType == type_string) || (fromType == type_varstring))
- args.append(*createConstant(from->queryCharset()->queryCodepageName()));
- callProcedure(ctx, func, args);
- break;
- }
- default:
- OwnedHqlExpr temp = pure.getTranslatedExpr();
- buildExprAssignViaString(ctx, target, temp, to->getStringLen());
- return;
- }
- break;
- case type_utf8:
- switch (fromType)
- {
- case type_unicode:
- case type_varunicode:
- case type_data:
- case type_string:
- case type_varstring:
- case type_utf8:
- {
- IIdAtom * func;
- switch(fromType)
- {
- case type_unicode:
- case type_varunicode:
- func = unicodeToUtf8Id;
- break;
- case type_utf8:
- func = utf8ToUtf8Id;
- break;
- case type_data:
- case type_string:
- case type_varstring:
- func = codepageToUtf8Id;
- break;
- default:
- throwUnexpected();
- }
- args.append(*getSizetConstant(toSize/4));
- args.append(*getElementPointer(targetVar));
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- if((fromType == type_data) || (fromType == type_string) || (fromType == type_varstring))
- args.append(*createConstant(from->queryCharset()->queryCodepageName()));
- callProcedure(ctx, func, args);
- break;
- }
- default:
- OwnedHqlExpr temp = pure.getTranslatedExpr();
- buildExprAssignViaString(ctx, target, temp, to->getStringLen());
- return;
- }
- break;
- case type_decimal:
- {
- CHqlBoundExpr cast;
- doBuildExprCast(ctx, to, pure, cast);
- ensurePushed(ctx, cast);
- IIdAtom * funcName = to->isSigned() ? DecPopDecimalId : DecPopUDecimalId;
- args.append(*getPointer(target.expr));
- args.append(*getSizetConstant(to->getSize()));
- args.append(*getSizetConstant(to->getPrecision()));
- callProcedure(ctx, funcName, args);
- }
- break;
- case type_swapint:
- {
- unsigned fromSize = from->getSize();
- if (fromType == type_int)
- {
- if (fromSize != toSize)
- {
- Owned<ITypeInfo> tempType = makeIntType(toSize, from->isSigned());
- pure.expr.setown(ensureExprType(pure.expr, tempType));
- }
- if (toSize != 1)
- {
- assignSwapInt(ctx, to, target, pure);
- return;
- }
- }
- CHqlBoundExpr cast;
- doBuildExprCast(ctx, to, pure, cast);
- ctx.addAssign(target.expr, cast.expr);
- }
- break;
- case type_int:
- case type_packedint:
- {
- unsigned fromSize = from->getSize();
- if ((fromType == type_swapint) && !((fromSize == 1) && (toSize == 1)))
- {
- if (fromSize != toSize)
- {
- CHqlBoundExpr tempInt;
- OwnedITypeInfo tempType = makeIntType(fromSize, from->isSigned());
- doBuildCastViaTemp(ctx, tempType, pure, tempInt);
-
- CHqlBoundExpr cast;
- doBuildExprCast(ctx, to, tempInt, cast);
- ctx.addAssign(target.expr, cast.expr);
- }
- else
- assignSwapInt(ctx, to, target, pure);
- return;
- }
- }
- //fall through
- case type_boolean:
- case type_real:
- case type_row:
- case type_pointer:
- {
- CHqlBoundExpr cast;
- doBuildExprCast(ctx, to, pure, cast);
- ctx.addAssign(target.expr, cast.expr);
- }
- break;
- default:
- throwCannotCast(from, to);
- break;
- }
- }
- void HqlCppTranslator::assignCastUnknownLength(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & pure)
- {
- assertex(!target.isFixedSize());
- // must be dynamically allocated return type
- ITypeInfo * to = target.queryType();
- ITypeInfo * from = pure.expr->queryType();
- type_t toType = to->getTypeCode();
- type_t fromType = from->getTypeCode();
- IHqlExpression * codepageParam = 0;
- HqlExprArray args;
- IIdAtom * funcName = NULL;
- // assertex(target.length && target.pointer || to->getTypeCode() == type_varstring || to->getTypeCode() == type_varunicode);
- switch (toType)
- {
- case type_qstring:
- {
- switch (fromType)
- {
- case type_qstring:
- funcName = qstrToQStrXId;
- break;
- case type_string:
- case type_data:
- case type_varstring:
- if(!queryDefaultTranslation(to->queryCharset(), from->queryCharset()))
- {
- funcName = strToQStrXId;
- break;
- }
- //fall through
- default:
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- break;
- }
- case type_string:
- case type_data:
- {
- unsigned srclen = from->getSize();
- switch (fromType)
- {
- case type_data:
- case type_string:
- case type_varstring:
- {
- ICharsetInfo * srcset = from->queryCharset();
- ICharsetInfo * tgtset = to->queryCharset();
-
- if (to->getTypeCode() == type_data)
- funcName = str2DataXId;
- else if ((srcset == tgtset) || (from->getTypeCode() == type_data))
- {
- funcName = str2StrXId;
- }
- else
- {
- if ((from->getSize() == INFINITE_LENGTH) && !pure.length)
- throwError(HQLERR_CastInfiniteString);
- ITranslationInfo * translator = queryDefaultTranslation(tgtset, srcset);
- if (translator)
- funcName = createIdAtom(translator->queryVarRtlFunction());
- else
- funcName = str2StrXId;
- }
- }
- break;
- case type_qstring:
- if(!queryDefaultTranslation(from->queryCharset(), to->queryCharset()))
- {
- funcName = (toType == type_data) ? qstr2DataXId : qstr2StrXId;
- break;
- }
- else
- {
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- case type_unicode:
- {
- if(toType == type_data)
- funcName = unicode2DataXId;
- else
- {
- funcName = unicode2CodepageXId;
- codepageParam = createConstant(to->queryCharset()->queryCodepageName());
- }
- break;
- }
- case type_varunicode:
- {
- if(toType == type_data)
- funcName = vunicode2DataXId;
- else
- {
- funcName = vunicode2CodepageXId;
- codepageParam = createConstant(to->queryCharset()->queryCodepageName());
- }
- break;
- }
- case type_utf8:
- {
- if(toType == type_data)
- funcName = utf82DataXId;
- else
- {
- funcName = utf82CodepageXId;
- codepageParam = createConstant(to->queryCharset()->queryCodepageName());
- }
- break;
- }
- case type_swapint:
- {
- CHqlBoundExpr recast;
- ITypeInfo * type = makeIntType(from->getSize(), from->isSigned());
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- case type_int:
- case type_real:
- case type_boolean:
- case type_packedint:
- {
- Owned<ICharsetInfo> asciiCharset = getCharset(asciiAtom);
- if (to->queryCharset() != asciiCharset)
- {
- //This should really be handled by the call processing.
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- if (fromType == type_real)
- funcName = f2axId;
- else if (fromType == type_boolean)
- funcName = bool2StrXId;
- else if (from->isSigned())
- funcName = (srclen > 4 ? ls82axId : ls42axId);
- else
- funcName = (srclen > 4 ? l82axId : l42axId);
- args.append(*pure.getTranslatedExpr());
- OwnedHqlExpr call = bindFunctionCall(funcName, args);
- buildExprAssign(ctx, target, call);
- return;
- }
- case type_void:
- if (pure.expr->getOperator() != no_decimalstack)
- {
- throwCannotCast(from, to);
- break;
- }
- //fall through
- case type_decimal:
- {
- ensurePushed(ctx, pure);
- OwnedHqlExpr call = bindFunctionCall(DecPopStringXId, args);
- buildExprAssign(ctx, target, call);
- return;
- }
- default:
- assertex(!"Unknown copy source type");
- return;
- }
- break;
- }
- case type_varstring:
- {
- unsigned srclen = from->getSize();
- switch (from->getTypeCode())
- {
- case type_data:
- case type_string:
- case type_varstring:
- {
- ICharsetInfo * srcset = from->queryCharset();
- ICharsetInfo * tgtset = to->queryCharset();
-
- if ((srcset == tgtset) || (to->getTypeCode() == type_data) || (from->getTypeCode() == type_data))
- {
- funcName = str2VStrXId;
- }
- else
- {
- funcName = estr2VStrXId;
- }
- }
- break;
- case type_unicode:
- {
- funcName = unicode2VCodepageXId;
- codepageParam = createConstant(to->queryCharset()->queryCodepageName());
- }
- break;
- case type_varunicode:
- {
- funcName = vunicode2VCodepageXId;
- codepageParam = createConstant(to->queryCharset()->queryCodepageName());
- }
- break;
- case type_qstring:
- case type_utf8:
- {
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(from->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- case type_swapint:
- {
- CHqlBoundExpr recast;
- ITypeInfo * type = makeIntType(from->getSize(), from->isSigned());
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- case type_int:
- case type_packedint:
- {
- //l2an4(tgtlen, tgt, expr);
- if (from->isSigned())
- funcName = (srclen > 4 ? ls82vxId : ls42vxId);
- else
- funcName = (srclen > 4 ? l82vxId : l42vxId);
- break;
- }
- case type_boolean:
- {
- funcName = bool2VStrXId;
- break;
- }
- case type_real:
- {
- funcName = f2vxId;;
- break;
- }
- case type_void:
- if (pure.expr->getOperator() != no_decimalstack)
- {
- throwCannotCast(from, to);
- break;
- }
- //fall through
- case type_decimal:
- {
- ensurePushed(ctx, pure);
- OwnedHqlExpr call = bindFunctionCall(DecPopVStringXId, args);
- buildExprAssign(ctx, target, call);
- return;
- }
- default:
- assertex(!"Unknown copy source type");
- return;
- }
- break;
- }
- case type_unicode:
- {
- switch (fromType)
- {
- case type_unicode:
- funcName = unicode2UnicodeXId;
- break;
- case type_varunicode:
- funcName = vunicode2UnicodeXId;
- break;
- case type_utf8:
- funcName = utf82UnicodeXId;
- break;
- case type_data:
- funcName = codepage2UnicodeXId;
- codepageParam = createConstant(from->queryCharset()->queryCodepageName());
- pure.expr.setown(createValue(no_implicitcast, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
- break;
- case type_string:
- funcName = codepage2UnicodeXId;
- codepageParam = createConstant(from->queryCharset()->queryCodepageName());
- pure.expr.setown(createValue(no_typetransfer, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
- break;
- case type_varstring:
- funcName = vcodepage2UnicodeXId;
- codepageParam = createConstant(from->queryCharset()->queryCodepageName());
- pure.expr.setown(createValue(no_typetransfer, makeVarStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
- break;
- default:
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- break;
- }
- case type_varunicode:
- {
- switch (fromType)
- {
- case type_unicode:
- case type_utf8: // go via unicode
- funcName = unicode2VUnicodeXId;
- break;
- case type_varunicode:
- funcName = vunicode2VUnicodeXId;
- break;
- case type_string:
- case type_data:
- funcName = codepage2VUnicodeXId;
- codepageParam = createConstant(from->queryCharset()->queryCodepageName());
- pure.expr.setown(createValue(no_typetransfer, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
- break;
- case type_varstring:
- funcName = vcodepage2VUnicodeXId;
- codepageParam = createConstant(from->queryCharset()->queryCodepageName());
- pure.expr.setown(createValue(no_typetransfer, makeVarStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
- break;
- default:
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- break;
- }
- case type_utf8:
- {
- switch (fromType)
- {
- case type_unicode:
- case type_varunicode:
- funcName = unicodeToUtf8XId;
- break;
- case type_utf8:
- funcName = utf8ToUtf8XId;
- break;
- case type_string:
- case type_data:
- case type_varstring:
- funcName = codepageToUtf8XId;
- codepageParam = createConstant(from->queryCharset()->queryCodepageName());
- pure.expr.setown(createValue(no_typetransfer, makeStringType(from->getStringLen(), NULL, NULL), LINK(pure.expr)));
- break;
- default:
- CHqlBoundExpr recast;
- ITypeInfo * type = makeStringType(to->getStringLen(), NULL, NULL);
- OwnedHqlExpr translated = createValue(no_implicitcast, type, pure.getTranslatedExpr());
- buildExpr(ctx, translated, recast);
- assignCastUnknownLength(ctx, target, recast);
- return;
- }
- break;
- }
- case type_set:
- if (isSameBasicType(to->queryChildType(), from->queryChildType()))
- {
- if (!target.isAll)
- {
- //Ugly. Create a dummy isAll field to assign to..
- assertex(!pure.isAll || matchesBoolean(pure.isAll, false));
- CHqlBoundTarget tempTarget;
- tempTarget.set(target);
- tempTarget.isAll.setown(ctx.getTempDeclare(queryBoolType(), NULL));
- assignCastUnknownLength(ctx, tempTarget, pure);
- return;
- }
- funcName = set2SetXId;
- }
- else
- {
- OwnedHqlExpr values = pure.getTranslatedExpr();
- buildSetAssignViaBuilder(ctx, target, values);
- return;
- }
- break;
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- {
- OwnedHqlExpr src = pure.getTranslatedExpr();
- buildDatasetAssign(ctx, target, src);
- return;
- }
- default:
- assertex(!"Unexpected target type for variable length");
- break;
- }
- args.append(*pure.getTranslatedExpr());
- if(codepageParam)
- args.append(*codepageParam);
- OwnedHqlExpr call = bindFunctionCall(funcName, args);
- buildExprAssign(ctx, target, call);
- }
- void HqlCppTranslator::expandFunctions(bool expandInline)
- {
- if (expandInline)
- {
- BuildCtx ctx(*code, prototypeAtom);
- ForEachItemIn(idx, code->helpers)
- {
- IHqlExpression & cur = (IHqlExpression &)code->helpers.item(idx);
- StringBuffer init;
- if (getAttribute(cur.queryChild(0), initfunctionAtom, init))
- {
- StringBuffer initproto("extern \"C\" void SERVICE_API ");
- initproto.append(init).append("(const char *);");
- ctx.addQuoted(initproto);
- }
- expandFunctionPrototype(ctx, &cur);
- }
- }
- else
- {
- CIArray includes;
- BuildCtx ctx(*code, includeAtom);
- ForEachItemIn(idx, code->helpers)
- {
- //StringBuffer include;
- //IHqlExpression & cur = (IHqlExpression &)code->helpers.item(idx);
- // getLibraryName(cur, include);
- //MORE!! Get the include name...
- }
- }
- }
- void HqlCppTranslator::bindAndPush(BuildCtx & ctx, IHqlExpression * value)
- {
- CHqlBoundExpr bound;
- buildExpr(ctx, value, bound);
- ensurePushed(ctx, bound);
- }
- bool HqlCppTranslator::ensurePushed(BuildCtx & ctx, const CHqlBoundExpr & pure)
- {
- if (!isPushed(pure))
- {
- //Temporary solution - create a critical block whenever the decimals are used.
- OwnedHqlExpr marker = createAttribute(decimalAtom);
- if (!ctx.queryMatchExpr(marker))
- {
- //If a group with no {} is added, we might get a name clash => make it unique
- StringBuffer s;
- getUniqueId(s.append("BcdCriticalBlock bcd")).append(";");
- ctx.addQuoted(s);
- ctx.associateExpr(marker, NULL);
- }
- ITypeInfo * type = pure.expr->queryType();
- HqlExprArray args;
- IIdAtom * funcName = NULL;
- switch (type->getTypeCode())
- {
- case type_data:
- case type_string:
- case type_varstring:
- funcName = DecPushStringId;
- if (type->queryCharset()->queryName() == ebcdicAtom)
- {
- CHqlBoundExpr temp;
- OwnedHqlExpr translated = pure.getTranslatedExpr();
- OwnedHqlExpr cast = createValue(no_cast, getAsciiType(type), translated.getClear());
- buildExpr(ctx, cast, temp);
- args.append(*getBoundLength(temp));
- args.append(*getElementPointer(temp.expr));
- }
- else
- {
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- }
- break;
- case type_qstring:
- funcName = DecPushQStringId;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_unicode:
- case type_varunicode:
- funcName = DecPushUnicodeId;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_utf8:
- funcName = DecPushUtf8Id;
- args.append(*getBoundLength(pure));
- args.append(*getElementPointer(pure.expr));
- break;
- case type_decimal:
- funcName = type->isSigned() ? DecPushDecimalId : DecPushUDecimalId;
- args.append(*getPointer(pure.expr));
- args.append(*getSizetConstant(type->getSize()));
- args.append(*getSizetConstant(type->getPrecision()));
- break;
- case type_swapint:
- {
- CHqlBoundExpr copyPure;
- copyPure.set(pure);
- //cast via intermediate int.
- OwnedITypeInfo tempType = makeIntType(type->getSize(), type->isSigned());
- CHqlBoundExpr boundCast;
- doBuildExprCast(ctx, tempType, copyPure, boundCast);
- funcName = type->isSigned() ? DecPushInt64Id : DecPushUInt64Id;
- args.append(*boundCast.expr.getLink());
- break;
- }
- //fall through
- case type_int:
- case type_packedint:
- //more signed/unsigned and optimize the length...
- funcName = type->isSigned() ? DecPushInt64Id : DecPushUInt64Id;
- args.append(*pure.expr.getLink());
- break;
- case type_enumerated:
- throwError2(HQLERR_CastXNotImplemented, "map", "decimal");
- break;
- case type_boolean:
- funcName = DecPushLongId;
- args.append(*pure.expr.getLink());
- break;
- case type_real:
- funcName = DecPushRealId;
- args.append(*pure.expr.getLink());
- break;
- default:
- throwError2(HQLERR_CastXNotImplemented, "unknown", "varstring");
- break;
- }
- if (funcName)
- callProcedure(ctx, funcName, args);
- return true;
- }
- return false;
- }
- static StringBuffer & appendCapital(StringBuffer & s, const char * name)
- {
- if (name && name[0])
- {
- s.append((char)toupper(*name));
- s.append(name+1);
- }
- return s;
- }
- bool HqlCppTranslator::expandFunctionPrototype(StringBuffer & s, IHqlExpression * funcdef)
- {
- return generateFunctionPrototype(s, funcdef, options.targetCompiler);
- }
- void HqlCppTranslator::expandFunctionPrototype(BuildCtx & ctx, IHqlExpression * funcdef)
- {
- StringBuffer s;
- if (expandFunctionPrototype(s, funcdef))
- {
- s.append(";");
- IHqlExpression *body = funcdef->queryChild(0);
- IHqlExpression *namespaceAttr = body->queryAttribute(namespaceAtom);
- if (namespaceAttr)
- {
- StringBuffer ns;
- getStringValue(ns, namespaceAttr->queryChild(0));
- ns.insert(0, "namespace ").appendf(" { %s }", s.str());
- ctx.addQuoted(ns);
- }
- else
- ctx.addQuoted(s);
- }
- }
- //Replace no_param with whatever they will have been bound to
- static IHqlExpression *createActualFromFormal(IHqlExpression *param)
- {
- StringBuffer temp;
- ITypeInfo *paramType = param->queryType();
- CHqlBoundExpr bound;
- //Case is significant if these parameters are use for BEGINC++ sections
- IIdAtom * paramName = param->queryId();
- const char * paramNameText = paramName->lower()->str();
- Linked<ITypeInfo> type = paramType;
- switch (paramType->getTypeCode())
- {
- case type_set:
- {
- appendCapital(temp.clear().append("isAll"), paramNameText);
- bound.isAll.setown(createVariable(temp.str(), makeBoolType()));
- }
- //fall through
- case type_string:
- case type_qstring:
- case type_data:
- case type_unicode:
- case type_utf8:
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- if (paramType->getSize() == UNKNOWN_LENGTH)
- {
- if (hasOutOfLineModifier(paramType) || hasLinkCountedModifier(paramType))
- {
- appendCapital(temp.clear().append("count"), paramNameText);
- bound.count.setown(createVariable(temp.str(), LINK(sizetType)));
- }
- else
- {
- appendCapital(temp.clear().append("len"), paramNameText);
- bound.length.setown(createVariable(temp.str(), LINK(sizetType)));
- }
- }
- type.setown(makeReferenceModifier(LINK(type)));
- break;
- }
- bound.expr.setown(createVariable(paramNameText, LINK(type)));
- return bound.getTranslatedExpr();
- }
- static IHqlExpression * replaceInlineParameters(IHqlExpression * funcdef, IHqlExpression * expr)
- {
- IHqlExpression * body = funcdef->queryChild(0);
- assertex(!body->hasAttribute(oldSetFormatAtom));
- IHqlExpression * formals = funcdef->queryChild(1);
- HqlMapTransformer simpleTransformer;
- StringBuffer paramNameText, temp;
- ForEachChild(i, formals)
- {
- IHqlExpression * param = formals->queryChild(i);
- OwnedHqlExpr actual = createActualFromFormal(param);
- simpleTransformer.setMapping(param, actual);
- }
- return simpleTransformer.transformRoot(expr);
- }
- void HqlCppTranslator::doBuildUserFunctionReturn(BuildCtx & ctx, ITypeInfo * type, IHqlExpression * value)
- {
- if (!options.spotCSE)
- {
- doBuildFunctionReturn(ctx, type, value);
- return;
- }
- switch (value->getOperator())
- {
- case no_if:
- if (false)///disable for the moment - look at changes in klogermann11 to see why, some v.good, some bad.
- {
- //optimize the way that cses are spotted to minimise unnecessary calculations
- OwnedHqlExpr branches = createComma(LINK(value->queryChild(1)), LINK(value->queryChild(2)));
- OwnedHqlExpr cond = LINK(value->queryChild(0));
- spotScalarCSE(cond, branches, NULL, NULL);
- BuildCtx subctx(ctx);
- IHqlStmt * stmt = buildFilterViaExpr(subctx, cond);
- doBuildUserFunctionReturn(subctx, type, branches->queryChild(0));
- subctx.selectElse(stmt);
- doBuildUserFunctionReturn(subctx, type, branches->queryChild(1));
- break;
- }
- default:
- {
- OwnedHqlExpr optimized = spotScalarCSE(value);
- if (value->isAction())
- buildStmt(ctx, value);
- else
- doBuildFunctionReturn(ctx, type, optimized);
- break;
- }
- }
- }
- void HqlCppTranslator::buildCppFunctionDefinition(BuildCtx &funcctx, IHqlExpression * bodyCode, const char *proto)
- {
- processCppBodyDirectives(bodyCode);
- IHqlExpression * location = queryLocation(bodyCode);
- const char * locationFilename = location ? location->querySourcePath()->str() : NULL;
- unsigned startLine = location ? location->getStartLine() : 0;
- IHqlExpression * cppBody = bodyCode->queryChild(0);
- if (cppBody->getOperator() == no_record)
- cppBody = bodyCode->queryChild(1);
- StringBuffer text;
- cppBody->queryValue()->getUTF8Value(text);
- //remove #option, and remove /r so we don't end up with mixed format end of lines.
- text.setLength(cleanupEmbeddedCpp(text.length(), (char*)text.str()));
- const char * start = text.str();
- loop
- {
- char next = *start;
- if (next == '\n')
- startLine++;
- else if (next != '\r')
- break;
- start++;
- }
- const char * body = start;
- const char * cppSeparatorText = "#body";
- const char * separator = strstr(body, cppSeparatorText);
- if (separator)
- {
- text.setCharAt(separator-text.str(), 0);
- if (location)
- funcctx.addLine(locationFilename, startLine);
- funcctx.addQuoted(body);
- if (location)
- funcctx.addLine();
- body = separator + strlen(cppSeparatorText);
- if (*body == '\r') body++;
- if (*body == '\n') body++;
- startLine += memcount(body-start, start, '\n');
- }
- funcctx.addQuotedCompound(proto);
- if (location)
- funcctx.addLine(locationFilename, startLine);
- funcctx.addQuoted(body);
- if (location)
- funcctx.addLine();
- }
- void HqlCppTranslator::buildScriptFunctionDefinition(BuildCtx &funcctx, IHqlExpression * funcdef, const char *proto)
- {
- ITypeInfo * returnType = funcdef->queryType()->queryChildType();
- IHqlExpression * outofline = funcdef->queryChild(0);
- assertex(outofline->getOperator() == no_outofline);
- IHqlExpression * bodyCode = outofline->queryChild(0);
- IHqlExpression *language = queryAttributeChild(bodyCode, languageAtom, 0);
- bool isImport = bodyCode->hasAttribute(importAtom);
- funcctx.addQuotedCompound(proto);
- HqlExprArray noargs;
- OwnedHqlExpr getPlugin = bindFunctionCall(language, noargs);
- OwnedHqlExpr pluginPtr = createQuoted("Owned<IEmbedContext> __plugin", makeBoolType()); // Not really bool - at some point ECL may support without this aliasing...
- buildAssignToTemp(funcctx, pluginPtr, getPlugin);
- StringBuffer createParam;
- createParam.append("Owned<IEmbedFunctionContext> __ctx = __plugin->createFunctionContext(");
- createParam.append(isImport ? "true" : "false");
- StringBuffer attrParam;
- ForEachChild(idx, bodyCode)
- {
- IHqlExpression *child = bodyCode->queryChild(idx);
- if (child->isAttribute() && child->queryName() != languageAtom && child->queryName() != importAtom)
- {
- attrParam.append(",");
- attrParam.append(child->queryName());
- StringBuffer attrValue;
- if (getStringValue(attrValue, child->queryChild(0)).length())
- {
- attrParam.append('=');
- appendStringAsCPP(attrParam, attrValue.length(), attrValue.str(), true);
- }
- }
- }
- if (attrParam.length())
- createParam.append(",\"").append(attrParam.str()+1).append('"');
- else
- createParam.append(",NULL");
- createParam.append(");");
- funcctx.addQuoted(createParam);
- OwnedHqlExpr ctxVar = createVariable("__ctx", makeBoolType());
- HqlExprArray scriptArgs;
- scriptArgs.append(*LINK(ctxVar));
- scriptArgs.append(*LINK(bodyCode->queryChild(0)));
- buildFunctionCall(funcctx, isImport ? importId : compileEmbeddedScriptId, scriptArgs);
- IHqlExpression *formals = funcdef->queryChild(1);
- ForEachChild(i, formals)
- {
- HqlExprArray args;
- args.append(*LINK(ctxVar));
- IHqlExpression * param = formals->queryChild(i);
- ITypeInfo *paramType = param->queryType();
- IIdAtom * paramId = param->queryId();
- const char * paramNameText = paramId->str();
- if (!options.preserveCaseExternalParameter)
- paramNameText = paramId->lower()->str();
- args.append(*createConstant(paramNameText));
- IIdAtom * bindFunc;
- switch (paramType->getTypeCode())
- {
- case type_int:
- bindFunc = paramType->isSigned() ? bindSignedParamId : bindUnsignedParamId;
- break;
- case type_varstring:
- bindFunc = bindVStringParamId;
- break;
- case type_string:
- bindFunc = bindStringParamId;
- break;
- case type_real:
- bindFunc = bindRealParamId;
- break;
- case type_boolean:
- bindFunc = bindBooleanParamId;
- break;
- case type_utf8:
- bindFunc = bindUtf8ParamId;
- break;
- case type_unicode:
- bindFunc = bindUnicodeParamId;
- break;
- case type_data:
- bindFunc = bindDataParamId;
- break;
- case type_row:
- bindFunc = bindRowParamId;
- break;
- case type_table:
- case type_groupedtable:
- bindFunc = bindDatasetParamId;
- break;
- case type_set:
- {
- bindFunc = bindSetParamId;
- ITypeInfo *childType = paramType->queryChildType();
- type_t typeCode = childType->getTypeCode();
- if (childType->isInteger() && !childType->isSigned())
- typeCode = type_unsigned;
- args.append(*createIntConstant(typeCode));
- args.append(*createIntConstant(childType->getSize()));
- break;
- }
- default:
- StringBuffer typeText;
- getFriendlyTypeStr(paramType, typeText);
- throwError1(HQLERR_EmbeddedTypeNotSupported_X, typeText.str());
- }
- args.append(*createActualFromFormal(param));
- buildFunctionCall(funcctx, bindFunc, args);
- }
- funcctx.addQuoted("__ctx->callFunction();");
- IIdAtom * returnFunc;
- HqlExprArray retargs;
- Owned<ITypeInfo> newReturnType;
- retargs.append(*LINK(ctxVar));
- switch (returnType->getTypeCode())
- {
- case type_int:
- returnFunc = returnType->isSigned() ? getSignedResultId : getUnsignedResultId;
- break;
- case type_varstring:
- case type_string:
- returnFunc = getStringResultId;
- break;
- case type_real:
- returnFunc = getRealResultId;
- break;
- case type_boolean:
- returnFunc = getBooleanResultId;
- break;
- case type_unicode:
- returnFunc = getUnicodeResultId;
- break;
- case type_utf8:
- returnFunc = getUTF8ResultId;
- break;
- case type_data:
- returnFunc = getDataResultId;
- break;
- case type_set:
- {
- returnFunc = getSetResultId;
- ITypeInfo *childType = returnType->queryChildType();
- type_t typeCode = childType->getTypeCode();
- if (childType->isInteger() && !childType->isSigned())
- typeCode = type_unsigned;
- retargs.append(*createIntConstant(typeCode));
- retargs.append(*createIntConstant(returnType->queryChildType()->getSize()));
- break;
- }
- case type_row:
- returnFunc = getRowResultId;
- newReturnType.set(returnType);
- break;
- case type_table:
- returnFunc = getDatasetResultId;
- newReturnType.set(returnType);
- break;
- case type_transform:
- returnFunc = getTransformResultId;
- newReturnType.set(returnType);
- break;
- case type_void:
- return;
- default:
- StringBuffer typeText;
- getFriendlyTypeStr(returnType, typeText);
- throwError1(HQLERR_EmbeddedTypeNotSupported_X, typeText.str());
- }
- OwnedHqlExpr call = bindFunctionCall(returnFunc, retargs, newReturnType);
- doBuildUserFunctionReturn(funcctx, returnType, call);
- }
- void HqlCppTranslator::buildFunctionDefinition(IHqlExpression * funcdef)
- {
- IHqlExpression * outofline = funcdef->queryChild(0);
- assertex(outofline->getOperator() == no_outofline);
- IHqlExpression * bodyCode = outofline->queryChild(0);
- StringBuffer proto;
- BuildCtx funcctx(*code, helperAtom);
- if (options.spanMultipleCpp)
- {
- const bool inChildActivity = true; // assume the worst
- OwnedHqlExpr pass = getSizetConstant(cppIndexNextActivity(inChildActivity));
- funcctx.addGroupPass(pass);
- }
- expandFunctionPrototype(proto, funcdef);
- if (bodyCode->getOperator() == no_embedbody)
- {
- if (!allowEmbeddedCpp())
- throwError(HQLERR_EmbeddedCppNotAllowed);
- IHqlExpression *languageAttr = bodyCode->queryAttribute(languageAtom);
- if (languageAttr)
- buildScriptFunctionDefinition(funcctx, funcdef, proto);
- else
- buildCppFunctionDefinition(funcctx, bodyCode, proto);
- }
- else
- {
- funcctx.addQuotedCompound(proto);
- //MORE: Need to work out how to handle functions that require the context.
- //Need to create a class instead.
- assertex(!outofline->hasAttribute(contextAtom));
- OwnedHqlExpr newCode = replaceInlineParameters(funcdef, bodyCode);
- newCode.setown(foldHqlExpression(newCode));
- ITypeInfo * returnType = funcdef->queryType()->queryChildType();
- doBuildUserFunctionReturn(funcctx, returnType, newCode);
- }
- }
- //---------------------------------------------------------------------------
- void HqlCppTranslator::doBuildPureSubExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
- {
- unsigned max = expr->numChildren();
- if (max == 0)
- tgt.expr.set(expr);
- else
- {
- HqlExprArray args;
- unsigned idx = 0;
- CHqlBoundExpr bound;
- for (idx = 0; idx < max; idx++)
- {
- buildExpr(ctx, expr->queryChild(idx), bound);
- args.append(*bound.expr.getClear());
- }
- tgt.expr.setown(expr->clone(args));
- }
- }
- //---------------------------------------------------------------------------
- IHqlExpression * HqlCppTranslator::getListLength(BuildCtx & ctx, IHqlExpression * expr)
- {
- CHqlBoundExpr bound;
- buildExpr(ctx, expr, bound);
- return getBoundLength(bound);
- }
- IHqlExpression * HqlCppTranslator::getBoundCount(const CHqlBoundExpr & bound)
- {
- if (bound.count)
- return bound.count.getLink();
- ITypeInfo * type = bound.expr->queryType();
- switch (type->getTypeCode())
- {
- case type_array:
- {
- if (bound.length)
- return convertBetweenCountAndSize(bound, true);
- unsigned size = type->getSize();
- if (size != UNKNOWN_LENGTH)
- return getSizetConstant(size / type->queryChildType()->getSize());
- UNIMPLEMENTED;
- }
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- case type_set:
- if (bound.length)
- return convertBetweenCountAndSize(bound, true);
- UNIMPLEMENTED;
- default:
- UNIMPLEMENTED;
- }
- }
- IHqlExpression * HqlCppTranslator::getBoundLength(const CHqlBoundExpr & bound)
- {
- if (bound.length)
- return bound.length.getLink();
- ITypeInfo * type = bound.expr->queryType();
- if (bound.expr->queryValue())
- return getSizetConstant(type->getStringLen());
- switch (type->getTypeCode())
- {
- case type_varstring:
- {
- HqlExprArray args;
- args.append(*getElementPointer(bound.expr));
- return bindTranslatedFunctionCall(strlenId, args);
- }
- case type_varunicode:
- {
- HqlExprArray args;
- args.append(*getElementPointer(bound.expr));
- return bindTranslatedFunctionCall(unicodeStrlenId, args);
- }
- case type_set:
- case type_array:
- case type_dictionary:
- case type_table:
- case type_groupedtable:
- assertex(!isArrayRowset(type));
- if (bound.count)
- return convertBetweenCountAndSize(bound, false);
- UNIMPLEMENTED;
- case type_utf8:
- {
- assertex(type->getSize() != UNKNOWN_LENGTH);
- HqlExprArray args;
- args.append(*getSizetConstant(type->getSize()));
- args.append(*getElementPointer(bound.expr));
- return bindTranslatedFunctionCall(utf8LengthId, args);
- }
- default:
- return getSizetConstant(type->getStringLen());
- }
- }
- IHqlExpression * HqlCppTranslator::getBoundSize(ITypeInfo * type, IHqlExpression * length, IHqlExpression * data)
- {
- type_t tc = type->getTypeCode();
- switch (tc)
- {
- case type_qstring:
- {
- if (length->queryValue())
- return getSizetConstant((size32_t)rtlQStrSize((size32_t)length->queryValue()->getIntValue()));
- HqlExprArray args;
- args.append(*LINK(length));
- return bindTranslatedFunctionCall(qstrSizeId, args);
- }
- case type_varstring:
- return adjustValue(length, 1);
- case type_varunicode:
- {
- OwnedHqlExpr temp = adjustValue(length, 1);
- return multiplyValue(temp, 2);
- }
- case type_unicode:
- return multiplyValue(length, 2);
- case type_utf8:
- {
- assertex(data);
- if (data->queryValue())
- return getSizetConstant(data->queryValue()->getSize());
- HqlExprArray args;
- args.append(*LINK(length));
- args.append(*getElementPointer(data));
- return bindTranslatedFunctionCall(utf8SizeId, args);
- }
- case type_array:
- case type_set:
- return LINK(length);
- default:
- return LINK(length);
- }
- }
- IHqlExpression * HqlCppTranslator::getBoundSize(const CHqlBoundExpr & bound)
- {
- ITypeInfo * type = bound.expr->queryType();
- if (bound.length)
- return getBoundSize(type, bound.length, bound.expr);
- type_t tc = type->getTypeCode();
- if (tc == type_row)
- {
- if (hasReferenceModifier(type))
- return getSizetConstant(sizeof(void*));
- IHqlExpression * record = ::queryRecord(type);
- ColumnToOffsetMap * map = queryRecordOffsetMap(record);
- if (map->isFixedWidth())
- return getSizetConstant(map->getFixedRecordSize());
- //call meta function mm.queryRecordSize(&row)
- StringBuffer metaInstance, temp;
- buildMetaForRecord(metaInstance, record);
- temp.append(metaInstance).append(".getRecordSize(");
- OwnedHqlExpr rowAddr = getPointer(bound.expr);
- generateExprCpp(temp, rowAddr);
- temp.append(")");
- return createQuoted(temp.str(), LINK(sizetType));
- }
- if (type->getSize() != UNKNOWN_LENGTH)
- return getSizetConstant(type->getSize());
- OwnedHqlExpr length = getBoundLength(bound);
- return getBoundSize(type, length, bound.expr);
- }
- IHqlExpression * HqlCppTranslator::getFirstCharacter(IHqlExpression * source)
- {
- if (source->getOperator() == no_constant)
- {
- StringBuffer temp;
- source->queryValue()->getStringValue(temp);
- return createUIntConstant((unsigned char)temp.charAt(0));
- }
- return createValue(no_index, makeCharType(), LINK(source), getZero());
- }
- IHqlExpression * HqlCppTranslator::getElementPointer(IHqlExpression * source)
- {
- ITypeInfo * srcType = source->queryType();
- switch (srcType->getTypeCode())
- {
- case type_string:
- case type_data:
- case type_qstring:
- case type_varstring:
- case type_unicode:
- case type_utf8:
- case type_varunicode:
- case type_set:
- case type_array:
- break;
- default:
- throwUnexpectedType(srcType);
- }
- if (source->getOperator() == no_constant)
- return LINK(source);
- OwnedHqlExpr pointer = getPointer(source);
- return ensureIndexable(pointer);
- }
- /* All in params: NOT linked */
- IHqlExpression * HqlCppTranslator::getIndexedElementPointer(IHqlExpression * source, IHqlExpression * index)
- {
- ITypeInfo * srcType = source->queryType();
- switch (srcType->getTypeCode())
- {
- case type_string:
- case type_data:
- case type_qstring:
- case type_varstring:
- case type_unicode:
- case type_utf8:
- case type_varunicode:
- break;
- default:
- throwUnexpectedType(srcType);
- }
- if (!index)
- return getElementPointer(source);
- IValue * value = index->queryValue();
- if (value && value->getIntValue() == 0)
- return getElementPointer(source);
- ITypeInfo * refType = LINK(srcType);
- if (!srcType->isReference())
- refType = makeReferenceModifier(refType);
- OwnedHqlExpr temp;
- if (srcType->getTypeCode() == type_utf8)
- {
- HqlExprArray args;
- args.append(*LINK(index));
- args.append(*getElementPointer(source));
- temp.setown(bindTranslatedFunctionCall(utf8SizeId, args));
- index = temp;
- }
- //special case string indexing
- if (source->getOperator() != no_constant)
- {
- if (!srcType->isReference() && !hasWrapperModifier(srcType))
- return createValue(no_address, refType, createValue(no_index, makeCharType(), ensureIndexable(source), LINK(index)));
- }
- return createValue(no_add, refType, ensureIndexable(source), LINK(index));
- }
- IHqlExpression * HqlCppTranslator::getIndexedElementPointer(IHqlExpression * source, unsigned index)
- {
- if (!index)
- return getElementPointer(source);
- OwnedHqlExpr ival = getSizetConstant(index);
- return getIndexedElementPointer(source, ival);
- }
- IHqlExpression * HqlCppTranslator::needFunction(IIdAtom * name)
- {
- assertex(name);
- HqlDummyLookupContext dummyctx(errorProcessor);
- return internalScope->lookupSymbol(name, LSFsharedOK, dummyctx);
- }
- unsigned HqlCppTranslator::processHint(IHqlExpression * expr)
- {
- unsigned oldHints = hints;
- IAtom * hint = NULL; // MORE how do I get this?
- if (hint == sizeAtom)
- hints = (hints & ~(HintSpeed|HintSize)) | HintSize;
- else if (hint == speedAtom)
- hints = (hints & ~(HintSize|HintSpeed)) | HintSpeed;
- return oldHints;
- }
- bool HqlCppTranslator::childrenRequireTemp(BuildCtx & ctx, IHqlExpression * expr, bool includeChildren)
- {
- unsigned numArgs = expr->numChildren();
- for (unsigned index = 0; index < numArgs; index++)
- if (requiresTemp(ctx, expr->queryChild(index), includeChildren))
- return true;
- return false;
- }
- bool HqlCppTranslator::requiresTemp(BuildCtx & ctx, IHqlExpression * expr, bool includeChildren)
- {
- switch (expr->getOperator())
- {
- case no_attr:
- case no_attr_link:
- case no_attr_expr:
- case no_quoted:
- case no_variable:
- case no_constant:
- case no_translated:
- case no_matchtext:
- case no_matchunicode:
- case no_matchlength:
- case no_matchattr:
- case no_matchrow:
- case no_matchutf8:
- case no_libraryinput:
- return false;
- case no_getresult:
- case no_getgraphresult:
- case no_workunit_dataset:
- return false; // if in an activity, then will be in setContext, if not then don't really care
- case no_preservemeta:
- return requiresTemp(ctx, expr->queryChild(0), includeChildren);
- case no_alias:
- {
- if (expr->isPure() && ctx.queryMatchExpr(expr->queryChild(0)))
- return false;
- if (!containsActiveDataset(expr)) // generates a earlier temp even if generating within the onCreate() function
- return false;
- return true;
- }
- case no_select:
- {
- bool isNew;
- IHqlExpression * ds = querySelectorDataset(expr, isNew);
- if (isNew)
- {
- if (!ds->isPure() || !ds->isDatarow())
- return true;
- if (!ctx.queryAssociation(ds, AssocRow, NULL))
- return true;
- }
- return false;
- }
- case no_field:
- throwUnexpected();
- return false; // more, depends on whether conditional etc.
- case no_sizeof:
- case no_offsetof:
- return false; /// auto creates one anyway.
- case no_typetransfer:
- switch (expr->queryChild(0)->queryType()->getTypeCode())
- {
- case type_qstring:
- case type_string:
- case type_data:
- case type_varstring:
- break;
- default:
- return true;
- }
- break;
- case no_substring:
- {
- SubStringInfo info(expr);
- if (!info.canGenerateInline() && !expr->hasAttribute(quickAtom))
- return true;
- break;
- }
- case no_call:
- case no_externalcall:
- {
- ITypeInfo * type = expr->queryType();
- switch (type->getTypeCode())
- {
- case type_string:
- case type_data:
- case type_qstring:
- case type_varstring:
- case type_unicode:
- case type_varunicode:
- case type_utf8:
- return true;
- }
- break;
- }
- case no_cast:
- case no_implicitcast:
- {
- ITypeInfo * type = expr->queryType();
- IHqlExpression * child = expr->queryChild(0);
- switch (type->getTypeCode())
- {
- case type_string:
- case type_data:
- if (!canRemoveStringCast(type, child->queryType()))
- return true;
- break;
- case type_varstring:
- if ((type->getSize() != UNKNOWN_LENGTH) || (child->queryType()->getTypeCode() != type_varstring))
- return true;
- break;
- }
- }
- break;
- case no_eq:
- case no_ne:
- case no_lt:
- case no_le:
- case no_gt:
- case no_ge:
- {
- if (!includeChildren)
- return false;
- unsigned numArgs = expr->numChildren();
- for (unsigned index = 0; index < numArgs; index++)
- {
- OwnedHqlExpr cur = getSimplifyCompareArg(expr->queryChild(index));
- //decimal comparisons can't be short circuited because they might cause a bcd stack overflow.
- if (cur->queryType()->getTypeCode() == type_decimal)
- return true;
- if (requiresTemp(ctx, cur, true))
- return true;
- }
- return false;
- }
- case no_mul:
- case no_div:
- case no_modulus:
- case no_add:
- case no_sub:
- case no_and:
- case no_or:
- case no_xor:
- case no_lshift:
- case no_rshift:
- case no_comma:
- case no_compound:
- case no_band:
- case no_bor:
- case no_bxor:
- case no_pselect:
- case no_index:
- case no_postinc:
- case no_postdec:
- case no_negate:
- case no_not:
- case no_bnot:
- case no_address:
- case no_deref:
- case no_preinc:
- case no_predec:
- case no_if:
- case no_charlen:
- break;
- case no_between:
- //Assume the worse for decimals.
- if (expr->queryChild(0)->queryType()->getTypeCode() == type_decimal)
- return true;
- break;
- case no_order:
- case no_crc:
- case no_hash:
- case no_hash32:
- case no_hash64:
- case no_hashmd5:
- case no_abs:
- return true;
- default:
- return true;
- }
- if (includeChildren)
- return childrenRequireTemp(ctx, expr, includeChildren);
- return false;
- }
- bool HqlCppTranslator::requiresTempAfterFirst(BuildCtx & ctx, IHqlExpression * expr)
- {
- unsigned numArgs = expr->numChildren();
- for (unsigned index = 1; index < numArgs; index++)
- if (requiresTemp(ctx, expr->queryChild(index), true))
- return true;
- return false;
- }
- void HqlCppTranslator::useFunction(IHqlExpression * func)
- {
- code->useFunction(func);
- }
- void HqlCppTranslator::useLibrary(const char * libname)
- {
- code->useLibrary(libname);
- }
- //===========================================================================
- static unique_id_t queryInstance = 0;
- HqlQueryInstance::HqlQueryInstance()
- {
- instance = ++queryInstance;
- }
- StringBuffer & HqlQueryInstance::queryDllName(StringBuffer & out)
- {
- return out.append("query").append(instance);
- }
|