sql_ut_antlr4.cpp 350 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265
  1. #include "sql_ut_antlr4.h"
  2. #include "format/sql_format.h"
  3. #include "lexer/lexer.h"
  4. #include <yql/essentials/providers/common/provider/yql_provider_names.h>
  5. #include <yql/essentials/sql/sql.h>
  6. #include <yql/essentials/sql/v1/lexer/antlr4/lexer.h>
  7. #include <util/generic/map.h>
  8. #include <library/cpp/testing/unittest/registar.h>
  9. #include <util/string/split.h>
  10. #include <format>
  11. using namespace NSQLTranslation;
  12. namespace {
  13. TParsedTokenList Tokenize(const TString& query) {
  14. NSQLTranslationV1::TLexers lexers;
  15. lexers.Antlr4 = NSQLTranslationV1::MakeAntlr4LexerFactory();
  16. auto lexer = NSQLTranslationV1::MakeLexer(lexers, false, true);
  17. TParsedTokenList tokens;
  18. NYql::TIssues issues;
  19. UNIT_ASSERT_C(Tokenize(*lexer, query, "Query", tokens, issues, SQL_MAX_PARSER_ERRORS),
  20. issues.ToString());
  21. return tokens;
  22. }
  23. TString ToString(const TParsedTokenList& tokens) {
  24. TStringBuilder reconstructedQuery;
  25. for (const auto& token : tokens) {
  26. if (token.Name == "WS" || token.Name == "EOF") {
  27. continue;
  28. }
  29. if (!reconstructedQuery.empty()) {
  30. reconstructedQuery << ' ';
  31. }
  32. reconstructedQuery << token.Content;
  33. }
  34. return reconstructedQuery;
  35. }
  36. }
  37. Y_UNIT_TEST_SUITE(AnsiMode) {
  38. Y_UNIT_TEST(PragmaAnsi) {
  39. UNIT_ASSERT(SqlToYql("PRAGMA ANSI 2016;").IsOk());
  40. }
  41. }
  42. Y_UNIT_TEST_SUITE(SqlParsingOnly) {
  43. ///This function is used in BACKWARD COMPATIBILITY tests below that LIMIT the sets of token that CAN NOT be used
  44. ///as identifiers in different contexts in a SQL request
  45. ///\return list of tokens that failed this check
  46. TVector<TString> ValidateTokens(const THashSet<TString>& forbidden, const std::function<TString (const TString& )>& makeRequest) {
  47. THashMap<TString, bool> allTokens;
  48. for (const auto& t: NSQLFormat::GetKeywords()) {
  49. allTokens[t] = !forbidden.contains((t));
  50. }
  51. for (const auto& f: forbidden) {
  52. UNIT_ASSERT(allTokens.contains(f)); //check that forbidden list contains tokens only(argument check)
  53. }
  54. TVector<TString> failed;
  55. for (const auto& [token, allowed]: allTokens) {
  56. if (SqlToYql(makeRequest(token)).IsOk() != allowed)
  57. failed.push_back(token);
  58. }
  59. return failed;
  60. }
  61. Y_UNIT_TEST(TokensAsColumnName) { //id_expr
  62. auto failed = ValidateTokens({
  63. "ALL", "ANY", "AS", "ASSUME", "ASYMMETRIC", "AUTOMAP", "BETWEEN", "BITCAST",
  64. "CALLABLE", "CASE", "CAST", "CUBE", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
  65. "DICT", "DISTINCT", "ENUM", "ERASE", "EXCEPT", "EXISTS", "FLOW", "FROM", "FULL",
  66. "HAVING", "HOP", "INTERSECT", "JSON_EXISTS", "JSON_QUERY", "JSON_VALUE", "LIMIT", "LIST",
  67. "NOT", "OPTIONAL", "PROCESS", "REDUCE", "REPEATABLE", "RESOURCE", "RETURN", "RETURNING", "ROLLUP",
  68. "SELECT", "SET", "STREAM", "STRUCT", "SYMMETRIC", "TAGGED", "TUPLE", "UNBOUNDED",
  69. "UNION", "VARIANT", "WHEN", "WHERE", "WINDOW", "WITHOUT"
  70. },
  71. [](const TString& token){
  72. TStringBuilder req;
  73. req << "SELECT " << token << " FROM Plato.Input";
  74. return req;
  75. }
  76. );
  77. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  78. }
  79. Y_UNIT_TEST(TokensAsWithoutColumnName) { //id_without
  80. auto failed = ValidateTokens({
  81. "ALL", "AS", "ASSUME", "ASYMMETRIC", "AUTOMAP", "BETWEEN", "BITCAST",
  82. "CALLABLE", "CASE", "CAST", "CUBE", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
  83. "DICT", "DISTINCT", "EMPTY_ACTION", "ENUM", "EXCEPT", "EXISTS", "FALSE", "FLOW", "FROM", "FULL",
  84. "HAVING", "HOP", "INTERSECT", "JSON_EXISTS", "JSON_QUERY", "JSON_VALUE", "LIMIT", "LIST",
  85. "NOT", "NULL", "OPTIONAL", "PROCESS", "REDUCE", "REPEATABLE", "RESOURCE", "RETURN", "RETURNING", "ROLLUP",
  86. "SELECT", "SET", "STRUCT", "SYMMETRIC", "TAGGED", "TRUE", "TUPLE", "UNBOUNDED",
  87. "UNION", "VARIANT", "WHEN", "WHERE", "WINDOW", "WITHOUT"
  88. },
  89. [](const TString& token){
  90. TStringBuilder req;
  91. req << "SELECT * WITHOUT " << token << " FROM Plato.Input";
  92. return req;
  93. }
  94. );
  95. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  96. }
  97. Y_UNIT_TEST(TokensAsColumnNameInAddColumn) { //id_schema
  98. auto failed = ValidateTokens({
  99. "ANY", "AUTOMAP", "CALLABLE", "COLUMN", "DICT", "ENUM", "ERASE", "FALSE", "FLOW",
  100. "LIST", "OPTIONAL", "REPEATABLE", "RESOURCE",
  101. "SET", "STREAM", "STRUCT", "TAGGED", "TRUE", "TUPLE", "VARIANT"
  102. },
  103. [](const TString& token){
  104. TStringBuilder req;
  105. req << "ALTER TABLE Plato.Input ADD COLUMN " << token << " Bool";
  106. return req;
  107. }
  108. );
  109. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  110. }
  111. Y_UNIT_TEST(TokensAsColumnAlias) {
  112. auto failed = ValidateTokens({
  113. "AUTOMAP", "FALSE",
  114. "REPEATABLE", "TRUE"
  115. },
  116. [](const TString& token){
  117. TStringBuilder req;
  118. req << "SELECT Col as " << token << " FROM Plato.Input";
  119. return req;
  120. }
  121. );
  122. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  123. }
  124. Y_UNIT_TEST(TokensAsTableName) { //id_table_or_type
  125. auto failed = ValidateTokens({
  126. "ANY", "AUTOMAP", "COLUMN", "ERASE", "FALSE",
  127. "REPEATABLE", "STREAM", "TRUE"
  128. },
  129. [](const TString& token){
  130. TStringBuilder req;
  131. req << "SELECT * FROM Plato." << token;
  132. return req;
  133. }
  134. );
  135. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  136. }
  137. Y_UNIT_TEST(TokensAsTableAlias) { //id_table
  138. auto failed = ValidateTokens({
  139. "AUTOMAP", "CALLABLE", "DICT", "ENUM","FALSE", "FLOW",
  140. "LIST", "OPTIONAL", "REPEATABLE", "RESOURCE",
  141. "SET", "STRUCT", "TAGGED", "TRUE", "TUPLE", "VARIANT"
  142. },
  143. [](const TString& token){
  144. TStringBuilder req;
  145. req << "SELECT * FROM Plato.Input AS " << token;
  146. return req;
  147. }
  148. );
  149. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  150. }
  151. Y_UNIT_TEST(TokensAsHints) { //id_hint
  152. auto failed = ValidateTokens({
  153. "AUTOMAP", "CALLABLE", "COLUMNS", "DICT", "ENUM", "FALSE", "FLOW",
  154. "LIST", "OPTIONAL", "REPEATABLE", "RESOURCE",
  155. "SCHEMA", "SET", "STRUCT", "TAGGED", "TRUE", "TUPLE", "VARIANT"
  156. },
  157. [](const TString& token){
  158. TStringBuilder req;
  159. req << "SELECT * FROM Plato.Input WITH " << token;
  160. return req;
  161. }
  162. );
  163. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  164. }
  165. Y_UNIT_TEST(TokensAsWindow) { //id_window
  166. auto failed = ValidateTokens({
  167. "AUTOMAP", "CALLABLE", "DICT", "ENUM", "FALSE", "FLOW", "GROUPS", "LIST", "OPTIONAL",
  168. "RANGE", "REPEATABLE", "RESOURCE", "ROWS", "SET", "STRUCT", "TAGGED" ,"TRUE", "TUPLE", "VARIANT"
  169. },
  170. [](const TString& token){
  171. TStringBuilder req;
  172. req << "SELECT * FROM Plato.Input WINDOW " << token << " AS ()";
  173. return req;
  174. }
  175. );
  176. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  177. }
  178. Y_UNIT_TEST(TokensAsIdExprIn) { //id_expr_in
  179. auto failed = ValidateTokens({
  180. "ALL", "ANY", "AS", "ASSUME", "ASYMMETRIC", "AUTOMAP", "BETWEEN", "BITCAST",
  181. "CALLABLE", "CASE", "CAST", "COMPACT", "CUBE", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
  182. "DICT", "DISTINCT", "ENUM", "ERASE", "EXCEPT", "EXISTS", "FLOW", "FROM", "FULL",
  183. "HAVING", "HOP", "INTERSECT", "JSON_EXISTS", "JSON_QUERY", "JSON_VALUE", "LIMIT", "LIST",
  184. "NOT", "OPTIONAL", "PROCESS", "REDUCE", "REPEATABLE", "RESOURCE", "RETURN", "RETURNING", "ROLLUP",
  185. "SELECT", "SET", "STREAM", "STRUCT", "SYMMETRIC", "TAGGED", "TUPLE", "UNBOUNDED",
  186. "UNION", "VARIANT", "WHEN", "WHERE", "WINDOW", "WITHOUT"
  187. },
  188. [](const TString& token){
  189. TStringBuilder req;
  190. req << "SELECT * FROM Plato.Input WHERE q IN " << token;
  191. return req;
  192. }
  193. );
  194. UNIT_ASSERT_VALUES_EQUAL(failed, TVector<TString>{});
  195. }
  196. Y_UNIT_TEST(TableHints) {
  197. UNIT_ASSERT(SqlToYql("SELECT * FROM plato.Input WITH INFER_SCHEMA").IsOk());
  198. UNIT_ASSERT(SqlToYql("SELECT * FROM plato.Input WITH (INFER_SCHEMA)").IsOk());
  199. }
  200. Y_UNIT_TEST(InNoHints) {
  201. TString query = "SELECT * FROM plato.Input WHERE key IN (1,2,3)";
  202. VerifySqlInHints(query, { "'('('warnNoAnsi))" }, {});
  203. VerifySqlInHints(query, { "'()" }, false);
  204. VerifySqlInHints(query, { "'('('ansi))" }, true);
  205. }
  206. Y_UNIT_TEST(InHintCompact) {
  207. // should parse COMPACT as hint
  208. TString query = "SELECT * FROM plato.Input WHERE key IN COMPACT(1, 2, 3)";
  209. VerifySqlInHints(query, { "'('isCompact)" });
  210. }
  211. Y_UNIT_TEST(InHintSubquery) {
  212. // should parse tableSource as hint
  213. TString query = "$subq = (SELECT key FROM plato.Input); SELECT * FROM plato.Input WHERE key IN $subq";
  214. VerifySqlInHints(query, { "'('tableSource)" });
  215. }
  216. Y_UNIT_TEST(InHintCompactSubquery) {
  217. TString query = "$subq = (SELECT key FROM plato.Input); SELECT * FROM plato.Input WHERE key IN COMPACT $subq";
  218. VerifySqlInHints(query, { "'('isCompact)", "'('tableSource)" });
  219. }
  220. Y_UNIT_TEST(CompactKeywordNotReservedForNames) {
  221. UNIT_ASSERT(SqlToYql("SELECT COMPACT FROM plato.Input WHERE COMPACT IN COMPACT(1, 2, 3)").IsOk());
  222. UNIT_ASSERT(SqlToYql("USE plato; SELECT * FROM COMPACT").IsOk());
  223. }
  224. Y_UNIT_TEST(FamilyKeywordNotReservedForNames) {
  225. // FIXME: check if we can get old behaviour
  226. //UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE FAMILY (FAMILY Uint32, PRIMARY KEY (FAMILY));").IsOk());
  227. //UNIT_ASSERT(SqlToYql("USE plato; SELECT FAMILY FROM FAMILY").IsOk());
  228. UNIT_ASSERT(SqlToYql("USE plato; SELECT FAMILY FROM Input").IsOk());
  229. }
  230. Y_UNIT_TEST(ResetKeywordNotReservedForNames) {
  231. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE RESET (RESET Uint32, PRIMARY KEY (RESET));").IsOk());
  232. UNIT_ASSERT(SqlToYql("USE plato; SELECT RESET FROM RESET").IsOk());
  233. }
  234. Y_UNIT_TEST(SyncKeywordNotReservedForNames) {
  235. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE SYNC (SYNC Uint32, PRIMARY KEY (SYNC));").IsOk());
  236. UNIT_ASSERT(SqlToYql("USE plato; SELECT SYNC FROM SYNC").IsOk());
  237. }
  238. Y_UNIT_TEST(AsyncKeywordNotReservedForNames) {
  239. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE ASYNC (ASYNC Uint32, PRIMARY KEY (ASYNC));").IsOk());
  240. UNIT_ASSERT(SqlToYql("USE plato; SELECT ASYNC FROM ASYNC").IsOk());
  241. }
  242. Y_UNIT_TEST(DisableKeywordNotReservedForNames) {
  243. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE DISABLE (DISABLE Uint32, PRIMARY KEY (DISABLE));").IsOk());
  244. UNIT_ASSERT(SqlToYql("USE plato; SELECT DISABLE FROM DISABLE").IsOk());
  245. }
  246. Y_UNIT_TEST(ChangefeedKeywordNotReservedForNames) {
  247. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE CHANGEFEED (CHANGEFEED Uint32, PRIMARY KEY (CHANGEFEED));").IsOk());
  248. UNIT_ASSERT(SqlToYql("USE plato; SELECT CHANGEFEED FROM CHANGEFEED").IsOk());
  249. }
  250. Y_UNIT_TEST(ReplicationKeywordNotReservedForNames) {
  251. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE REPLICATION (REPLICATION Uint32, PRIMARY KEY (REPLICATION));").IsOk());
  252. UNIT_ASSERT(SqlToYql("USE plato; SELECT REPLICATION FROM REPLICATION").IsOk());
  253. }
  254. Y_UNIT_TEST(TransferKeywordNotReservedForNames) {
  255. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE TRANSFER (TRANSFER Uint32, PRIMARY KEY (TRANSFER));").IsOk());
  256. UNIT_ASSERT(SqlToYql("USE plato; SELECT TRANSFER FROM TRANSFER").IsOk());
  257. }
  258. Y_UNIT_TEST(SecondsKeywordNotReservedForNames) {
  259. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE SECONDS (SECONDS Uint32, PRIMARY KEY (SECONDS));").IsOk());
  260. UNIT_ASSERT(SqlToYql("USE plato; SELECT SECONDS FROM SECONDS").IsOk());
  261. }
  262. Y_UNIT_TEST(MillisecondsKeywordNotReservedForNames) {
  263. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE MILLISECONDS (MILLISECONDS Uint32, PRIMARY KEY (MILLISECONDS));").IsOk());
  264. UNIT_ASSERT(SqlToYql("USE plato; SELECT MILLISECONDS FROM MILLISECONDS").IsOk());
  265. }
  266. Y_UNIT_TEST(MicrosecondsKeywordNotReservedForNames) {
  267. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE MICROSECONDS (MICROSECONDS Uint32, PRIMARY KEY (MICROSECONDS));").IsOk());
  268. UNIT_ASSERT(SqlToYql("USE plato; SELECT MICROSECONDS FROM MICROSECONDS").IsOk());
  269. }
  270. Y_UNIT_TEST(NanosecondsKeywordNotReservedForNames) {
  271. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE NANOSECONDS (NANOSECONDS Uint32, PRIMARY KEY (NANOSECONDS));").IsOk());
  272. UNIT_ASSERT(SqlToYql("USE plato; SELECT NANOSECONDS FROM NANOSECONDS").IsOk());
  273. }
  274. Y_UNIT_TEST(Jubilee) {
  275. NYql::TAstParseResult res = SqlToYql("USE plato; INSERT INTO Arcadia (r2000000) VALUES (\"2M GET!!!\");");
  276. UNIT_ASSERT(res.Root);
  277. }
  278. Y_UNIT_TEST(QualifiedAsteriskBefore) {
  279. NYql::TAstParseResult res = SqlToYql(
  280. "PRAGMA DisableSimpleColumns;"
  281. "select interested_table.*, LENGTH(value) AS megahelpful_len from plato.Input as interested_table;"
  282. );
  283. UNIT_ASSERT(res.Root);
  284. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  285. static bool seenStar = false;
  286. if (word == "FlattenMembers") {
  287. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("interested_table."));
  288. } else if (word == "SqlProjectItem") {
  289. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("megahelpful_len")));
  290. UNIT_ASSERT_VALUES_EQUAL(seenStar, true);
  291. } else if (word == "SqlProjectStarItem") {
  292. seenStar = true;
  293. }
  294. };
  295. TWordCountHive elementStat = {{TString("FlattenMembers"), 0}, {TString("SqlProjectItem"), 0}, {TString("SqlProjectStarItem"), 0}};
  296. VerifyProgram(res, elementStat, verifyLine);
  297. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["FlattenMembers"]);
  298. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectItem"]);
  299. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectStarItem"]);
  300. }
  301. Y_UNIT_TEST(QualifiedAsteriskAfter) {
  302. NYql::TAstParseResult res = SqlToYql(
  303. "PRAGMA DisableSimpleColumns;"
  304. "select LENGTH(value) AS megahelpful_len, interested_table.* from plato.Input as interested_table;"
  305. );
  306. UNIT_ASSERT(res.Root);
  307. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  308. static bool seenStar = false;
  309. if (word == "FlattenMembers") {
  310. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("interested_table."));
  311. } else if (word == "SqlProjectItem") {
  312. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("megahelpful_len")));
  313. UNIT_ASSERT_VALUES_EQUAL(seenStar, false);
  314. } else if (word == "SqlProjectStarItem") {
  315. seenStar = true;
  316. }
  317. };
  318. TWordCountHive elementStat = {{TString("FlattenMembers"), 0}, {TString("SqlProjectItem"), 0}, {TString("SqlProjectStarItem"), 0}};
  319. VerifyProgram(res, elementStat, verifyLine);
  320. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["FlattenMembers"]);
  321. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectItem"]);
  322. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectStarItem"]);
  323. }
  324. Y_UNIT_TEST(QualifiedMembers) {
  325. NYql::TAstParseResult res = SqlToYql("select interested_table.key, interested_table.value from plato.Input as interested_table;");
  326. UNIT_ASSERT(res.Root);
  327. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  328. const bool fieldKey = TString::npos != line.find(Quote("key"));
  329. const bool fieldValue = TString::npos != line.find(Quote("value"));
  330. const bool refOnTable = TString::npos != line.find("interested_table.");
  331. if (word == "SqlProjectItem") {
  332. UNIT_ASSERT(fieldKey || fieldValue);
  333. UNIT_ASSERT(!refOnTable);
  334. } else if (word == "Write!") {
  335. UNIT_ASSERT(fieldKey && fieldValue && !refOnTable);
  336. }
  337. };
  338. TWordCountHive elementStat = {{TString("SqlProjectStarItem"), 0}, {TString("SqlProjectItem"), 0}, {TString("Write!"), 0}};
  339. VerifyProgram(res, elementStat, verifyLine);
  340. UNIT_ASSERT_VALUES_EQUAL(0, elementStat["SqlProjectStarItem"]);
  341. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["SqlProjectItem"]);
  342. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  343. }
  344. Y_UNIT_TEST(ExplainQueryPlan) {
  345. UNIT_ASSERT(SqlToYql("EXPLAIN SELECT 1;").IsOk());
  346. UNIT_ASSERT(SqlToYql("EXPLAIN QUERY PLAN SELECT 1;").IsOk());
  347. }
  348. Y_UNIT_TEST(JoinParseCorrect) {
  349. NYql::TAstParseResult res = SqlToYql(
  350. "PRAGMA DisableSimpleColumns;"
  351. " SELECT table_bb.*, table_aa.key as megakey"
  352. " FROM plato.Input AS table_aa"
  353. " JOIN plato.Input AS table_bb"
  354. " ON table_aa.value == table_bb.value;"
  355. );
  356. UNIT_ASSERT(res.Root);
  357. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  358. if (word == "SelectMembers") {
  359. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("table_aa."));
  360. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("table_bb."));
  361. } else if (word == "SqlProjectItem") {
  362. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("megakey")));
  363. } else if (word == "SqlColumn") {
  364. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("table_aa")));
  365. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("key")));
  366. }
  367. };
  368. TWordCountHive elementStat = {{TString("SqlProjectItem"), 0}, {TString("SqlProjectStarItem"), 0}, {TString("SelectMembers"), 0}, {TString("SqlColumn"), 0}};
  369. VerifyProgram(res, elementStat, verifyLine);
  370. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectItem"]);
  371. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectStarItem"]);
  372. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SelectMembers"]);
  373. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlColumn"]);
  374. }
  375. Y_UNIT_TEST(Join3Table) {
  376. NYql::TAstParseResult res = SqlToYql(
  377. " PRAGMA DisableSimpleColumns;"
  378. " SELECT table_bb.*, table_aa.key as gigakey, table_cc.* "
  379. " FROM plato.Input AS table_aa"
  380. " JOIN plato.Input AS table_bb ON table_aa.key == table_bb.key"
  381. " JOIN plato.Input AS table_cc ON table_aa.subkey == table_cc.subkey;"
  382. );
  383. Err2Str(res);
  384. UNIT_ASSERT(res.Root);
  385. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  386. if (word == "SelectMembers") {
  387. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("table_aa."));
  388. UNIT_ASSERT(line.find("table_bb.") != TString::npos || line.find("table_cc.") != TString::npos);
  389. } else if (word == "SqlProjectItem") {
  390. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("gigakey")));
  391. } else if (word == "SqlColumn") {
  392. const auto posTableAA = line.find(Quote("table_aa"));
  393. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, posTableAA);
  394. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("key")));
  395. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("table_aa", posTableAA + 3));
  396. }
  397. };
  398. TWordCountHive elementStat = {{TString("SqlProjectItem"), 0}, {TString("SqlProjectStarItem"), 0}, {TString("SelectMembers"), 0}, {TString("SqlColumn"), 0}};
  399. VerifyProgram(res, elementStat, verifyLine);
  400. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectItem"]);
  401. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["SqlProjectStarItem"]);
  402. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["SelectMembers"]);
  403. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlColumn"]);
  404. }
  405. Y_UNIT_TEST(DisabledJoinCartesianProduct) {
  406. NYql::TAstParseResult res = SqlToYql("pragma DisableAnsiImplicitCrossJoin; use plato; select * from A,B,C");
  407. UNIT_ASSERT(!res.Root);
  408. UNIT_ASSERT_STRINGS_EQUAL(res.Issues.ToString(), "<main>:1:67: Error: Cartesian product of tables is disabled. Please use explicit CROSS JOIN or enable it via PRAGMA AnsiImplicitCrossJoin\n");
  409. }
  410. Y_UNIT_TEST(JoinCartesianProduct) {
  411. NYql::TAstParseResult res = SqlToYql("pragma AnsiImplicitCrossJoin; use plato; select * from A,B,C");
  412. UNIT_ASSERT(res.Root);
  413. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  414. if (word == "EquiJoin") {
  415. auto pos = line.find("Cross");
  416. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, pos);
  417. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Cross", pos + 1));
  418. }
  419. };
  420. TWordCountHive elementStat = {{TString("EquiJoin"), 0}};
  421. VerifyProgram(res, elementStat, verifyLine);
  422. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["EquiJoin"]);
  423. }
  424. Y_UNIT_TEST(CreateAlterUserWithLoginNoLogin) {
  425. auto reqCreateUser = SqlToYql(R"(
  426. USE plato;
  427. CREATE USER user1;
  428. )");
  429. UNIT_ASSERT(reqCreateUser.IsOk());
  430. auto reqAlterUser = SqlToYql(R"(
  431. USE plato;
  432. ALTER USER user1;
  433. )");
  434. UNIT_ASSERT(!reqAlterUser.IsOk());
  435. UNIT_ASSERT_STRING_CONTAINS(reqAlterUser.Issues.ToString(), "Error: mismatched input ';' expecting {ENCRYPTED, HASH, LOGIN, NOLOGIN, PASSWORD, RENAME, WITH}");
  436. auto reqPasswordAndLogin = SqlToYql(R"(
  437. USE plato;
  438. CREATE USER user1 LOgin;
  439. )");
  440. UNIT_ASSERT(reqPasswordAndLogin.IsOk());
  441. auto reqPasswordAndNoLogin = SqlToYql(R"(
  442. USE plato;
  443. CREATE USER user1 PASSWORD '123' NOLOGIN;
  444. )");
  445. UNIT_ASSERT(reqPasswordAndNoLogin.IsOk());
  446. auto reqLogin = SqlToYql(R"(
  447. USE plato;
  448. CREATE USER user1 LOGIN;
  449. )");
  450. UNIT_ASSERT(reqLogin.IsOk());
  451. auto reqNoLogin = SqlToYql(R"(
  452. USE plato;
  453. CREATE USER user1 NOLOGIN;
  454. )");
  455. UNIT_ASSERT(reqNoLogin.IsOk());
  456. auto reqLoginNoLogin = SqlToYql(R"(
  457. USE plato;
  458. CREATE USER user1 LOGIN NOLOGIN;
  459. )");
  460. UNIT_ASSERT(!reqLoginNoLogin.IsOk());
  461. UNIT_ASSERT_STRING_CONTAINS(reqLoginNoLogin.Issues.ToString(), "Error: Conflicting or redundant options");
  462. auto reqAlterLoginNoLogin = SqlToYql(R"(
  463. USE plato;
  464. CREATE USER user1 LOGIN;
  465. ALTER USER user1 NOLOGIN;
  466. )");
  467. UNIT_ASSERT(reqAlterLoginNoLogin.IsOk());
  468. auto reqAlterLoginNoLoginWithPassword = SqlToYql(R"(
  469. USE plato;
  470. CREATE USER user1 LOGIN;
  471. ALTER USER user1 PASSWORD '321' NOLOGIN;
  472. )");
  473. UNIT_ASSERT(reqAlterLoginNoLoginWithPassword.IsOk());
  474. }
  475. Y_UNIT_TEST(CreateUserWithHash) {
  476. auto reqCreateUser = SqlToYql(R"(
  477. USE plato;
  478. CREATE USER user1 HASH '{
  479. "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
  480. "salt": "U+tzBtgo06EBQCjlARA6Jg==",
  481. "type": "argon2id"
  482. }';
  483. )");
  484. UNIT_ASSERT(reqCreateUser.IsOk());
  485. auto reqCreateUserWithNoLogin = SqlToYql(R"(
  486. USE plato;
  487. CREATE USER user1 HASH '{
  488. "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
  489. "salt": "U+tzBtgo06EBQCjlARA6Jg==",
  490. "type": "argon2id"
  491. }'
  492. NOLOGIN;
  493. )");
  494. UNIT_ASSERT(reqCreateUserWithNoLogin.IsOk());
  495. auto reqCreateUserWithPassword = SqlToYql(R"(
  496. USE plato;
  497. CREATE USER user1 HASH '{
  498. "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
  499. "salt": "U+tzBtgo06EBQCjlARA6Jg==",
  500. "type": "argon2id"
  501. }'
  502. PASSWORD '123';
  503. )");
  504. UNIT_ASSERT(!reqCreateUserWithPassword.IsOk());
  505. UNIT_ASSERT_STRING_CONTAINS(reqCreateUserWithPassword.Issues.ToString(), "Error: Conflicting or redundant options");
  506. auto reqAlterUser = SqlToYql(R"(
  507. USE plato;
  508. CREATE USER user1;
  509. ALTER USER user1 HASH '{
  510. "hash": "p4ffeMugohqyBwyckYCK1TjJfz3LIHbKiGL+t+oEhzw=",
  511. "salt": "U+tzBtgo06EBQCjlARA6Jg==",
  512. "type": "argon2id"
  513. }';
  514. )");
  515. UNIT_ASSERT(reqAlterUser.IsOk());
  516. }
  517. Y_UNIT_TEST(JoinWithoutConcreteColumns) {
  518. NYql::TAstParseResult res = SqlToYql(
  519. " use plato;"
  520. " SELECT a.v, b.value"
  521. " FROM `Input1` VIEW `ksv` AS a"
  522. " JOIN `Input2` AS b"
  523. " ON a.k == b.key;"
  524. );
  525. UNIT_ASSERT(res.Root);
  526. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  527. if (word == "SqlProjectItem") {
  528. UNIT_ASSERT(line.find(Quote("a.v")) != TString::npos || line.find(Quote("b.value")) != TString::npos);
  529. } else if (word == "SqlColumn") {
  530. const auto posTableA = line.find(Quote("a"));
  531. const auto posTableB = line.find(Quote("b"));
  532. if (posTableA != TString::npos) {
  533. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("v")));
  534. } else {
  535. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, posTableB);
  536. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("value")));
  537. }
  538. }
  539. };
  540. TWordCountHive elementStat = {{TString("SqlProjectStarItem"), 0}, {TString("SqlProjectItem"), 0}, {TString("SqlColumn"), 0}};
  541. VerifyProgram(res, elementStat, verifyLine);
  542. UNIT_ASSERT_VALUES_EQUAL(0, elementStat["SqlProjectStarItem"]);
  543. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["SqlProjectItem"]);
  544. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["SqlColumn"]);
  545. }
  546. Y_UNIT_TEST(JoinWithSameValues) {
  547. NYql::TAstParseResult res = SqlToYql("SELECT a.value, b.value FROM plato.Input AS a JOIN plato.Input as b ON a.key == b.key;");
  548. UNIT_ASSERT(res.Root);
  549. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  550. if (word == "SqlProjectItem") {
  551. const bool isValueFromA = TString::npos != line.find(Quote("a.value"));
  552. const bool isValueFromB = TString::npos != line.find(Quote("b.value"));
  553. UNIT_ASSERT(isValueFromA || isValueFromB);
  554. } if (word == "Write!") {
  555. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("a.a."));
  556. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("b.b."));
  557. }
  558. };
  559. TWordCountHive elementStat = {{TString("SqlProjectStarItem"), 0}, {TString("SqlProjectItem"), 0}, {"Write!", 0}};
  560. VerifyProgram(res, elementStat, verifyLine);
  561. UNIT_ASSERT_VALUES_EQUAL(0, elementStat["SqlProjectStarItem"]);
  562. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["SqlProjectItem"]);
  563. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  564. }
  565. Y_UNIT_TEST(SameColumnsForDifferentTables) {
  566. NYql::TAstParseResult res = SqlToYql("SELECT a.key, b.key FROM plato.Input as a JOIN plato.Input as b on a.key==b.key;");
  567. UNIT_ASSERT(res.Root);
  568. }
  569. Y_UNIT_TEST(SameColumnsForDifferentTablesFullJoin) {
  570. NYql::TAstParseResult res = SqlToYql("SELECT a.key, b.key, a.value, b.value FROM plato.Input AS a FULL JOIN plato.Input AS b USING(key);");
  571. UNIT_ASSERT(res.Root);
  572. }
  573. Y_UNIT_TEST(JoinStreamLookupStrategyHint) {
  574. {
  575. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input AS a JOIN /*+ StreamLookup() */ plato.Input AS b USING(key);");
  576. UNIT_ASSERT(res.Root);
  577. }
  578. //case insensitive
  579. {
  580. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input AS a JOIN /*+ streamlookup() */ plato.Input AS b USING(key);");
  581. UNIT_ASSERT(res.Root);
  582. }
  583. }
  584. Y_UNIT_TEST(JoinConflictingStrategyHint) {
  585. {
  586. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input AS a JOIN /*+ StreamLookup() */ /*+ Merge() */ plato.Input AS b USING(key);");
  587. UNIT_ASSERT(!res.Root);
  588. UNIT_ASSERT_STRINGS_EQUAL(res.Issues.ToString(), "<main>:1:91: Error: Conflicting join strategy hints\n");
  589. }
  590. }
  591. Y_UNIT_TEST(JoinDuplicatingStrategyHint) {
  592. {
  593. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input AS a JOIN /*+ StreamLookup() */ /*+ StreamLookup() */ plato.Input AS b USING(key);");
  594. UNIT_ASSERT(!res.Root);
  595. UNIT_ASSERT_STRINGS_EQUAL(res.Issues.ToString(), "<main>:1:98: Error: Duplicate join strategy hint\n");
  596. }
  597. }
  598. Y_UNIT_TEST(WarnCrossJoinStrategyHint) {
  599. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input AS a CROSS JOIN /*+ merge() */ plato.Input AS b;");
  600. UNIT_ASSERT(res.Root);
  601. UNIT_ASSERT_STRINGS_EQUAL(res.Issues.ToString(), "<main>:1:32: Warning: Non-default join strategy will not be used for CROSS JOIN, code: 4534\n");
  602. }
  603. Y_UNIT_TEST(WarnCartesianProductStrategyHint) {
  604. NYql::TAstParseResult res = SqlToYql("pragma AnsiImplicitCrossJoin; use plato; SELECT * FROM A, /*+ merge() */ B;");
  605. UNIT_ASSERT(res.Root);
  606. UNIT_ASSERT_STRINGS_EQUAL(res.Issues.ToString(), "<main>:1:74: Warning: Non-default join strategy will not be used for CROSS JOIN, code: 4534\n");
  607. }
  608. Y_UNIT_TEST(WarnUnknownJoinStrategyHint) {
  609. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input AS a JOIN /*+ xmerge() */ plato.Input AS b USING (key);");
  610. UNIT_ASSERT(res.Root);
  611. UNIT_ASSERT_STRINGS_EQUAL(res.Issues.ToString(), "<main>:1:41: Warning: Unsupported join hint: xmerge, code: 4534\n");
  612. }
  613. Y_UNIT_TEST(ReverseLabels) {
  614. NYql::TAstParseResult res = SqlToYql("select in.key as subkey, subkey as key from plato.Input as in;");
  615. UNIT_ASSERT(res.Root);
  616. }
  617. Y_UNIT_TEST(AutogenerationAliasWithoutCollisionConflict1) {
  618. NYql::TAstParseResult res = SqlToYql("select LENGTH(Value), key as column1 from plato.Input;");
  619. UNIT_ASSERT(res.Root);
  620. }
  621. Y_UNIT_TEST(AutogenerationAliasWithoutCollision2Conflict2) {
  622. NYql::TAstParseResult res = SqlToYql("select key as column0, LENGTH(Value) from plato.Input;");
  623. UNIT_ASSERT(res.Root);
  624. }
  625. Y_UNIT_TEST(InputAliasForQualifiedAsterisk) {
  626. NYql::TAstParseResult res = SqlToYql("use plato; select zyuzya.*, key from plato.Input as zyuzya;");
  627. UNIT_ASSERT(res.Root);
  628. }
  629. Y_UNIT_TEST(SelectSupportsResultColumnsWithTrailingComma) {
  630. NYql::TAstParseResult res = SqlToYql("select a, b, c, from plato.Input;");
  631. UNIT_ASSERT(res.Root);
  632. }
  633. Y_UNIT_TEST(SelectOrderByLabeledColumn) {
  634. NYql::TAstParseResult res = SqlToYql("pragma DisableOrderedColumns; select key as goal from plato.Input order by goal");
  635. UNIT_ASSERT(res.Root);
  636. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  637. if (word == "DataSource") {
  638. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("plato"));
  639. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Input"));
  640. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("goal"));
  641. } else if (word == "Sort") {
  642. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("goal"));
  643. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("key"));
  644. }
  645. };
  646. TWordCountHive elementStat = {{TString("DataSource"), 0}, {TString("Sort"), 0}};
  647. VerifyProgram(res, elementStat, verifyLine);
  648. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["DataSource"]);
  649. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Sort"]);
  650. }
  651. Y_UNIT_TEST(SelectOrderBySimpleExpr) {
  652. NYql::TAstParseResult res = SqlToYql("select a from plato.Input order by a + a");
  653. UNIT_ASSERT(res.Root);
  654. }
  655. Y_UNIT_TEST(SelectAssumeOrderByTableRowAccess) {
  656. NYql::TAstParseResult res = SqlToYql("$key = 'foo';select * from plato.Input assume order by TableRow().$key");
  657. UNIT_ASSERT(res.Root);
  658. }
  659. Y_UNIT_TEST(SelectOrderByDuplicateLabels) {
  660. NYql::TAstParseResult res = SqlToYql("select a from plato.Input order by a, a");
  661. UNIT_ASSERT(res.Root);
  662. }
  663. Y_UNIT_TEST(SelectOrderByExpression) {
  664. NYql::TAstParseResult res = SqlToYql("select * from plato.Input as i order by cast(key as uint32) + cast(subkey as uint32)");
  665. UNIT_ASSERT(res.Root);
  666. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  667. if (word == "Sort") {
  668. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"+MayWarn\""));
  669. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("key"));
  670. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("subkey"));
  671. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Bool 'true)"));
  672. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("i.key"));
  673. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("i.subkey"));
  674. }
  675. };
  676. TWordCountHive elementStat = {{TString("Sort"), 0}};
  677. VerifyProgram(res, elementStat, verifyLine);
  678. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Sort"]);
  679. }
  680. Y_UNIT_TEST(SelectOrderByExpressionDesc) {
  681. NYql::TAstParseResult res = SqlToYql("pragma disablesimplecolumns; select i.*, key, subkey from plato.Input as i order by cast(i.key as uint32) - cast(i.subkey as uint32) desc");
  682. UNIT_ASSERT(res.Root);
  683. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  684. if (word == "Sort") {
  685. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"-MayWarn\""));
  686. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"key\""));
  687. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"subkey\""));
  688. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Bool 'false)"));
  689. } else if (word == "Write!") {
  690. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'columns"));
  691. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"key\""));
  692. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"subkey\""));
  693. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("prefix"));
  694. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"i.\""));
  695. }
  696. };
  697. TWordCountHive elementStat = {{TString("Sort"), 0}, {TString("Write!"), 0}};
  698. VerifyProgram(res, elementStat, verifyLine);
  699. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Sort"]);
  700. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  701. }
  702. Y_UNIT_TEST(SelectOrderByExpressionAsc) {
  703. NYql::TAstParseResult res = SqlToYql("select i.key, i.subkey from plato.Input as i order by cast(key as uint32) % cast(i.subkey as uint32) asc");
  704. UNIT_ASSERT(res.Root);
  705. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  706. if (word == "Sort") {
  707. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"%MayWarn\""));
  708. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"key\""));
  709. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"subkey\""));
  710. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Bool 'true)"));
  711. } else if (word == "Write!") {
  712. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'columns"));
  713. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"key\""));
  714. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"subkey\""));
  715. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("i."));
  716. }
  717. };
  718. TWordCountHive elementStat = {{TString("Sort"), 0}, {TString("Write!"), 0}};
  719. VerifyProgram(res, elementStat, verifyLine);
  720. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Sort"]);
  721. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  722. }
  723. Y_UNIT_TEST(ReferenceToKeyInSubselect) {
  724. NYql::TAstParseResult res = SqlToYql("select b.key from (select a.key from plato.Input as a) as b;");
  725. UNIT_ASSERT(res.Root);
  726. }
  727. Y_UNIT_TEST(OrderByCastValue) {
  728. NYql::TAstParseResult res = SqlToYql("select i.key, i.subkey from plato.Input as i order by cast(key as uint32) desc;");
  729. UNIT_ASSERT(res.Root);
  730. }
  731. Y_UNIT_TEST(GroupByCastValue) {
  732. NYql::TAstParseResult res = SqlToYql("select count(1) from plato.Input as i group by cast(key as uint8);");
  733. UNIT_ASSERT(res.Root);
  734. }
  735. Y_UNIT_TEST(KeywordInSelectColumns) {
  736. NYql::TAstParseResult res = SqlToYql("select in, s.check from (select 1 as in, \"test\" as check) as s;");
  737. UNIT_ASSERT(res.Root);
  738. }
  739. Y_UNIT_TEST(SelectAllGroupBy) {
  740. NYql::TAstParseResult res = SqlToYql("select * from plato.Input group by subkey;");
  741. UNIT_ASSERT(res.Root);
  742. }
  743. Y_UNIT_TEST(CreateObjectWithFeatures) {
  744. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET) WITH (Key1=Value1, K2=V2);");
  745. UNIT_ASSERT(res.Root);
  746. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  747. if (word == "Write") {
  748. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('\"K2\" '\"V2\") '('\"Key1\" '\"Value1\")"));
  749. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  750. }
  751. };
  752. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  753. VerifyProgram(res, elementStat, verifyLine);
  754. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  755. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  756. }
  757. Y_UNIT_TEST(CreateObjectIfNotExists) {
  758. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT IF NOT EXISTS secretId (TYPE SECRET) WITH (Key1=Value1, K2=V2);");
  759. UNIT_ASSERT(res.Root);
  760. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  761. if (word == "Write") {
  762. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObjectIfNotExists"));
  763. }
  764. };
  765. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  766. VerifyProgram(res, elementStat, verifyLine);
  767. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  768. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  769. }
  770. Y_UNIT_TEST(CreateObjectWithFeaturesStrings) {
  771. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET) WITH (Key1=\"Value1\", K2='V2', K3=V3, K4='', K5=`aaa`, K6='a\\'aa');");
  772. UNIT_ASSERT(res.Root);
  773. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  774. if (word == "Write") {
  775. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('\"K2\" '\"V2\") '('\"K3\" '\"V3\") '('\"K4\" '\"\") '('\"K5\" '\"aaa\") '('\"K6\" '\"a'aa\") '('\"Key1\" '\"Value1\")"));
  776. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  777. }
  778. };
  779. TWordCountHive elementStat = {{TString("Write"), 0}, {TString("SECRET"), 0}};
  780. VerifyProgram(res, elementStat, verifyLine);
  781. }
  782. Y_UNIT_TEST(UpsertObjectWithFeatures) {
  783. NYql::TAstParseResult res = SqlToYql("USE plato; UPSERT OBJECT secretId (TYPE SECRET) WITH (Key1=Value1, K2=V2);");
  784. UNIT_ASSERT(res.Root);
  785. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  786. if (word == "Write") {
  787. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('\"K2\" '\"V2\") '('\"Key1\" '\"Value1\")"));
  788. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("upsertObject"));
  789. }
  790. };
  791. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  792. VerifyProgram(res, elementStat, verifyLine);
  793. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  794. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  795. }
  796. Y_UNIT_TEST(CreateObjectWithFeaturesAndFlags) {
  797. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET) WITH (Key1=Value1, K2=V2, RECURSE);");
  798. UNIT_ASSERT(res.Root);
  799. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  800. if (word == "Write") {
  801. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('\"Key1\" '\"Value1\") '('\"RECURSE\")"));
  802. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  803. }
  804. };
  805. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  806. VerifyProgram(res, elementStat, verifyLine);
  807. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  808. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  809. }
  810. Y_UNIT_TEST(Select1Type) {
  811. NYql::TAstParseResult res = SqlToYql("SELECT 1 type;");
  812. UNIT_ASSERT(res.Root);
  813. }
  814. Y_UNIT_TEST(SelectTableType) {
  815. NYql::TAstParseResult res = SqlToYql("USE plato; SELECT * from T type;");
  816. UNIT_ASSERT(res.Root);
  817. }
  818. Y_UNIT_TEST(CreateObjectNoFeatures) {
  819. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE OBJECT secretId (TYPE SECRET);");
  820. UNIT_ASSERT(res.Root);
  821. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  822. if (word == "Write") {
  823. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features"));
  824. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  825. }
  826. };
  827. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  828. VerifyProgram(res, elementStat, verifyLine);
  829. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  830. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  831. }
  832. Y_UNIT_TEST(AlterObjectWithFeatures) {
  833. NYql::TAstParseResult res = SqlToYql(
  834. "USE plato;\n"
  835. "declare $path as String;\n"
  836. "ALTER OBJECT secretId (TYPE SECRET) SET (Key1=$path, K2=V2);"
  837. );
  838. UNIT_ASSERT(res.Root);
  839. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  840. if (word == "Write") {
  841. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'features"));
  842. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"Key1\" (EvaluateAtom \"$path\""));
  843. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"K2\" '\"V2\""));
  844. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alterObject"));
  845. }
  846. };
  847. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  848. VerifyProgram(res, elementStat, verifyLine);
  849. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  850. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  851. }
  852. Y_UNIT_TEST(AlterObjectNoFeatures) {
  853. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER OBJECT secretId (TYPE SECRET);");
  854. UNIT_ASSERT(!res.Root);
  855. }
  856. Y_UNIT_TEST(DropObjectNoFeatures) {
  857. NYql::TAstParseResult res = SqlToYql("USE plato; DROP OBJECT secretId (TYPE SECRET);");
  858. UNIT_ASSERT(res.Root);
  859. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  860. if (word == "Write") {
  861. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features"));
  862. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  863. }
  864. };
  865. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  866. VerifyProgram(res, elementStat, verifyLine);
  867. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  868. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  869. }
  870. Y_UNIT_TEST(DropObjectWithFeatures) {
  871. NYql::TAstParseResult res = SqlToYql("USE plato; DROP OBJECT secretId (TYPE SECRET) WITH (A, B, C);");
  872. UNIT_ASSERT(res.Root);
  873. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  874. if (word == "Write") {
  875. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'features"));
  876. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  877. }
  878. };
  879. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  880. VerifyProgram(res, elementStat, verifyLine);
  881. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  882. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  883. }
  884. Y_UNIT_TEST(DropObjectWithOneOption) {
  885. NYql::TAstParseResult res = SqlToYql("USE plato; DROP OBJECT secretId (TYPE SECRET) WITH OVERRIDE;");
  886. UNIT_ASSERT(res.Root);
  887. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  888. if (word == "Write") {
  889. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'features"));
  890. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"OVERRIDE\""));
  891. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  892. }
  893. };
  894. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  895. VerifyProgram(res, elementStat, verifyLine);
  896. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  897. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  898. }
  899. Y_UNIT_TEST(DropObjectIfExists) {
  900. NYql::TAstParseResult res = SqlToYql("USE plato; DROP OBJECT IF EXISTS secretId (TYPE SECRET);");
  901. UNIT_ASSERT(res.Root);
  902. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  903. if (word == "Write") {
  904. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObjectIfExists"));
  905. }
  906. };
  907. TWordCountHive elementStat = { {TString("Write"), 0}, {TString("SECRET"), 0} };
  908. VerifyProgram(res, elementStat, verifyLine);
  909. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  910. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SECRET"]);
  911. }
  912. Y_UNIT_TEST(PrimaryKeyParseCorrect) {
  913. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE tableName (Key Uint32, Subkey Int64, Value String, PRIMARY KEY (Key, Subkey));");
  914. UNIT_ASSERT(res.Root);
  915. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  916. if (word == "Write") {
  917. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"Key\""));
  918. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"Subkey\""));
  919. }
  920. };
  921. TWordCountHive elementStat = {{TString("Write"), 0}, {TString("primarykey"), 0}};
  922. VerifyProgram(res, elementStat, verifyLine);
  923. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  924. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["primarykey"]);
  925. }
  926. Y_UNIT_TEST(AlterDatabaseAst) {
  927. NYql::TAstParseResult request = SqlToYql("USE plato; ALTER DATABASE `/Root/test` OWNER TO user1;");
  928. UNIT_ASSERT(request.IsOk());
  929. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  930. Y_UNUSED(word);
  931. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(
  932. R"(let world (Write! world sink (Key '('databasePath (String '"/Root/test"))) (Void) '('('mode 'alterDatabase) '('owner '"user1"))))"
  933. ));
  934. };
  935. TWordCountHive elementStat({TString("\'mode \'alterDatabase")});
  936. VerifyProgram(request, elementStat, verifyLine);
  937. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["\'mode \'alterDatabase"]);
  938. }
  939. Y_UNIT_TEST(CreateTableNonNullableYqlTypeAstCorrect) {
  940. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32 not null);");
  941. UNIT_ASSERT(res.Root);
  942. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  943. if (word == "Write!") {
  944. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  945. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (DataType 'Int32) '('columnConstrains '('('not_null))) '())))))))__"));
  946. }
  947. };
  948. TWordCountHive elementStat = {{TString("Write!"), 0}};
  949. VerifyProgram(res, elementStat, verifyLine);
  950. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  951. }
  952. Y_UNIT_TEST(CreateTableNullableYqlTypeAstCorrect) {
  953. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32);");
  954. UNIT_ASSERT(res.Root);
  955. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  956. if (word == "Write!") {
  957. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  958. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))))))__"));
  959. }
  960. };
  961. TWordCountHive elementStat = {{TString("Write!"), 0}};
  962. VerifyProgram(res, elementStat, verifyLine);
  963. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  964. }
  965. Y_UNIT_TEST(CreateTableNonNullablePgTypeAstCorrect) {
  966. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a pg_int4 not null);");
  967. UNIT_ASSERT(res.Root);
  968. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  969. if (word == "Write!") {
  970. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  971. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (PgType '_int4) '('columnConstrains '('('not_null))) '())))))))__"));
  972. }
  973. };
  974. TWordCountHive elementStat = {{TString("Write!"), 0}};
  975. VerifyProgram(res, elementStat, verifyLine);
  976. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  977. }
  978. Y_UNIT_TEST(CreateTableNullablePgTypeAstCorrect) {
  979. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a pg_int4);");
  980. UNIT_ASSERT(res.Root);
  981. res.Root->PrettyPrintTo(Cout, PRETTY_FLAGS);
  982. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  983. if (word == "Write!") {
  984. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  985. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (AsOptionalType (PgType '_int4)) '('columnConstrains '()) '()))))))__"));
  986. }
  987. };
  988. TWordCountHive elementStat = {{TString("Write!"), 0}};
  989. VerifyProgram(res, elementStat, verifyLine);
  990. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  991. }
  992. Y_UNIT_TEST(CreateTableNullPkColumnsAreAllowed) {
  993. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32, primary key(a));");
  994. UNIT_ASSERT(res.Root);
  995. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  996. if (word == "Write!") {
  997. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  998. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))) '('primarykey '('"a")))))__"));
  999. }
  1000. };
  1001. TWordCountHive elementStat = {{TString("Write!"), 0}};
  1002. VerifyProgram(res, elementStat, verifyLine);
  1003. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1004. }
  1005. Y_UNIT_TEST(CreateTableNotNullPkColumnsAreIdempotentAstCorrect) {
  1006. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32 not null, primary key(a));");
  1007. UNIT_ASSERT(res.Root);
  1008. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1009. if (word == "Write!") {
  1010. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  1011. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (DataType 'Int32) '('columnConstrains '('('not_null))) '()))) '('primarykey '('"a"))))))__"));
  1012. }
  1013. };
  1014. TWordCountHive elementStat = {{TString("Write!"), 0}};
  1015. VerifyProgram(res, elementStat, verifyLine);
  1016. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1017. }
  1018. Y_UNIT_TEST(CreateTableWithIfNotExists) {
  1019. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE IF NOT EXISTS t (a int32, primary key(a));");
  1020. UNIT_ASSERT(res.Root);
  1021. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1022. if (word == "Write!") {
  1023. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  1024. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create_if_not_exists) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))) '('primarykey '('"a")))))__"));
  1025. }
  1026. };
  1027. TWordCountHive elementStat = {{TString("Write!"), 0}};
  1028. VerifyProgram(res, elementStat, verifyLine);
  1029. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1030. }
  1031. Y_UNIT_TEST(CreateTempTable) {
  1032. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TEMP TABLE t (a int32, primary key(a));");
  1033. UNIT_ASSERT(res.Root);
  1034. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1035. if (word == "Write!") {
  1036. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos,
  1037. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))) '('primarykey '('"a")) '('temporary))))__"), line);
  1038. }
  1039. };
  1040. TWordCountHive elementStat = {{TString("Write!"), 0}};
  1041. VerifyProgram(res, elementStat, verifyLine);
  1042. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1043. }
  1044. Y_UNIT_TEST(CreateTemporaryTable) {
  1045. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TEMPORARY TABLE t (a int32, primary key(a));");
  1046. UNIT_ASSERT(res.Root);
  1047. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1048. if (word == "Write!") {
  1049. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos,
  1050. line.find(R"__((Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a" (AsOptionalType (DataType 'Int32)) '('columnConstrains '()) '()))) '('primarykey '('"a")) '('temporary))))__"), line);
  1051. }
  1052. };
  1053. TWordCountHive elementStat = {{TString("Write!"), 0}};
  1054. VerifyProgram(res, elementStat, verifyLine);
  1055. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1056. }
  1057. Y_UNIT_TEST(CreateTableWithoutTypes) {
  1058. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a, primary key(a));");
  1059. UNIT_ASSERT(!res.Root);
  1060. }
  1061. Y_UNIT_TEST(CreateTableAsSelectWithTypes) {
  1062. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32, primary key(a)) AS SELECT * FROM ts;");
  1063. UNIT_ASSERT(!res.Root);
  1064. }
  1065. Y_UNIT_TEST(CreateTableAsSelect) {
  1066. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a, b, primary key(a)) AS SELECT * FROM ts;");
  1067. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  1068. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1069. if (word == "Write!") {
  1070. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  1071. line.find(R"__((let world (Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '('('"a") '('"b"))) '('primarykey '('"a"))))))__"));
  1072. }
  1073. if (word == "Read!") {
  1074. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  1075. line.find(R"__((Read! world (DataSource '"yt" '"plato") (MrTableConcat (Key '('table (String '"ts")))))__"));
  1076. }
  1077. };
  1078. TWordCountHive elementStat = {{TString("Write!"), 0}, {TString("Read!"), 0}};
  1079. VerifyProgram(res, elementStat, verifyLine);
  1080. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1081. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Read!"]);
  1082. }
  1083. Y_UNIT_TEST(CreateTableAsSelectOnlyPrimary) {
  1084. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (primary key(a)) AS SELECT * FROM ts;");
  1085. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  1086. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1087. if (word == "Write!") {
  1088. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  1089. line.find(R"__((let world (Write! world sink (Key '('tablescheme (String '"t"))) values '('('mode 'create) '('columns '()) '('primarykey '('"a"))))))__"));
  1090. }
  1091. if (word == "Read!") {
  1092. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  1093. line.find(R"__((Read! world (DataSource '"yt" '"plato") (MrTableConcat (Key '('table (String '"ts")))))__"));
  1094. }
  1095. };
  1096. TWordCountHive elementStat = {{TString("Write!"), 0}, {TString("Read!"), 0}};
  1097. VerifyProgram(res, elementStat, verifyLine);
  1098. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  1099. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Read!"]);
  1100. }
  1101. Y_UNIT_TEST(CreateTableAsValuesFail) {
  1102. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a, primary key(a)) AS VALUES (1), (2);");
  1103. UNIT_ASSERT(!res.Root);
  1104. }
  1105. Y_UNIT_TEST(CreateTableDuplicatedPkColumnsFail) {
  1106. NYql::TAstParseResult res = SqlToYql("USE plato; CREATE TABLE t (a int32 not null, primary key(a, a));");
  1107. UNIT_ASSERT(!res.Root);
  1108. }
  1109. Y_UNIT_TEST(DeleteFromTableByKey) {
  1110. NYql::TAstParseResult res = SqlToYql("delete from plato.Input where key = 200;", 10, "kikimr");
  1111. UNIT_ASSERT(res.Root);
  1112. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1113. if (word == "Write") {
  1114. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete)"));
  1115. }
  1116. };
  1117. TWordCountHive elementStat = {{TString("Write"), 0}};
  1118. VerifyProgram(res, elementStat, verifyLine);
  1119. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1120. }
  1121. Y_UNIT_TEST(DeleteFromTable) {
  1122. NYql::TAstParseResult res = SqlToYql("delete from plato.Input;", 10, "kikimr");
  1123. UNIT_ASSERT(res.Root);
  1124. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1125. if (word == "Write") {
  1126. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete)"));
  1127. }
  1128. };
  1129. TWordCountHive elementStat = {{TString("Write"), 0}};
  1130. VerifyProgram(res, elementStat, verifyLine);
  1131. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1132. }
  1133. Y_UNIT_TEST(DeleteFromTableBatch) {
  1134. NYql::TAstParseResult res = SqlToYql("batch delete from plato.Input;", 10, "kikimr");
  1135. UNIT_ASSERT(res.Root);
  1136. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1137. if (word == "Write") {
  1138. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete)"));
  1139. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('is_batch 'true)"));
  1140. }
  1141. };
  1142. TWordCountHive elementStat = {{TString("Write"), 0}};
  1143. VerifyProgram(res, elementStat, verifyLine);
  1144. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1145. }
  1146. Y_UNIT_TEST(DeleteFromTableOnValues) {
  1147. NYql::TAstParseResult res = SqlToYql("delete from plato.Input on (key) values (1);",
  1148. 10, "kikimr");
  1149. UNIT_ASSERT(res.Root);
  1150. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1151. if (word == "Write") {
  1152. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete_on)"));
  1153. }
  1154. };
  1155. TWordCountHive elementStat = {{TString("Write"), 0}};
  1156. VerifyProgram(res, elementStat, verifyLine);
  1157. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1158. }
  1159. Y_UNIT_TEST(DeleteFromTableOnSelect) {
  1160. NYql::TAstParseResult res = SqlToYql(
  1161. "delete from plato.Input on select key from plato.Input where value > 0;", 10, "kikimr");
  1162. UNIT_ASSERT(res.Root);
  1163. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1164. if (word == "Write") {
  1165. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'delete_on)"));
  1166. }
  1167. };
  1168. TWordCountHive elementStat = {{TString("Write"), 0}};
  1169. VerifyProgram(res, elementStat, verifyLine);
  1170. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1171. }
  1172. Y_UNIT_TEST(DeleteFromTableOnBatch) {
  1173. NYql::TAstParseResult res = SqlToYql("batch delete from plato.Input on (key) values (1);",
  1174. 10, "kikimr");
  1175. UNIT_ASSERT(!res.Root);
  1176. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:6: Error: BATCH DELETE is unsupported with ON\n");
  1177. }
  1178. Y_UNIT_TEST(UpdateByValues) {
  1179. NYql::TAstParseResult res = SqlToYql("update plato.Input set key = 777, value = 'cool' where key = 200;", 10, "kikimr");
  1180. UNIT_ASSERT(res.Root);
  1181. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1182. if (word == "Write") {
  1183. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update)"));
  1184. } else if (word == "AsStruct") {
  1185. const bool isKey = line.find("key") != TString::npos;
  1186. const bool isValue = line.find("value") != TString::npos;
  1187. UNIT_ASSERT(isKey || isValue);
  1188. if (isKey) {
  1189. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("777")));
  1190. } else if (isValue) {
  1191. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("cool")));
  1192. }
  1193. }
  1194. };
  1195. TWordCountHive elementStat = {{TString("Write"), 0}, {TString("AsStruct"), 0}};
  1196. VerifyProgram(res, elementStat, verifyLine);
  1197. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1198. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["AsStruct"]);
  1199. }
  1200. Y_UNIT_TEST(UpdateByValuesBatch) {
  1201. NYql::TAstParseResult res = SqlToYql("batch update plato.Input set key = 777, value = 'cool' where key = 200;", 10, "kikimr");
  1202. UNIT_ASSERT(res.Root);
  1203. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1204. if (word == "Write") {
  1205. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update)"));
  1206. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('is_batch 'true)"));
  1207. }
  1208. };
  1209. TWordCountHive elementStat = {{TString("Write"), 0}};
  1210. VerifyProgram(res, elementStat, verifyLine);
  1211. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1212. }
  1213. Y_UNIT_TEST(UpdateByMultiValues) {
  1214. NYql::TAstParseResult res = SqlToYql("update plato.Input set (key, value, subkey) = ('2','ddd',':') where key = 200;", 10, "kikimr");
  1215. UNIT_ASSERT(res.Root);
  1216. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1217. if (word == "Write") {
  1218. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update)"));
  1219. } else if (word == "AsStruct") {
  1220. const bool isKey = line.find("key") != TString::npos;
  1221. const bool isSubkey = line.find("subkey") != TString::npos;
  1222. const bool isValue = line.find("value") != TString::npos;
  1223. UNIT_ASSERT(isKey || isSubkey || isValue);
  1224. if (isKey && !isSubkey) {
  1225. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("2")));
  1226. } else if (isSubkey) {
  1227. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote(":")));
  1228. } else if (isValue) {
  1229. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("ddd")));
  1230. }
  1231. }
  1232. };
  1233. TWordCountHive elementStat = {{TString("Write"), 0}, {TString("AsStruct"), 0}};
  1234. VerifyProgram(res, elementStat, verifyLine);
  1235. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1236. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["AsStruct"]);
  1237. }
  1238. Y_UNIT_TEST(UpdateBySelect) {
  1239. NYql::TAstParseResult res = SqlToYql("update plato.Input set (key, value, subkey) = (select key, value, subkey from plato.Input where key = 911) where key = 200;", 10, "kikimr");
  1240. UNIT_ASSERT(res.Root);
  1241. int lineIndex = 0;
  1242. int writeLineIndex = -1;
  1243. bool found = false;
  1244. TVerifyLineFunc verifyLine = [&lineIndex, &writeLineIndex, &found](const TString& word, const TString& line) {
  1245. if (word == "Write") {
  1246. writeLineIndex = lineIndex;
  1247. found = line.find("('mode 'update)") != TString::npos;
  1248. } else if (word == "mode") {
  1249. found |= lineIndex == writeLineIndex + 1 && line.find("('mode 'update)") != TString::npos;
  1250. UNIT_ASSERT(found);
  1251. }
  1252. ++lineIndex;
  1253. };
  1254. TWordCountHive elementStat = {{TString("Write"), 0}, {TString("mode"), 0}};
  1255. VerifyProgram(res, elementStat, verifyLine);
  1256. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1257. }
  1258. Y_UNIT_TEST(UpdateSelfModifyAll) {
  1259. NYql::TAstParseResult res = SqlToYql("update plato.Input set subkey = subkey + 's';", 10, "kikimr");
  1260. UNIT_ASSERT(res.Root);
  1261. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1262. if (word == "Write") {
  1263. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update)"));
  1264. } else if (word == "AsStruct") {
  1265. const bool isSubkey = line.find("subkey") != TString::npos;
  1266. UNIT_ASSERT(isSubkey);
  1267. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("subkey")));
  1268. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(Quote("s")));
  1269. }
  1270. };
  1271. TWordCountHive elementStat = {{TString("Write"), 0}, {TString("AsStruct"), 0}};
  1272. VerifyProgram(res, elementStat, verifyLine);
  1273. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1274. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["AsStruct"]);
  1275. }
  1276. Y_UNIT_TEST(UpdateOnValues) {
  1277. NYql::TAstParseResult res = SqlToYql("update plato.Input on (key, value) values (5, 'cool')", 10, "kikimr");
  1278. UNIT_ASSERT(res.Root);
  1279. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1280. if (word == "Write") {
  1281. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update_on)"));
  1282. }
  1283. };
  1284. TWordCountHive elementStat = {{TString("Write"), 0}};
  1285. VerifyProgram(res, elementStat, verifyLine);
  1286. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1287. }
  1288. Y_UNIT_TEST(UpdateOnSelect) {
  1289. NYql::TAstParseResult res = SqlToYql(
  1290. "update plato.Input on select key, value + 1 as value from plato.Input", 10, "kikimr");
  1291. UNIT_ASSERT(res.Root);
  1292. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1293. if (word == "Write") {
  1294. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("('mode 'update_on)"));
  1295. }
  1296. };
  1297. TWordCountHive elementStat = {{TString("Write"), 0}};
  1298. VerifyProgram(res, elementStat, verifyLine);
  1299. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1300. }
  1301. Y_UNIT_TEST(UpdateOnBatch) {
  1302. NYql::TAstParseResult res = SqlToYql("batch update plato.Input on (key, value) values (5, 'cool')", 10, "kikimr");
  1303. UNIT_ASSERT(!res.Root);
  1304. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:6: Error: BATCH UPDATE is unsupported with ON\n");
  1305. }
  1306. Y_UNIT_TEST(UnionAllTest) {
  1307. NYql::TAstParseResult res = SqlToYql("PRAGMA DisableEmitUnionMerge; SELECT key FROM plato.Input UNION ALL select subkey FROM plato.Input;");
  1308. UNIT_ASSERT(res.Root);
  1309. TWordCountHive elementStat = {{TString("UnionAll"), 0}};
  1310. VerifyProgram(res, elementStat, {});
  1311. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["UnionAll"]);
  1312. }
  1313. Y_UNIT_TEST(UnionAllMergeTest) {
  1314. NYql::TAstParseResult res = SqlToYql("PRAGMA EmitUnionMerge; SELECT key FROM plato.Input UNION ALL select subkey FROM plato.Input;");
  1315. UNIT_ASSERT(res.Root);
  1316. TWordCountHive elementStat = {{TString("UnionMerge"), 0}};
  1317. VerifyProgram(res, elementStat, {});
  1318. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["UnionMerge"]);
  1319. }
  1320. Y_UNIT_TEST(UnionTest) {
  1321. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input UNION select subkey FROM plato.Input;");
  1322. UNIT_ASSERT(res.Root);
  1323. TWordCountHive elementStat = {{TString("Union"), 0}};
  1324. VerifyProgram(res, elementStat, {});
  1325. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Union"]);
  1326. }
  1327. Y_UNIT_TEST(UnionAggregationTest) {
  1328. NYql::TAstParseResult res = SqlToYql(R"(
  1329. PRAGMA DisableEmitUnionMerge;
  1330. SELECT 1
  1331. UNION ALL
  1332. SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
  1333. UNION
  1334. SELECT 1 UNION SELECT 1 UNION SELECT 1 UNION SELECT 1
  1335. UNION ALL
  1336. SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1;
  1337. )");
  1338. UNIT_ASSERT(res.Root);
  1339. TWordCountHive elementStat = {{TString("Union"), 0}, {TString("UnionAll"), 0}};
  1340. VerifyProgram(res, elementStat, {});
  1341. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["UnionAll"]);
  1342. UNIT_ASSERT_VALUES_EQUAL(3, elementStat["Union"]);
  1343. }
  1344. Y_UNIT_TEST(UnionMergeAggregationTest) {
  1345. NYql::TAstParseResult res = SqlToYql(R"(
  1346. PRAGMA EmitUnionMerge;
  1347. SELECT 1
  1348. UNION ALL
  1349. SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
  1350. UNION
  1351. SELECT 1 UNION SELECT 1 UNION SELECT 1 UNION SELECT 1
  1352. UNION ALL
  1353. SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1;
  1354. )");
  1355. UNIT_ASSERT(res.Root);
  1356. TWordCountHive elementStat = {{TString("Union"), 0}, {TString("UnionMerge"), 0}};
  1357. VerifyProgram(res, elementStat, {});
  1358. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["UnionMerge"]);
  1359. UNIT_ASSERT_VALUES_EQUAL(3, elementStat["Union"]);
  1360. }
  1361. Y_UNIT_TEST(DeclareDecimalParameter) {
  1362. NYql::TAstParseResult res = SqlToYql("declare $value as Decimal(22,9); select $value as cnt;");
  1363. UNIT_ASSERT(res.Root);
  1364. }
  1365. Y_UNIT_TEST(SimpleGroupBy) {
  1366. NYql::TAstParseResult res = SqlToYql("select count(1),z from plato.Input group by key as z order by z;");
  1367. UNIT_ASSERT(res.Root);
  1368. }
  1369. Y_UNIT_TEST(EmptyColumnName0) {
  1370. /// Now it's parsed well and error occur on validate step like "4:31:Empty struct member name is not allowed" in "4:31:Function: AddMember"
  1371. NYql::TAstParseResult res = SqlToYql("insert into plato.Output (``, list1) values (0, AsList(0, 1, 2));");
  1372. /// Verify that parsed well without crash
  1373. UNIT_ASSERT(res.Root);
  1374. }
  1375. Y_UNIT_TEST(KikimrRollback) {
  1376. NYql::TAstParseResult res = SqlToYql("use plato; select * from Input; rollback;", 10, "kikimr");
  1377. UNIT_ASSERT(res.Root);
  1378. TWordCountHive elementStat = {{TString("rollback"), 0}};
  1379. VerifyProgram(res, elementStat);
  1380. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["rollback"]);
  1381. }
  1382. Y_UNIT_TEST(PragmaFile) {
  1383. NYql::TAstParseResult res = SqlToYql(R"(pragma file("HW", "sbr:181041334");)");
  1384. UNIT_ASSERT(res.Root);
  1385. TWordCountHive elementStat = {{TString(R"((let world (Configure! world (DataSource '"config") '"AddFileByUrl" '"HW" '"sbr:181041334")))"), 0}};
  1386. VerifyProgram(res, elementStat);
  1387. UNIT_ASSERT_VALUES_EQUAL(1, elementStat.cbegin()->second);
  1388. }
  1389. Y_UNIT_TEST(DoNotCrashOnNamedInFilter) {
  1390. NYql::TAstParseResult res = SqlToYql("USE plato; $all = ($table_name) -> { return true; }; SELECT * FROM FILTER(Input, $all)");
  1391. UNIT_ASSERT(res.Root);
  1392. }
  1393. Y_UNIT_TEST(PragmasFileAndUdfOrder) {
  1394. NYql::TAstParseResult res = SqlToYql(R"(
  1395. PRAGMA file("libvideoplayers_udf.so", "https://proxy.sandbox.yandex-team.ru/235185290");
  1396. PRAGMA udf("libvideoplayers_udf.so");
  1397. )");
  1398. UNIT_ASSERT(res.Root);
  1399. const auto programm = GetPrettyPrint(res);
  1400. const auto file = programm.find("AddFileByUrl");
  1401. const auto udfs = programm.find("ImportUdfs");
  1402. UNIT_ASSERT(file < udfs);
  1403. }
  1404. Y_UNIT_TEST(ProcessUserType) {
  1405. NYql::TAstParseResult res = SqlToYql("process plato.Input using Kikimr::PushData(TableRows());", 1, TString(NYql::KikimrProviderName));
  1406. UNIT_ASSERT(res.Root);
  1407. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1408. if (word == "Kikimr.PushData") {
  1409. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("TupleType"));
  1410. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("TypeOf"));
  1411. }
  1412. };
  1413. TWordCountHive elementStat = {{TString("Kikimr.PushData"), 0}};
  1414. VerifyProgram(res, elementStat, verifyLine);
  1415. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Kikimr.PushData"]);
  1416. }
  1417. Y_UNIT_TEST(ProcessUserTypeAuth) {
  1418. NYql::TAstParseResult res = SqlToYql("process plato.Input using YDB::PushData(TableRows(), AsTuple('oauth', SecureParam('api:oauth')));", 1, TString(NYql::KikimrProviderName));
  1419. UNIT_ASSERT(res.Root);
  1420. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1421. if (word == "YDB.PushData") {
  1422. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("TupleType"));
  1423. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("TypeOf"));
  1424. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("api:oauth"));
  1425. }
  1426. };
  1427. TWordCountHive elementStat = {{TString("YDB.PushData"), 0}};
  1428. VerifyProgram(res, elementStat, verifyLine);
  1429. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["YDB.PushData"]);
  1430. }
  1431. Y_UNIT_TEST(SelectStreamRtmr) {
  1432. NYql::TAstParseResult res = SqlToYql(
  1433. "USE plato; INSERT INTO Output SELECT STREAM key FROM Input;",
  1434. 10, TString(NYql::RtmrProviderName));
  1435. UNIT_ASSERT(res.Root);
  1436. res = SqlToYql(
  1437. "USE plato; INSERT INTO Output SELECT key FROM Input;",
  1438. 10, TString(NYql::RtmrProviderName));
  1439. UNIT_ASSERT(res.Root);
  1440. }
  1441. Y_UNIT_TEST(SelectStreamRtmrJoinWithYt) {
  1442. NYql::TAstParseResult res = SqlToYql(
  1443. "USE plato; INSERT INTO Output SELECT STREAM key FROM Input LEFT JOIN hahn.ttt as t ON Input.key = t.Name;",
  1444. 10, TString(NYql::RtmrProviderName));
  1445. UNIT_ASSERT(res.Root);
  1446. }
  1447. Y_UNIT_TEST(SelectStreamNonRtmr) {
  1448. NYql::TAstParseResult res = SqlToYql(
  1449. "USE plato; INSERT INTO Output SELECT STREAM key FROM Input;",
  1450. 10);
  1451. UNIT_ASSERT(!res.Root);
  1452. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:31: Error: SELECT STREAM is unsupported for non-streaming sources\n");
  1453. }
  1454. Y_UNIT_TEST(GroupByHopRtmr) {
  1455. NYql::TAstParseResult res = SqlToYql(R"(
  1456. USE plato; INSERT INTO Output SELECT key, SUM(value) AS value FROM Input
  1457. GROUP BY key, HOP(subkey, "PT10S", "PT30S", "PT20S");
  1458. )", 10, TString(NYql::RtmrProviderName));
  1459. UNIT_ASSERT(res.Root);
  1460. }
  1461. Y_UNIT_TEST(GroupByHopRtmrSubquery) {
  1462. // 'use plato' intentially avoided
  1463. NYql::TAstParseResult res = SqlToYql(R"(
  1464. SELECT COUNT(*) AS value FROM (SELECT * FROM plato.Input)
  1465. GROUP BY HOP(Data, "PT10S", "PT30S", "PT20S")
  1466. )", 10, TString(NYql::RtmrProviderName));
  1467. UNIT_ASSERT(res.Root);
  1468. }
  1469. Y_UNIT_TEST(GroupByHopRtmrSubqueryBinding) {
  1470. NYql::TAstParseResult res = SqlToYql(R"(
  1471. USE plato;
  1472. $q = SELECT * FROM Input;
  1473. INSERT INTO Output SELECT STREAM * FROM (
  1474. SELECT COUNT(*) AS value FROM $q
  1475. GROUP BY HOP(Data, "PT10S", "PT30S", "PT20S")
  1476. );
  1477. )", 10, TString(NYql::RtmrProviderName));
  1478. UNIT_ASSERT(res.Root);
  1479. }
  1480. Y_UNIT_TEST(GroupByNoHopRtmr) {
  1481. NYql::TAstParseResult res = SqlToYql(R"(
  1482. USE plato; INSERT INTO Output SELECT STREAM key, SUM(value) AS value FROM Input
  1483. GROUP BY key;
  1484. )", 10, TString(NYql::RtmrProviderName));
  1485. UNIT_ASSERT(!res.Root);
  1486. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:22: Error: Streaming group by query must have a hopping window specification.\n");
  1487. }
  1488. Y_UNIT_TEST(KikimrInserts) {
  1489. NYql::TAstParseResult res = SqlToYql(R"(
  1490. USE plato;
  1491. INSERT INTO Output SELECT key, value FROM Input;
  1492. INSERT OR ABORT INTO Output SELECT key, value FROM Input;
  1493. INSERT OR IGNORE INTO Output SELECT key, value FROM Input;
  1494. INSERT OR REVERT INTO Output SELECT key, value FROM Input;
  1495. )", 10, TString(NYql::KikimrProviderName));
  1496. UNIT_ASSERT(res.Root);
  1497. }
  1498. Y_UNIT_TEST(WarnMissingIsBeforeNotNull) {
  1499. NYql::TAstParseResult res = SqlToYql("select 1 NOT NULL");
  1500. UNIT_ASSERT(res.Root);
  1501. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Warning: Missing IS keyword before NOT NULL, code: 4507\n");
  1502. }
  1503. Y_UNIT_TEST(Subqueries) {
  1504. NYql::TAstParseResult res = SqlToYql(R"(
  1505. USE plato;
  1506. $sq1 = (SELECT * FROM plato.Input);
  1507. $sq2 = SELECT * FROM plato.Input;
  1508. $squ1 = (
  1509. SELECT * FROM plato.Input
  1510. UNION ALL
  1511. SELECT * FROM plato.Input
  1512. );
  1513. $squ2 =
  1514. SELECT * FROM plato.Input
  1515. UNION ALL
  1516. SELECT * FROM plato.Input;
  1517. $squ3 = (
  1518. (SELECT * FROM plato.Input)
  1519. UNION ALL
  1520. (SELECT * FROM plato.Input)
  1521. );
  1522. SELECT * FROM $sq1;
  1523. SELECT * FROM $sq2;
  1524. SELECT * FROM $squ1;
  1525. SELECT * FROM $squ2;
  1526. SELECT * FROM $squ3;
  1527. )");
  1528. UNIT_ASSERT(res.Root);
  1529. }
  1530. Y_UNIT_TEST(SubqueriesJoin) {
  1531. NYql::TAstParseResult res = SqlToYql(R"(
  1532. USE plato;
  1533. $left = SELECT * FROM plato.Input1 WHERE value != "BadValue";
  1534. $right = SELECT * FROM plato.Input2;
  1535. SELECT * FROM $left AS l
  1536. JOIN $right AS r
  1537. ON l.key == r.key;
  1538. )");
  1539. UNIT_ASSERT(res.Root);
  1540. }
  1541. Y_UNIT_TEST(AnyInBackticksAsTableName) {
  1542. NYql::TAstParseResult res = SqlToYql("use plato; select * from `any`;");
  1543. UNIT_ASSERT(res.Root);
  1544. }
  1545. Y_UNIT_TEST(AnyJoinForTableAndSubQuery) {
  1546. NYql::TAstParseResult res = SqlToYql(R"(
  1547. USE plato;
  1548. $r = SELECT * FROM plato.Input2;
  1549. SELECT * FROM ANY plato.Input1 AS l
  1550. LEFT JOIN ANY $r AS r
  1551. USING (key);
  1552. )");
  1553. UNIT_ASSERT(res.Root);
  1554. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1555. if (word == "EquiJoin") {
  1556. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('left 'any)"));
  1557. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('right 'any)"));
  1558. }
  1559. };
  1560. TWordCountHive elementStat = {{TString("left"), 0}, {TString("right"), 0}};
  1561. VerifyProgram(res, elementStat, verifyLine);
  1562. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["left"]);
  1563. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["right"]);
  1564. }
  1565. Y_UNIT_TEST(AnyJoinForTableAndTableSource) {
  1566. NYql::TAstParseResult res = SqlToYql(R"(
  1567. USE plato;
  1568. $r = AsList(
  1569. AsStruct("aaa" as key, "bbb" as subkey, "ccc" as value)
  1570. );
  1571. SELECT * FROM ANY plato.Input1 AS l
  1572. LEFT JOIN ANY AS_TABLE($r) AS r
  1573. USING (key);
  1574. )");
  1575. UNIT_ASSERT(res.Root);
  1576. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1577. if (word == "EquiJoin") {
  1578. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('left 'any)"));
  1579. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('right 'any)"));
  1580. }
  1581. };
  1582. TWordCountHive elementStat = {{TString("left"), 0}, {TString("right"), 0}};
  1583. VerifyProgram(res, elementStat, verifyLine);
  1584. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["left"]);
  1585. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["right"]);
  1586. }
  1587. Y_UNIT_TEST(AnyJoinNested) {
  1588. NYql::TAstParseResult res = SqlToYql(R"(
  1589. USE plato;
  1590. FROM ANY Input1 as a
  1591. JOIN Input2 as b ON a.key = b.key
  1592. LEFT JOIN ANY Input3 as c ON a.key = c.key
  1593. RIGHT JOIN ANY Input4 as d ON d.key = b.key
  1594. CROSS JOIN Input5
  1595. SELECT *;
  1596. )");
  1597. UNIT_ASSERT(res.Root);
  1598. TWordCountHive elementStat = {{TString("left"), 0}, {TString("right"), 0}};
  1599. VerifyProgram(res, elementStat);
  1600. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["left"]);
  1601. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["right"]);
  1602. }
  1603. Y_UNIT_TEST(InlineAction) {
  1604. NYql::TAstParseResult res = SqlToYql(
  1605. "do begin\n"
  1606. " select 1\n"
  1607. "; end do\n");
  1608. UNIT_ASSERT(res.Root);
  1609. UNIT_ASSERT_NO_DIFF(Err2Str(res), "");
  1610. }
  1611. Y_UNIT_TEST(FlattenByCorrelationName) {
  1612. UNIT_ASSERT(SqlToYql("select * from plato.Input as t flatten by t.x").IsOk());
  1613. UNIT_ASSERT(SqlToYql("select * from plato.Input as t flatten by t -- same as flatten by t.t").IsOk());
  1614. }
  1615. Y_UNIT_TEST(DiscoveryMode) {
  1616. UNIT_ASSERT(SqlToYqlWithMode("insert into plato.Output select * from plato.Input", NSQLTranslation::ESqlMode::DISCOVERY).IsOk());
  1617. UNIT_ASSERT(SqlToYqlWithMode("select * from plato.concat(Input1, Input2)", NSQLTranslation::ESqlMode::DISCOVERY).IsOk());
  1618. UNIT_ASSERT(SqlToYqlWithMode("select * from plato.each(AsList(\"Input1\", \"Input2\"))", NSQLTranslation::ESqlMode::DISCOVERY).IsOk());
  1619. }
  1620. Y_UNIT_TEST(CubeWithAutoGeneratedLikeColumnName) {
  1621. UNIT_ASSERT(SqlToYql("select key,subkey,group from plato.Input group by cube(key,subkey,group)").IsOk());
  1622. }
  1623. Y_UNIT_TEST(CubeWithAutoGeneratedLikeAlias) {
  1624. UNIT_ASSERT(SqlToYql("select key,subkey,group from plato.Input group by cube(key,subkey,value as group)").IsOk());
  1625. }
  1626. Y_UNIT_TEST(FilterCanBeUsedAsColumnIdOrBind) {
  1627. UNIT_ASSERT(SqlToYql("select filter from plato.Input").IsOk());
  1628. UNIT_ASSERT(SqlToYql("select 1 as filter").IsOk());
  1629. UNIT_ASSERT(SqlToYql("$filter = 1; select $filter").IsOk());
  1630. }
  1631. Y_UNIT_TEST(DuplicateSemicolonsAreAllowedBetweenTopLevelStatements) {
  1632. UNIT_ASSERT(SqlToYql(";;select 1; ; select 2;/*comment*/;select 3;;--comment\n;select 4;;").IsOk());
  1633. }
  1634. Y_UNIT_TEST(DuplicateAndMissingTrailingSemicolonsAreAllowedBetweenActionStatements) {
  1635. TString req =
  1636. "define action $action($b,$c) as\n"
  1637. " ;;$d = $b + $c;\n"
  1638. " select $b;\n"
  1639. " select $c;;\n"
  1640. " select $d,\n"
  1641. "end define;\n"
  1642. "\n"
  1643. "do $action(1,2);";
  1644. UNIT_ASSERT(SqlToYql(req).IsOk());
  1645. }
  1646. Y_UNIT_TEST(DuplicateAndMissingTrailingSemicolonsAreAllowedBetweenInlineActionStatements) {
  1647. TString req =
  1648. "do begin\n"
  1649. " ;select 1,\n"
  1650. "end do;\n"
  1651. "evaluate for $i in AsList(1,2,3) do begin\n"
  1652. " select $i;;\n"
  1653. " select $i + $i;;\n"
  1654. "end do;";
  1655. UNIT_ASSERT(SqlToYql(req).IsOk());
  1656. }
  1657. Y_UNIT_TEST(DuplicateSemicolonsAreAllowedBetweenLambdaStatements) {
  1658. TString req =
  1659. "$x=1;\n"
  1660. "$foo = ($a, $b)->{\n"
  1661. " ;;$v = $a + $b;\n"
  1662. " $bar = ($c) -> {; return $c << $x};;\n"
  1663. " return $bar($v);;\n"
  1664. "};\n"
  1665. "select $foo(1,2);";
  1666. UNIT_ASSERT(SqlToYql(req).IsOk());
  1667. }
  1668. Y_UNIT_TEST(StringLiteralWithEscapedBackslash) {
  1669. NYql::TAstParseResult res1 = SqlToYql(R"foo(SELECT 'a\\';)foo");
  1670. NYql::TAstParseResult res2 = SqlToYql(R"foo(SELECT "a\\";)foo");
  1671. UNIT_ASSERT(res1.Root);
  1672. UNIT_ASSERT(res2.Root);
  1673. TWordCountHive elementStat = {{TString("a\\"), 0}};
  1674. VerifyProgram(res1, elementStat);
  1675. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["a\\"]);
  1676. VerifyProgram(res2, elementStat);
  1677. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["a\\"]);
  1678. }
  1679. Y_UNIT_TEST(StringMultiLineLiteralWithEscapes) {
  1680. UNIT_ASSERT(SqlToYql("SELECT @@@foo@@@@bar@@@").IsOk());
  1681. UNIT_ASSERT(SqlToYql("SELECT @@@@@@@@@").IsOk());
  1682. }
  1683. Y_UNIT_TEST(StringMultiLineLiteralConsequitiveAt) {
  1684. UNIT_ASSERT(!SqlToYql("SELECT @").IsOk());
  1685. UNIT_ASSERT(!SqlToYql("SELECT @@").IsOk());
  1686. UNIT_ASSERT(!SqlToYql("SELECT @@@").IsOk());
  1687. UNIT_ASSERT( SqlToYql("SELECT @@@@").IsOk());
  1688. UNIT_ASSERT( SqlToYql("SELECT @@@@@").IsOk());
  1689. UNIT_ASSERT(!SqlToYql("SELECT @@@@@@").IsOk());
  1690. UNIT_ASSERT(!SqlToYql("SELECT @@@@@@@").IsOk());
  1691. UNIT_ASSERT( SqlToYql("SELECT @@@@@@@@").IsOk());
  1692. UNIT_ASSERT( SqlToYql("SELECT @@@@@@@@@").IsOk());
  1693. UNIT_ASSERT(!SqlToYql("SELECT @@@@@@@@@@").IsOk());
  1694. }
  1695. Y_UNIT_TEST(ConstnessForListDictSetCreate) {
  1696. auto req = "$foo = ($x, $y) -> (\"aaaa\");\n"
  1697. "\n"
  1698. "select\n"
  1699. " $foo(sum(key), ListCreate(String)),\n"
  1700. " $foo(sum(key), DictCreate(String, String)),\n"
  1701. " $foo(sum(key), SetCreate(String)),\n"
  1702. "from (select 1 as key);";
  1703. UNIT_ASSERT(SqlToYql(req).IsOk());
  1704. }
  1705. Y_UNIT_TEST(CanUseEmptyTupleInWindowPartitionBy) {
  1706. auto req = "select sum(key) over w\n"
  1707. "from plato.Input\n"
  1708. "window w as (partition compact by (), (subkey), (), value || value as dvalue);";
  1709. UNIT_ASSERT(SqlToYql(req).IsOk());
  1710. }
  1711. Y_UNIT_TEST(DenyAnsiOrderByLimitLegacyMode) {
  1712. auto req = "pragma DisableAnsiOrderByLimitInUnionAll;\n"
  1713. "use plato;\n"
  1714. "\n"
  1715. "select * from Input order by key limit 10\n"
  1716. "union all\n"
  1717. "select * from Input order by key limit 1;";
  1718. auto res = SqlToYql(req);
  1719. UNIT_ASSERT(!res.Root);
  1720. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: DisableAnsiOrderByLimitInUnionAll pragma is deprecated and no longer supported\n");
  1721. }
  1722. Y_UNIT_TEST(ReduceUsingUdfWithShortcutsWorks) {
  1723. auto req = "use plato;\n"
  1724. "\n"
  1725. "$arg = 'foo';\n"
  1726. "$func = XXX::YYY($arg);\n"
  1727. "\n"
  1728. "REDUCE Input ON key using $func(subkey);\n"
  1729. "REDUCE Input ON key using $func(UUU::VVV(TableRow()));\n";
  1730. UNIT_ASSERT(SqlToYql(req).IsOk());
  1731. req = "use plato;\n"
  1732. "\n"
  1733. "$arg = 'foo';\n"
  1734. "$func = XXX::YYY($arg);\n"
  1735. "\n"
  1736. "REDUCE Input ON key using all $func(subkey);\n"
  1737. "REDUCE Input ON key using all $func(UUU::VVV(TableRow()));";
  1738. UNIT_ASSERT(SqlToYql(req).IsOk());
  1739. }
  1740. Y_UNIT_TEST(YsonDisableStrict) {
  1741. UNIT_ASSERT(SqlToYql("pragma yson.DisableStrict = \"false\";").IsOk());
  1742. UNIT_ASSERT(SqlToYql("pragma yson.DisableStrict;").IsOk());
  1743. }
  1744. Y_UNIT_TEST(YsonStrict) {
  1745. UNIT_ASSERT(SqlToYql("pragma yson.Strict = \"false\";").IsOk());
  1746. UNIT_ASSERT(SqlToYql("pragma yson.Strict;").IsOk());
  1747. }
  1748. Y_UNIT_TEST(JoinByTuple) {
  1749. auto req = "use plato;\n"
  1750. "\n"
  1751. "select * from T1 as a\n"
  1752. "join T2 as b\n"
  1753. "on AsTuple(a.key, a.subkey) = AsTuple(b.key, b.subkey);";
  1754. UNIT_ASSERT(SqlToYql(req).IsOk());
  1755. }
  1756. Y_UNIT_TEST(JoinByStruct) {
  1757. auto req = "use plato;\n"
  1758. "\n"
  1759. "select * from T1 as a\n"
  1760. "join T2 as b\n"
  1761. "on AsStruct(a.key as k, a.subkey as sk) = AsStruct(b.key as k, b.subkey as sk);";
  1762. UNIT_ASSERT(SqlToYql(req).IsOk());
  1763. }
  1764. Y_UNIT_TEST(JoinByUdf) {
  1765. auto req = "use plato;\n"
  1766. "\n"
  1767. "select a.align\n"
  1768. "from T1 as a\n"
  1769. "join T2 as b\n"
  1770. "on Yson::SerializeJsonEncodeUtf8(a.align)=b.align;";
  1771. UNIT_ASSERT(SqlToYql(req).IsOk());
  1772. }
  1773. Y_UNIT_TEST(EscapedIdentifierAsLambdaArg) {
  1774. auto req = "$f = ($`foo bar`, $x) -> { return $`foo bar` + $x; };\n"
  1775. "\n"
  1776. "select $f(1, 2);";
  1777. auto res = SqlToYql(req);
  1778. UNIT_ASSERT(res.Root);
  1779. const auto programm = GetPrettyPrint(res);
  1780. auto expected = "(lambda '(\"$foo bar\" \"$x\")";
  1781. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1782. }
  1783. Y_UNIT_TEST(UdfSyntaxSugarOnlyCallable) {
  1784. auto req = "SELECT Udf(DateTime::FromString)('2022-01-01');";
  1785. auto res = SqlToYql(req);
  1786. UNIT_ASSERT(res.Root);
  1787. const auto programm = GetPrettyPrint(res);
  1788. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType)))";
  1789. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1790. }
  1791. Y_UNIT_TEST(UdfSyntaxSugarTypeNoRun) {
  1792. auto req = "SELECT Udf(DateTime::FromString, String, Tuple<Int32, Float>, 'foo' as TypeConfig)('2022-01-01');";
  1793. auto res = SqlToYql(req);
  1794. UNIT_ASSERT(res.Root);
  1795. const auto programm = GetPrettyPrint(res);
  1796. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType (DataType 'String) (TupleType (DataType 'Int32) (DataType 'Float)))) '\"foo\")";
  1797. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1798. }
  1799. Y_UNIT_TEST(UdfSyntaxSugarRunNoType) {
  1800. auto req = "SELECT Udf(DateTime::FromString, String, Tuple<Int32, Float>, Void() as RunConfig)('2022-01-01');";
  1801. auto res = SqlToYql(req);
  1802. UNIT_ASSERT(res.Root);
  1803. const auto programm = GetPrettyPrint(res);
  1804. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType (DataType 'String) (TupleType (DataType 'Int32) (DataType 'Float)))) '\"\" (Void))";
  1805. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1806. }
  1807. Y_UNIT_TEST(UdfSyntaxSugarFullTest) {
  1808. auto req = "SELECT Udf(DateTime::FromString, String, Tuple<Int32, Float>, 'foo' as TypeConfig, Void() As RunConfig)('2022-01-01');";
  1809. auto res = SqlToYql(req);
  1810. UNIT_ASSERT(res.Root);
  1811. const auto programm = GetPrettyPrint(res);
  1812. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType (DataType 'String) (TupleType (DataType 'Int32) (DataType 'Float)))) '\"foo\" (Void))";
  1813. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1814. }
  1815. Y_UNIT_TEST(UdfSyntaxSugarOtherRunConfigs) {
  1816. auto req = "SELECT Udf(DateTime::FromString, String, Tuple<Int32, Float>, 'foo' as TypeConfig, '55' As RunConfig)('2022-01-01');";
  1817. auto res = SqlToYql(req);
  1818. UNIT_ASSERT(res.Root);
  1819. const auto programm = GetPrettyPrint(res);
  1820. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType (DataType 'String) (TupleType (DataType 'Int32) (DataType 'Float)))) '\"foo\" (String '\"55\"))";
  1821. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1822. }
  1823. Y_UNIT_TEST(UdfSyntaxSugarOtherRunConfigs2) {
  1824. auto req = "SELECT Udf(DateTime::FromString, String, Tuple<Int32, Float>, 'foo' as TypeConfig, AsTuple(32, 'no', AsStruct(1e-9 As SomeFloat)) As RunConfig)('2022-01-01');";
  1825. auto res = SqlToYql(req);
  1826. UNIT_ASSERT(res.Root);
  1827. const auto programm = GetPrettyPrint(res);
  1828. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType (DataType 'String) (TupleType (DataType 'Int32) (DataType 'Float)))) '\"foo\" '((Int32 '\"32\") (String '\"no\") (AsStruct '('\"SomeFloat\" (Double '\"1e-9\")))))";
  1829. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1830. }
  1831. Y_UNIT_TEST(UdfSyntaxSugarOptional) {
  1832. auto req = "SELECT Udf(DateTime::FromString, String?, Int32??, Tuple<Int32, Float>, \"foo\" as TypeConfig, Void() As RunConfig)(\"2022-01-01\");";
  1833. auto res = SqlToYql(req);
  1834. UNIT_ASSERT(res.Root);
  1835. const auto programm = GetPrettyPrint(res);
  1836. auto expected = "(SqlCall '\"DateTime.FromString\" '((PositionalArgs (String '\"2022-01-01\")) (AsStruct)) (TupleType (TypeOf '((String '\"2022-01-01\"))) (TypeOf (AsStruct)) (TupleType (OptionalType (DataType 'String)) (OptionalType (OptionalType (DataType 'Int32))) (TupleType (DataType 'Int32) (DataType 'Float)))) '\"foo\" (Void))";
  1837. UNIT_ASSERT(programm.find(expected) != TString::npos);
  1838. }
  1839. Y_UNIT_TEST(CompactionPolicyParseCorrect) {
  1840. NYql::TAstParseResult res = SqlToYql(
  1841. R"( USE plato;
  1842. CREATE TABLE tableName (Key Uint32, Value String, PRIMARY KEY (Key))
  1843. WITH ( COMPACTION_POLICY = "SomeCompactionPreset" );)"
  1844. );
  1845. UNIT_ASSERT(res.Root);
  1846. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1847. if (word == "Write") {
  1848. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("compactionPolicy"));
  1849. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("SomeCompactionPreset"));
  1850. }
  1851. };
  1852. TWordCountHive elementStat = { {TString("Write"), 0} };
  1853. VerifyProgram(res, elementStat, verifyLine);
  1854. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1855. }
  1856. Y_UNIT_TEST(AutoPartitioningBySizeParseCorrect) {
  1857. NYql::TAstParseResult res = SqlToYql(
  1858. R"( USE plato;
  1859. CREATE TABLE tableName (Key Uint32, Value String, PRIMARY KEY (Key))
  1860. WITH ( AUTO_PARTITIONING_BY_SIZE = ENABLED );)"
  1861. );
  1862. UNIT_ASSERT(res.Root);
  1863. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1864. if (word == "Write") {
  1865. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("autoPartitioningBySize"));
  1866. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("ENABLED"));
  1867. }
  1868. };
  1869. TWordCountHive elementStat = { {TString("Write"), 0} };
  1870. VerifyProgram(res, elementStat, verifyLine);
  1871. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1872. }
  1873. Y_UNIT_TEST(UniformPartitionsParseCorrect) {
  1874. NYql::TAstParseResult res = SqlToYql(
  1875. R"( USE plato;
  1876. CREATE TABLE tableName (Key Uint32, Value String, PRIMARY KEY (Key))
  1877. WITH ( UNIFORM_PARTITIONS = 16 );)"
  1878. );
  1879. UNIT_ASSERT(res.Root);
  1880. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1881. if (word == "Write") {
  1882. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("uniformPartitions"));
  1883. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("16"));
  1884. }
  1885. };
  1886. TWordCountHive elementStat = { {TString("Write"), 0} };
  1887. VerifyProgram(res, elementStat, verifyLine);
  1888. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1889. }
  1890. Y_UNIT_TEST(DateTimeTtlParseCorrect) {
  1891. NYql::TAstParseResult res = SqlToYql(
  1892. R"( USE plato;
  1893. CREATE TABLE tableName (Key Uint32, CreatedAt Timestamp, PRIMARY KEY (Key))
  1894. WITH (TTL = Interval("P1D") On CreatedAt);)"
  1895. );
  1896. UNIT_ASSERT(res.Root);
  1897. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1898. if (word == "Write") {
  1899. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings"));
  1900. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers"));
  1901. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay"));
  1902. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000"));
  1903. }
  1904. };
  1905. TWordCountHive elementStat = { {TString("Write"), 0} };
  1906. VerifyProgram(res, elementStat, verifyLine);
  1907. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1908. }
  1909. Y_UNIT_TEST(IntTtlParseCorrect) {
  1910. NYql::TAstParseResult res = SqlToYql(
  1911. R"( USE plato;
  1912. CREATE TABLE tableName (Key Uint32, CreatedAt Uint32, PRIMARY KEY (Key))
  1913. WITH (TTL = Interval("P1D") On CreatedAt AS SECONDS);)"
  1914. );
  1915. UNIT_ASSERT(res.Root);
  1916. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1917. if (word == "Write") {
  1918. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings"));
  1919. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers"));
  1920. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay"));
  1921. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000"));
  1922. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnUnit"));
  1923. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("seconds"));
  1924. }
  1925. };
  1926. TWordCountHive elementStat = { {TString("Write"), 0} };
  1927. VerifyProgram(res, elementStat, verifyLine);
  1928. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1929. }
  1930. Y_UNIT_TEST(TtlTieringParseCorrect) {
  1931. NYql::TAstParseResult res = SqlToYql(
  1932. R"( USE plato;
  1933. CREATE TABLE tableName (Key Uint32, CreatedAt Uint32, PRIMARY KEY (Key))
  1934. WITH (TTL =
  1935. Interval("P1D") TO EXTERNAL DATA SOURCE Tier1,
  1936. Interval("P2D") TO EXTERNAL DATA SOURCE Tier2,
  1937. Interval("P30D") DELETE
  1938. On CreatedAt AS SECONDS);)"
  1939. );
  1940. UNIT_ASSERT(res.Root);
  1941. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1942. if (word == "Write") {
  1943. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings"));
  1944. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers"));
  1945. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay"));
  1946. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storageName"));
  1947. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier1"));
  1948. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier2"));
  1949. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000"));
  1950. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("172800000"));
  1951. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("2592000000"));
  1952. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnUnit"));
  1953. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("seconds"));
  1954. }
  1955. };
  1956. TWordCountHive elementStat = { {TString("Write"), 0} };
  1957. VerifyProgram(res, elementStat, verifyLine);
  1958. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1959. }
  1960. Y_UNIT_TEST(TtlTieringWithOtherActionsParseCorrect) {
  1961. NYql::TAstParseResult res = SqlToYql(
  1962. R"( USE plato;
  1963. ALTER TABLE tableName
  1964. ADD FAMILY cold (DATA = "rot"),
  1965. SET TTL
  1966. Interval("P1D") TO EXTERNAL DATA SOURCE Tier1,
  1967. Interval("P2D") TO EXTERNAL DATA SOURCE Tier2,
  1968. Interval("P30D") DELETE
  1969. ON CreatedAt,
  1970. ALTER COLUMN payload_v2 SET FAMILY cold,
  1971. ALTER FAMILY default SET DATA "ssd"
  1972. ;)"
  1973. );
  1974. UNIT_ASSERT(res.Root);
  1975. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  1976. if (word == "Write") {
  1977. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("addColumnFamilies"));
  1978. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("cold"));
  1979. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alterColumnFamilies"));
  1980. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("default"));
  1981. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("setTtlSettings"));
  1982. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiers"));
  1983. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("evictionDelay"));
  1984. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storageName"));
  1985. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier1"));
  1986. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("Tier2"));
  1987. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("86400000"));
  1988. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("172800000"));
  1989. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("2592000000"));
  1990. }
  1991. };
  1992. TWordCountHive elementStat = { {TString("Write"), 0} };
  1993. VerifyProgram(res, elementStat, verifyLine);
  1994. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  1995. }
  1996. Y_UNIT_TEST(TieringParseCorrect) {
  1997. NYql::TAstParseResult res = SqlToYql(
  1998. R"( USE plato;
  1999. CREATE TABLE tableName (Key Uint32, Value String, PRIMARY KEY (Key))
  2000. WITH ( TIERING = 'my_tiering' );)"
  2001. );
  2002. UNIT_ASSERT(res.Root);
  2003. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2004. if (word == "Write") {
  2005. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tiering"));
  2006. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("my_tiering"));
  2007. }
  2008. };
  2009. TWordCountHive elementStat = { {TString("Write"), 0} };
  2010. VerifyProgram(res, elementStat, verifyLine);
  2011. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2012. }
  2013. Y_UNIT_TEST(StoreExternalBlobsParseCorrect) {
  2014. NYql::TAstParseResult res = SqlToYql(
  2015. R"( USE plato;
  2016. CREATE TABLE tableName (Key Uint32, Value String, PRIMARY KEY (Key))
  2017. WITH ( STORE_EXTERNAL_BLOBS = ENABLED );)"
  2018. );
  2019. UNIT_ASSERT(res.Root);
  2020. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2021. if (word == "Write") {
  2022. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("storeExternalBlobs"));
  2023. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("ENABLED"));
  2024. }
  2025. };
  2026. TWordCountHive elementStat = { {TString("Write"), 0} };
  2027. VerifyProgram(res, elementStat, verifyLine);
  2028. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2029. }
  2030. Y_UNIT_TEST(DefaultValueColumn2) {
  2031. auto res = SqlToYql(R"( use plato;
  2032. $lambda = () -> {
  2033. RETURN CAST(RandomUuid(2) as String)
  2034. };
  2035. CREATE TABLE tableName (
  2036. Key Uint32 DEFAULT RandomNumber(1),
  2037. Value String DEFAULT $lambda,
  2038. PRIMARY KEY (Key)
  2039. );
  2040. )");
  2041. UNIT_ASSERT_C(res.Root, Err2Str(res));
  2042. const auto program = GetPrettyPrint(res);
  2043. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, program.find("RandomNumber"));
  2044. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, program.find("RandomUuid"));
  2045. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, program.find("columnConstrains"));
  2046. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, program.find("columnConstrains"));
  2047. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, program.find("Write"));
  2048. #if 0
  2049. Cerr << program << Endl;
  2050. #endif
  2051. TWordCountHive elementStat = { {TString("Write"), 0} };
  2052. VerifyProgram(res, elementStat);
  2053. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2054. }
  2055. Y_UNIT_TEST(DefaultValueColumn3) {
  2056. auto res = SqlToYql(R"( use plato;
  2057. CREATE TABLE tableName (
  2058. database_id Utf8,
  2059. cloud_id Utf8,
  2060. global_id Utf8 DEFAULT database_id || "=====",
  2061. PRIMARY KEY (database_id)
  2062. );
  2063. )");
  2064. UNIT_ASSERT_VALUES_EQUAL(Err2Str(res), "<main>:6:40: Error: Column reference \"database_id\" is not allowed in current scope\n");
  2065. UNIT_ASSERT(!res.Root);
  2066. }
  2067. Y_UNIT_TEST(DefaultValueColumn) {
  2068. auto res = SqlToYql(R"( use plato;
  2069. CREATE TABLE tableName (
  2070. Key Uint32 FAMILY cold DEFAULT 5,
  2071. Value String FAMILY default DEFAULT "empty",
  2072. PRIMARY KEY (Key),
  2073. FAMILY default (
  2074. DATA = "test",
  2075. COMPRESSION = "lz4"
  2076. ),
  2077. FAMILY cold (
  2078. DATA = "test",
  2079. COMPRESSION = "off"
  2080. )
  2081. );
  2082. )");
  2083. UNIT_ASSERT_C(res.Root, Err2Str(res));
  2084. #if 0
  2085. const auto program = GetPrettyPrint(res);
  2086. Cerr << program << Endl;
  2087. #endif
  2088. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2089. if (word == "Write") {
  2090. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("default"));
  2091. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnConstrains"));
  2092. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("columnFamilies"));
  2093. }
  2094. };
  2095. TWordCountHive elementStat = { {TString("Write"), 0} };
  2096. VerifyProgram(res, elementStat, verifyLine);
  2097. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2098. }
  2099. Y_UNIT_TEST(ChangefeedParseCorrect) {
  2100. auto res = SqlToYql(R"( USE plato;
  2101. CREATE TABLE tableName (
  2102. Key Uint32, PRIMARY KEY (Key),
  2103. CHANGEFEED feedName WITH (
  2104. MODE = 'KEYS_ONLY',
  2105. FORMAT = 'json',
  2106. INITIAL_SCAN = TRUE,
  2107. VIRTUAL_TIMESTAMPS = FALSE,
  2108. BARRIERS_INTERVAL = Interval("PT1S"),
  2109. RETENTION_PERIOD = Interval("P1D"),
  2110. TOPIC_MIN_ACTIVE_PARTITIONS = 10,
  2111. AWS_REGION = 'aws:region'
  2112. )
  2113. );
  2114. )");
  2115. UNIT_ASSERT_C(res.Root, Err2Str(res));
  2116. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2117. if (word == "Write") {
  2118. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("changefeed"));
  2119. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("mode"));
  2120. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("KEYS_ONLY"));
  2121. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("format"));
  2122. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("json"));
  2123. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("initial_scan"));
  2124. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("true"));
  2125. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("virtual_timestamps"));
  2126. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("false"));
  2127. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("barriers_interval"));
  2128. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("retention_period"));
  2129. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("topic_min_active_partitions"));
  2130. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("aws_region"));
  2131. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("aws:region"));
  2132. }
  2133. };
  2134. TWordCountHive elementStat = { {TString("Write"), 0} };
  2135. VerifyProgram(res, elementStat, verifyLine);
  2136. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2137. }
  2138. Y_UNIT_TEST(CloneForAsTableWorksWithCube) {
  2139. UNIT_ASSERT(SqlToYql("SELECT * FROM AS_TABLE([<|k1:1, k2:1|>]) GROUP BY CUBE(k1, k2);").IsOk());
  2140. }
  2141. Y_UNIT_TEST(WindowPartitionByColumnProperlyEscaped) {
  2142. NYql::TAstParseResult res = SqlToYql("SELECT SUM(key) OVER w FROM plato.Input WINDOW w AS (PARTITION BY `column with space`);");
  2143. UNIT_ASSERT(res.Root);
  2144. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2145. if (word == "CalcOverWindow") {
  2146. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("\"column with space\""));
  2147. }
  2148. };
  2149. TWordCountHive elementStat = { {TString("CalcOverWindow"), 0} };
  2150. VerifyProgram(res, elementStat, verifyLine);
  2151. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["CalcOverWindow"]);
  2152. }
  2153. Y_UNIT_TEST(WindowPartitionByExpressionWithoutAliasesAreAllowed) {
  2154. NYql::TAstParseResult res = SqlToYql("SELECT SUM(key) OVER w FROM plato.Input as i WINDOW w AS (PARTITION BY ii.subkey);");
  2155. UNIT_ASSERT(res.Root);
  2156. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2157. if (word == "AddMember") {
  2158. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("AddMember row 'group_w_0 (SqlAccess 'struct (Member row '\"ii\")"));
  2159. }
  2160. if (word == "CalcOverWindow") {
  2161. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("CalcOverWindow core '('\"group_w_0\")"));
  2162. }
  2163. };
  2164. TWordCountHive elementStat = { {TString("CalcOverWindow"), 0}, {TString("AddMember"), 0} };
  2165. VerifyProgram(res, elementStat, verifyLine);
  2166. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["CalcOverWindow"]);
  2167. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["AddMember"]);
  2168. }
  2169. Y_UNIT_TEST(PqReadByAfterUse) {
  2170. ExpectFailWithError("use plato; pragma PqReadBy='plato2';",
  2171. "<main>:1:28: Error: Cluster in PqReadPqBy pragma differs from cluster specified in USE statement: plato2 != plato\n");
  2172. UNIT_ASSERT(SqlToYql("pragma PqReadBy='plato2';").IsOk());
  2173. UNIT_ASSERT(SqlToYql("pragma PqReadBy='plato2'; use plato;").IsOk());
  2174. UNIT_ASSERT(SqlToYql("$x='plato'; use rtmr:$x; pragma PqReadBy='plato2';").IsOk());
  2175. UNIT_ASSERT(SqlToYql("use plato; pragma PqReadBy='dq';").IsOk());
  2176. }
  2177. Y_UNIT_TEST(MrObject) {
  2178. NYql::TAstParseResult res = SqlToYql(
  2179. "declare $path as String;\n"
  2180. "select * from plato.object($path, `format`, \"comp\" || \"ression\" as compression, 1 as bar) with schema (Int32 as y, String as x)"
  2181. );
  2182. UNIT_ASSERT(res.Root);
  2183. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2184. if (word == "MrObject") {
  2185. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  2186. line.find(R"__((MrObject (EvaluateAtom "$path") '"format" '('('"compression" (Concat (String '"comp") (String '"ression"))) '('"bar" (Int32 '"1")))))__"));
  2187. } else if (word == "userschema") {
  2188. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  2189. line.find(R"__('('('"userschema" (StructType '('"y" (DataType 'Int32)) '('"x" (DataType 'String))) '('"y" '"x"))))__"));
  2190. }
  2191. };
  2192. TWordCountHive elementStat = {{TString("MrObject"), 0}, {TString("userschema"), 0}};
  2193. VerifyProgram(res, elementStat, verifyLine);
  2194. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["MrObject"]);
  2195. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["userschema"]);
  2196. }
  2197. Y_UNIT_TEST(TableBindings) {
  2198. NSQLTranslation::TTranslationSettings settings = GetSettingsWithS3Binding("foo");
  2199. NYql::TAstParseResult res = SqlToYqlWithSettings(
  2200. "select * from bindings.foo",
  2201. settings
  2202. );
  2203. UNIT_ASSERT(res.Root);
  2204. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2205. if (word == "MrObject") {
  2206. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  2207. line.find(R"__((MrTableConcat (Key '('table (String '"path")))) (Void) '('('"bar" '"1") '('"compression" '"ccompression") '('"format" '"format") '('"partitionedby" '"key" '"subkey") '('"userschema" (SqlTypeFromYson)__"));
  2208. }
  2209. };
  2210. TWordCountHive elementStat = {{TString("MrTableConcat"), 0}};
  2211. VerifyProgram(res, elementStat, verifyLine);
  2212. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["MrTableConcat"]);
  2213. settings.DefaultCluster = "plato";
  2214. settings.BindingsMode = NSQLTranslation::EBindingsMode::DISABLED;
  2215. res = SqlToYqlWithSettings(
  2216. "select * from bindings.foo",
  2217. settings
  2218. );
  2219. UNIT_ASSERT_VALUES_EQUAL(Err2Str(res), "<main>:1:15: Error: Please remove 'bindings.' from your query, the support for this syntax has ended, code: 4601\n");
  2220. UNIT_ASSERT(!res.Root);
  2221. settings.BindingsMode = NSQLTranslation::EBindingsMode::DROP;
  2222. res = SqlToYqlWithSettings(
  2223. "select * from bindings.foo",
  2224. settings
  2225. );
  2226. UNIT_ASSERT(res.Root);
  2227. TVerifyLineFunc verifyLine2 = [](const TString& word, const TString& line) {
  2228. if (word == "MrTableConcat") {
  2229. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  2230. line.find(R"__((MrTableConcat (Key '('table (String '"foo")))) (Void) '())))__"));
  2231. }
  2232. };
  2233. TWordCountHive elementStat2 = {{TString("MrTableConcat"), 0}};
  2234. VerifyProgram(res, elementStat2, verifyLine2);
  2235. UNIT_ASSERT_VALUES_EQUAL(1, elementStat2["MrTableConcat"]);
  2236. settings.BindingsMode = NSQLTranslation::EBindingsMode::DROP_WITH_WARNING;
  2237. res = SqlToYqlWithSettings(
  2238. "select * from bindings.foo",
  2239. settings
  2240. );
  2241. UNIT_ASSERT_VALUES_EQUAL(Err2Str(res), "<main>:1:15: Warning: Please remove 'bindings.' from your query, the support for this syntax will be dropped soon, code: 4538\n");
  2242. UNIT_ASSERT(res.Root);
  2243. TWordCountHive elementStat3 = {{TString("MrTableConcat"), 0}};
  2244. VerifyProgram(res, elementStat3, verifyLine2);
  2245. UNIT_ASSERT_VALUES_EQUAL(1, elementStat3["MrTableConcat"]);
  2246. }
  2247. Y_UNIT_TEST(TableBindingsWithInsert) {
  2248. NSQLTranslation::TTranslationSettings settings = GetSettingsWithS3Binding("foo");
  2249. NYql::TAstParseResult res = SqlToYqlWithSettings(
  2250. "insert into bindings.foo with truncate (x, y) values (1, 2);",
  2251. settings
  2252. );
  2253. UNIT_ASSERT(res.Root);
  2254. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2255. if (word == "Write!") {
  2256. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  2257. line.find(R"__((Write! world sink (Key '('table (String '"path"))) values '('('"bar" '"1") '('"compression" '"ccompression") '('"format" '"format") '('"partitionedby" '"key" '"subkey") '('"userschema" (SqlTypeFromYson)__"));
  2258. }
  2259. };
  2260. TWordCountHive elementStat = {{TString("Write!"), 0}};
  2261. VerifyProgram(res, elementStat, verifyLine);
  2262. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write!"]);
  2263. settings.DefaultCluster = "plato";
  2264. settings.BindingsMode = NSQLTranslation::EBindingsMode::DISABLED;
  2265. res = SqlToYqlWithSettings(
  2266. "insert into bindings.foo with truncate (x, y) values (1, 2);",
  2267. settings
  2268. );
  2269. UNIT_ASSERT_VALUES_EQUAL(Err2Str(res), "<main>:1:13: Error: Please remove 'bindings.' from your query, the support for this syntax has ended, code: 4601\n");
  2270. UNIT_ASSERT(!res.Root);
  2271. settings.BindingsMode = NSQLTranslation::EBindingsMode::DROP;
  2272. res = SqlToYqlWithSettings(
  2273. "insert into bindings.foo with truncate (x, y) values (1, 2);",
  2274. settings
  2275. );
  2276. UNIT_ASSERT_VALUES_EQUAL(Err2Str(res), "");
  2277. UNIT_ASSERT(res.Root);
  2278. TVerifyLineFunc verifyLine2 = [](const TString& word, const TString& line) {
  2279. if (word == "Write!") {
  2280. //UNIT_ASSERT_VALUES_EQUAL(line, "");
  2281. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  2282. line.find(R"__((Write! world sink (Key '('table (String '"foo"))) values '('('mode 'renew)))__"));
  2283. }
  2284. };
  2285. TWordCountHive elementStat2 = {{TString("Write!"), 0}};
  2286. VerifyProgram(res, elementStat2, verifyLine2);
  2287. UNIT_ASSERT_VALUES_EQUAL(1, elementStat2["Write!"]);
  2288. settings.BindingsMode = NSQLTranslation::EBindingsMode::DROP_WITH_WARNING;
  2289. res = SqlToYqlWithSettings(
  2290. "insert into bindings.foo with truncate (x, y) values (1, 2);",
  2291. settings
  2292. );
  2293. UNIT_ASSERT_VALUES_EQUAL(Err2Str(res), "<main>:1:13: Warning: Please remove 'bindings.' from your query, the support for this syntax will be dropped soon, code: 4538\n");
  2294. UNIT_ASSERT(res.Root);
  2295. TWordCountHive elementStat3 = {{TString("Write!"), 0}};
  2296. VerifyProgram(res, elementStat3, verifyLine2);
  2297. UNIT_ASSERT_VALUES_EQUAL(1, elementStat3["Write!"]);
  2298. }
  2299. Y_UNIT_TEST(TrailingCommaInWithout) {
  2300. UNIT_ASSERT(SqlToYql("SELECT * WITHOUT stream, FROM plato.Input").IsOk());
  2301. UNIT_ASSERT(SqlToYql("SELECT a.* WITHOUT a.intersect, FROM plato.Input AS a").IsOk());
  2302. UNIT_ASSERT(SqlToYql("SELECT a.* WITHOUT col1, col2, a.col3, FROM plato.Input AS a").IsOk());
  2303. }
  2304. Y_UNIT_TEST(NoStackOverflowOnBigCaseStatement) {
  2305. TStringBuilder req;
  2306. req << "select case 1 + 123";
  2307. for (size_t i = 0; i < 20000; ++i) {
  2308. req << " when " << i << " then " << i + 1;
  2309. }
  2310. req << " else 100500 end;";
  2311. UNIT_ASSERT(SqlToYql(req).IsOk());
  2312. }
  2313. Y_UNIT_TEST(CollectPreaggregatedInListLiteral) {
  2314. UNIT_ASSERT(SqlToYql("SELECT [COUNT(DISTINCT a+b)] FROM plato.Input").IsOk());
  2315. }
  2316. Y_UNIT_TEST(SmartParenInGroupByClause) {
  2317. UNIT_ASSERT(SqlToYql("SELECT * FROM plato.Input GROUP BY (k, v)").IsOk());
  2318. }
  2319. Y_UNIT_TEST(AlterTableRenameToIsCorrect) {
  2320. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table RENAME TO moved").IsOk());
  2321. }
  2322. Y_UNIT_TEST(AlterTableAddDropColumnIsCorrect) {
  2323. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table ADD COLUMN addc uint64, DROP COLUMN dropc, ADD addagain uint64").IsOk());
  2324. }
  2325. Y_UNIT_TEST(AlterTableSetTTLIsCorrect) {
  2326. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table SET (TTL = Interval(\"PT3H\") ON column)").IsOk());
  2327. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table SET (TTL = Interval(\"PT3H\") ON column AS SECONDS)").IsOk());
  2328. }
  2329. Y_UNIT_TEST(AlterTableSetTieringIsCorrect) {
  2330. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table SET (TIERING = 'my_tiering')").IsOk());
  2331. }
  2332. Y_UNIT_TEST(AlterTableAddChangefeedIsCorrect) {
  2333. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table ADD CHANGEFEED feed WITH (MODE = 'UPDATES', FORMAT = 'json')").IsOk());
  2334. }
  2335. Y_UNIT_TEST(AlterTableAlterChangefeedIsCorrect) {
  2336. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table ALTER CHANGEFEED feed DISABLE").IsOk());
  2337. ExpectFailWithError("USE plato; ALTER TABLE table ALTER CHANGEFEED feed SET (FORMAT = 'proto');",
  2338. "<main>:1:57: Error: FORMAT alter is not supported\n");
  2339. }
  2340. Y_UNIT_TEST(AlterTableDropChangefeedIsCorrect) {
  2341. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table DROP CHANGEFEED feed").IsOk());
  2342. }
  2343. Y_UNIT_TEST(AlterTableSetPartitioningIsCorrect) {
  2344. UNIT_ASSERT(SqlToYql("USE plato; ALTER TABLE table SET (AUTO_PARTITIONING_BY_SIZE = DISABLED)").IsOk());
  2345. }
  2346. Y_UNIT_TEST(AlterTableAddIndexWithIsNotSupported) {
  2347. ExpectFailWithError("USE plato; ALTER TABLE table ADD INDEX idx GLOBAL ON (col) WITH (a=b)",
  2348. "<main>:1:40: Error: with: alternative is not implemented yet: \n");
  2349. }
  2350. Y_UNIT_TEST(AlterTableAddIndexLocalIsNotSupported) {
  2351. ExpectFailWithError("USE plato; ALTER TABLE table ADD INDEX idx LOCAL ON (col)",
  2352. "<main>:1:40: Error: local: alternative is not implemented yet: \n");
  2353. }
  2354. Y_UNIT_TEST(CreateTableAddIndexVector) {
  2355. const auto result = SqlToYql(R"(USE plato;
  2356. CREATE TABLE table (
  2357. pk INT32 NOT NULL,
  2358. col String,
  2359. INDEX idx GLOBAL USING vector_kmeans_tree
  2360. ON (col) COVER (col)
  2361. WITH (distance=cosine, vector_type=float, vector_dimension=1024,),
  2362. PRIMARY KEY (pk))
  2363. )");
  2364. UNIT_ASSERT_C(result.IsOk(), result.Issues.ToString());
  2365. }
  2366. Y_UNIT_TEST(AlterTableAddIndexVector) {
  2367. const auto result = SqlToYql(R"(USE plato;
  2368. ALTER TABLE table ADD INDEX idx
  2369. GLOBAL USING vector_kmeans_tree
  2370. ON (col) COVER (col)
  2371. WITH (distance=cosine, vector_type="float", vector_dimension=1024)
  2372. )");
  2373. UNIT_ASSERT_C(result.IsOk(), result.Issues.ToString());
  2374. }
  2375. Y_UNIT_TEST(AlterTableAddIndexUnknownSubtype) {
  2376. ExpectFailWithError("USE plato; ALTER TABLE table ADD INDEX idx GLOBAL USING unknown ON (col)",
  2377. "<main>:1:57: Error: UNKNOWN index subtype is not supported\n");
  2378. }
  2379. Y_UNIT_TEST(AlterTableAddIndexMissedParameter) {
  2380. ExpectFailWithError(R"(USE plato;
  2381. ALTER TABLE table ADD INDEX idx
  2382. GLOBAL USING vector_kmeans_tree
  2383. ON (col)
  2384. WITH (distance=cosine, vector_type=float)
  2385. )",
  2386. "<main>:5:52: Error: vector_dimension should be set\n");
  2387. }
  2388. Y_UNIT_TEST(AlterTableAlterIndexSetPartitioningIsCorrect) {
  2389. const auto result = SqlToYql("USE plato; ALTER TABLE table ALTER INDEX index SET AUTO_PARTITIONING_MIN_PARTITIONS_COUNT 10");
  2390. UNIT_ASSERT_C(result.IsOk(), result.Issues.ToString());
  2391. }
  2392. Y_UNIT_TEST(AlterTableAlterIndexSetMultiplePartitioningSettings) {
  2393. const auto result = SqlToYql("USE plato; ALTER TABLE table ALTER INDEX index SET "
  2394. "(AUTO_PARTITIONING_BY_LOAD = ENABLED, AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 10)"
  2395. );
  2396. UNIT_ASSERT_C(result.IsOk(), result.Issues.ToString());
  2397. }
  2398. Y_UNIT_TEST(AlterTableAlterIndexResetPartitioningIsNotSupported) {
  2399. ExpectFailWithError("USE plato; ALTER TABLE table ALTER INDEX index RESET (AUTO_PARTITIONING_MIN_PARTITIONS_COUNT)",
  2400. "<main>:1:55: Error: AUTO_PARTITIONING_MIN_PARTITIONS_COUNT reset is not supported\n"
  2401. );
  2402. }
  2403. Y_UNIT_TEST(AlterTableAlterColumnDropNotNullAstCorrect) {
  2404. auto reqSetNull = SqlToYql(R"(
  2405. USE plato;
  2406. CREATE TABLE tableName (
  2407. id Uint32,
  2408. val Uint32 NOT NULL,
  2409. PRIMARY KEY (id)
  2410. );
  2411. COMMIT;
  2412. ALTER TABLE tableName ALTER COLUMN val DROP NOT NULL;
  2413. )");
  2414. UNIT_ASSERT(reqSetNull.IsOk());
  2415. UNIT_ASSERT(reqSetNull.Root);
  2416. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2417. Y_UNUSED(word);
  2418. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(
  2419. R"(let world (Write! world sink (Key '('tablescheme (String '"tableName"))) (Void) '('('mode 'alter) '('actions '('('alterColumns '('('"val" '('changeColumnConstraints '('('drop_not_null)))))))))))"
  2420. ));
  2421. };
  2422. TWordCountHive elementStat({TString("\'mode \'alter")});
  2423. VerifyProgram(reqSetNull, elementStat, verifyLine);
  2424. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["\'mode \'alter"]);
  2425. }
  2426. Y_UNIT_TEST(AlterSequence) {
  2427. UNIT_ASSERT(SqlToYql(R"(
  2428. USE plato;
  2429. ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5;
  2430. )").IsOk());
  2431. UNIT_ASSERT(SqlToYql(R"(
  2432. USE plato;
  2433. ALTER SEQUENCE sequence INCREMENT 2;
  2434. )").IsOk());
  2435. UNIT_ASSERT(SqlToYql(R"(
  2436. USE plato;
  2437. ALTER SEQUENCE sequence INCREMENT 2 START 1000;
  2438. )").IsOk());
  2439. UNIT_ASSERT(SqlToYql(R"(
  2440. USE plato;
  2441. ALTER SEQUENCE sequence RESTART START 1000;
  2442. )").IsOk());
  2443. UNIT_ASSERT(SqlToYql(R"(
  2444. USE plato;
  2445. ALTER SEQUENCE IF EXISTS sequence INCREMENT 1000 START 100 RESTART;
  2446. )").IsOk());
  2447. UNIT_ASSERT(SqlToYql(R"(
  2448. USE plato;
  2449. ALTER SEQUENCE IF EXISTS sequence RESTART 1000 START WITH 100 INCREMENT BY 7;
  2450. )").IsOk());
  2451. }
  2452. Y_UNIT_TEST(AlterSequenceIncorrect) {
  2453. {
  2454. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5 RESTART;");
  2455. UNIT_ASSERT(!res.Root);
  2456. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:75: Error: Restart value defined more than once\n");
  2457. }
  2458. {
  2459. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 START 100 RESTART WITH 5;");
  2460. UNIT_ASSERT(!res.Root);
  2461. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:60: Error: Start value defined more than once\n");
  2462. }
  2463. {
  2464. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence INCREMENT BY 7 START WITH 10 INCREMENT 2 RESTART WITH 5 RESTART;");
  2465. UNIT_ASSERT(!res.Root);
  2466. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:62: Error: Increment defined more than once\n");
  2467. }
  2468. {
  2469. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 100 START WITH 10 INCREMENT 2 RESTART WITH 5;");
  2470. UNIT_ASSERT(!res.Root);
  2471. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:77: Error: Restart value defined more than once\n");
  2472. }
  2473. {
  2474. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1234234543563435151456 START WITH 10 INCREMENT 2;");
  2475. UNIT_ASSERT(!res.Root);
  2476. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:49: Error: Failed to parse number from string: 1234234543563435151456, number limit overflow\n");
  2477. }
  2478. {
  2479. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 9223372036854775817 INCREMENT 4;");
  2480. UNIT_ASSERT(!res.Root);
  2481. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Start value: 9223372036854775817 cannot be greater than max value: 9223372036854775807\n");
  2482. }
  2483. {
  2484. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 9223372036854775827 START WITH 5 INCREMENT 4;");
  2485. UNIT_ASSERT(!res.Root);
  2486. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Restart value: 9223372036854775827 cannot be greater than max value: 9223372036854775807\n");
  2487. }
  2488. {
  2489. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 4 INCREMENT 0;");
  2490. UNIT_ASSERT(!res.Root);
  2491. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Increment must not be zero\n");
  2492. }
  2493. {
  2494. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 0 START WITH 4 INCREMENT 1;");
  2495. UNIT_ASSERT(!res.Root);
  2496. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Restart value: 0 cannot be less than min value: 1\n");
  2497. }
  2498. {
  2499. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 0 INCREMENT 1;");
  2500. UNIT_ASSERT(!res.Root);
  2501. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Start value: 0 cannot be less than min value: 1\n");
  2502. }
  2503. {
  2504. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence RESTART WITH 1 START WITH 1 INCREMENT 9223372036854775837;");
  2505. UNIT_ASSERT(!res.Root);
  2506. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Increment: 9223372036854775837 cannot be greater than max value: 9223372036854775807\n");
  2507. }
  2508. }
  2509. Y_UNIT_TEST(AlterSequenceCorrect) {
  2510. {
  2511. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE sequence START WITH 10 INCREMENT 2 RESTART WITH 5;");
  2512. UNIT_ASSERT(res.Root);
  2513. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2514. if (word == "Write") {
  2515. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence"));
  2516. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter"));
  2517. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("alter_if_exists"));
  2518. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("start"));
  2519. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment"));
  2520. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("restart"));
  2521. }
  2522. };
  2523. TWordCountHive elementStat = { {TString("Write"), 0}};
  2524. VerifyProgram(res, elementStat, verifyLine);
  2525. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2526. }
  2527. {
  2528. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE IF EXISTS sequence INCREMENT 2 RESTART;");
  2529. UNIT_ASSERT(res.Root);
  2530. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2531. if (word == "Write") {
  2532. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence"));
  2533. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter_if_exists"));
  2534. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment"));
  2535. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("restart"));
  2536. }
  2537. };
  2538. TWordCountHive elementStat = { {TString("Write"), 0}};
  2539. VerifyProgram(res, elementStat, verifyLine);
  2540. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2541. }
  2542. {
  2543. NYql::TAstParseResult res = SqlToYql("USE plato; ALTER SEQUENCE IF EXISTS sequence START 10 INCREMENT BY 2;");
  2544. UNIT_ASSERT(res.Root);
  2545. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2546. if (word == "Write") {
  2547. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("sequence"));
  2548. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter_if_exists"));
  2549. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("start"));
  2550. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("restart"));
  2551. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("increment"));
  2552. }
  2553. };
  2554. TWordCountHive elementStat = { {TString("Write"), 0}};
  2555. VerifyProgram(res, elementStat, verifyLine);
  2556. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2557. }
  2558. }
  2559. Y_UNIT_TEST(ShowCreateTable) {
  2560. NYql::TAstParseResult res = SqlToYql(R"(
  2561. USE plato;
  2562. SHOW CREATE TABLE user;
  2563. )");
  2564. UNIT_ASSERT(res.Root);
  2565. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2566. if (word == "Read") {
  2567. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("showCreateTable"));
  2568. }
  2569. };
  2570. TWordCountHive elementStat = {{TString("Read"), 0}, {TString("showCreateTable"), 0}};
  2571. VerifyProgram(res, elementStat, verifyLine);
  2572. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Read"]);
  2573. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["showCreateTable"]);
  2574. }
  2575. Y_UNIT_TEST(OptionalAliases) {
  2576. UNIT_ASSERT(SqlToYql("USE plato; SELECT foo FROM (SELECT key foo FROM Input);").IsOk());
  2577. UNIT_ASSERT(SqlToYql("USE plato; SELECT a.x FROM Input1 a JOIN Input2 b ON a.key = b.key;").IsOk());
  2578. UNIT_ASSERT(SqlToYql("USE plato; SELECT a.x FROM (VALUES (1,2), (3,4)) a(x,key) JOIN Input b ON a.key = b.key;").IsOk());
  2579. }
  2580. Y_UNIT_TEST(TableNameConstness) {
  2581. UNIT_ASSERT(SqlToYql("USE plato; $path = 'foo'; SELECT TableName($path), count(*) FROM Input;").IsOk());
  2582. UNIT_ASSERT(SqlToYql("$path = 'foo'; SELECT TableName($path, 'yt'), count(*) FROM plato.Input;").IsOk());
  2583. ExpectFailWithError("USE plato; SELECT TableName(), count(*) FROM plato.Input;",
  2584. "<main>:1:19: Error: Expression has to be an aggregation function or key column, because aggregation is used elsewhere in this subquery\n");
  2585. }
  2586. Y_UNIT_TEST(UseShouldWorkAsColumnName) {
  2587. UNIT_ASSERT(SqlToYql("select use from (select 1 as use);").IsOk());
  2588. }
  2589. Y_UNIT_TEST(TrueFalseWorkAfterDollar) {
  2590. UNIT_ASSERT(SqlToYql("$ true = false; SELECT $ true or false;").IsOk());
  2591. UNIT_ASSERT(SqlToYql("$False = 0; SELECT $False;").IsOk());
  2592. }
  2593. Y_UNIT_TEST(WithSchemaEquals) {
  2594. UNIT_ASSERT(SqlToYql("select * from plato.T with schema Struct<a:Int32, b:String>;").IsOk());
  2595. UNIT_ASSERT(SqlToYql("select * from plato.T with columns = Struct<a:Int32, b:String>;").IsOk());
  2596. }
  2597. Y_UNIT_TEST(WithNonStructSchemaS3) {
  2598. NSQLTranslation::TTranslationSettings settings;
  2599. settings.ClusterMapping["s3bucket"] = NYql::S3ProviderName;
  2600. UNIT_ASSERT(SqlToYqlWithSettings("select * from s3bucket.`foo` with schema (col1 Int32, String as col2, Int64 as col3);", settings).IsOk());
  2601. }
  2602. Y_UNIT_TEST(AllowNestedTuplesInGroupBy) {
  2603. NYql::TAstParseResult res = SqlToYql("select count(*) from plato.Input group by 1 + (x, y, z);");
  2604. UNIT_ASSERT(res.Root);
  2605. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  2606. Y_UNUSED(word);
  2607. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Aggregate core '('\"group0\")"));
  2608. };
  2609. TWordCountHive elementStat({"Aggregate"});
  2610. VerifyProgram(res, elementStat, verifyLine);
  2611. UNIT_ASSERT(elementStat["Aggregate"] == 1);
  2612. }
  2613. Y_UNIT_TEST(AllowGroupByWithParens) {
  2614. NYql::TAstParseResult res = SqlToYql("select count(*) from plato.Input group by (x, y as alias1, z);");
  2615. UNIT_ASSERT(res.Root);
  2616. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  2617. Y_UNUSED(word);
  2618. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Aggregate core '('\"x\" '\"alias1\" '\"z\")"));
  2619. };
  2620. TWordCountHive elementStat({"Aggregate"});
  2621. VerifyProgram(res, elementStat, verifyLine);
  2622. UNIT_ASSERT(elementStat["Aggregate"] == 1);
  2623. }
  2624. Y_UNIT_TEST(CreateAsyncReplicationParseCorrect) {
  2625. auto req = R"(
  2626. USE plato;
  2627. CREATE ASYNC REPLICATION MyReplication
  2628. FOR table1 AS table2, table3 AS table4
  2629. WITH (
  2630. CONNECTION_STRING = "grpc://localhost:2135/?database=/MyDatabase",
  2631. ENDPOINT = "localhost:2135",
  2632. DATABASE = "/MyDatabase"
  2633. );
  2634. )";
  2635. auto res = SqlToYql(req);
  2636. UNIT_ASSERT(res.Root);
  2637. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2638. if (word == "Write") {
  2639. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("MyReplication"));
  2640. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("create"));
  2641. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("table1"));
  2642. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("table2"));
  2643. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("table3"));
  2644. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("table4"));
  2645. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("connection_string"));
  2646. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("grpc://localhost:2135/?database=/MyDatabase"));
  2647. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("endpoint"));
  2648. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("localhost:2135"));
  2649. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("database"));
  2650. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("/MyDatabase"));
  2651. }
  2652. };
  2653. TWordCountHive elementStat = { {TString("Write"), 0}};
  2654. VerifyProgram(res, elementStat, verifyLine);
  2655. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2656. }
  2657. Y_UNIT_TEST(CreateAsyncReplicationUnsupportedSettings) {
  2658. auto reqTpl = R"(
  2659. USE plato;
  2660. CREATE ASYNC REPLICATION MyReplication
  2661. FOR table1 AS table2, table3 AS table4
  2662. WITH (
  2663. %s = "%s"
  2664. )
  2665. )";
  2666. auto settings = THashMap<TString, TString>{
  2667. {"STATE", "DONE"},
  2668. {"FAILOVER_MODE", "FORCE"},
  2669. };
  2670. for (const auto& [k, v] : settings) {
  2671. auto req = Sprintf(reqTpl, k.c_str(), v.c_str());
  2672. auto res = SqlToYql(req);
  2673. UNIT_ASSERT(!res.Root);
  2674. UNIT_ASSERT_NO_DIFF(Err2Str(res), Sprintf("<main>:6:%zu: Error: %s is not supported in CREATE\n", 20 + k.size(), k.c_str()));
  2675. }
  2676. }
  2677. Y_UNIT_TEST(AsyncReplicationInvalidCommitInterval) {
  2678. auto req = R"(
  2679. USE plato;
  2680. CREATE ASYNC REPLICATION MyReplication
  2681. FOR table1 AS table2, table3 AS table4
  2682. WITH (
  2683. COMMIT_INTERVAL = "FOO"
  2684. );
  2685. )";
  2686. auto res = SqlToYql(req);
  2687. UNIT_ASSERT(!res.Root);
  2688. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:6:35: Error: Literal of Interval type is expected for COMMIT_INTERVAL\n");
  2689. }
  2690. Y_UNIT_TEST(AlterAsyncReplicationParseCorrect) {
  2691. auto req = R"(
  2692. USE plato;
  2693. ALTER ASYNC REPLICATION MyReplication
  2694. SET (
  2695. STATE = "DONE",
  2696. FAILOVER_MODE = "FORCE"
  2697. );
  2698. )";
  2699. auto res = SqlToYql(req);
  2700. UNIT_ASSERT(res.Root);
  2701. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2702. if (word == "Write") {
  2703. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("MyReplication"));
  2704. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter"));
  2705. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("state"));
  2706. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("DONE"));
  2707. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("failover_mode"));
  2708. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("FORCE"));
  2709. }
  2710. };
  2711. TWordCountHive elementStat = { {TString("Write"), 0}};
  2712. VerifyProgram(res, elementStat, verifyLine);
  2713. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2714. }
  2715. Y_UNIT_TEST(AlterAsyncReplicationSettings) {
  2716. auto reqTpl = R"(
  2717. USE plato;
  2718. ALTER ASYNC REPLICATION MyReplication
  2719. SET (
  2720. %s = "%s"
  2721. )
  2722. )";
  2723. auto settings = THashMap<TString, TString>{
  2724. {"connection_string", "grpc://localhost:2135/?database=/MyDatabase"},
  2725. {"endpoint", "localhost:2135"},
  2726. {"database", "/MyDatabase"},
  2727. {"token", "foo"},
  2728. {"token_secret_name", "foo_secret_name"},
  2729. {"user", "user"},
  2730. {"password", "bar"},
  2731. {"password_secret_name", "bar_secret_name"},
  2732. };
  2733. for (const auto& [k, v] : settings) {
  2734. auto req = Sprintf(reqTpl, k.c_str(), v.c_str());
  2735. auto res = SqlToYql(req);
  2736. UNIT_ASSERT(res.Root);
  2737. TVerifyLineFunc verifyLine = [&k, &v](const TString& word, const TString& line) {
  2738. if (word == "Write") {
  2739. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("MyReplication"));
  2740. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("alter"));
  2741. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(k));
  2742. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(v));
  2743. }
  2744. };
  2745. TWordCountHive elementStat = { {TString("Write"), 0}};
  2746. VerifyProgram(res, elementStat, verifyLine);
  2747. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2748. }
  2749. }
  2750. Y_UNIT_TEST(AlterAsyncReplicationUnsupportedSettings) {
  2751. {
  2752. auto req = R"(
  2753. USE plato;
  2754. ALTER ASYNC REPLICATION MyReplication SET (CONSISTENCY_LEVEL = "GLOBAL");
  2755. )";
  2756. auto res = SqlToYql(req);
  2757. UNIT_ASSERT(!res.Root);
  2758. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:80: Error: CONSISTENCY_LEVEL is not supported in ALTER\n");
  2759. }
  2760. {
  2761. auto req = R"(
  2762. USE plato;
  2763. ALTER ASYNC REPLICATION MyReplication SET (COMMIT_INTERVAL = Interval("PT10S"));
  2764. )";
  2765. auto res = SqlToYql(req);
  2766. UNIT_ASSERT(!res.Root);
  2767. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:87: Error: COMMIT_INTERVAL is not supported in ALTER\n");
  2768. }
  2769. }
  2770. Y_UNIT_TEST(AsyncReplicationInvalidSettings) {
  2771. auto req = R"(
  2772. USE plato;
  2773. ALTER ASYNC REPLICATION MyReplication SET (FOO = "BAR");
  2774. )";
  2775. auto res = SqlToYql(req);
  2776. UNIT_ASSERT(!res.Root);
  2777. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:62: Error: Unknown replication setting: FOO\n");
  2778. }
  2779. Y_UNIT_TEST(DropAsyncReplicationParseCorrect) {
  2780. auto req = R"(
  2781. USE plato;
  2782. DROP ASYNC REPLICATION MyReplication;
  2783. )";
  2784. auto res = SqlToYql(req);
  2785. UNIT_ASSERT(res.Root);
  2786. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2787. if (word == "Write") {
  2788. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("MyReplication"));
  2789. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("drop"));
  2790. }
  2791. };
  2792. TWordCountHive elementStat = { {TString("Write"), 0}};
  2793. VerifyProgram(res, elementStat, verifyLine);
  2794. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2795. }
  2796. Y_UNIT_TEST(DropAsyncReplicationCascade) {
  2797. auto req = R"(
  2798. USE plato;
  2799. DROP ASYNC REPLICATION MyReplication CASCADE;
  2800. )";
  2801. auto res = SqlToYql(req);
  2802. UNIT_ASSERT(res.Root);
  2803. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2804. if (word == "Write") {
  2805. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropCascade"));
  2806. }
  2807. };
  2808. TWordCountHive elementStat = { {TString("Write"), 0}};
  2809. VerifyProgram(res, elementStat, verifyLine);
  2810. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  2811. }
  2812. Y_UNIT_TEST(PragmaCompactGroupBy) {
  2813. auto req = "PRAGMA CompactGroupBy; SELECT key, COUNT(*) FROM plato.Input GROUP BY key;";
  2814. auto res = SqlToYql(req);
  2815. UNIT_ASSERT(res.Root);
  2816. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2817. if (word == "Aggregate") {
  2818. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'('compact)"));
  2819. }
  2820. };
  2821. TWordCountHive elementStat = { {TString("Aggregate"), 0}};
  2822. VerifyProgram(res, elementStat, verifyLine);
  2823. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Aggregate"]);
  2824. }
  2825. Y_UNIT_TEST(PragmaDisableCompactGroupBy) {
  2826. auto req = "PRAGMA DisableCompactGroupBy; SELECT key, COUNT(*) FROM plato.Input GROUP /*+ compact() */ BY key;";
  2827. auto res = SqlToYql(req);
  2828. UNIT_ASSERT(res.Root);
  2829. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  2830. if (word == "Aggregate") {
  2831. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'('compact)"));
  2832. }
  2833. };
  2834. TWordCountHive elementStat = { {TString("Aggregate"), 0}};
  2835. VerifyProgram(res, elementStat, verifyLine);
  2836. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Aggregate"]);
  2837. }
  2838. Y_UNIT_TEST(AutoSampleWorksWithNamedSubquery) {
  2839. UNIT_ASSERT(SqlToYql("$src = select * from plato.Input; select * from $src sample 0.2").IsOk());
  2840. }
  2841. Y_UNIT_TEST(AutoSampleWorksWithSubquery) {
  2842. UNIT_ASSERT(SqlToYql("select * from (select * from plato.Input) sample 0.2").IsOk());
  2843. }
  2844. Y_UNIT_TEST(CreateTableTrailingComma) {
  2845. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE tableName (Key Uint32, PRIMARY KEY (Key),);").IsOk());
  2846. UNIT_ASSERT(SqlToYql("USE plato; CREATE TABLE tableName (Key Uint32,);").IsOk());
  2847. }
  2848. Y_UNIT_TEST(BetweenSymmetric) {
  2849. UNIT_ASSERT(SqlToYql("select 3 between symmetric 5 and 4;").IsOk());
  2850. UNIT_ASSERT(SqlToYql("select 3 between asymmetric 5 and 4;").IsOk());
  2851. UNIT_ASSERT(SqlToYql("use plato; select key between symmetric and and and from Input;").IsOk());
  2852. UNIT_ASSERT(SqlToYql("use plato; select key between and and and from Input;").IsOk());
  2853. }
  2854. }
  2855. Y_UNIT_TEST_SUITE(ExternalFunction) {
  2856. Y_UNIT_TEST(ValidUseFunctions) {
  2857. UNIT_ASSERT(SqlToYql(
  2858. "PROCESS plato.Input"
  2859. " USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'foo', <|a: 123, b: a + 641|>)"
  2860. " WITH INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>,"
  2861. " CONCURRENCY=3, OPTIMIZE_FOR='CALLS'").IsOk());
  2862. // use CALLS without quotes, as keyword
  2863. UNIT_ASSERT(SqlToYql(
  2864. "PROCESS plato.Input"
  2865. " USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'foo')"
  2866. " WITH INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>,"
  2867. " OPTIMIZE_FOR=CALLS").IsOk());
  2868. UNIT_ASSERT(SqlToYql(
  2869. "PROCESS plato.Input"
  2870. " USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'foo', TableRow())"
  2871. " WITH INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>,"
  2872. " CONCURRENCY=3").IsOk());
  2873. UNIT_ASSERT(SqlToYql(
  2874. "PROCESS plato.Input"
  2875. " USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'foo')"
  2876. " WITH INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>,"
  2877. " CONCURRENCY=3, BATCH_SIZE=1000000, CONNECTION='yc-folder34fse-con',"
  2878. " INIT=[0, 900]").IsOk());
  2879. UNIT_ASSERT(SqlToYql(
  2880. "PROCESS plato.Input"
  2881. " USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'bar', TableRow())"
  2882. " WITH UNKNOWN_PARAM_1='837747712', UNKNOWN_PARAM_2=Tuple<Uint16, Utf8>,"
  2883. " INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>").IsOk());
  2884. }
  2885. Y_UNIT_TEST(InValidUseFunctions) {
  2886. ExpectFailWithError("PROCESS plato.Input USING some::udf(*) WITH INPUT_TYPE=Struct<a:Int32>",
  2887. "<main>:1:33: Error: PROCESS without USING EXTERNAL FUNCTION doesn't allow WITH block\n");
  2888. ExpectFailWithError("PROCESS plato.Input USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'jhhjfh88134d')"
  2889. " WITH INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>"
  2890. " ASSUME ORDER BY key",
  2891. "<main>:1:129: Error: PROCESS with USING EXTERNAL FUNCTION doesn't allow ASSUME block\n");
  2892. ExpectFailWithError("PROCESS plato.Input USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'foo', 'bar', 'baz')",
  2893. "<main>:1:15: Error: EXTERNAL FUNCTION requires from 2 to 3 arguments, but got: 4\n");
  2894. ExpectFailWithError("PROCESS plato.Input\n"
  2895. " USING EXTERNAL FUNCTION('YANDEX-CLOUD', 'foo', <|field_1: a1, field_b: b1|>)\n"
  2896. " WITH INPUT_TYPE=Struct<a:Int32>, OUTPUT_TYPE=Struct<b:Int32>,\n"
  2897. " CONCURRENCY=3, BATCH_SIZE=1000000, CONNECTION='yc-folder34fse-con',\n"
  2898. " CONCURRENCY=5, INPUT_TYPE=Struct<b:Bool>,\n"
  2899. " INIT=[0, 900]\n",
  2900. "<main>:5:2: Error: WITH \"CONCURRENCY\" clause should be specified only once\n"
  2901. "<main>:5:17: Error: WITH \"INPUT_TYPE\" clause should be specified only once\n");
  2902. }
  2903. }
  2904. Y_UNIT_TEST_SUITE(SqlToYQLErrors) {
  2905. Y_UNIT_TEST(UdfSyntaxSugarMissingCall) {
  2906. auto req = "SELECT Udf(DateTime::FromString, \"foo\" as RunConfig);";
  2907. auto res = SqlToYql(req);
  2908. TString a1 = Err2Str(res);
  2909. TString a2("<main>:1:8: Error: Abstract Udf Node can't be used as a part of expression.\n");
  2910. UNIT_ASSERT_NO_DIFF(a1, a2);
  2911. }
  2912. Y_UNIT_TEST(UdfSyntaxSugarIsNotCallable) {
  2913. auto req = "SELECT Udf(123, \"foo\" as RunConfig);";
  2914. auto res = SqlToYql(req);
  2915. TString a1 = Err2Str(res);
  2916. TString a2("<main>:1:8: Error: Udf: first argument must be a callable, like Foo::Bar\n");
  2917. UNIT_ASSERT_NO_DIFF(a1, a2);
  2918. }
  2919. Y_UNIT_TEST(UdfSyntaxSugarNoArgs) {
  2920. auto req = "SELECT Udf()();";
  2921. auto res = SqlToYql(req);
  2922. TString a1 = Err2Str(res);
  2923. TString a2("<main>:1:8: Error: Udf: expected at least one argument\n");
  2924. UNIT_ASSERT_NO_DIFF(a1, a2);
  2925. }
  2926. Y_UNIT_TEST(StrayUTF8) {
  2927. /// 'c' in plato is russian here
  2928. NYql::TAstParseResult res = SqlToYql("select * from сedar.Input");
  2929. UNIT_ASSERT(!res.Root);
  2930. TString a1 = Err2Str(res);
  2931. TString a2(R"foo(<main>:1:14: Error: token recognition error at: 'с'
  2932. )foo");
  2933. UNIT_ASSERT_NO_DIFF(a1, a2);
  2934. }
  2935. Y_UNIT_TEST(IvalidStringLiteralWithEscapedBackslash) {
  2936. NYql::TAstParseResult res1 = SqlToYql(R"foo($bar = 'a\\'b';)foo");
  2937. NYql::TAstParseResult res2 = SqlToYql(R"foo($bar = "a\\"b";)foo");
  2938. UNIT_ASSERT(!res1.Root);
  2939. UNIT_ASSERT(!res2.Root);
  2940. UNIT_ASSERT_NO_DIFF(Err2Str(res1), "<main>:1:13: Error: token recognition error at: '';'\n");
  2941. UNIT_ASSERT_NO_DIFF(Err2Str(res2), "<main>:1:13: Error: token recognition error at: '\";'\n");
  2942. }
  2943. Y_UNIT_TEST(InvalidHexInStringLiteral) {
  2944. NYql::TAstParseResult res = SqlToYql("select \"foo\\x1\\xfe\"");
  2945. UNIT_ASSERT(!res.Root);
  2946. TString a1 = Err2Str(res);
  2947. TString a2 = "<main>:1:15: Error: Failed to parse string literal: Invalid hexadecimal value\n";
  2948. UNIT_ASSERT_NO_DIFF(a1, a2);
  2949. }
  2950. Y_UNIT_TEST(InvalidOctalInMultilineStringLiteral) {
  2951. NYql::TAstParseResult res = SqlToYql("select \"foo\n"
  2952. "bar\n"
  2953. "\\01\"");
  2954. UNIT_ASSERT(!res.Root);
  2955. TString a1 = Err2Str(res);
  2956. TString a2 = "<main>:3:4: Error: Failed to parse string literal: Invalid octal value\n";
  2957. UNIT_ASSERT_NO_DIFF(a1, a2);
  2958. }
  2959. Y_UNIT_TEST(InvalidDoubleAtString) {
  2960. NYql::TAstParseResult res = SqlToYql("select @@@@@@");
  2961. UNIT_ASSERT(!res.Root);
  2962. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: extraneous input '@' expecting {<EOF>, ';'}\n");
  2963. }
  2964. Y_UNIT_TEST(InvalidDoubleAtStringWhichWasAcceptedEarlier) {
  2965. NYql::TAstParseResult res = SqlToYql("SELECT @@foo@@ @ @@bar@@");
  2966. UNIT_ASSERT(!res.Root);
  2967. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:15: Error: mismatched input '@' expecting {<EOF>, ';'}\n");
  2968. }
  2969. Y_UNIT_TEST(InvalidStringFromTable) {
  2970. NYql::TAstParseResult res = SqlToYql("select \"FOO\"\"BAR from plato.foo");
  2971. UNIT_ASSERT(!res.Root);
  2972. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: token recognition error at: '\"BAR from plato.foo'\n");
  2973. }
  2974. Y_UNIT_TEST(InvalidDoubleAtStringFromTable) {
  2975. NYql::TAstParseResult res = SqlToYql("select @@@@@@ from plato.foo");
  2976. UNIT_ASSERT(!res.Root);
  2977. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: mismatched input '@' expecting {<EOF>, ';'}\n");
  2978. }
  2979. Y_UNIT_TEST(SelectInvalidSyntax) {
  2980. NYql::TAstParseResult res = SqlToYql("select 1 form Wat");
  2981. UNIT_ASSERT(!res.Root);
  2982. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:14: Error: extraneous input 'Wat' expecting {<EOF>, ';'}\n");
  2983. }
  2984. Y_UNIT_TEST(SelectNoCluster) {
  2985. NYql::TAstParseResult res = SqlToYql("select foo from bar");
  2986. UNIT_ASSERT(!res.Root);
  2987. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: No cluster name given and no default cluster is selected\n");
  2988. }
  2989. Y_UNIT_TEST(SelectDuplicateColumns) {
  2990. NYql::TAstParseResult res = SqlToYql("select a, a from plato.Input");
  2991. UNIT_ASSERT(!res.Root);
  2992. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:11: Error: Unable to use duplicate column names. Collision in name: a\n");
  2993. }
  2994. Y_UNIT_TEST(SelectDuplicateLabels) {
  2995. NYql::TAstParseResult res = SqlToYql("select a as foo, b as foo from plato.Input");
  2996. UNIT_ASSERT(!res.Root);
  2997. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:18: Error: Unable to use duplicate column names. Collision in name: foo\n");
  2998. }
  2999. Y_UNIT_TEST(SelectCaseWithoutThen) {
  3000. NYql::TAstParseResult res = SqlToYql("select case when true 1;");
  3001. UNIT_ASSERT(!res.Root);
  3002. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3003. "<main>:1:22: Error: missing THEN at \'1\'\n"
  3004. "<main>:1:23: Error: extraneous input \';\' expecting {ELSE, END, WHEN}\n"
  3005. );
  3006. }
  3007. Y_UNIT_TEST(SelectComplexCaseWithoutThen) {
  3008. NYql::TAstParseResult res = SqlToYql(
  3009. "SELECT *\n"
  3010. "FROM plato.Input AS a\n"
  3011. "WHERE CASE WHEN a.key = \"foo\" a.subkey ELSE a.value END\n"
  3012. );
  3013. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:30: Error: missing THEN at 'a'\n");
  3014. }
  3015. Y_UNIT_TEST(SelectCaseWithoutEnd) {
  3016. NYql::TAstParseResult res = SqlToYql("select case a when b then c end from plato.Input");
  3017. UNIT_ASSERT(!res.Root);
  3018. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: ELSE is required\n");
  3019. }
  3020. Y_UNIT_TEST(SelectWithBadAggregationNoInput) {
  3021. NYql::TAstParseResult res = SqlToYql("select a, Min(b), c");
  3022. UNIT_ASSERT(!res.Root);
  3023. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3024. "<main>:1:1: Error: Column references are not allowed without FROM\n"
  3025. "<main>:1:8: Error: Column reference 'a'\n"
  3026. "<main>:1:1: Error: Column references are not allowed without FROM\n"
  3027. "<main>:1:15: Error: Column reference 'b'\n"
  3028. "<main>:1:1: Error: Column references are not allowed without FROM\n"
  3029. "<main>:1:19: Error: Column reference 'c'\n"
  3030. );
  3031. }
  3032. Y_UNIT_TEST(SelectWithBadAggregation) {
  3033. ExpectFailWithError("select count(*), 1 + key from plato.Input",
  3034. "<main>:1:22: Error: Column `key` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3035. }
  3036. Y_UNIT_TEST(SelectWithBadAggregatedTerms) {
  3037. ExpectFailWithError("select key, 2 * subkey from plato.Input group by key",
  3038. "<main>:1:17: Error: Column `subkey` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3039. }
  3040. Y_UNIT_TEST(SelectDistinctWithBadAggregation) {
  3041. ExpectFailWithError("select distinct count(*), 1 + key from plato.Input",
  3042. "<main>:1:31: Error: Column `key` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3043. ExpectFailWithError("select distinct key, 2 * subkey from plato.Input group by key",
  3044. "<main>:1:26: Error: Column `subkey` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3045. }
  3046. Y_UNIT_TEST(SelectWithBadAggregationInHaving) {
  3047. ExpectFailWithError("select key from plato.Input group by key\n"
  3048. "having \"f\" || value == \"foo\"",
  3049. "<main>:2:15: Error: Column `value` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3050. }
  3051. Y_UNIT_TEST(JoinWithNonAggregatedColumnInProjection) {
  3052. ExpectFailWithError("select a.key, 1 + b.subkey\n"
  3053. "from plato.Input1 as a join plato.Input2 as b using(key)\n"
  3054. "group by a.key;",
  3055. "<main>:1:19: Error: Column `b.subkey` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3056. ExpectFailWithError("select a.key, 1 + b.subkey.x\n"
  3057. "from plato.Input1 as a join plato.Input2 as b using(key)\n"
  3058. "group by a.key;",
  3059. "<main>:1:19: Error: Column must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3060. }
  3061. Y_UNIT_TEST(SelectWithBadAggregatedTermsWithSources) {
  3062. ExpectFailWithError("select key, 1 + a.subkey\n"
  3063. "from plato.Input1 as a\n"
  3064. "group by a.key;",
  3065. "<main>:1:17: Error: Column `a.subkey` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3066. ExpectFailWithError("select key, 1 + a.subkey.x\n"
  3067. "from plato.Input1 as a\n"
  3068. "group by a.key;",
  3069. "<main>:1:17: Error: Column must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3070. }
  3071. Y_UNIT_TEST(WarnForAggregationBySelectAlias) {
  3072. NYql::TAstParseResult res = SqlToYql("select c + 1 as c from plato.Input\n"
  3073. "group by c");
  3074. UNIT_ASSERT(res.Root);
  3075. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3076. "<main>:2:11: Warning: GROUP BY will aggregate by column `c` instead of aggregating by SELECT expression with same alias, code: 4532\n"
  3077. "<main>:1:10: Warning: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n");
  3078. res = SqlToYql("select c + 1 as c from plato.Input\n"
  3079. "group by Math::Floor(c + 2) as c;");
  3080. UNIT_ASSERT(res.Root);
  3081. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3082. "<main>:2:22: Warning: GROUP BY will aggregate by column `c` instead of aggregating by SELECT expression with same alias, code: 4532\n"
  3083. "<main>:1:10: Warning: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n");
  3084. }
  3085. Y_UNIT_TEST(NoWarnForAggregationBySelectAliasWhenAggrFunctionsAreUsedInAlias) {
  3086. NYql::TAstParseResult res = SqlToYql("select\n"
  3087. " cast(avg(val) as int) as value,\n"
  3088. " value as key\n"
  3089. "from\n"
  3090. " plato.Input\n"
  3091. "group by value");
  3092. UNIT_ASSERT(res.Root);
  3093. UNIT_ASSERT(res.Issues.Size() == 0);
  3094. res = SqlToYql("select\n"
  3095. " cast(avg(val) over w as int) as value,\n"
  3096. " value as key\n"
  3097. "from\n"
  3098. " plato.Input\n"
  3099. "group by value\n"
  3100. "window w as ()");
  3101. UNIT_ASSERT(res.Root);
  3102. UNIT_ASSERT(res.Issues.Size() == 0);
  3103. }
  3104. Y_UNIT_TEST(NoWarnForAggregationBySelectAliasWhenQualifiedNameIsUsed) {
  3105. NYql::TAstParseResult res = SqlToYql("select\n"
  3106. " Unwrap(a.key) as key\n"
  3107. "from plato.Input as a\n"
  3108. "join plato.Input2 as b using(k)\n"
  3109. "group by a.key;");
  3110. UNIT_ASSERT(res.Root);
  3111. UNIT_ASSERT(res.Issues.Size() == 0);
  3112. res = SqlToYql("select Unwrap(a.key) as key\n"
  3113. "from plato.Input as a\n"
  3114. "group by a.key;");
  3115. UNIT_ASSERT(res.Root);
  3116. UNIT_ASSERT(res.Issues.Size() == 0);
  3117. }
  3118. Y_UNIT_TEST(NoWarnForAggregationBySelectAliasWhenTrivialRenamingIsUsed) {
  3119. NYql::TAstParseResult res = SqlToYql("select a.key as key\n"
  3120. "from plato.Input as a\n"
  3121. "group by key;");
  3122. UNIT_ASSERT(res.Root);
  3123. UNIT_ASSERT(res.Issues.Size() == 0);
  3124. res = SqlToYql("select key as key\n"
  3125. "from plato.Input\n"
  3126. "group by key;");
  3127. UNIT_ASSERT(res.Root);
  3128. UNIT_ASSERT(res.Issues.Size() == 0);
  3129. }
  3130. Y_UNIT_TEST(ErrorByAggregatingByExpressionWithSameExpressionInSelect) {
  3131. ExpectFailWithError("select k * 2 from plato.Input group by k * 2",
  3132. "<main>:1:8: Error: Column `k` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3133. }
  3134. Y_UNIT_TEST(ErrorForAggregationBySelectAlias) {
  3135. ExpectFailWithError("select key, Math::Floor(1.1 + a.subkey) as foo\n"
  3136. "from plato.Input as a\n"
  3137. "group by a.key, foo;",
  3138. "<main>:3:17: Warning: GROUP BY will aggregate by column `foo` instead of aggregating by SELECT expression with same alias, code: 4532\n"
  3139. "<main>:1:19: Warning: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n"
  3140. "<main>:1:31: Error: Column `a.subkey` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3141. ExpectFailWithError("select c + 1 as c from plato.Input\n"
  3142. "group by Math::Floor(c + 2);",
  3143. "<main>:2:22: Warning: GROUP BY will aggregate by column `c` instead of aggregating by SELECT expression with same alias, code: 4532\n"
  3144. "<main>:1:10: Warning: You should probably use alias in GROUP BY instead of using it here. Please consult documentation for more details, code: 4532\n"
  3145. "<main>:1:8: Error: Column `c` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3146. }
  3147. Y_UNIT_TEST(ExplainQueryPlan) {
  3148. NYql::TAstParseResult res = SqlToYql("EXPLAIN Q U E R Y PLAN SELECT 1;");
  3149. UNIT_ASSERT(!res.Root);
  3150. UNIT_ASSERT_STRING_CONTAINS(Err2Str(res), "<main>:1:8: Error: mismatched input 'Q' expecting {");
  3151. }
  3152. Y_UNIT_TEST(SelectWithDuplicateGroupingColumns) {
  3153. NYql::TAstParseResult res = SqlToYql("select c from plato.Input group by c, c");
  3154. UNIT_ASSERT(!res.Root);
  3155. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Duplicate grouping column: c\n");
  3156. }
  3157. Y_UNIT_TEST(SelectWithBadAggregationInGrouping) {
  3158. NYql::TAstParseResult res = SqlToYql("select a, Min(b), c group by c");
  3159. UNIT_ASSERT(!res.Root);
  3160. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Column references are not allowed without FROM\n"
  3161. "<main>:1:30: Error: Column reference 'c'\n");
  3162. }
  3163. Y_UNIT_TEST(SelectWithOpOnBadAggregation) {
  3164. ExpectFailWithError("select 1 + a + Min(b) from plato.Input",
  3165. "<main>:1:12: Error: Column `a` must either be a key column in GROUP BY or it should be used in aggregation function\n");
  3166. }
  3167. Y_UNIT_TEST(SelectOrderByConstantNum) {
  3168. NYql::TAstParseResult res = SqlToYql("select a from plato.Input order by 1");
  3169. UNIT_ASSERT(!res.Root);
  3170. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:36: Error: Unable to ORDER BY constant expression\n");
  3171. }
  3172. Y_UNIT_TEST(SelectOrderByConstantExpr) {
  3173. NYql::TAstParseResult res = SqlToYql("select a from plato.Input order by 1 * 42");
  3174. UNIT_ASSERT(!res.Root);
  3175. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:38: Error: Unable to ORDER BY constant expression\n");
  3176. }
  3177. Y_UNIT_TEST(SelectOrderByConstantString) {
  3178. NYql::TAstParseResult res = SqlToYql("select a from plato.Input order by \"nest\"");
  3179. UNIT_ASSERT(!res.Root);
  3180. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:36: Error: Unable to ORDER BY constant expression\n");
  3181. }
  3182. Y_UNIT_TEST(SelectOrderByAggregated) {
  3183. NYql::TAstParseResult res = SqlToYql("select a from plato.Input order by min(a)");
  3184. UNIT_ASSERT(!res.Root);
  3185. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:36: Error: Unable to ORDER BY aggregated values\n");
  3186. }
  3187. Y_UNIT_TEST(ErrorInOrderByExpresison) {
  3188. NYql::TAstParseResult res = SqlToYql("select key, value from plato.Input order by (key as zey)");
  3189. UNIT_ASSERT(!res.Root);
  3190. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:45: Error: You should use in ORDER BY column name, qualified field, callable function or expression\n");
  3191. }
  3192. Y_UNIT_TEST(ErrorsInOrderByWhenColumnIsMissingInProjection) {
  3193. ExpectFailWithError("select subkey from (select 1 as subkey) order by key", "<main>:1:50: Error: Column key is not in source column set\n");
  3194. ExpectFailWithError("select subkey from plato.Input as a order by x.key", "<main>:1:46: Error: Unknown correlation name: x\n");
  3195. ExpectFailWithError("select distinct a, b from plato.Input order by c", "<main>:1:48: Error: Column c is not in source column set. Did you mean a?\n");
  3196. ExpectFailWithError("select count(*) as a from plato.Input order by c", "<main>:1:48: Error: Column c is not in source column set. Did you mean a?\n");
  3197. ExpectFailWithError("select count(*) as a, b, from plato.Input group by b order by c", "<main>:1:63: Error: Column c is not in source column set. Did you mean a?\n");
  3198. UNIT_ASSERT(SqlToYql("select a, b from plato.Input order by c").IsOk());
  3199. }
  3200. Y_UNIT_TEST(SelectAggregatedWhere) {
  3201. NYql::TAstParseResult res = SqlToYql("select * from plato.Input where count(key)");
  3202. UNIT_ASSERT(!res.Root);
  3203. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:33: Error: Can not use aggregated values in filtering\n");
  3204. }
  3205. Y_UNIT_TEST(DoubleFrom) {
  3206. NYql::TAstParseResult res = SqlToYql("from plato.Input select * from plato.Input");
  3207. UNIT_ASSERT(!res.Root);
  3208. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:27: Error: Only one FROM clause is allowed\n");
  3209. }
  3210. Y_UNIT_TEST(SelectJoinMissingCorrName) {
  3211. NYql::TAstParseResult res = SqlToYql("select * from plato.Input1 as a join plato.Input2 as b on a.key == key");
  3212. UNIT_ASSERT(!res.Root);
  3213. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:65: Error: JOIN: column requires correlation name\n");
  3214. }
  3215. Y_UNIT_TEST(SelectJoinMissingCorrName1) {
  3216. NYql::TAstParseResult res = SqlToYql(
  3217. "use plato;\n"
  3218. "$foo = select * from Input1;\n"
  3219. "select * from Input2 join $foo USING(key);\n"
  3220. );
  3221. UNIT_ASSERT(!res.Root);
  3222. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:27: Error: JOIN: missing correlation name for source\n");
  3223. }
  3224. Y_UNIT_TEST(SelectJoinMissingCorrName2) {
  3225. NYql::TAstParseResult res = SqlToYql(
  3226. "use plato;\n"
  3227. "$foo = select * from Input1;\n"
  3228. "select * from Input2 cross join $foo;\n"
  3229. );
  3230. UNIT_ASSERT(!res.Root);
  3231. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:33: Error: JOIN: missing correlation name for source\n");
  3232. }
  3233. Y_UNIT_TEST(SelectJoinEmptyCorrNames) {
  3234. NYql::TAstParseResult res = SqlToYql(
  3235. "$left = (SELECT * FROM plato.Input1 LIMIT 2);\n"
  3236. "$right = (SELECT * FROM plato.Input2 LIMIT 2);\n"
  3237. "SELECT * FROM $left FULL JOIN $right USING (key);\n"
  3238. );
  3239. UNIT_ASSERT(!res.Root);
  3240. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:45: Error: At least one correlation name is required in join\n");
  3241. }
  3242. Y_UNIT_TEST(SelectJoinSameCorrNames) {
  3243. NYql::TAstParseResult res = SqlToYql("SELECT Input.key FROM plato.Input JOIN plato.Input1 ON Input.key == Input.subkey\n");
  3244. UNIT_ASSERT(!res.Root);
  3245. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:66: Error: JOIN: different correlation names are required for joined tables\n");
  3246. }
  3247. Y_UNIT_TEST(SelectJoinConstPredicateArg) {
  3248. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input1 as A JOIN plato.Input2 as B ON A.key == B.key AND A.subkey == \"wtf\"\n");
  3249. UNIT_ASSERT(!res.Root);
  3250. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:87: Error: JOIN: each equality predicate argument must depend on exactly one JOIN input\n");
  3251. }
  3252. Y_UNIT_TEST(SelectJoinNonEqualityPredicate) {
  3253. NYql::TAstParseResult res = SqlToYql("SELECT * FROM plato.Input1 as A JOIN plato.Input2 as B ON A.key == B.key AND A.subkey > B.subkey\n");
  3254. UNIT_ASSERT(!res.Root);
  3255. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:87: Error: JOIN ON expression must be a conjunction of equality predicates\n");
  3256. }
  3257. Y_UNIT_TEST(SelectEquiJoinCorrNameOutOfScope) {
  3258. NYql::TAstParseResult res = SqlToYql(
  3259. "PRAGMA equijoin;\n"
  3260. "SELECT * FROM plato.A JOIN plato.B ON A.key == C.key JOIN plato.C ON A.subkey == C.subkey;\n"
  3261. );
  3262. UNIT_ASSERT(!res.Root);
  3263. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:45: Error: JOIN: can not use source: C in equality predicate, it is out of current join scope\n");
  3264. }
  3265. Y_UNIT_TEST(SelectEquiJoinNoRightSource) {
  3266. NYql::TAstParseResult res = SqlToYql(
  3267. "PRAGMA equijoin;\n"
  3268. "SELECT * FROM plato.A JOIN plato.B ON A.key == B.key JOIN plato.C ON A.subkey == B.subkey;\n"
  3269. );
  3270. UNIT_ASSERT(!res.Root);
  3271. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:79: Error: JOIN ON equality predicate must have one of its arguments from the rightmost source\n");
  3272. }
  3273. Y_UNIT_TEST(SelectEquiJoinOuterWithoutType) {
  3274. NYql::TAstParseResult res = SqlToYql(
  3275. "SELECT * FROM plato.A Outer JOIN plato.B ON A.key == B.key;\n"
  3276. );
  3277. UNIT_ASSERT(!res.Root);
  3278. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:23: Error: Invalid join type: OUTER JOIN. OUTER keyword is optional and can only be used after LEFT, RIGHT or FULL\n");
  3279. }
  3280. Y_UNIT_TEST(SelectEquiJoinOuterWithWrongType) {
  3281. NYql::TAstParseResult res = SqlToYql(
  3282. "SELECT * FROM plato.A LEFT semi OUTER JOIN plato.B ON A.key == B.key;\n"
  3283. );
  3284. UNIT_ASSERT(!res.Root);
  3285. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:33: Error: Invalid join type: LEFT SEMI OUTER JOIN. OUTER keyword is optional and can only be used after LEFT, RIGHT or FULL\n");
  3286. }
  3287. Y_UNIT_TEST(InsertNoCluster) {
  3288. NYql::TAstParseResult res = SqlToYql("insert into Output (foo) values (1)");
  3289. UNIT_ASSERT(!res.Root);
  3290. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: No cluster name given and no default cluster is selected\n");
  3291. }
  3292. Y_UNIT_TEST(InsertValuesNoLabels) {
  3293. NYql::TAstParseResult res = SqlToYql("insert into plato.Output values (1)");
  3294. UNIT_ASSERT(!res.Root);
  3295. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:19: Error: INSERT INTO ... VALUES requires specification of table columns\n");
  3296. }
  3297. Y_UNIT_TEST(UpsertValuesNoLabelsKikimr) {
  3298. NYql::TAstParseResult res = SqlToYql("upsert into plato.Output values (1)", 10, TString(NYql::KikimrProviderName));
  3299. UNIT_ASSERT(!res.Root);
  3300. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:19: Error: UPSERT INTO ... VALUES requires specification of table columns\n");
  3301. }
  3302. Y_UNIT_TEST(ReplaceValuesNoLabelsKikimr) {
  3303. NYql::TAstParseResult res = SqlToYql("replace into plato.Output values (1)", 10, TString(NYql::KikimrProviderName));
  3304. UNIT_ASSERT(!res.Root);
  3305. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:20: Error: REPLACE INTO ... VALUES requires specification of table columns\n");
  3306. }
  3307. Y_UNIT_TEST(InsertValuesInvalidLabels) {
  3308. NYql::TAstParseResult res = SqlToYql("insert into plato.Output (foo) values (1, 2)");
  3309. UNIT_ASSERT(!res.Root);
  3310. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:27: Error: VALUES have 2 columns, INSERT INTO expects: 1\n");
  3311. }
  3312. Y_UNIT_TEST(BuiltinFileOpNoArgs) {
  3313. NYql::TAstParseResult res = SqlToYql("select FilePath()");
  3314. UNIT_ASSERT(!res.Root);
  3315. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: FilePath() requires exactly 1 arguments, given: 0\n");
  3316. }
  3317. Y_UNIT_TEST(ProcessWithHaving) {
  3318. NYql::TAstParseResult res = SqlToYql("process plato.Input using some::udf(value) having value == 1");
  3319. UNIT_ASSERT(!res.Root);
  3320. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:15: Error: PROCESS does not allow HAVING yet! You may request it on yql@ maillist.\n");
  3321. }
  3322. Y_UNIT_TEST(ReduceNoBy) {
  3323. NYql::TAstParseResult res = SqlToYql("reduce plato.Input using some::udf(value)");
  3324. UNIT_ASSERT(!res.Root);
  3325. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:19: Error: mismatched input 'using' expecting {',', ON, PRESORT}\n");
  3326. }
  3327. Y_UNIT_TEST(ReduceDistinct) {
  3328. NYql::TAstParseResult res = SqlToYql("reduce plato.Input on key using some::udf(distinct value)");
  3329. UNIT_ASSERT(!res.Root);
  3330. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:43: Error: DISTINCT can not be used in PROCESS/REDUCE\n");
  3331. }
  3332. Y_UNIT_TEST(CreateTableWithView) {
  3333. NYql::TAstParseResult res = SqlToYql("CREATE TABLE plato.foo:bar (key INT);");
  3334. UNIT_ASSERT(!res.Root);
  3335. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:22: Error: mismatched input ':' expecting '('\n");
  3336. }
  3337. Y_UNIT_TEST(AsteriskWithSomethingAfter) {
  3338. NYql::TAstParseResult res = SqlToYql("select *, LENGTH(value) from plato.Input;");
  3339. UNIT_ASSERT(!res.Root);
  3340. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Unable to use plain '*' with other projection items. Please use qualified asterisk instead: '<table>.*' (<table> can be either table name or table alias).\n");
  3341. }
  3342. Y_UNIT_TEST(AsteriskWithSomethingBefore) {
  3343. NYql::TAstParseResult res = SqlToYql("select LENGTH(value), * from plato.Input;");
  3344. UNIT_ASSERT(!res.Root);
  3345. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:23: Error: Unable to use plain '*' with other projection items. Please use qualified asterisk instead: '<table>.*' (<table> can be either table name or table alias).\n");
  3346. }
  3347. Y_UNIT_TEST(DuplicatedQualifiedAsterisk) {
  3348. NYql::TAstParseResult res = SqlToYql("select in.*, key, in.* from plato.Input as in;");
  3349. UNIT_ASSERT(!res.Root);
  3350. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:19: Error: Unable to use twice same quialified asterisk. Invalid source: in\n");
  3351. }
  3352. Y_UNIT_TEST(BrokenLabel) {
  3353. NYql::TAstParseResult res = SqlToYql("select in.*, key as `funny.label` from plato.Input as in;");
  3354. UNIT_ASSERT(!res.Root);
  3355. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:14: Error: Unable to use '.' in column name. Invalid column name: funny.label\n");
  3356. }
  3357. Y_UNIT_TEST(KeyConflictDetect0) {
  3358. NYql::TAstParseResult res = SqlToYql("select key, in.key as key from plato.Input as in;");
  3359. UNIT_ASSERT(!res.Root);
  3360. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:13: Error: Unable to use duplicate column names. Collision in name: key\n");
  3361. }
  3362. Y_UNIT_TEST(KeyConflictDetect1) {
  3363. NYql::TAstParseResult res = SqlToYql("select length(key) as key, key from plato.Input;");
  3364. UNIT_ASSERT(!res.Root);
  3365. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:28: Error: Unable to use duplicate column names. Collision in name: key\n");
  3366. }
  3367. Y_UNIT_TEST(KeyConflictDetect2) {
  3368. NYql::TAstParseResult res = SqlToYql("select key, in.key from plato.Input as in;");
  3369. UNIT_ASSERT(!res.Root);
  3370. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Duplicate column: key\n");
  3371. }
  3372. Y_UNIT_TEST(AutogenerationAliasWithCollisionConflict1) {
  3373. UNIT_ASSERT(SqlToYql("select LENGTH(Value), key as column0 from plato.Input;").IsOk());
  3374. }
  3375. Y_UNIT_TEST(AutogenerationAliasWithCollisionConflict2) {
  3376. UNIT_ASSERT(SqlToYql("select key as column1, LENGTH(Value) from plato.Input;").IsOk());
  3377. }
  3378. Y_UNIT_TEST(MissedSourceTableForQualifiedAsteriskOnSimpleSelect) {
  3379. NYql::TAstParseResult res = SqlToYql("use plato; select Intop.*, Input.key from plato.Input;");
  3380. UNIT_ASSERT(!res.Root);
  3381. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:19: Error: Unknown correlation name: Intop\n");
  3382. }
  3383. Y_UNIT_TEST(MissedSourceTableForQualifiedAsteriskOnJoin) {
  3384. NYql::TAstParseResult res = SqlToYql("use plato; select tmissed.*, t2.*, t1.key from plato.Input as t1 join plato.Input as t2 on t1.key==t2.key;");
  3385. UNIT_ASSERT(!res.Root);
  3386. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:19: Error: Unknown correlation name for asterisk: tmissed\n");
  3387. }
  3388. Y_UNIT_TEST(UnableToReferenceOnNotExistSubcolumn) {
  3389. NYql::TAstParseResult res = SqlToYql("select b.subkey from (select key from plato.Input as a) as b;");
  3390. UNIT_ASSERT(!res.Root);
  3391. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Column subkey is not in source column set\n");
  3392. }
  3393. Y_UNIT_TEST(ConflictOnSameNameWithQualify0) {
  3394. NYql::TAstParseResult res = SqlToYql("select in.key, in.key as key from plato.Input as in;");
  3395. UNIT_ASSERT(!res.Root);
  3396. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Duplicate column: key\n");
  3397. }
  3398. Y_UNIT_TEST(ConflictOnSameNameWithQualify1) {
  3399. NYql::TAstParseResult res = SqlToYql("select in.key, length(key) as key from plato.Input as in;");
  3400. UNIT_ASSERT(!res.Root);
  3401. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Duplicate column: key\n");
  3402. }
  3403. Y_UNIT_TEST(ConflictOnSameNameWithQualify2) {
  3404. NYql::TAstParseResult res = SqlToYql("select key, in.key from plato.Input as in;");
  3405. UNIT_ASSERT(!res.Root);
  3406. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Duplicate column: key\n");
  3407. }
  3408. Y_UNIT_TEST(ConflictOnSameNameWithQualify3) {
  3409. NYql::TAstParseResult res = SqlToYql("select in.key, subkey as key from plato.Input as in;");
  3410. UNIT_ASSERT(!res.Root);
  3411. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Duplicate column: key\n");
  3412. }
  3413. Y_UNIT_TEST(SelectFlattenBySameColumns) {
  3414. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key, key as kk)");
  3415. UNIT_ASSERT(!res.Root);
  3416. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:46: Error: Duplicate column name found: key in FlattenBy section\n");
  3417. }
  3418. Y_UNIT_TEST(SelectFlattenBySameAliases) {
  3419. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key as kk, subkey as kk);");
  3420. UNIT_ASSERT(!res.Root);
  3421. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:52: Error: Duplicate alias found: kk in FlattenBy section\n");
  3422. }
  3423. Y_UNIT_TEST(SelectFlattenByExprSameAliases) {
  3424. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key as kk, ListSkip(subkey,1) as kk);");
  3425. UNIT_ASSERT(!res.Root);
  3426. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:52: Error: Collision between alias and column name: kk in FlattenBy section\n");
  3427. }
  3428. Y_UNIT_TEST(SelectFlattenByConflictNameAndAlias0) {
  3429. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key, subkey as key);");
  3430. UNIT_ASSERT(!res.Root);
  3431. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:46: Error: Collision between alias and column name: key in FlattenBy section\n");
  3432. }
  3433. Y_UNIT_TEST(SelectFlattenByConflictNameAndAlias1) {
  3434. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key as kk, subkey as key);");
  3435. UNIT_ASSERT(!res.Root);
  3436. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:52: Error: Collision between alias and column name: key in FlattenBy section\n");
  3437. }
  3438. Y_UNIT_TEST(SelectFlattenByExprConflictNameAndAlias1) {
  3439. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key as kk, ListSkip(subkey,1) as key);");
  3440. UNIT_ASSERT(!res.Root);
  3441. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:52: Error: Duplicate column name found: key in FlattenBy section\n");
  3442. }
  3443. Y_UNIT_TEST(SelectFlattenByUnnamedExpr) {
  3444. NYql::TAstParseResult res = SqlToYql("select key from plato.Input flatten by (key, ListSkip(key, 1))");
  3445. UNIT_ASSERT(!res.Root);
  3446. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:46: Error: Unnamed expression after FLATTEN BY is not allowed\n");
  3447. }
  3448. Y_UNIT_TEST(UseInOnStrings) {
  3449. NYql::TAstParseResult res = SqlToYql("select * from plato.Input where \"foo\" in \"foovalue\";");
  3450. UNIT_ASSERT(!res.Root);
  3451. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:42: Error: Unable to use IN predicate with string argument, it won't search substring - "
  3452. "expecting tuple, list, dict or single column table source\n");
  3453. }
  3454. Y_UNIT_TEST(UseSubqueryInScalarContextInsideIn) {
  3455. NYql::TAstParseResult res = SqlToYql("$q = (select key from plato.Input); select * from plato.Input where subkey in ($q);");
  3456. UNIT_ASSERT(res.Root);
  3457. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:79: Warning: Using subrequest in scalar context after IN, "
  3458. "perhaps you should remove parenthesis here, code: 4501\n");
  3459. }
  3460. Y_UNIT_TEST(InHintsWithKeywordClash) {
  3461. NYql::TAstParseResult res = SqlToYql("SELECT COMPACT FROM plato.Input WHERE COMPACT IN COMPACT `COMPACT`(1,2,3)");
  3462. UNIT_ASSERT(!res.Root);
  3463. // should try to parse last compact as call expression
  3464. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:58: Error: Unknown builtin: COMPACT\n");
  3465. }
  3466. Y_UNIT_TEST(ErrorColumnPosition) {
  3467. NYql::TAstParseResult res = SqlToYql(
  3468. "USE plato;\n"
  3469. "SELECT \n"
  3470. "value FROM (\n"
  3471. "select key from Input\n"
  3472. ");\n"
  3473. );
  3474. UNIT_ASSERT(!res.Root);
  3475. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:1: Error: Column value is not in source column set\n");
  3476. }
  3477. Y_UNIT_TEST(PrimaryViewAbortMapReduce) {
  3478. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input VIEW PRIMARY KEY");
  3479. UNIT_ASSERT(!res.Root);
  3480. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:17: Error: primary view is not supported for yt tables\n");
  3481. }
  3482. Y_UNIT_TEST(InsertAbortMapReduce) {
  3483. NYql::TAstParseResult res = SqlToYql("INSERT OR ABORT INTO plato.Output SELECT key FROM plato.Input");
  3484. UNIT_ASSERT(!res.Root);
  3485. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:0: Error: INSERT OR ABORT INTO is not supported for yt tables\n");
  3486. }
  3487. Y_UNIT_TEST(ReplaceIntoMapReduce) {
  3488. NYql::TAstParseResult res = SqlToYql("REPLACE INTO plato.Output SELECT key FROM plato.Input");
  3489. UNIT_ASSERT(!res.Root);
  3490. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:0: Error: Meaning of REPLACE INTO has been changed, now you should use INSERT INTO <table> WITH TRUNCATE ... for yt\n");
  3491. }
  3492. Y_UNIT_TEST(UpsertIntoMapReduce) {
  3493. NYql::TAstParseResult res = SqlToYql("UPSERT INTO plato.Output SELECT key FROM plato.Input");
  3494. UNIT_ASSERT(!res.Root);
  3495. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:0: Error: UPSERT INTO is not supported for yt tables\n");
  3496. }
  3497. Y_UNIT_TEST(UpdateMapReduce) {
  3498. NYql::TAstParseResult res = SqlToYql("UPDATE plato.Output SET value = value + 1 WHERE key < 1");
  3499. UNIT_ASSERT(!res.Root);
  3500. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:0: Error: UPDATE is unsupported for yt\n");
  3501. }
  3502. Y_UNIT_TEST(DeleteMapReduce) {
  3503. NYql::TAstParseResult res = SqlToYql("DELETE FROM plato.Output WHERE key < 1");
  3504. UNIT_ASSERT(!res.Root);
  3505. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:0: Error: DELETE is unsupported for yt\n");
  3506. }
  3507. Y_UNIT_TEST(ReplaceIntoWithTruncate) {
  3508. NYql::TAstParseResult res = SqlToYql("REPLACE INTO plato.Output WITH TRUNCATE SELECT key FROM plato.Input");
  3509. UNIT_ASSERT(!res.Root);
  3510. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:32: Error: Unable REPLACE INTO with truncate mode\n");
  3511. }
  3512. Y_UNIT_TEST(UpsertIntoWithTruncate) {
  3513. NYql::TAstParseResult res = SqlToYql("UPSERT INTO plato.Output WITH TRUNCATE SELECT key FROM plato.Input");
  3514. UNIT_ASSERT(!res.Root);
  3515. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:31: Error: Unable UPSERT INTO with truncate mode\n");
  3516. }
  3517. Y_UNIT_TEST(InsertIntoWithTruncateKikimr) {
  3518. NYql::TAstParseResult res = SqlToYql("INSERT INTO plato.Output WITH TRUNCATE SELECT key FROM plato.Input", 10, TString(NYql::KikimrProviderName));
  3519. UNIT_ASSERT(!res.Root);
  3520. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:0: Error: INSERT INTO WITH TRUNCATE is not supported for kikimr tables\n");
  3521. }
  3522. Y_UNIT_TEST(InsertIntoWithWrongArgumentCount) {
  3523. NYql::TAstParseResult res = SqlToYql("insert into plato.Output with truncate (key, value, subkey) values (5, '1', '2', '3');");
  3524. UNIT_ASSERT(!res.Root);
  3525. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:53: Error: VALUES have 4 columns, INSERT INTO ... WITH TRUNCATE expects: 3\n");
  3526. }
  3527. Y_UNIT_TEST(UpsertWithWrongArgumentCount) {
  3528. NYql::TAstParseResult res = SqlToYql("upsert into plato.Output (key, value, subkey) values (2, '3');", 10, TString(NYql::KikimrProviderName));
  3529. UNIT_ASSERT(!res.Root);
  3530. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:39: Error: VALUES have 2 columns, UPSERT INTO expects: 3\n");
  3531. }
  3532. Y_UNIT_TEST(GroupingSetByExprWithoutAlias) {
  3533. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input GROUP BY GROUPING SETS (cast(key as uint32), subkey);");
  3534. UNIT_ASSERT(!res.Root);
  3535. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:53: Error: Unnamed expressions are not supported in GROUPING SETS. Please use '<expr> AS <name>'.\n");
  3536. }
  3537. Y_UNIT_TEST(GroupingSetByExprWithoutAlias2) {
  3538. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input GROUP BY subkey || subkey, GROUPING SETS (\n"
  3539. "cast(key as uint32), subkey);");
  3540. UNIT_ASSERT(!res.Root);
  3541. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:1: Error: Unnamed expressions are not supported in GROUPING SETS. Please use '<expr> AS <name>'.\n");
  3542. }
  3543. Y_UNIT_TEST(CubeByExprWithoutAlias) {
  3544. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input GROUP BY CUBE (key, subkey / key);");
  3545. UNIT_ASSERT(!res.Root);
  3546. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:56: Error: Unnamed expressions are not supported in CUBE. Please use '<expr> AS <name>'.\n");
  3547. }
  3548. Y_UNIT_TEST(RollupByExprWithoutAlias) {
  3549. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input GROUP BY ROLLUP (subkey / key);");
  3550. UNIT_ASSERT(!res.Root);
  3551. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:53: Error: Unnamed expressions are not supported in ROLLUP. Please use '<expr> AS <name>'.\n");
  3552. }
  3553. Y_UNIT_TEST(GroupByHugeCubeDeniedNoPragma) {
  3554. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input GROUP BY CUBE (key, subkey, value, key + subkey as sum, key - subkey as sub, key + val as keyval);");
  3555. UNIT_ASSERT(!res.Root);
  3556. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:119: Error: GROUP BY CUBE is allowed only for 5 columns, but you use 6\n");
  3557. }
  3558. Y_UNIT_TEST(GroupByInvalidPragma) {
  3559. NYql::TAstParseResult res = SqlToYql("PRAGMA GroupByCubeLimit = '-4';");
  3560. UNIT_ASSERT(!res.Root);
  3561. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:27: Error: Expected unsigned integer literal as a single argument for: GroupByCubeLimit\n");
  3562. }
  3563. Y_UNIT_TEST(GroupByHugeCubeDeniedPragme) {
  3564. NYql::TAstParseResult res = SqlToYql("PRAGMA GroupByCubeLimit = '4'; SELECT key FROM plato.Input GROUP BY CUBE (key, subkey, value, key + subkey as sum, key - subkey as sub);");
  3565. UNIT_ASSERT(!res.Root);
  3566. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:132: Error: GROUP BY CUBE is allowed only for 4 columns, but you use 5\n");
  3567. }
  3568. Y_UNIT_TEST(GroupByFewBigCubes) {
  3569. NYql::TAstParseResult res = SqlToYql("SELECT key FROM plato.Input GROUP BY CUBE(key, subkey, key + subkey as sum), CUBE(value, value + key + subkey as total);");
  3570. UNIT_ASSERT(!res.Root);
  3571. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Unable to GROUP BY more than 64 groups, you try use 80 groups\n");
  3572. }
  3573. Y_UNIT_TEST(GroupByFewBigCubesWithPragmaLimit) {
  3574. NYql::TAstParseResult res = SqlToYql("PRAGMA GroupByLimit = '16'; SELECT key FROM plato.Input GROUP BY GROUPING SETS(key, subkey, key + subkey as sum), ROLLUP(value, value + key + subkey as total);");
  3575. UNIT_ASSERT(!res.Root);
  3576. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:29: Error: Unable to GROUP BY more than 16 groups, you try use 18 groups\n");
  3577. }
  3578. Y_UNIT_TEST(NoGroupingColumn0) {
  3579. NYql::TAstParseResult res = SqlToYql(
  3580. "select count(1), key_first, val_first, grouping(key_first, val_first, nomind) as group\n"
  3581. "from plato.Input group by grouping sets (cast(key as uint32) /100 as key_first, Substring(value, 1, 1) as val_first);");
  3582. UNIT_ASSERT(!res.Root);
  3583. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:71: Error: Column 'nomind' is not a grouping column\n");
  3584. }
  3585. Y_UNIT_TEST(NoGroupingColumn1) {
  3586. NYql::TAstParseResult res = SqlToYql("select count(1), grouping(key, value) as group_duo from plato.Input group by cube (key, subkey);");
  3587. UNIT_ASSERT(!res.Root);
  3588. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:32: Error: Column 'value' is not a grouping column\n");
  3589. }
  3590. Y_UNIT_TEST(EmptyAccess0) {
  3591. NYql::TAstParseResult res = SqlToYql("insert into plato.Output (list0, list1) values (AsList(0, 1, 2), AsList(``));");
  3592. UNIT_ASSERT(!res.Root);
  3593. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:73: Error: Column reference \"\" is not allowed in current scope\n");
  3594. }
  3595. Y_UNIT_TEST(EmptyAccess1) {
  3596. NYql::TAstParseResult res = SqlToYql("insert into plato.Output (list0, list1) values (AsList(0, 1, 2), ``);");
  3597. UNIT_ASSERT(!res.Root);
  3598. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:66: Error: Column reference \"\" is not allowed in current scope\n");
  3599. }
  3600. Y_UNIT_TEST(UseUnknownColumnInInsert) {
  3601. NYql::TAstParseResult res = SqlToYql("insert into plato.Output (list0, list1) values (AsList(0, 1, 2), AsList(`test`));");
  3602. UNIT_ASSERT(!res.Root);
  3603. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:73: Error: Column reference \"test\" is not allowed in current scope\n");
  3604. }
  3605. Y_UNIT_TEST(GroupByEmptyColumn) {
  3606. NYql::TAstParseResult res = SqlToYql("select count(1) from plato.Input group by ``;");
  3607. UNIT_ASSERT(!res.Root);
  3608. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:43: Error: Column name can not be empty\n");
  3609. }
  3610. Y_UNIT_TEST(ConvertNumberOutOfBase) {
  3611. NYql::TAstParseResult res = SqlToYql("select 0o80l;");
  3612. UNIT_ASSERT(!res.Root);
  3613. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Failed to parse number from string: 0o80l, char: '8' is out of base: 8\n");
  3614. }
  3615. Y_UNIT_TEST(ConvertNumberOutOfRangeForInt64ButFitsInUint64) {
  3616. NYql::TAstParseResult res = SqlToYql("select 0xc000000000000000l;");
  3617. UNIT_ASSERT(!res.Root);
  3618. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Failed to parse 13835058055282163712 as integer literal of Int64 type: value out of range for Int64\n");
  3619. }
  3620. Y_UNIT_TEST(ConvertNumberOutOfRangeUint64) {
  3621. NYql::TAstParseResult res = SqlToYql("select 0xc0000000000000000l;");
  3622. UNIT_ASSERT(!res.Root);
  3623. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Failed to parse number from string: 0xc0000000000000000l, number limit overflow\n");
  3624. res = SqlToYql("select 1234234543563435151456;\n");
  3625. UNIT_ASSERT(!res.Root);
  3626. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Failed to parse number from string: 1234234543563435151456, number limit overflow\n");
  3627. }
  3628. Y_UNIT_TEST(ConvertNumberNegativeOutOfRange) {
  3629. NYql::TAstParseResult res = SqlToYql("select -9223372036854775808;\n"
  3630. "select -9223372036854775809;");
  3631. UNIT_ASSERT(!res.Root);
  3632. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:8: Error: Failed to parse negative integer: -9223372036854775809, number limit overflow\n");
  3633. }
  3634. Y_UNIT_TEST(InvaildUsageReal0) {
  3635. NYql::TAstParseResult res = SqlToYql("select .0;");
  3636. UNIT_ASSERT(!res.Root);
  3637. UNIT_ASSERT_STRING_CONTAINS(Err2Str(res), "<main>:1:7: Error: extraneous input '.' expecting {");
  3638. }
  3639. Y_UNIT_TEST(InvaildUsageReal1) {
  3640. NYql::TAstParseResult res = SqlToYql("select .0f;");
  3641. UNIT_ASSERT(!res.Root);
  3642. UNIT_ASSERT_STRING_CONTAINS(Err2Str(res), "<main>:1:7: Error: extraneous input '.' expecting {");
  3643. }
  3644. Y_UNIT_TEST(InvaildUsageWinFunctionWithoutWindow) {
  3645. NYql::TAstParseResult res = SqlToYql("select lead(key, 2) from plato.Input;");
  3646. UNIT_ASSERT(!res.Root);
  3647. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Failed to use window function Lead without window specification\n");
  3648. }
  3649. Y_UNIT_TEST(DropTableWithIfExists) {
  3650. NYql::TAstParseResult res = SqlToYql("DROP TABLE IF EXISTS plato.foo;");
  3651. UNIT_ASSERT(res.Root);
  3652. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  3653. if (word == "Write") {
  3654. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("drop_if_exists"));
  3655. }
  3656. };
  3657. TWordCountHive elementStat = { {TString("Write"), 0}};
  3658. VerifyProgram(res, elementStat, verifyLine);
  3659. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  3660. }
  3661. Y_UNIT_TEST(TooManyErrors) {
  3662. const char* q = R"(
  3663. USE plato;
  3664. select A, B, C, D, E, F, G, H, I, J, K, L, M, N from (select b from `abc`);
  3665. )";
  3666. NYql::TAstParseResult res = SqlToYql(q, 10);
  3667. UNIT_ASSERT(!res.Root);
  3668. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3669. R"(<main>:3:16: Error: Column A is not in source column set. Did you mean b?
  3670. <main>:3:19: Error: Column B is not in source column set. Did you mean b?
  3671. <main>:3:22: Error: Column C is not in source column set. Did you mean b?
  3672. <main>:3:25: Error: Column D is not in source column set. Did you mean b?
  3673. <main>:3:28: Error: Column E is not in source column set. Did you mean b?
  3674. <main>:3:31: Error: Column F is not in source column set. Did you mean b?
  3675. <main>:3:34: Error: Column G is not in source column set. Did you mean b?
  3676. <main>:3:37: Error: Column H is not in source column set. Did you mean b?
  3677. <main>:3:40: Error: Column I is not in source column set. Did you mean b?
  3678. <main>: Error: Too many issues, code: 1
  3679. )");
  3680. };
  3681. Y_UNIT_TEST(ShouldCloneBindingForNamedParameter) {
  3682. NYql::TAstParseResult res = SqlToYql(R"($f = () -> {
  3683. $value_type = TypeOf(1);
  3684. $pair_type = StructType(
  3685. TypeOf("2") AS key,
  3686. $value_type AS value
  3687. );
  3688. RETURN TupleType(
  3689. ListType($value_type),
  3690. $pair_type);
  3691. };
  3692. select FormatType($f());
  3693. )");
  3694. UNIT_ASSERT(res.Root);
  3695. }
  3696. Y_UNIT_TEST(BlockedInvalidFrameBounds) {
  3697. auto check = [](const TString& frame, const TString& err) {
  3698. const TString prefix = "SELECT SUM(x) OVER w FROM plato.Input WINDOW w AS (PARTITION BY key ORDER BY subkey\n";
  3699. NYql::TAstParseResult res = SqlToYql(prefix + frame + ")");
  3700. UNIT_ASSERT(!res.Root);
  3701. UNIT_ASSERT_NO_DIFF(Err2Str(res), err);
  3702. };
  3703. check("ROWS UNBOUNDED FOLLOWING", "<main>:2:5: Error: Frame cannot start from UNBOUNDED FOLLOWING\n");
  3704. check("ROWS BETWEEN 5 PRECEDING AND UNBOUNDED PRECEDING", "<main>:2:29: Error: Frame cannot end with UNBOUNDED PRECEDING\n");
  3705. check("ROWS BETWEEN CURRENT ROW AND 5 PRECEDING", "<main>:2:13: Error: Frame cannot start from CURRENT ROW and end with PRECEDING\n");
  3706. check("ROWS BETWEEN 5 FOLLOWING AND CURRENT ROW", "<main>:2:14: Error: Frame cannot start from FOLLOWING and end with CURRENT ROW\n");
  3707. check("ROWS BETWEEN 5 FOLLOWING AND 5 PRECEDING", "<main>:2:14: Error: Frame cannot start from FOLLOWING and end with PRECEDING\n");
  3708. }
  3709. Y_UNIT_TEST(BlockedRangeValueWithoutSingleOrderBy) {
  3710. UNIT_ASSERT(SqlToYql("SELECT COUNT(*) OVER (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM plato.Input").IsOk());
  3711. UNIT_ASSERT(SqlToYql("SELECT COUNT(*) OVER (RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) FROM plato.Input").IsOk());
  3712. auto res = SqlToYql("SELECT COUNT(*) OVER (RANGE 5 PRECEDING) FROM plato.Input");
  3713. UNIT_ASSERT(!res.Root);
  3714. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:29: Error: RANGE with <offset> PRECEDING/FOLLOWING requires exactly one expression in ORDER BY partition clause\n");
  3715. res = SqlToYql("SELECT COUNT(*) OVER (ORDER BY key, value RANGE 5 PRECEDING) FROM plato.Input");
  3716. UNIT_ASSERT(!res.Root);
  3717. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:49: Error: RANGE with <offset> PRECEDING/FOLLOWING requires exactly one expression in ORDER BY partition clause\n");
  3718. }
  3719. Y_UNIT_TEST(NoColumnsInFrameBounds) {
  3720. NYql::TAstParseResult res = SqlToYql(
  3721. "SELECT SUM(x) OVER w FROM plato.Input WINDOW w AS (ROWS BETWEEN\n"
  3722. " 1 + key PRECEDING AND 2 + key FOLLOWING);");
  3723. UNIT_ASSERT(!res.Root);
  3724. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:6: Error: Column reference \"key\" is not allowed in current scope\n");
  3725. }
  3726. Y_UNIT_TEST(WarnOnEmptyFrameBounds) {
  3727. NYql::TAstParseResult res = SqlToYql(
  3728. "SELECT SUM(x) OVER w FROM plato.Input WINDOW w AS (PARTITION BY key ORDER BY subkey\n"
  3729. "ROWS BETWEEN 10 FOLLOWING AND 5 FOLLOWING)");
  3730. UNIT_ASSERT(res.Root);
  3731. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:14: Warning: Used frame specification implies empty window frame, code: 4520\n");
  3732. }
  3733. Y_UNIT_TEST(WarnOnRankWithUnorderedWindow) {
  3734. NYql::TAstParseResult res = SqlToYql("SELECT RANK() OVER w FROM plato.Input WINDOW w AS ()");
  3735. UNIT_ASSERT(res.Root);
  3736. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Warning: Rank() is used with unordered window - all rows will be considered equal to each other, code: 4521\n");
  3737. }
  3738. Y_UNIT_TEST(WarnOnRankExprWithUnorderedWindow) {
  3739. NYql::TAstParseResult res = SqlToYql("SELECT RANK(key) OVER w FROM plato.Input WINDOW w AS ()");
  3740. UNIT_ASSERT(res.Root);
  3741. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Warning: Rank(<expression>) is used with unordered window - the result is likely to be undefined, code: 4521\n");
  3742. }
  3743. Y_UNIT_TEST(AnyAsTableName) {
  3744. NYql::TAstParseResult res = SqlToYql("use plato; select * from any;");
  3745. UNIT_ASSERT(!res.Root);
  3746. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:28: Error: no viable alternative at input 'any;'\n");
  3747. }
  3748. Y_UNIT_TEST(IncorrectOrderOfLambdaOptionalArgs) {
  3749. NYql::TAstParseResult res = SqlToYql("$f = ($x?, $y)->($x + $y); select $f(1);");
  3750. UNIT_ASSERT(!res.Root);
  3751. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Non-optional argument can not follow optional one\n");
  3752. }
  3753. Y_UNIT_TEST(IncorrectOrderOfActionOptionalArgs) {
  3754. NYql::TAstParseResult res = SqlToYql("define action $f($x?, $y) as select $x,$y; end define; do $f(1);");
  3755. UNIT_ASSERT(!res.Root);
  3756. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:23: Error: Non-optional argument can not follow optional one\n");
  3757. }
  3758. Y_UNIT_TEST(NotAllowedQuestionOnNamedNode) {
  3759. NYql::TAstParseResult res = SqlToYql("$f = 1; select $f?;");
  3760. UNIT_ASSERT(!res.Root);
  3761. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:18: Error: Unexpected token '?' at the end of expression\n");
  3762. }
  3763. Y_UNIT_TEST(AnyAndCrossJoin) {
  3764. NYql::TAstParseResult res = SqlToYql("use plato; select * from any Input1 cross join Input2");
  3765. UNIT_ASSERT(!res.Root);
  3766. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:26: Error: ANY should not be used with Cross JOIN\n");
  3767. res = SqlToYql("use plato; select * from Input1 cross join any Input2");
  3768. UNIT_ASSERT(!res.Root);
  3769. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:44: Error: ANY should not be used with Cross JOIN\n");
  3770. }
  3771. Y_UNIT_TEST(AnyWithCartesianProduct) {
  3772. NYql::TAstParseResult res = SqlToYql("pragma AnsiImplicitCrossJoin; use plato; select * from any Input1, Input2");
  3773. UNIT_ASSERT(!res.Root);
  3774. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:56: Error: ANY should not be used with Cross JOIN\n");
  3775. res = SqlToYql("pragma AnsiImplicitCrossJoin; use plato; select * from Input1, any Input2");
  3776. UNIT_ASSERT(!res.Root);
  3777. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:64: Error: ANY should not be used with Cross JOIN\n");
  3778. }
  3779. Y_UNIT_TEST(ErrorPlainEndAsInlineActionTerminator) {
  3780. NYql::TAstParseResult res = SqlToYql(
  3781. "do begin\n"
  3782. " select 1\n"
  3783. "; end\n");
  3784. UNIT_ASSERT(!res.Root);
  3785. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:0: Error: missing DO at '<EOF>'\n");
  3786. }
  3787. Y_UNIT_TEST(ErrorMultiWayJoinWithUsing) {
  3788. NYql::TAstParseResult res = SqlToYql(
  3789. "USE plato;\n"
  3790. "PRAGMA DisableSimpleColumns;\n"
  3791. "SELECT *\n"
  3792. "FROM Input1 AS a\n"
  3793. "JOIN Input2 AS b USING(key)\n"
  3794. "JOIN Input3 AS c ON a.key = c.key;\n"
  3795. );
  3796. UNIT_ASSERT(!res.Root);
  3797. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3798. "<main>:5:24: Error: Multi-way JOINs should be connected with ON clause instead of USING clause\n"
  3799. );
  3800. }
  3801. Y_UNIT_TEST(RequireLabelInFlattenByWithDot) {
  3802. NYql::TAstParseResult res = SqlToYql("select * from plato.Input flatten by x.y");
  3803. UNIT_ASSERT(!res.Root);
  3804. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  3805. "<main>:1:40: Error: Unnamed expression after FLATTEN BY is not allowed\n"
  3806. );
  3807. }
  3808. Y_UNIT_TEST(WarnUnnamedColumns) {
  3809. NYql::TAstParseResult res = SqlToYql(
  3810. "PRAGMA WarnUnnamedColumns;\n"
  3811. "\n"
  3812. "SELECT key, subkey, key || subkey FROM plato.Input ORDER BY subkey;\n");
  3813. UNIT_ASSERT(res.Root);
  3814. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:28: Warning: Autogenerated column name column2 will be used for expression, code: 4516\n");
  3815. }
  3816. Y_UNIT_TEST(WarnSourceColumnMismatch) {
  3817. NYql::TAstParseResult res = SqlToYql(
  3818. "insert into plato.Output (key, subkey, new_value, one_more_value) select key as Key, subkey, value, \"x\" from plato.Input;");
  3819. UNIT_ASSERT(res.Root);
  3820. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:51: Warning: Column names in SELECT don't match column specification in parenthesis. \"key\" doesn't match \"Key\". \"new_value\" doesn't match \"value\", code: 4517\n");
  3821. }
  3822. Y_UNIT_TEST(YtCaseInsensitive) {
  3823. NYql::TAstParseResult res = SqlToYql("select * from PlatO.foo;");
  3824. UNIT_ASSERT(res.Root);
  3825. res = SqlToYql("use PlatO; select * from foo;");
  3826. UNIT_ASSERT(res.Root);
  3827. }
  3828. Y_UNIT_TEST(KikimrCaseSensitive) {
  3829. NYql::TAstParseResult res = SqlToYql("select * from PlatO.foo;", 10, "kikimr");
  3830. UNIT_ASSERT(!res.Root);
  3831. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:15: Error: Unknown cluster: PlatO\n");
  3832. res = SqlToYql("use PlatO; select * from foo;", 10, "kikimr");
  3833. UNIT_ASSERT(!res.Root);
  3834. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:5: Error: Unknown cluster: PlatO\n");
  3835. }
  3836. Y_UNIT_TEST(DiscoveryModeForbidden) {
  3837. NYql::TAstParseResult res = SqlToYqlWithMode("insert into plato.Output select * from plato.range(\"\", Input1, Input4)", NSQLTranslation::ESqlMode::DISCOVERY);
  3838. UNIT_ASSERT(!res.Root);
  3839. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:40: Error: range is not allowed in Discovery mode, code: 4600\n");
  3840. res = SqlToYqlWithMode("insert into plato.Output select * from plato.like(\"\", \"Input%\")", NSQLTranslation::ESqlMode::DISCOVERY);
  3841. UNIT_ASSERT(!res.Root);
  3842. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:40: Error: like is not allowed in Discovery mode, code: 4600\n");
  3843. res = SqlToYqlWithMode("insert into plato.Output select * from plato.regexp(\"\", \"Input.\")", NSQLTranslation::ESqlMode::DISCOVERY);
  3844. UNIT_ASSERT(!res.Root);
  3845. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:40: Error: regexp is not allowed in Discovery mode, code: 4600\n");
  3846. res = SqlToYqlWithMode("insert into plato.Output select * from plato.filter(\"\", ($name) -> { return find($name, \"Input\") is not null; })", NSQLTranslation::ESqlMode::DISCOVERY);
  3847. UNIT_ASSERT(!res.Root);
  3848. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:40: Error: filter is not allowed in Discovery mode, code: 4600\n");
  3849. res = SqlToYqlWithMode("select Path from plato.folder(\"\") where Type == \"table\"", NSQLTranslation::ESqlMode::DISCOVERY);
  3850. UNIT_ASSERT(!res.Root);
  3851. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:18: Error: folder is not allowed in Discovery mode, code: 4600\n");
  3852. }
  3853. Y_UNIT_TEST(YsonFuncWithoutArgs) {
  3854. UNIT_ASSERT(SqlToYql("SELECT Yson::SerializeText(Yson::From());").IsOk());
  3855. }
  3856. Y_UNIT_TEST(CanNotUseOrderByInNonLastSelectInUnionAllChain) {
  3857. auto req = "pragma AnsiOrderByLimitInUnionAll;\n"
  3858. "use plato;\n"
  3859. "\n"
  3860. "select * from Input order by key\n"
  3861. "union all\n"
  3862. "select * from Input order by key limit 1;";
  3863. auto res = SqlToYql(req);
  3864. UNIT_ASSERT(!res.Root);
  3865. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:21: Error: ORDER BY within UNION ALL is only allowed after last subquery\n");
  3866. }
  3867. Y_UNIT_TEST(CanNotUseLimitInNonLastSelectInUnionAllChain) {
  3868. auto req = "pragma AnsiOrderByLimitInUnionAll;\n"
  3869. "use plato;\n"
  3870. "\n"
  3871. "select * from Input limit 1\n"
  3872. "union all\n"
  3873. "select * from Input order by key limit 1;";
  3874. auto res = SqlToYql(req);
  3875. UNIT_ASSERT(!res.Root);
  3876. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:21: Error: LIMIT within UNION ALL is only allowed after last subquery\n");
  3877. }
  3878. Y_UNIT_TEST(CanNotUseDiscardInNonFirstSelectInUnionAllChain) {
  3879. auto req = "pragma AnsiOrderByLimitInUnionAll;\n"
  3880. "use plato;\n"
  3881. "\n"
  3882. "select * from Input\n"
  3883. "union all\n"
  3884. "discard select * from Input;";
  3885. auto res = SqlToYql(req);
  3886. UNIT_ASSERT(!res.Root);
  3887. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:6:1: Error: DISCARD within UNION ALL is only allowed before first subquery\n");
  3888. }
  3889. Y_UNIT_TEST(CanNotUseIntoResultInNonLastSelectInUnionAllChain) {
  3890. auto req = "use plato;\n"
  3891. "pragma AnsiOrderByLimitInUnionAll;\n"
  3892. "\n"
  3893. "select * from Input\n"
  3894. "union all\n"
  3895. "discard select * from Input;";
  3896. auto res = SqlToYql(req);
  3897. UNIT_ASSERT(!res.Root);
  3898. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:6:1: Error: DISCARD within UNION ALL is only allowed before first subquery\n");
  3899. }
  3900. Y_UNIT_TEST(YsonStrictInvalidPragma) {
  3901. auto res = SqlToYql("pragma yson.Strict = \"wrong\";");
  3902. UNIT_ASSERT(!res.Root);
  3903. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:22: Error: Expected 'true', 'false' or no parameter for: Strict\n");
  3904. }
  3905. Y_UNIT_TEST(WarnTableNameInSomeContexts) {
  3906. UNIT_ASSERT(SqlToYql("use plato; select TableName() from Input;").IsOk());
  3907. UNIT_ASSERT(SqlToYql("use plato; select TableName(\"aaaa\");").IsOk());
  3908. UNIT_ASSERT(SqlToYql("select TableName(\"aaaa\", \"yt\");").IsOk());
  3909. auto res = SqlToYql("select TableName() from plato.Input;");
  3910. UNIT_ASSERT(!res.Root);
  3911. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: TableName requires either service name as second argument or current cluster name\n");
  3912. res = SqlToYql("use plato;\n"
  3913. "select TableName() from Input1 as a join Input2 as b using(key);");
  3914. UNIT_ASSERT(res.Root);
  3915. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:8: Warning: TableName() may produce empty result when used in ambiguous context (with JOIN), code: 4525\n");
  3916. res = SqlToYql("use plato;\n"
  3917. "select SOME(TableName()), key from Input group by key;");
  3918. UNIT_ASSERT(res.Root);
  3919. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:13: Warning: TableName() will produce empty result when used with aggregation.\n"
  3920. "Please consult documentation for possible workaround, code: 4525\n");
  3921. }
  3922. Y_UNIT_TEST(WarnOnDistincWithHavingWithoutAggregations) {
  3923. auto res = SqlToYql("select distinct key from plato.Input having key != '0';");
  3924. UNIT_ASSERT(res.Root);
  3925. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:49: Warning: The usage of HAVING without aggregations with SELECT DISTINCT is non-standard and will stop working soon. Please use WHERE instead., code: 4526\n");
  3926. }
  3927. Y_UNIT_TEST(FlattenByExprWithNestedNull) {
  3928. auto res = SqlToYql("USE plato;\n"
  3929. "\n"
  3930. "SELECT * FROM (SELECT 1 AS region_id)\n"
  3931. "FLATTEN BY (\n"
  3932. " CAST($unknown(region_id) AS List<String>) AS region\n"
  3933. ")");
  3934. UNIT_ASSERT(!res.Root);
  3935. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:10: Error: Unknown name: $unknown\n");
  3936. }
  3937. Y_UNIT_TEST(EmptySymbolNameIsForbidden) {
  3938. auto req = " $`` = 1; select $``;";
  3939. auto res = SqlToYql(req);
  3940. UNIT_ASSERT(!res.Root);
  3941. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:5: Error: Empty symbol name is not allowed\n");
  3942. }
  3943. Y_UNIT_TEST(WarnOnBinaryOpWithNullArg) {
  3944. auto req = "select * from plato.Input where cast(key as Int32) != NULL";
  3945. auto res = SqlToYql(req);
  3946. UNIT_ASSERT(res.Root);
  3947. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:52: Warning: Binary operation != will return NULL here, code: 4529\n");
  3948. req = "select 1 or null";
  3949. res = SqlToYql(req);
  3950. UNIT_ASSERT(res.Root);
  3951. UNIT_ASSERT_NO_DIFF(Err2Str(res), "");
  3952. }
  3953. Y_UNIT_TEST(ErrorIfTableSampleArgUsesColumns) {
  3954. auto req = "SELECT key FROM plato.Input TABLESAMPLE BERNOULLI(MIN_OF(100.0, CAST(subkey as Int32)));";
  3955. auto res = SqlToYql(req);
  3956. UNIT_ASSERT(!res.Root);
  3957. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:70: Error: Column reference \"subkey\" is not allowed in current scope\n");
  3958. }
  3959. Y_UNIT_TEST(DerivedColumnListForSelectIsNotSupportedYet) {
  3960. auto req = "SELECT a,b,c FROM plato.Input as t(x,y,z);";
  3961. auto res = SqlToYql(req);
  3962. UNIT_ASSERT(!res.Root);
  3963. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:35: Error: Derived column list is only supported for VALUES\n");
  3964. }
  3965. Y_UNIT_TEST(ErrorIfValuesHasDifferentCountOfColumns) {
  3966. auto req = "VALUES (1,2,3), (4,5);";
  3967. auto res = SqlToYql(req);
  3968. UNIT_ASSERT(!res.Root);
  3969. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:17: Error: All VALUES items should have same size: expecting 3, got 2\n");
  3970. }
  3971. Y_UNIT_TEST(ErrorIfDerivedColumnSizeExceedValuesColumnCount) {
  3972. auto req = "SELECT * FROM(VALUES (1,2), (3,4)) as t(x,y,z);";
  3973. auto res = SqlToYql(req);
  3974. UNIT_ASSERT(!res.Root);
  3975. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:40: Error: Derived column list size exceeds column count in VALUES\n");
  3976. }
  3977. Y_UNIT_TEST(WarnoOnAutogeneratedNamesForValues) {
  3978. auto req = "PRAGMA WarnUnnamedColumns;\n"
  3979. "SELECT * FROM (VALUES (1,2,3,4), (5,6,7,8)) as t(x,y);";
  3980. auto res = SqlToYql(req);
  3981. UNIT_ASSERT(res.Root);
  3982. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:16: Warning: Autogenerated column names column2...column3 will be used here, code: 4516\n");
  3983. }
  3984. Y_UNIT_TEST(ErrUnionAllWithOrderByWithoutExplicitLegacyMode) {
  3985. auto req = "use plato;\n"
  3986. "\n"
  3987. "select * from Input order by key\n"
  3988. "union all\n"
  3989. "select * from Input order by key;";
  3990. auto res = SqlToYql(req);
  3991. UNIT_ASSERT(!res.Root);
  3992. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:21: Error: ORDER BY within UNION ALL is only allowed after last subquery\n");
  3993. }
  3994. Y_UNIT_TEST(ErrUnionAllWithLimitWithoutExplicitLegacyMode) {
  3995. auto req = "use plato;\n"
  3996. "\n"
  3997. "select * from Input limit 10\n"
  3998. "union all\n"
  3999. "select * from Input limit 1;";
  4000. auto res = SqlToYql(req);
  4001. UNIT_ASSERT(!res.Root);
  4002. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:21: Error: LIMIT within UNION ALL is only allowed after last subquery\n");
  4003. }
  4004. Y_UNIT_TEST(ErrUnionAllWithIntoResultWithoutExplicitLegacyMode) {
  4005. auto req = "use plato;\n"
  4006. "\n"
  4007. "select * from Input into result aaa\n"
  4008. "union all\n"
  4009. "select * from Input;";
  4010. auto res = SqlToYql(req);
  4011. UNIT_ASSERT(!res.Root);
  4012. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:21: Error: INTO RESULT within UNION ALL is only allowed after last subquery\n");
  4013. }
  4014. Y_UNIT_TEST(ErrUnionAllWithDiscardWithoutExplicitLegacyMode) {
  4015. auto req = "use plato;\n"
  4016. "\n"
  4017. "select * from Input\n"
  4018. "union all\n"
  4019. "discard select * from Input;";
  4020. auto res = SqlToYql(req);
  4021. UNIT_ASSERT(!res.Root);
  4022. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:1: Error: DISCARD within UNION ALL is only allowed before first subquery\n");
  4023. }
  4024. Y_UNIT_TEST(ErrUnionAllKeepsIgnoredOrderByWarning) {
  4025. auto req = "use plato;\n"
  4026. "\n"
  4027. "SELECT * FROM (\n"
  4028. " SELECT * FROM Input\n"
  4029. " UNION ALL\n"
  4030. " SELECT t.* FROM Input AS t ORDER BY t.key\n"
  4031. ");";
  4032. auto res = SqlToYql(req);
  4033. UNIT_ASSERT(!res.Root);
  4034. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:3: Warning: ORDER BY without LIMIT in subquery will be ignored, code: 4504\n"
  4035. "<main>:6:39: Error: Unknown correlation name: t\n");
  4036. }
  4037. Y_UNIT_TEST(ErrOrderByIgnoredButCheckedForMissingColumns) {
  4038. auto req = "$src = SELECT key FROM (SELECT 1 as key, 2 as subkey) ORDER BY x; SELECT * FROM $src;";
  4039. ExpectFailWithError(req, "<main>:1:8: Warning: ORDER BY without LIMIT in subquery will be ignored, code: 4504\n"
  4040. "<main>:1:64: Error: Column x is not in source column set\n");
  4041. req = "$src = SELECT key FROM plato.Input ORDER BY x; SELECT * FROM $src;";
  4042. auto res = SqlToYql(req);
  4043. UNIT_ASSERT(res.Root);
  4044. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Warning: ORDER BY without LIMIT in subquery will be ignored, code: 4504\n");
  4045. }
  4046. Y_UNIT_TEST(InvalidTtlInterval) {
  4047. auto req = R"(
  4048. USE plato;
  4049. CREATE TABLE tableName (Key Uint32, CreatedAt Timestamp, PRIMARY KEY (Key))
  4050. WITH (TTL = 1 On CreatedAt);
  4051. )";
  4052. auto res = SqlToYql(req);
  4053. UNIT_ASSERT(!res.Root);
  4054. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:25: Error: Literal of Interval type is expected for TTL\n"
  4055. "<main>:4:25: Error: Invalid TTL settings\n");
  4056. }
  4057. Y_UNIT_TEST(InvalidTtlUnit) {
  4058. auto req = R"(
  4059. USE plato;
  4060. CREATE TABLE tableName (Key Uint32, CreatedAt Uint32, PRIMARY KEY (Key))
  4061. WITH (TTL = Interval("P1D") On CreatedAt AS PICOSECONDS);
  4062. )";
  4063. auto res = SqlToYql(req);
  4064. UNIT_ASSERT(!res.Root);
  4065. UNIT_ASSERT_STRING_CONTAINS(Err2Str(res), "mismatched input 'PICOSECONDS' expecting {MICROSECONDS, MILLISECONDS, NANOSECONDS, SECONDS}");
  4066. }
  4067. Y_UNIT_TEST(InvalidChangefeedSink) {
  4068. auto req = R"(
  4069. USE plato;
  4070. CREATE TABLE tableName (
  4071. Key Uint32, PRIMARY KEY (Key),
  4072. CHANGEFEED feedName WITH (SINK_TYPE = "S3", MODE = "KEYS_ONLY", FORMAT = "json")
  4073. );
  4074. )";
  4075. auto res = SqlToYql(req);
  4076. UNIT_ASSERT(!res.Root);
  4077. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:55: Error: Unknown changefeed sink type: S3\n");
  4078. }
  4079. Y_UNIT_TEST(InvalidChangefeedSettings) {
  4080. auto req = R"(
  4081. USE plato;
  4082. CREATE TABLE tableName (
  4083. Key Uint32, PRIMARY KEY (Key),
  4084. CHANGEFEED feedName WITH (SINK_TYPE = "local", FOO = "bar")
  4085. );
  4086. )";
  4087. auto res = SqlToYql(req);
  4088. UNIT_ASSERT(!res.Root);
  4089. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:64: Error: Unknown changefeed setting: FOO\n");
  4090. }
  4091. Y_UNIT_TEST(InvalidChangefeedInitialScan) {
  4092. auto req = R"(
  4093. USE plato;
  4094. CREATE TABLE tableName (
  4095. Key Uint32, PRIMARY KEY (Key),
  4096. CHANGEFEED feedName WITH (MODE = "KEYS_ONLY", FORMAT = "json", INITIAL_SCAN = "foo")
  4097. );
  4098. )";
  4099. auto res = SqlToYql(req);
  4100. UNIT_ASSERT(!res.Root);
  4101. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:95: Error: Literal of Bool type is expected for INITIAL_SCAN\n");
  4102. }
  4103. Y_UNIT_TEST(InvalidChangefeedVirtualTimestamps) {
  4104. auto req = R"(
  4105. USE plato;
  4106. CREATE TABLE tableName (
  4107. Key Uint32, PRIMARY KEY (Key),
  4108. CHANGEFEED feedName WITH (MODE = "KEYS_ONLY", FORMAT = "json", VIRTUAL_TIMESTAMPS = "foo")
  4109. );
  4110. )";
  4111. auto res = SqlToYql(req);
  4112. UNIT_ASSERT(!res.Root);
  4113. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:101: Error: Literal of Bool type is expected for VIRTUAL_TIMESTAMPS\n");
  4114. }
  4115. Y_UNIT_TEST(InvalidChangefeedResolvedTimestamps) {
  4116. auto req = R"(
  4117. USE plato;
  4118. CREATE TABLE tableName (
  4119. Key Uint32, PRIMARY KEY (Key),
  4120. CHANGEFEED feedName WITH (MODE = "KEYS_ONLY", FORMAT = "json", BARRIERS_INTERVAL = "foo")
  4121. );
  4122. )";
  4123. auto res = SqlToYql(req);
  4124. UNIT_ASSERT(!res.Root);
  4125. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:100: Error: Literal of Interval type is expected for BARRIERS_INTERVAL\n");
  4126. }
  4127. Y_UNIT_TEST(InvalidChangefeedRetentionPeriod) {
  4128. auto req = R"(
  4129. USE plato;
  4130. CREATE TABLE tableName (
  4131. Key Uint32, PRIMARY KEY (Key),
  4132. CHANGEFEED feedName WITH (MODE = "KEYS_ONLY", FORMAT = "json", RETENTION_PERIOD = "foo")
  4133. );
  4134. )";
  4135. auto res = SqlToYql(req);
  4136. UNIT_ASSERT(!res.Root);
  4137. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:99: Error: Literal of Interval type is expected for RETENTION_PERIOD\n");
  4138. }
  4139. Y_UNIT_TEST(InvalidChangefeedTopicPartitions) {
  4140. auto req = R"(
  4141. USE plato;
  4142. CREATE TABLE tableName (
  4143. Key Uint32, PRIMARY KEY (Key),
  4144. CHANGEFEED feedName WITH (MODE = "KEYS_ONLY", FORMAT = "json", TOPIC_MIN_ACTIVE_PARTITIONS = "foo")
  4145. );
  4146. )";
  4147. auto res = SqlToYql(req);
  4148. UNIT_ASSERT(!res.Root);
  4149. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:110: Error: Literal of integer type is expected for TOPIC_MIN_ACTIVE_PARTITIONS\n");
  4150. }
  4151. Y_UNIT_TEST(InvalidChangefeedAwsRegion) {
  4152. auto req = R"(
  4153. USE plato;
  4154. CREATE TABLE tableName (
  4155. Key Uint32, PRIMARY KEY (Key),
  4156. CHANGEFEED feedName WITH (MODE = "KEYS_ONLY", FORMAT = "json", AWS_REGION = true)
  4157. );
  4158. )";
  4159. auto res = SqlToYql(req);
  4160. UNIT_ASSERT(!res.Root);
  4161. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:5:93: Error: Literal of String type is expected for AWS_REGION\n");
  4162. }
  4163. Y_UNIT_TEST(ErrJoinWithGroupingSetsWithoutCorrelationName) {
  4164. auto req = "USE plato;\n"
  4165. "\n"
  4166. "SELECT k1, k2, subkey\n"
  4167. "FROM T1 AS a JOIN T2 AS b USING (key)\n"
  4168. "GROUP BY GROUPING SETS(\n"
  4169. " (a.key as k1, b.subkey as k2),\n"
  4170. " (k1),\n"
  4171. " (subkey)\n"
  4172. ");";
  4173. auto res = SqlToYql(req);
  4174. UNIT_ASSERT(!res.Root);
  4175. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:8:4: Error: Columns in grouping sets should have correlation name, error in key: subkey\n");
  4176. }
  4177. Y_UNIT_TEST(ErrJoinWithGroupByWithoutCorrelationName) {
  4178. auto req = "USE plato;\n"
  4179. "\n"
  4180. "SELECT k1, k2,\n"
  4181. " value\n"
  4182. "FROM T1 AS a JOIN T2 AS b USING (key)\n"
  4183. "GROUP BY a.key as k1, b.subkey as k2,\n"
  4184. " value;";
  4185. ExpectFailWithError(req,
  4186. "<main>:7:5: Error: Columns in GROUP BY should have correlation name, error in key: value\n");
  4187. }
  4188. Y_UNIT_TEST(ErrWithMissingFrom) {
  4189. auto req = "select 1 as key where 1 > 1;";
  4190. auto res = SqlToYql(req);
  4191. UNIT_ASSERT(!res.Root);
  4192. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:25: Error: Filtering is not allowed without FROM\n");
  4193. req = "select 1 + count(*);";
  4194. res = SqlToYql(req);
  4195. UNIT_ASSERT(!res.Root);
  4196. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:12: Error: Aggregation is not allowed without FROM\n");
  4197. req = "select 1 as key, subkey + value;";
  4198. res = SqlToYql(req);
  4199. UNIT_ASSERT(!res.Root);
  4200. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Column references are not allowed without FROM\n"
  4201. "<main>:1:18: Error: Column reference 'subkey'\n"
  4202. "<main>:1:1: Error: Column references are not allowed without FROM\n"
  4203. "<main>:1:27: Error: Column reference 'value'\n");
  4204. req = "select count(1) group by key;";
  4205. res = SqlToYql(req);
  4206. UNIT_ASSERT(!res.Root);
  4207. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:1: Error: Column references are not allowed without FROM\n"
  4208. "<main>:1:26: Error: Column reference 'key'\n");
  4209. }
  4210. Y_UNIT_TEST(ErrWithMissingFromForWindow) {
  4211. auto req = "$c = () -> (1 + count(1) over w);\n"
  4212. "select $c();";
  4213. ExpectFailWithError(req,
  4214. "<main>:1:9: Error: Window and aggregation functions are not allowed in this context\n"
  4215. "<main>:1:17: Error: Failed to use aggregation function Count without window specification or in wrong place\n");
  4216. req = "$c = () -> (1 + lead(1) over w);\n"
  4217. "select $c();";
  4218. ExpectFailWithError(req,
  4219. "<main>:1:17: Error: Window functions are not allowed in this context\n"
  4220. "<main>:1:17: Error: Failed to use window function Lead without window specification or in wrong place\n");
  4221. req = "select 1 + count(1) over w window w as ();";
  4222. ExpectFailWithError(req,
  4223. "<main>:1:1: Error: Window and aggregation functions are not allowed without FROM\n"
  4224. "<main>:1:12: Error: Failed to use aggregation function Count without window specification or in wrong place\n");
  4225. req = "select 1 + lead(1) over w window w as ();";
  4226. ExpectFailWithError(req,
  4227. "<main>:1:12: Error: Window functions are not allowed without FROM\n"
  4228. "<main>:1:12: Error: Failed to use window function Lead without window specification or in wrong place\n");
  4229. }
  4230. Y_UNIT_TEST(ErrWithMissingFromForInplaceWindow) {
  4231. auto req = "$c = () -> (1 + count(1) over ());\n"
  4232. "select $c();";
  4233. ExpectFailWithError(req,
  4234. "<main>:1:26: Error: Window and aggregation functions are not allowed in this context\n");
  4235. req = "$c = () -> (1 + lead(1) over (rows between unbounded preceding and current row));\n"
  4236. "select $c();";
  4237. ExpectFailWithError(req,
  4238. "<main>:1:25: Error: Window and aggregation functions are not allowed in this context\n");
  4239. req = "select 1 + count(1) over ();";
  4240. ExpectFailWithError(req,
  4241. "<main>:1:1: Error: Window and aggregation functions are not allowed without FROM\n"
  4242. "<main>:1:12: Error: Failed to use aggregation function Count without window specification or in wrong place\n");
  4243. req = "select 1 + lead(1) over (rows between current row and unbounded following);";
  4244. ExpectFailWithError(req,
  4245. "<main>:1:12: Error: Window functions are not allowed without FROM\n"
  4246. "<main>:1:12: Error: Failed to use window function Lead without window specification or in wrong place\n");
  4247. }
  4248. Y_UNIT_TEST(ErrDistinctInWrongPlace) {
  4249. auto req = "select Some::Udf(distinct key) from plato.Input;";
  4250. ExpectFailWithError(req,
  4251. "<main>:1:18: Error: DISTINCT can only be used in aggregation functions\n");
  4252. req = "select sum(key)(distinct foo) from plato.Input;";
  4253. ExpectFailWithError(req,
  4254. "<main>:1:17: Error: DISTINCT can only be used in aggregation functions\n");
  4255. req = "select len(distinct foo) from plato.Input;";
  4256. ExpectFailWithError(req,
  4257. "<main>:1:8: Error: DISTINCT can only be used in aggregation functions\n");
  4258. req = "$foo = ($x) -> ($x); select $foo(distinct key) from plato.Input;";
  4259. ExpectFailWithError(req,
  4260. "<main>:1:34: Error: DISTINCT can only be used in aggregation functions\n");
  4261. }
  4262. Y_UNIT_TEST(ErrForNotSingleChildInInlineAST) {
  4263. ExpectFailWithError("select YQL::\"\"",
  4264. "<main>:1:8: Error: Failed to parse YQL: expecting AST root node with single child, but got 0\n");
  4265. ExpectFailWithError("select YQL::@@ \t@@",
  4266. "<main>:1:8: Error: Failed to parse YQL: expecting AST root node with single child, but got 0\n");
  4267. auto req = "$lambda = YQL::@@(lambda '(x)(+ x x)) (lambda '(y)(+ y y))@@;\n"
  4268. "select ListMap([1, 2, 3], $lambda);";
  4269. ExpectFailWithError(req,
  4270. "<main>:1:11: Error: Failed to parse YQL: expecting AST root node with single child, but got 2\n");
  4271. }
  4272. Y_UNIT_TEST(ErrEmptyColumnName) {
  4273. ExpectFailWithError("select * without \"\" from plato.Input",
  4274. "<main>:1:18: Error: String literal can not be used here\n");
  4275. ExpectFailWithError("select * without `` from plato.Input;",
  4276. "<main>:1:18: Error: Empty column name is not allowed\n");
  4277. ExpectFailWithErrorForAnsiLexer("select * without \"\" from plato.Input",
  4278. "<main>:1:18: Error: Empty column name is not allowed\n");
  4279. ExpectFailWithErrorForAnsiLexer("select * without `` from plato.Input;",
  4280. "<main>:1:18: Error: Empty column name is not allowed\n");
  4281. }
  4282. Y_UNIT_TEST(ErrOnNonZeroArgumentsForTableRows) {
  4283. ExpectFailWithError("$udf=\"\";process plato.Input using $udf(TableRows(k))",
  4284. "<main>:1:40: Error: TableRows requires exactly 0 arguments\n");
  4285. }
  4286. Y_UNIT_TEST(ErrGroupByWithAggregationFunctionAndDistinctExpr) {
  4287. ExpectFailWithError("select * from plato.Input group by count(distinct key|key)",
  4288. "<main>:1:36: Error: Unable to GROUP BY aggregated values\n");
  4289. }
  4290. // FIXME: check if we can get old behaviour
  4291. #if 0
  4292. Y_UNIT_TEST(ErrWithSchemaWithColumnsWithoutType) {
  4293. ExpectFailWithError("select * from plato.Input with COLUMNs",
  4294. "<main>:1:32: Error: Expected type after COLUMNS\n"
  4295. "<main>:1:32: Error: Failed to parse table hints\n");
  4296. ExpectFailWithError("select * from plato.Input with scheMa",
  4297. "<main>:1:32: Error: Expected type after SCHEMA\n"
  4298. "<main>:1:32: Error: Failed to parse table hints\n");
  4299. }
  4300. #endif
  4301. Y_UNIT_TEST(ErrCollectPreaggregatedInListLiteralWithoutFrom) {
  4302. ExpectFailWithError("SELECT([VARIANCE(DISTINCT[])])",
  4303. "<main>:1:1: Error: Column references are not allowed without FROM\n"
  4304. "<main>:1:9: Error: Column reference '_yql_preagg_Variance0'\n");
  4305. }
  4306. Y_UNIT_TEST(ErrGroupBySmartParenAsTuple) {
  4307. ExpectFailWithError("SELECT * FROM plato.Input GROUP BY (k, v,)",
  4308. "<main>:1:41: Error: Unexpected trailing comma in grouping elements list\n");
  4309. }
  4310. Y_UNIT_TEST(HandleNestedSmartParensInGroupBy) {
  4311. ExpectFailWithError("SELECT * FROM plato.Input GROUP BY (+() as k)",
  4312. "<main>:1:37: Error: Unable to GROUP BY constant expression\n");
  4313. }
  4314. Y_UNIT_TEST(ErrRenameWithAddColumn) {
  4315. ExpectFailWithError("USE plato; ALTER TABLE table RENAME TO moved, ADD COLUMN addc uint64",
  4316. "<main>:1:40: Error: RENAME TO can not be used together with another table action\n");
  4317. }
  4318. Y_UNIT_TEST(ErrAddColumnAndRename) {
  4319. // FIXME: fix positions in ALTER TABLE
  4320. ExpectFailWithError("USE plato; ALTER TABLE table ADD COLUMN addc uint64, RENAME TO moved",
  4321. "<main>:1:46: Error: RENAME TO can not be used together with another table action\n");
  4322. }
  4323. Y_UNIT_TEST(InvalidUuidValue) {
  4324. ExpectFailWithError("SELECT Uuid('123e4567ae89ba12d3aa456a426614174ab0')",
  4325. "<main>:1:8: Error: Invalid value \"123e4567ae89ba12d3aa456a426614174ab0\" for type Uuid\n");
  4326. ExpectFailWithError("SELECT Uuid('123e4567ae89b-12d3-a456-426614174000')",
  4327. "<main>:1:8: Error: Invalid value \"123e4567ae89b-12d3-a456-426614174000\" for type Uuid\n");
  4328. }
  4329. Y_UNIT_TEST(WindowFunctionWithoutOver) {
  4330. ExpectFailWithError("SELECT LAST_VALUE(foo) FROM plato.Input",
  4331. "<main>:1:8: Error: Can't use window function LastValue without window specification (OVER keyword is missing)\n");
  4332. ExpectFailWithError("SELECT LAST_VALUE(foo) FROM plato.Input GROUP BY key",
  4333. "<main>:1:8: Error: Can't use window function LastValue without window specification (OVER keyword is missing)\n");
  4334. }
  4335. Y_UNIT_TEST(CreateAlterUserWithoutCluster) {
  4336. ExpectFailWithError("\n CREATE USER user ENCRYPTED PASSWORD 'foobar';", "<main>:2:2: Error: USE statement is missing - no default cluster is selected\n");
  4337. ExpectFailWithError("ALTER USER CURRENT_USER RENAME TO $foo;", "<main>:1:1: Error: USE statement is missing - no default cluster is selected\n");
  4338. }
  4339. Y_UNIT_TEST(ModifyPermissionsWithoutCluster) {
  4340. ExpectFailWithError("\n GRANT CONNECT ON `/Root` TO user;", "<main>:2:2: Error: USE statement is missing - no default cluster is selected\n");
  4341. ExpectFailWithError("\n REVOKE MANAGE ON `/Root` FROM user;", "<main>:2:2: Error: USE statement is missing - no default cluster is selected\n");
  4342. }
  4343. Y_UNIT_TEST(ReservedRoleNames) {
  4344. ExpectFailWithError("USE plato; CREATE USER current_User;", "<main>:1:24: Error: System role CURRENT_USER can not be used here\n");
  4345. ExpectFailWithError("USE plato; ALTER USER current_User RENAME TO Current_role", "<main>:1:46: Error: System role CURRENT_ROLE can not be used here\n");
  4346. UNIT_ASSERT(SqlToYql("USE plato; DROP GROUP IF EXISTS a, b, c, current_User;").IsOk());
  4347. }
  4348. Y_UNIT_TEST(DisableClassicDivisionWithError) {
  4349. ExpectFailWithError("pragma ClassicDivision = 'false'; select $foo / 30;", "<main>:1:42: Error: Unknown name: $foo\n");
  4350. }
  4351. Y_UNIT_TEST(AggregationOfAgrregatedDistinctExpr) {
  4352. ExpectFailWithError("select sum(sum(distinct x + 1)) from plato.Input", "<main>:1:12: Error: Aggregation of aggregated values is forbidden\n");
  4353. }
  4354. Y_UNIT_TEST(WarnForUnusedSqlHint) {
  4355. NYql::TAstParseResult res = SqlToYql("select * from plato.Input1 as a join /*+ merge() */ plato.Input2 as b using(key);\n"
  4356. "select --+ foo(bar)\n"
  4357. " 1;");
  4358. UNIT_ASSERT(res.Root);
  4359. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:23: Warning: Hint foo will not be used, code: 4534\n");
  4360. }
  4361. Y_UNIT_TEST(WarnForDeprecatedSchema) {
  4362. NSQLTranslation::TTranslationSettings settings;
  4363. settings.ClusterMapping["s3bucket"] = NYql::S3ProviderName;
  4364. NYql::TAstParseResult res = SqlToYqlWithSettings("select * from s3bucket.`foo` with schema (col1 Int32, String as col2, Int64 as col3);", settings);
  4365. UNIT_ASSERT(res.Root);
  4366. UNIT_ASSERT_STRING_CONTAINS(res.Issues.ToString(), "Warning: Deprecated syntax for positional schema: please use 'column type' instead of 'type AS column', code: 4535\n");
  4367. }
  4368. Y_UNIT_TEST(ErrorOnColumnNameInMaxByLimit) {
  4369. ExpectFailWithError(
  4370. "SELECT AGGREGATE_BY(AsTuple(value, key), AggregationFactory(\"MAX_BY\", subkey)) FROM plato.Input;",
  4371. "<main>:1:42: Error: Source does not allow column references\n"
  4372. "<main>:1:71: Error: Column reference 'subkey'\n");
  4373. }
  4374. Y_UNIT_TEST(ErrorInLibraryWithTopLevelNamedSubquery) {
  4375. TString withUnusedSubq = "$unused = select max(key) from plato.Input;\n"
  4376. "\n"
  4377. "define subquery $foo() as\n"
  4378. " $count = select count(*) from plato.Input;\n"
  4379. " select * from plato.Input limit $count / 2;\n"
  4380. "end define;\n"
  4381. "export $foo;\n";
  4382. UNIT_ASSERT(SqlToYqlWithMode(withUnusedSubq, NSQLTranslation::ESqlMode::LIBRARY).IsOk());
  4383. TString withTopLevelSubq = "$count = select count(*) from plato.Input;\n"
  4384. "\n"
  4385. "define subquery $foo() as\n"
  4386. " select * from plato.Input limit $count / 2;\n"
  4387. "end define;\n"
  4388. "export $foo;\n";
  4389. auto res = SqlToYqlWithMode(withTopLevelSubq, NSQLTranslation::ESqlMode::LIBRARY);
  4390. UNIT_ASSERT(!res.Root);
  4391. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:17: Error: Named subquery can not be used as a top level statement in libraries\n");
  4392. }
  4393. Y_UNIT_TEST(SessionStartAndSessionStateShouldSurviveSessionWindowArgsError){
  4394. TString query = R"(
  4395. $init = ($_row) -> (min(1, 2)); -- error: aggregation func min() can not be used here
  4396. $calculate = ($_row, $_state) -> (1);
  4397. $update = ($_row, $_state) -> (2);
  4398. SELECT
  4399. SessionStart() over w as session_start,
  4400. SessionState() over w as session_state,
  4401. FROM plato.Input as t
  4402. WINDOW w AS (
  4403. PARTITION BY user, SessionWindow(ts + 1, $init, $update, $calculate)
  4404. )
  4405. )";
  4406. ExpectFailWithError(query, "<main>:2:33: Error: Aggregation function Min requires exactly 1 argument(s), given: 2\n");
  4407. }
  4408. Y_UNIT_TEST(ScalarContextUsage1) {
  4409. TString query = R"(
  4410. $a = (select 1 as x, 2 as y);
  4411. select 1 + $a;
  4412. )";
  4413. ExpectFailWithError(query, "<main>:2:39: Error: Source used in expression should contain one concrete column\n"
  4414. "<main>:3:24: Error: Source is used here\n");
  4415. }
  4416. Y_UNIT_TEST(ScalarContextUsage2) {
  4417. TString query = R"(
  4418. use plato;
  4419. $a = (select 1 as x, 2 as y);
  4420. select * from concat($a);
  4421. )";
  4422. ExpectFailWithError(query, "<main>:3:39: Error: Source used in expression should contain one concrete column\n"
  4423. "<main>:4:34: Error: Source is used here\n");
  4424. }
  4425. Y_UNIT_TEST(ScalarContextUsage3) {
  4426. TString query = R"(
  4427. use plato;
  4428. $a = (select 1 as x, 2 as y);
  4429. select * from range($a);
  4430. )";
  4431. ExpectFailWithError(query, "<main>:3:39: Error: Source used in expression should contain one concrete column\n"
  4432. "<main>:4:33: Error: Source is used here\n");
  4433. }
  4434. Y_UNIT_TEST(ScalarContextUsage4) {
  4435. TString query = R"(
  4436. use plato;
  4437. $a = (select 1 as x, 2 as y);
  4438. insert into $a select 1;
  4439. )";
  4440. ExpectFailWithError(query, "<main>:3:39: Error: Source used in expression should contain one concrete column\n"
  4441. "<main>:4:25: Error: Source is used here\n");
  4442. }
  4443. }
  4444. void CheckUnused(const TString& req, const TString& symbol, unsigned row, unsigned col) {
  4445. auto res = SqlToYql(req);
  4446. UNIT_ASSERT(res.Root);
  4447. UNIT_ASSERT_NO_DIFF(Err2Str(res), TStringBuilder() << "<main>:" << row << ":" << col << ": Warning: Symbol " << symbol << " is not used, code: 4527\n");
  4448. }
  4449. Y_UNIT_TEST_SUITE(WarnUnused) {
  4450. Y_UNIT_TEST(ActionOrSubquery) {
  4451. TString req = " $a()\n"
  4452. "as select 1;\n"
  4453. "end define;\n"
  4454. "\n"
  4455. "select 1;";
  4456. CheckUnused("define action\n" + req, "$a", 2, 3);
  4457. CheckUnused("define subquery\n" + req, "$a", 2, 3);
  4458. }
  4459. Y_UNIT_TEST(Import) {
  4460. TString req = "import lib1 symbols\n"
  4461. " $sqr;\n"
  4462. "select 1;";
  4463. CheckUnused(req, "$sqr", 2, 3);
  4464. req = "import lib1 symbols\n"
  4465. " $sqr as\n"
  4466. " $sq;\n"
  4467. "select 1;";
  4468. CheckUnused(req, "$sq", 3, 5);
  4469. }
  4470. Y_UNIT_TEST(NamedNodeStatement) {
  4471. TString req = " $a, $a = AsTuple(1, 2);\n"
  4472. "select $a;";
  4473. CheckUnused(req, "$a", 1, 2);
  4474. req = "$a, $b = AsTuple(1, 2);\n"
  4475. "select $a;";
  4476. CheckUnused(req, "$b", 1, 6);
  4477. CheckUnused(" $a = 1; $a = 2; select $a;", "$a", 1, 2);
  4478. }
  4479. Y_UNIT_TEST(Declare) {
  4480. CheckUnused("declare $a as String;select 1;", "$a", 1, 9);
  4481. }
  4482. Y_UNIT_TEST(ActionParams) {
  4483. TString req = "define action $a($x, $y) as\n"
  4484. " select $x;\n"
  4485. "end define;\n"
  4486. "\n"
  4487. "do $a(1,2);";
  4488. CheckUnused(req, "$y", 1, 22);
  4489. }
  4490. Y_UNIT_TEST(SubqueryParams) {
  4491. TString req = "use plato;\n"
  4492. "define subquery $q($name, $x) as\n"
  4493. " select * from $name;\n"
  4494. "end define;\n"
  4495. "\n"
  4496. "select * from $q(\"Input\", 1);";
  4497. CheckUnused(req, "$x", 2, 27);
  4498. }
  4499. Y_UNIT_TEST(For) {
  4500. TString req = "define action $a() as\n"
  4501. " select 1;\n"
  4502. "end define;\n"
  4503. "\n"
  4504. "for $i in ListFromRange(1, 10)\n"
  4505. "do $a();";
  4506. CheckUnused(req, "$i", 5, 5);
  4507. }
  4508. Y_UNIT_TEST(LambdaParams) {
  4509. TString req = "$lambda = ($x, $y) -> ($x);\n"
  4510. "select $lambda(1, 2);";
  4511. CheckUnused(req, "$y", 1, 16);
  4512. }
  4513. Y_UNIT_TEST(InsideLambdaBody) {
  4514. TString req = "$lambda = () -> {\n"
  4515. " $x = 1; return 1;\n"
  4516. "};\n"
  4517. "select $lambda();";
  4518. CheckUnused(req, "$x", 2, 3);
  4519. req = "$lambda = () -> {\n"
  4520. " $x = 1; $x = 2; return $x;\n"
  4521. "};\n"
  4522. "select $lambda();";
  4523. CheckUnused(req, "$x", 2, 3);
  4524. }
  4525. Y_UNIT_TEST(InsideAction) {
  4526. TString req = "define action $a() as\n"
  4527. " $x = 1; select 1;\n"
  4528. "end define;\n"
  4529. "\n"
  4530. "do $a();";
  4531. CheckUnused(req, "$x", 2, 3);
  4532. req = "define action $a() as\n"
  4533. " $x = 1; $x = 2; select $x;\n"
  4534. "end define;\n"
  4535. "\n"
  4536. "do $a();";
  4537. CheckUnused(req, "$x", 2, 3);
  4538. }
  4539. Y_UNIT_TEST(NoWarnOnNestedActions) {
  4540. auto req = "pragma warning(\"error\", \"4527\");\n"
  4541. "define action $action($b) as\n"
  4542. " define action $aaa() as\n"
  4543. " select $b;\n"
  4544. " end define;\n"
  4545. " do $aaa();\n"
  4546. "end define;\n"
  4547. "\n"
  4548. "do $action(1);";
  4549. UNIT_ASSERT(SqlToYql(req).IsOk());
  4550. }
  4551. Y_UNIT_TEST(NoWarnForUsageAfterSubquery) {
  4552. auto req = "use plato;\n"
  4553. "pragma warning(\"error\", \"4527\");\n"
  4554. "\n"
  4555. "$a = 1;\n"
  4556. "\n"
  4557. "define subquery $q($table) as\n"
  4558. " select * from $table;\n"
  4559. "end define;\n"
  4560. "\n"
  4561. "select * from $q(\"Input\");\n"
  4562. "select $a;";
  4563. UNIT_ASSERT(SqlToYql(req).IsOk());
  4564. }
  4565. }
  4566. Y_UNIT_TEST_SUITE(AnonymousNames) {
  4567. Y_UNIT_TEST(ReferenceAnonymousVariableIsForbidden) {
  4568. auto req = "$_ = 1; select $_;";
  4569. auto res = SqlToYql(req);
  4570. UNIT_ASSERT(!res.Root);
  4571. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:16: Error: Unable to reference anonymous name $_\n");
  4572. req = "$`_` = 1; select $`_`;";
  4573. res = SqlToYql(req);
  4574. UNIT_ASSERT(!res.Root);
  4575. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:18: Error: Unable to reference anonymous name $_\n");
  4576. }
  4577. Y_UNIT_TEST(Declare) {
  4578. auto req = "declare $_ as String;";
  4579. auto res = SqlToYql(req);
  4580. UNIT_ASSERT(!res.Root);
  4581. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:9: Error: Can not use anonymous name '$_' in DECLARE statement\n");
  4582. }
  4583. Y_UNIT_TEST(ActionSubquery) {
  4584. auto req = "define action $_() as select 1; end define;";
  4585. auto res = SqlToYql(req);
  4586. UNIT_ASSERT(!res.Root);
  4587. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:15: Error: Can not use anonymous name '$_' as ACTION name\n");
  4588. req = "define subquery $_() as select 1; end define;";
  4589. res = SqlToYql(req);
  4590. UNIT_ASSERT(!res.Root);
  4591. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:17: Error: Can not use anonymous name '$_' as SUBQUERY name\n");
  4592. }
  4593. Y_UNIT_TEST(Import) {
  4594. auto req = "import lib symbols $sqr as $_;";
  4595. auto res = SqlToYql(req);
  4596. UNIT_ASSERT(!res.Root);
  4597. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:28: Error: Can not import anonymous name $_\n");
  4598. }
  4599. Y_UNIT_TEST(Export) {
  4600. auto req = "export $_;";
  4601. auto res = SqlToYqlWithMode(req, NSQLTranslation::ESqlMode::LIBRARY);
  4602. UNIT_ASSERT(!res.Root);
  4603. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:8: Error: Can not export anonymous name $_\n");
  4604. }
  4605. Y_UNIT_TEST(AnonymousInActionArgs) {
  4606. auto req = "pragma warning(\"error\", \"4527\");\n"
  4607. "define action $a($_, $y, $_) as\n"
  4608. " select $y;\n"
  4609. "end define;\n"
  4610. "\n"
  4611. "do $a(1,2,3);";
  4612. UNIT_ASSERT(SqlToYql(req).IsOk());
  4613. }
  4614. Y_UNIT_TEST(AnonymousInSubqueryArgs) {
  4615. auto req = "use plato;\n"
  4616. "pragma warning(\"error\", \"4527\");\n"
  4617. "define subquery $q($_, $y, $_) as\n"
  4618. " select * from $y;\n"
  4619. "end define;\n"
  4620. "\n"
  4621. "select * from $q(1,\"Input\",3);";
  4622. UNIT_ASSERT(SqlToYql(req).IsOk());
  4623. }
  4624. Y_UNIT_TEST(AnonymousInLambdaArgs) {
  4625. auto req = "pragma warning(\"error\", \"4527\");\n"
  4626. "$lambda = ($_, $x, $_) -> ($x);\n"
  4627. "select $lambda(1,2,3);";
  4628. UNIT_ASSERT(SqlToYql(req).IsOk());
  4629. }
  4630. Y_UNIT_TEST(AnonymousInFor) {
  4631. auto req = "pragma warning(\"error\", \"4527\");\n"
  4632. "evaluate for $_ in ListFromRange(1, 10) do begin select 1; end do;";
  4633. UNIT_ASSERT(SqlToYql(req).IsOk());
  4634. }
  4635. Y_UNIT_TEST(Assignment) {
  4636. auto req = "pragma warning(\"error\", \"4527\");\n"
  4637. "$_ = 1;\n"
  4638. "$_, $x, $_ = AsTuple(1,2,3);\n"
  4639. "select $x;";
  4640. UNIT_ASSERT(SqlToYql(req).IsOk());
  4641. }
  4642. }
  4643. Y_UNIT_TEST_SUITE(JsonValue) {
  4644. Y_UNIT_TEST(JsonValueArgumentCount) {
  4645. NYql::TAstParseResult res = SqlToYql("select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json));");
  4646. UNIT_ASSERT(!res.Root);
  4647. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:49: Error: mismatched input ')' expecting ','\n");
  4648. }
  4649. Y_UNIT_TEST(JsonValueJsonPathMustBeLiteralString) {
  4650. NYql::TAstParseResult res = SqlToYql("$jsonPath = \"strict $.key\"; select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), $jsonPath);");
  4651. UNIT_ASSERT(!res.Root);
  4652. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:79: Error: mismatched input '$' expecting STRING_VALUE\n");
  4653. }
  4654. Y_UNIT_TEST(JsonValueTranslation) {
  4655. NYql::TAstParseResult res = SqlToYql("select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), \"strict $.key\");");
  4656. UNIT_ASSERT(res.Root);
  4657. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  4658. Y_UNUSED(word);
  4659. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"strict $.key\""));
  4660. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("SafeCast"));
  4661. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("DataType 'Json"));
  4662. };
  4663. TWordCountHive elementStat({"JsonValue"});
  4664. VerifyProgram(res, elementStat, verifyLine);
  4665. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["JsonValue"]);
  4666. }
  4667. Y_UNIT_TEST(JsonValueReturningSection) {
  4668. for (const auto& typeName : {"Bool", "Int64", "Double", "String"}) {
  4669. NYql::TAstParseResult res = SqlToYql(
  4670. TStringBuilder() << "select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), \"strict $.key\" RETURNING " << typeName << ");"
  4671. );
  4672. UNIT_ASSERT(res.Root);
  4673. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4674. Y_UNUSED(word);
  4675. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'\"strict $.key\""));
  4676. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("SafeCast"));
  4677. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("DataType 'Json"));
  4678. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(TStringBuilder() << "DataType '" << typeName));
  4679. };
  4680. TWordCountHive elementStat({typeName});
  4681. VerifyProgram(res, elementStat, verifyLine);
  4682. UNIT_ASSERT(elementStat[typeName] > 0);
  4683. }
  4684. }
  4685. Y_UNIT_TEST(JsonValueInvalidReturningType) {
  4686. NYql::TAstParseResult res = SqlToYql("select JSON_VALUE(CAST(@@{'key': 1238}@@ as Json), 'strict $.key' RETURNING invalid);");
  4687. UNIT_ASSERT(!res.Root);
  4688. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:77: Error: Unknown simple type 'invalid'\n");
  4689. }
  4690. Y_UNIT_TEST(JsonValueAndReturningInExpressions) {
  4691. NYql::TAstParseResult res = SqlToYql(
  4692. "USE plato\n;"
  4693. "$json_value = \"some string\";\n"
  4694. "SELECT $json_value;\n"
  4695. "SELECT 1 as json_value;\n"
  4696. "SELECT $json_value as json_value;\n"
  4697. "$returning = \"another string\";\n"
  4698. "SELECT $returning;\n"
  4699. "SELECT 1 as returning;\n"
  4700. "SELECT $returning as returning;\n"
  4701. );
  4702. UNIT_ASSERT(res.Root);
  4703. }
  4704. Y_UNIT_TEST(JsonValueValidCaseHandlers) {
  4705. const TVector<std::pair<TString, TString>> testCases = {
  4706. {"", "'DefaultValue (Null)"},
  4707. {"NULL", "'DefaultValue (Null)"},
  4708. {"ERROR", "'Error (Null)"},
  4709. {"DEFAULT 123", "'DefaultValue (Int32 '\"123\")"},
  4710. };
  4711. for (const auto& onEmpty : testCases) {
  4712. for (const auto& onError : testCases) {
  4713. TStringBuilder query;
  4714. query << "$json = CAST(@@{\"key\": 1238}@@ as Json);\n"
  4715. << "SELECT JSON_VALUE($json, \"strict $.key\"";
  4716. if (!onEmpty.first.empty()) {
  4717. query << " " << onEmpty.first << " ON EMPTY";
  4718. }
  4719. if (!onError.first.empty()) {
  4720. query << " " << onError.first << " ON ERROR";
  4721. }
  4722. query << ");\n";
  4723. NYql::TAstParseResult res = SqlToYql(query);
  4724. UNIT_ASSERT(res.Root);
  4725. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4726. Y_UNUSED(word);
  4727. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(onEmpty.second + " " + onError.second));
  4728. };
  4729. TWordCountHive elementStat({"JsonValue"});
  4730. VerifyProgram(res, elementStat, verifyLine);
  4731. UNIT_ASSERT(elementStat["JsonValue"] > 0);
  4732. }
  4733. }
  4734. }
  4735. Y_UNIT_TEST(JsonValueTooManyCaseHandlers) {
  4736. NYql::TAstParseResult res = SqlToYql(
  4737. "select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), \"strict $.key\" NULL ON EMPTY NULL ON ERROR NULL ON EMPTY);\n"
  4738. );
  4739. UNIT_ASSERT(!res.Root);
  4740. UNIT_ASSERT_NO_DIFF(
  4741. Err2Str(res),
  4742. "<main>:1:52: Error: Only 1 ON EMPTY and/or 1 ON ERROR clause is expected\n"
  4743. );
  4744. }
  4745. Y_UNIT_TEST(JsonValueTooManyOnEmpty) {
  4746. NYql::TAstParseResult res = SqlToYql(
  4747. "select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), \"strict $.key\" NULL ON EMPTY NULL ON EMPTY);\n"
  4748. );
  4749. UNIT_ASSERT(!res.Root);
  4750. UNIT_ASSERT_NO_DIFF(
  4751. Err2Str(res),
  4752. "<main>:1:52: Error: Only 1 ON EMPTY clause is expected\n"
  4753. );
  4754. }
  4755. Y_UNIT_TEST(JsonValueTooManyOnError) {
  4756. NYql::TAstParseResult res = SqlToYql(
  4757. "select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), \"strict $.key\" NULL ON ERROR NULL ON ERROR);\n"
  4758. );
  4759. UNIT_ASSERT(!res.Root);
  4760. UNIT_ASSERT_NO_DIFF(
  4761. Err2Str(res),
  4762. "<main>:1:52: Error: Only 1 ON ERROR clause is expected\n"
  4763. );
  4764. }
  4765. Y_UNIT_TEST(JsonValueOnEmptyAfterOnError) {
  4766. NYql::TAstParseResult res = SqlToYql(
  4767. "select JSON_VALUE(CAST(@@{\"key\": 1238}@@ as Json), \"strict $.key\" NULL ON ERROR NULL ON EMPTY);\n"
  4768. );
  4769. UNIT_ASSERT(!res.Root);
  4770. UNIT_ASSERT_NO_DIFF(
  4771. Err2Str(res),
  4772. "<main>:1:52: Error: ON EMPTY clause must be before ON ERROR clause\n"
  4773. );
  4774. }
  4775. Y_UNIT_TEST(JsonValueNullInput) {
  4776. NYql::TAstParseResult res = SqlToYql(R"(SELECT JSON_VALUE(NULL, "strict $.key");)");
  4777. UNIT_ASSERT(res.Root);
  4778. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4779. Y_UNUSED(word);
  4780. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Nothing (OptionalType (DataType 'Json)))"));
  4781. };
  4782. TWordCountHive elementStat({"JsonValue"});
  4783. VerifyProgram(res, elementStat, verifyLine);
  4784. UNIT_ASSERT(elementStat["JsonValue"] > 0);
  4785. }
  4786. }
  4787. Y_UNIT_TEST_SUITE(JsonExists) {
  4788. Y_UNIT_TEST(JsonExistsValidHandlers) {
  4789. const TVector<std::pair<TString, TString>> testCases = {
  4790. {"", "(Just (Bool '\"false\"))"},
  4791. {"TRUE ON ERROR", "(Just (Bool '\"true\"))"},
  4792. {"FALSE ON ERROR", "(Just (Bool '\"false\"))"},
  4793. {"UNKNOWN ON ERROR", "(Nothing (OptionalType (DataType 'Bool)))"},
  4794. // NOTE: in this case we expect arguments of JsonExists callable to end immediately
  4795. // after variables. This parenthesis at the end of the expression is left on purpose
  4796. {"ERROR ON ERROR", "(Utf8 '\"strict $.key\") (JsonVariables))"},
  4797. };
  4798. for (const auto& item : testCases) {
  4799. NYql::TAstParseResult res = SqlToYql(
  4800. TStringBuilder() << R"(
  4801. $json = CAST(@@{"key": 1238}@@ as Json);
  4802. SELECT JSON_EXISTS($json, "strict $.key" )" << item.first << ");\n"
  4803. );
  4804. UNIT_ASSERT(res.Root);
  4805. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4806. Y_UNUSED(word);
  4807. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(item.second));
  4808. };
  4809. TWordCountHive elementStat({"JsonExists"});
  4810. VerifyProgram(res, elementStat, verifyLine);
  4811. UNIT_ASSERT(elementStat["JsonExists"] > 0);
  4812. }
  4813. }
  4814. Y_UNIT_TEST(JsonExistsInvalidHandler) {
  4815. NYql::TAstParseResult res = SqlToYql(R"(
  4816. $json = CAST(@@{"key": 1238}@@ as Json);
  4817. $default = false;
  4818. SELECT JSON_EXISTS($json, "strict $.key" $default ON ERROR);
  4819. )");
  4820. UNIT_ASSERT(!res.Root);
  4821. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:53: Error: mismatched input '$' expecting {')', ERROR, FALSE, TRUE, UNKNOWN}\n");
  4822. }
  4823. Y_UNIT_TEST(JsonExistsNullInput) {
  4824. NYql::TAstParseResult res = SqlToYql(R"(SELECT JSON_EXISTS(NULL, "strict $.key");)");
  4825. UNIT_ASSERT(res.Root);
  4826. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4827. Y_UNUSED(word);
  4828. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Nothing (OptionalType (DataType 'Json)))"));
  4829. };
  4830. TWordCountHive elementStat({"JsonExists"});
  4831. VerifyProgram(res, elementStat, verifyLine);
  4832. UNIT_ASSERT(elementStat["JsonExists"] > 0);
  4833. }
  4834. }
  4835. Y_UNIT_TEST_SUITE(JsonQuery) {
  4836. Y_UNIT_TEST(JsonQueryValidHandlers) {
  4837. using TTestSuite = const TVector<std::pair<TString, TString>>;
  4838. TTestSuite wrapCases = {
  4839. {"", "'NoWrap"},
  4840. {"WITHOUT WRAPPER", "'NoWrap"},
  4841. {"WITHOUT ARRAY WRAPPER", "'NoWrap"},
  4842. {"WITH WRAPPER", "'Wrap"},
  4843. {"WITH ARRAY WRAPPER", "'Wrap"},
  4844. {"WITH UNCONDITIONAL WRAPPER", "'Wrap"},
  4845. {"WITH UNCONDITIONAL ARRAY WRAPPER", "'Wrap"},
  4846. {"WITH CONDITIONAL WRAPPER", "'ConditionalWrap"},
  4847. {"WITH CONDITIONAL ARRAY WRAPPER", "'ConditionalWrap"},
  4848. };
  4849. TTestSuite handlerCases = {
  4850. {"", "'Null"},
  4851. {"ERROR", "'Error"},
  4852. {"NULL", "'Null"},
  4853. {"EMPTY ARRAY", "'EmptyArray"},
  4854. {"EMPTY OBJECT", "'EmptyObject"},
  4855. };
  4856. for (const auto& wrap : wrapCases) {
  4857. for (const auto& onError : handlerCases) {
  4858. for (const auto& onEmpty : handlerCases) {
  4859. TStringBuilder query;
  4860. query << R"($json = CAST(@@{"key": [123]}@@ as Json);
  4861. SELECT JSON_QUERY($json, "strict $.key" )" << wrap.first;
  4862. if (!onEmpty.first.empty()) {
  4863. if (wrap.first.StartsWith("WITH ")) {
  4864. continue;
  4865. }
  4866. query << " " << onEmpty.first << " ON EMPTY";
  4867. }
  4868. if (!onError.first.empty()) {
  4869. query << " " << onError.first << " ON ERROR";
  4870. }
  4871. query << ");\n";
  4872. NYql::TAstParseResult res = SqlToYql(query);
  4873. UNIT_ASSERT(res.Root);
  4874. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4875. Y_UNUSED(word);
  4876. const TString args = TStringBuilder() << wrap.second << " " << onEmpty.second << " " << onError.second;
  4877. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(args));
  4878. };
  4879. Cout << wrap.first << " " << onEmpty.first << " " << onError.first << Endl;
  4880. TWordCountHive elementStat({"JsonQuery"});
  4881. VerifyProgram(res, elementStat, verifyLine);
  4882. UNIT_ASSERT(elementStat["JsonQuery"] > 0);
  4883. }
  4884. }
  4885. }
  4886. }
  4887. Y_UNIT_TEST(JsonQueryOnEmptyWithWrapper) {
  4888. NYql::TAstParseResult res = SqlToYql(R"(
  4889. $json = CAST(@@{"key": 1238}@@ as Json);
  4890. SELECT JSON_QUERY($json, "strict $" WITH ARRAY WRAPPER EMPTY ARRAY ON EMPTY);
  4891. )");
  4892. UNIT_ASSERT(!res.Root);
  4893. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:38: Error: ON EMPTY is prohibited because WRAPPER clause is specified\n");
  4894. }
  4895. Y_UNIT_TEST(JsonQueryNullInput) {
  4896. NYql::TAstParseResult res = SqlToYql(R"(SELECT JSON_QUERY(NULL, "strict $.key");)");
  4897. UNIT_ASSERT(res.Root);
  4898. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4899. Y_UNUSED(word);
  4900. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("(Nothing (OptionalType (DataType 'Json)))"));
  4901. };
  4902. TWordCountHive elementStat({"JsonQuery"});
  4903. VerifyProgram(res, elementStat, verifyLine);
  4904. UNIT_ASSERT(elementStat["JsonQuery"] > 0);
  4905. }
  4906. }
  4907. Y_UNIT_TEST_SUITE(JsonPassing) {
  4908. Y_UNIT_TEST(SupportedVariableTypes) {
  4909. const TVector<TString> functions = {"JSON_EXISTS", "JSON_VALUE", "JSON_QUERY"};
  4910. for (const auto& function : functions) {
  4911. const auto query = Sprintf(R"(
  4912. pragma CompactNamedExprs;
  4913. $json = CAST(@@{"key": 1238}@@ as Json);
  4914. SELECT %s(
  4915. $json,
  4916. "strict $.key"
  4917. PASSING
  4918. "string" as var1,
  4919. 1.234 as var2,
  4920. CAST(1 as Int64) as var3,
  4921. true as var4,
  4922. $json as var5
  4923. ))",
  4924. function.data()
  4925. );
  4926. NYql::TAstParseResult res = SqlToYql(query);
  4927. UNIT_ASSERT(res.Root);
  4928. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4929. Y_UNUSED(word);
  4930. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var1" (String '"string")))"), "Cannot find `var1`");
  4931. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var2" (Double '"1.234")))"), "Cannot find `var2`");
  4932. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var3" (SafeCast (Int32 '"1") (DataType 'Int64))))"), "Cannot find `var3`");
  4933. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var4" (Bool '"true")))"), "Cannot find `var4`");
  4934. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var5" namedexprnode0))"), "Cannot find `var5`");
  4935. };
  4936. TWordCountHive elementStat({"JsonVariables"});
  4937. VerifyProgram(res, elementStat, verifyLine);
  4938. UNIT_ASSERT(elementStat["JsonVariables"] > 0);
  4939. }
  4940. }
  4941. Y_UNIT_TEST(ValidVariableNames) {
  4942. const TVector<TString> functions = {"JSON_EXISTS", "JSON_VALUE", "JSON_QUERY"};
  4943. for (const auto& function : functions) {
  4944. const auto query = Sprintf(R"(
  4945. $json = CAST(@@{"key": 1238}@@ as Json);
  4946. SELECT %s(
  4947. $json,
  4948. "strict $.key"
  4949. PASSING
  4950. "one" as var1,
  4951. "two" as "VaR2",
  4952. "three" as `var3`,
  4953. "four" as VaR4
  4954. ))",
  4955. function.data()
  4956. );
  4957. NYql::TAstParseResult res = SqlToYql(query);
  4958. UNIT_ASSERT(res.Root);
  4959. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  4960. Y_UNUSED(word);
  4961. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var1" (String '"one")))"), "Cannot find `var1`");
  4962. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"VaR2" (String '"two")))"), "Cannot find `VaR2`");
  4963. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"var3" (String '"three")))"), "Cannot find `var3`");
  4964. UNIT_ASSERT_VALUES_UNEQUAL_C(TString::npos, line.find(R"('('"VaR4" (String '"four")))"), "Cannot find `VaR4`");
  4965. };
  4966. TWordCountHive elementStat({"JsonVariables"});
  4967. VerifyProgram(res, elementStat, verifyLine);
  4968. UNIT_ASSERT(elementStat["JsonVariables"] > 0);
  4969. }
  4970. }
  4971. }
  4972. Y_UNIT_TEST_SUITE(MigrationToJsonApi) {
  4973. Y_UNIT_TEST(WarningOnDeprecatedJsonUdf) {
  4974. NYql::TAstParseResult res = SqlToYql(R"(
  4975. $json = CAST(@@{"key": 1234}@@ as Json);
  4976. SELECT Json::Parse($json);
  4977. )");
  4978. UNIT_ASSERT(res.Root);
  4979. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:3:26: Warning: Json UDF is deprecated. Please use JSON API instead, code: 4506\n");
  4980. }
  4981. }
  4982. Y_UNIT_TEST_SUITE(AnsiIdentsNegative) {
  4983. Y_UNIT_TEST(EnableAnsiLexerFromRequestSpecialComments) {
  4984. auto req = "\n"
  4985. "\t --!ansi_lexer \n"
  4986. "-- Some comment\n"
  4987. "-- another comment\n"
  4988. "pragma SimpleColumns;\n"
  4989. "\n"
  4990. "select 1, '''' as empty;";
  4991. auto res = SqlToYql(req);
  4992. UNIT_ASSERT(res.IsOk());
  4993. UNIT_ASSERT(res.Issues.Size() == 0);
  4994. }
  4995. Y_UNIT_TEST(AnsiLexerShouldNotBeEnabledHere) {
  4996. auto req = "$str = '\n"
  4997. "--!ansi_lexer\n"
  4998. "--!syntax_v1\n"
  4999. "';\n"
  5000. "\n"
  5001. "select 1, $str, \"\" as empty;";
  5002. auto res = SqlToYql(req);
  5003. UNIT_ASSERT(res.IsOk());
  5004. UNIT_ASSERT(res.Issues.Size() == 0);
  5005. }
  5006. Y_UNIT_TEST(DoubleQuotesInDictsTuplesOrLists) {
  5007. auto req = "$d = { 'a': 1, \"b\": 2, 'c': 3,};";
  5008. auto res = SqlToYqlWithAnsiLexer(req);
  5009. UNIT_ASSERT(!res.Root);
  5010. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:16: Error: Column reference \"b\" is not allowed in current scope\n");
  5011. req = "$t = (1, 2, \"a\");";
  5012. res = SqlToYqlWithAnsiLexer(req);
  5013. UNIT_ASSERT(!res.Root);
  5014. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:13: Error: Column reference \"a\" is not allowed in current scope\n");
  5015. req = "$l = ['a', 'b', \"c\"];";
  5016. res = SqlToYqlWithAnsiLexer(req);
  5017. UNIT_ASSERT(!res.Root);
  5018. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:17: Error: Column reference \"c\" is not allowed in current scope\n");
  5019. }
  5020. Y_UNIT_TEST(MultilineComments) {
  5021. auto req = "/*/**/ select 1;";
  5022. auto res = SqlToYql(req);
  5023. UNIT_ASSERT(res.Root);
  5024. res = SqlToYqlWithAnsiLexer(req);
  5025. UNIT_ASSERT(res.IsOk());
  5026. UNIT_ASSERT(res.Issues.Size() == 0);
  5027. req = "/*\n"
  5028. "--/*\n"
  5029. "*/ select 1;";
  5030. res = SqlToYql(req);
  5031. UNIT_ASSERT(res.Root);
  5032. res = SqlToYqlWithAnsiLexer(req);
  5033. UNIT_ASSERT(res.IsOk());
  5034. UNIT_ASSERT(res.Issues.Size() == 0);
  5035. req = "/*\n"
  5036. "/*\n"
  5037. "--*/\n"
  5038. "*/ select 1;";
  5039. res = SqlToYql(req);
  5040. UNIT_ASSERT(!res.Root);
  5041. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:4:0: Error: mismatched input '*' expecting {';', '(', '$', ALTER, ANALYZE, BACKUP, BATCH, COMMIT, CREATE, DECLARE, DEFINE, DELETE, DISCARD, DO, DROP, EVALUATE, EXPLAIN, EXPORT, FOR, FROM, GRANT, IF, IMPORT, INSERT, PARALLEL, PRAGMA, PROCESS, REDUCE, REPLACE, RESTORE, REVOKE, ROLLBACK, SELECT, SHOW, UPDATE, UPSERT, USE, VALUES}\n");
  5042. res = SqlToYqlWithAnsiLexer(req);
  5043. UNIT_ASSERT(res.Root);
  5044. }
  5045. }
  5046. Y_UNIT_TEST_SUITE(AnsiOptionalAs) {
  5047. Y_UNIT_TEST(OptionalAsInProjection) {
  5048. UNIT_ASSERT(SqlToYql("PRAGMA AnsiOptionalAs; SELECT a b, c FROM plato.Input;").IsOk());
  5049. ExpectFailWithError("PRAGMA DisableAnsiOptionalAs;\n"
  5050. "SELECT a b, c FROM plato.Input;",
  5051. "<main>:2:10: Error: Expecting mandatory AS here. Did you miss comma? Please add PRAGMA AnsiOptionalAs; for ANSI compatibility\n");
  5052. }
  5053. Y_UNIT_TEST(OptionalAsWithKeywords) {
  5054. UNIT_ASSERT(SqlToYql("PRAGMA AnsiOptionalAs; SELECT a type, b data, c source FROM plato.Input;").IsOk());
  5055. }
  5056. }
  5057. Y_UNIT_TEST_SUITE(SessionWindowNegative) {
  5058. Y_UNIT_TEST(SessionWindowWithoutSource) {
  5059. ExpectFailWithError("SELECT 1 + SessionWindow(ts, 32);",
  5060. "<main>:1:12: Error: SessionWindow requires data source\n");
  5061. }
  5062. Y_UNIT_TEST(SessionWindowInProjection) {
  5063. ExpectFailWithError("SELECT 1 + SessionWindow(ts, 32) from plato.Input;",
  5064. "<main>:1:12: Error: SessionWindow can only be used as a top-level GROUP BY / PARTITION BY expression\n");
  5065. }
  5066. Y_UNIT_TEST(SessionWindowWithNonConstSecondArg) {
  5067. ExpectFailWithError(
  5068. "SELECT key, session_start FROM plato.Input\n"
  5069. "GROUP BY SessionWindow(ts, 32 + subkey) as session_start, key;",
  5070. "<main>:2:10: Error: Source does not allow column references\n"
  5071. "<main>:2:33: Error: Column reference 'subkey'\n");
  5072. }
  5073. Y_UNIT_TEST(SessionWindowWithWrongNumberOfArgs) {
  5074. ExpectFailWithError("SELECT * FROM plato.Input GROUP BY SessionWindow()",
  5075. "<main>:1:36: Error: SessionWindow requires either two or four arguments\n");
  5076. ExpectFailWithError("SELECT * FROM plato.Input GROUP BY SessionWindow(key, subkey, 100)",
  5077. "<main>:1:36: Error: SessionWindow requires either two or four arguments\n");
  5078. }
  5079. Y_UNIT_TEST(DuplicateSessionWindow) {
  5080. ExpectFailWithError(
  5081. "SELECT\n"
  5082. " *\n"
  5083. "FROM plato.Input\n"
  5084. "GROUP BY\n"
  5085. " SessionWindow(ts, 10),\n"
  5086. " user,\n"
  5087. " SessionWindow(ts, 20)\n"
  5088. ";",
  5089. "<main>:7:5: Error: Duplicate session window specification:\n"
  5090. "<main>:5:5: Error: Previous session window is declared here\n");
  5091. ExpectFailWithError(
  5092. "SELECT\n"
  5093. " MIN(key) over w\n"
  5094. "FROM plato.Input\n"
  5095. "WINDOW w AS (\n"
  5096. " PARTITION BY SessionWindow(ts, 10), user,\n"
  5097. " SessionWindow(ts, 20)\n"
  5098. ");",
  5099. "<main>:6:5: Error: Duplicate session window specification:\n"
  5100. "<main>:5:18: Error: Previous session window is declared here\n");
  5101. }
  5102. Y_UNIT_TEST(SessionStartStateWithoutSource) {
  5103. ExpectFailWithError("SELECT 1 + SessionStart();",
  5104. "<main>:1:12: Error: SessionStart requires data source\n");
  5105. ExpectFailWithError("SELECT 1 + SessionState();",
  5106. "<main>:1:12: Error: SessionState requires data source\n");
  5107. }
  5108. Y_UNIT_TEST(SessionStartStateWithoutGroupByOrWindow) {
  5109. ExpectFailWithError("SELECT 1 + SessionStart() from plato.Input;",
  5110. "<main>:1:12: Error: SessionStart can not be used without aggregation by SessionWindow\n");
  5111. ExpectFailWithError("SELECT 1 + SessionState() from plato.Input;",
  5112. "<main>:1:12: Error: SessionState can not be used without aggregation by SessionWindow\n");
  5113. }
  5114. Y_UNIT_TEST(SessionStartStateWithGroupByWithoutSession) {
  5115. ExpectFailWithError("SELECT 1 + SessionStart() from plato.Input group by user;",
  5116. "<main>:1:12: Error: SessionStart can not be used here: SessionWindow specification is missing in GROUP BY\n");
  5117. ExpectFailWithError("SELECT 1 + SessionState() from plato.Input group by user;",
  5118. "<main>:1:12: Error: SessionState can not be used here: SessionWindow specification is missing in GROUP BY\n");
  5119. }
  5120. Y_UNIT_TEST(SessionStartStateWithoutOverWithWindowWithoutSession) {
  5121. ExpectFailWithError("SELECT 1 + SessionStart(), MIN(key) over w from plato.Input window w as ()",
  5122. "<main>:1:12: Error: SessionStart can not be used without aggregation by SessionWindow. Maybe you forgot to add OVER `window_name`?\n");
  5123. ExpectFailWithError("SELECT 1 + SessionState(), MIN(key) over w from plato.Input window w as ()",
  5124. "<main>:1:12: Error: SessionState can not be used without aggregation by SessionWindow. Maybe you forgot to add OVER `window_name`?\n");
  5125. }
  5126. Y_UNIT_TEST(SessionStartStateWithWindowWithoutSession) {
  5127. ExpectFailWithError("SELECT 1 + SessionStart() over w, MIN(key) over w from plato.Input window w as ()",
  5128. "<main>:1:12: Error: SessionStart can not be used with window w: SessionWindow specification is missing in PARTITION BY\n");
  5129. ExpectFailWithError("SELECT 1 + SessionState() over w, MIN(key) over w from plato.Input window w as ()",
  5130. "<main>:1:12: Error: SessionState can not be used with window w: SessionWindow specification is missing in PARTITION BY\n");
  5131. }
  5132. Y_UNIT_TEST(SessionStartStateWithSessionedWindow) {
  5133. ExpectFailWithError("SELECT 1 + SessionStart(), MIN(key) over w from plato.Input group by key window w as (partition by SessionWindow(ts, 1)) ",
  5134. "<main>:1:12: Error: SessionStart can not be used here: SessionWindow specification is missing in GROUP BY. Maybe you forgot to add OVER `window_name`?\n");
  5135. ExpectFailWithError("SELECT 1 + SessionState(), MIN(key) over w from plato.Input group by key window w as (partition by SessionWindow(ts, 1)) ",
  5136. "<main>:1:12: Error: SessionState can not be used here: SessionWindow specification is missing in GROUP BY. Maybe you forgot to add OVER `window_name`?\n");
  5137. }
  5138. Y_UNIT_TEST(AggregationBySessionStateIsNotSupportedYet) {
  5139. ExpectFailWithError("SELECT SOME(1 + SessionState()), key from plato.Input group by key, SessionWindow(ts, 1);",
  5140. "<main>:1:17: Error: SessionState with GROUP BY is not supported yet\n");
  5141. }
  5142. Y_UNIT_TEST(SessionWindowInRtmr) {
  5143. NYql::TAstParseResult res = SqlToYql(
  5144. "SELECT * FROM plato.Input GROUP BY SessionWindow(ts, 10);",
  5145. 10, TString(NYql::RtmrProviderName));
  5146. UNIT_ASSERT(!res.Root);
  5147. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:1:54: Error: Streaming group by query must have a hopping window specification.\n");
  5148. res = SqlToYql(R"(
  5149. SELECT key, SUM(value) AS value FROM plato.Input
  5150. GROUP BY key, HOP(subkey, "PT10S", "PT30S", "PT20S"), SessionWindow(ts, 10);
  5151. )", 10, TString(NYql::RtmrProviderName));
  5152. UNIT_ASSERT(!res.Root);
  5153. UNIT_ASSERT_NO_DIFF(Err2Str(res), "<main>:2:13: Error: SessionWindow is unsupported for streaming sources\n");
  5154. }
  5155. }
  5156. Y_UNIT_TEST_SUITE(LibraSqlSugar) {
  5157. auto makeResult = [](TStringBuf settings) {
  5158. return SqlToYql(
  5159. TStringBuilder()
  5160. << settings
  5161. << "\n$udf1 = MyLibra::MakeLibraPreprocessor($settings);"
  5162. << "\n$udf2 = CustomLibra::MakeLibraPreprocessor($settings);"
  5163. << "\nPROCESS plato.Input USING $udf1(TableRow())"
  5164. << "\nUNION ALL"
  5165. << "\nPROCESS plato.Input USING $udf2(TableRow());"
  5166. );
  5167. };
  5168. Y_UNIT_TEST(EmptySettings) {
  5169. auto res = makeResult(R"(
  5170. $settings = AsStruct();
  5171. )");
  5172. UNIT_ASSERT(res.IsOk());
  5173. }
  5174. Y_UNIT_TEST(OnlyEntities) {
  5175. auto res = makeResult(R"(
  5176. $settings = AsStruct(
  5177. AsList("A", "B", "C") AS Entities
  5178. );
  5179. )");
  5180. UNIT_ASSERT(res.IsOk());
  5181. }
  5182. Y_UNIT_TEST(EntitiesWithStrategy) {
  5183. auto res = makeResult(R"(
  5184. $settings = AsStruct(
  5185. AsList("A", "B", "C") AS Entities,
  5186. "blacklist" AS EntitiesStrategy
  5187. );
  5188. )");
  5189. UNIT_ASSERT(res.IsOk());
  5190. }
  5191. Y_UNIT_TEST(AllSettings) {
  5192. auto res = makeResult(R"(
  5193. $settings = AsStruct(
  5194. AsList("A", "B", "C") AS Entities,
  5195. "whitelist" AS EntitiesStrategy,
  5196. "path" AS BlockstatDict,
  5197. false AS ParseWithFat,
  5198. "map" AS Mode
  5199. );
  5200. )");
  5201. UNIT_ASSERT(res.IsOk());
  5202. }
  5203. Y_UNIT_TEST(BadStrategy) {
  5204. auto res = makeResult(R"(
  5205. $settings = AsStruct("bad" AS EntitiesStrategy);
  5206. )");
  5207. UNIT_ASSERT_STRING_CONTAINS(
  5208. Err2Str(res),
  5209. "Error: MakeLibraPreprocessor got invalid entities strategy: expected 'whitelist' or 'blacklist'"
  5210. );
  5211. }
  5212. Y_UNIT_TEST(BadEntities) {
  5213. auto res = makeResult(R"(
  5214. $settings = AsStruct(AsList("A", 1) AS Entities);
  5215. )");
  5216. UNIT_ASSERT_STRING_CONTAINS(Err2Str(res), "Error: MakeLibraPreprocessor entity must be string literal");
  5217. }
  5218. }
  5219. Y_UNIT_TEST_SUITE(TrailingQuestionsNegative) {
  5220. Y_UNIT_TEST(Basic) {
  5221. ExpectFailWithError("SELECT 1?;", "<main>:1:9: Error: Unexpected token '?' at the end of expression\n");
  5222. ExpectFailWithError("SELECT 1? + 1;", "<main>:1:10: Error: mismatched input '+' expecting {<EOF>, ';'}\n");
  5223. ExpectFailWithError("SELECT 1 + 1??? < 2", "<main>:1:13: Error: Unexpected token '?' at the end of expression\n");
  5224. ExpectFailWithError("SELECT 1? > 2? > 3?",
  5225. "<main>:1:11: Error: Unexpected token '?' at the end of expression\n"
  5226. "<main>:1:16: Error: Unexpected token '?' at the end of expression\n"
  5227. "<main>:1:21: Error: Unexpected token '?' at the end of expression\n");
  5228. }
  5229. Y_UNIT_TEST(SmartParen) {
  5230. ExpectFailWithError("$x = 1; SELECT (Int32?, $x?)", "<main>:1:27: Error: Unexpected token '?' at the end of expression\n");
  5231. ExpectFailWithError("SELECT (Int32, foo?)", "<main>:1:19: Error: Unexpected token '?' at the end of expression\n");
  5232. }
  5233. Y_UNIT_TEST(LambdaOptArgs) {
  5234. ExpectFailWithError("$l = ($x, $y?, $z??, $t?) -> ($x);", "<main>:1:18: Error: Expecting at most one '?' token here (for optional lambda parameters), but got 2\n");
  5235. }
  5236. }
  5237. Y_UNIT_TEST_SUITE(FlexibleTypes) {
  5238. Y_UNIT_TEST(AssumeOrderByType) {
  5239. UNIT_ASSERT(SqlToYql("PRAGMA FlexibleTypes; SELECT 1 AS int32 ASSUME ORDER BY int32").IsOk());
  5240. }
  5241. Y_UNIT_TEST(GroupingSets) {
  5242. UNIT_ASSERT(SqlToYql("PRAGMA FlexibleTypes; SELECT COUNT(*) AS cnt, text, uuid FROM plato.Input GROUP BY GROUPING SETS((uuid), (uuid, text));").IsOk());
  5243. }
  5244. Y_UNIT_TEST(WeakField) {
  5245. UNIT_ASSERT(SqlToYql("PRAGMA FlexibleTypes; SELECT WeakField(text, string) as text FROM plato.Input").IsOk());
  5246. }
  5247. Y_UNIT_TEST(Aggregation1) {
  5248. TString q =
  5249. "PRAGMA FlexibleTypes;\n"
  5250. "$foo = ($x, $const, $type) -> ($x || $const || FormatType($type));\n"
  5251. "SELECT $foo(SOME(x), 'aaa', String) FROM plato.Input GROUP BY y;";
  5252. UNIT_ASSERT(SqlToYql(q).IsOk());
  5253. }
  5254. Y_UNIT_TEST(Aggregation2) {
  5255. TString q =
  5256. "PRAGMA FlexibleTypes;\n"
  5257. "SELECT 1 + String + MAX(key) FROM plato.Input;";
  5258. UNIT_ASSERT(SqlToYql(q).IsOk());
  5259. }
  5260. }
  5261. Y_UNIT_TEST_SUITE(ExternalDeclares) {
  5262. Y_UNIT_TEST(BasicUsage) {
  5263. NSQLTranslation::TTranslationSettings settings;
  5264. settings.DeclaredNamedExprs["foo"] = "String";
  5265. auto res = SqlToYqlWithSettings("select $foo;", settings);
  5266. UNIT_ASSERT(res.IsOk());
  5267. UNIT_ASSERT(res.Issues.Size() == 0);
  5268. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5269. if (word == "declare") {
  5270. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"__((declare "$foo" (DataType 'String)))__"));
  5271. }
  5272. };
  5273. TWordCountHive elementStat = {{TString("declare"), 0}};
  5274. VerifyProgram(res, elementStat, verifyLine);
  5275. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["declare"]);
  5276. }
  5277. Y_UNIT_TEST(DeclareOverrides) {
  5278. NSQLTranslation::TTranslationSettings settings;
  5279. settings.DeclaredNamedExprs["foo"] = "String";
  5280. auto res = SqlToYqlWithSettings("declare $foo as Int32; select $foo;", settings);
  5281. UNIT_ASSERT(res.IsOk());
  5282. UNIT_ASSERT(res.Issues.Size() == 0);
  5283. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5284. if (word == "declare") {
  5285. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"__((declare "$foo" (DataType 'Int32)))__"));
  5286. }
  5287. };
  5288. TWordCountHive elementStat = {{TString("declare"), 0}};
  5289. VerifyProgram(res, elementStat, verifyLine);
  5290. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["declare"]);
  5291. }
  5292. Y_UNIT_TEST(UnusedDeclareDoesNotProduceWarning) {
  5293. NSQLTranslation::TTranslationSettings settings;
  5294. settings.DeclaredNamedExprs["foo"] = "String";
  5295. auto res = SqlToYqlWithSettings("select 1;", settings);
  5296. UNIT_ASSERT(res.IsOk());
  5297. UNIT_ASSERT(res.Issues.Size() == 0);
  5298. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5299. if (word == "declare") {
  5300. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"__((declare "$foo" (DataType 'String)))__"));
  5301. }
  5302. };
  5303. TWordCountHive elementStat = {{TString("declare"), 0}};
  5304. VerifyProgram(res, elementStat, verifyLine);
  5305. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["declare"]);
  5306. }
  5307. Y_UNIT_TEST(DeclaresWithInvalidTypesFails) {
  5308. NSQLTranslation::TTranslationSettings settings;
  5309. settings.DeclaredNamedExprs["foo"] = "List<BadType>";
  5310. auto res = SqlToYqlWithSettings("select 1;", settings);
  5311. UNIT_ASSERT(!res.Root);
  5312. UNIT_ASSERT_NO_DIFF(Err2Str(res),
  5313. "<main>:0:5: Error: Unknown type: 'BadType'\n"
  5314. "<main>: Error: Failed to parse type for externally declared name 'foo'\n");
  5315. }
  5316. }
  5317. Y_UNIT_TEST_SUITE(ExternalDataSource) {
  5318. Y_UNIT_TEST(CreateExternalDataSourceWithAuthNone) {
  5319. NYql::TAstParseResult res = SqlToYql(R"sql(
  5320. USE plato;
  5321. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5322. SOURCE_TYPE="ObjectStorage",
  5323. LOCATION="my-bucket",
  5324. AUTH_METHOD="NONE"
  5325. );
  5326. )sql");
  5327. UNIT_ASSERT(res.Root);
  5328. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5329. if (word == "Write") {
  5330. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"NONE") '('"location" '"my-bucket") '('"source_type" '"ObjectStorage"))#");
  5331. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5332. }
  5333. };
  5334. TWordCountHive elementStat = { {TString("Write"), 0} };
  5335. VerifyProgram(res, elementStat, verifyLine);
  5336. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5337. }
  5338. Y_UNIT_TEST(CreateExternalDataSourceWithAuthServiceAccount) {
  5339. NYql::TAstParseResult res = SqlToYql(R"sql(
  5340. USE plato;
  5341. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5342. SOURCE_TYPE="ObjectStorage",
  5343. LOCATION="my-bucket",
  5344. AUTH_METHOD="SERVICE_ACCOUNT",
  5345. SERVICE_ACCOUNT_ID="sa",
  5346. SERVICE_ACCOUNT_SECRET_NAME="sa_secret_name"
  5347. );
  5348. )sql");
  5349. UNIT_ASSERT(res.Root);
  5350. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5351. if (word == "Write") {
  5352. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"SERVICE_ACCOUNT") '('"location" '"my-bucket") '('"service_account_id" '"sa") '('"service_account_secret_name" '"sa_secret_name") '('"source_type" '"ObjectStorage"))#");
  5353. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5354. }
  5355. };
  5356. TWordCountHive elementStat = { {TString("Write"), 0} };
  5357. VerifyProgram(res, elementStat, verifyLine);
  5358. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5359. }
  5360. Y_UNIT_TEST(CreateExternalDataSourceWithBasic) {
  5361. NYql::TAstParseResult res = SqlToYql(R"sql(
  5362. USE plato;
  5363. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5364. SOURCE_TYPE="PostgreSQL",
  5365. LOCATION="protocol://host:port/",
  5366. AUTH_METHOD="BASIC",
  5367. LOGIN="admin",
  5368. PASSWORD_SECRET_NAME="secret_name"
  5369. );
  5370. )sql");
  5371. UNIT_ASSERT(res.Root);
  5372. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5373. if (word == "Write") {
  5374. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"BASIC") '('"location" '"protocol://host:port/") '('"login" '"admin") '('"password_secret_name" '"secret_name") '('"source_type" '"PostgreSQL"))#");
  5375. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5376. }
  5377. };
  5378. TWordCountHive elementStat = { {TString("Write"), 0} };
  5379. VerifyProgram(res, elementStat, verifyLine);
  5380. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5381. }
  5382. Y_UNIT_TEST(CreateExternalDataSourceWithMdbBasic) {
  5383. NYql::TAstParseResult res = SqlToYql(R"sql(
  5384. USE plato;
  5385. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5386. SOURCE_TYPE="PostgreSQL",
  5387. LOCATION="protocol://host:port/",
  5388. AUTH_METHOD="MDB_BASIC",
  5389. SERVICE_ACCOUNT_ID="sa",
  5390. SERVICE_ACCOUNT_SECRET_NAME="sa_secret_name",
  5391. LOGIN="admin",
  5392. PASSWORD_SECRET_NAME="secret_name"
  5393. );
  5394. )sql");
  5395. UNIT_ASSERT(res.Root);
  5396. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5397. if (word == "Write") {
  5398. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"MDB_BASIC") '('"location" '"protocol://host:port/") '('"login" '"admin") '('"password_secret_name" '"secret_name") '('"service_account_id" '"sa") '('"service_account_secret_name" '"sa_secret_name") '('"source_type" '"PostgreSQL"))#");
  5399. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5400. }
  5401. };
  5402. TWordCountHive elementStat = { {TString("Write"), 0} };
  5403. VerifyProgram(res, elementStat, verifyLine);
  5404. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5405. }
  5406. Y_UNIT_TEST(CreateExternalDataSourceWithAws) {
  5407. NYql::TAstParseResult res = SqlToYql(R"sql(
  5408. USE plato;
  5409. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5410. SOURCE_TYPE="PostgreSQL",
  5411. LOCATION="protocol://host:port/",
  5412. AUTH_METHOD="AWS",
  5413. AWS_ACCESS_KEY_ID_SECRET_NAME="secred_id_name",
  5414. AWS_SECRET_ACCESS_KEY_SECRET_NAME="secret_key_name",
  5415. AWS_REGION="ru-central-1"
  5416. );
  5417. )sql");
  5418. UNIT_ASSERT(res.Root);
  5419. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5420. if (word == "Write") {
  5421. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"AWS") '('"aws_access_key_id_secret_name" '"secred_id_name") '('"aws_region" '"ru-central-1") '('"aws_secret_access_key_secret_name" '"secret_key_name") '('"location" '"protocol://host:port/") '('"source_type" '"PostgreSQL"))#");
  5422. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5423. }
  5424. };
  5425. TWordCountHive elementStat = { {TString("Write"), 0} };
  5426. VerifyProgram(res, elementStat, verifyLine);
  5427. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5428. }
  5429. Y_UNIT_TEST(CreateExternalDataSourceWithToken) {
  5430. NYql::TAstParseResult res = SqlToYql(R"sql(
  5431. USE plato;
  5432. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5433. SOURCE_TYPE="YT",
  5434. LOCATION="protocol://host:port/",
  5435. AUTH_METHOD="TOKEN",
  5436. TOKEN_SECRET_NAME="token_name"
  5437. );
  5438. )sql");
  5439. UNIT_ASSERT(res.Root);
  5440. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5441. if (word == "Write") {
  5442. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"TOKEN") '('"location" '"protocol://host:port/") '('"source_type" '"YT") '('"token_secret_name" '"token_name"))#");
  5443. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5444. }
  5445. };
  5446. TWordCountHive elementStat = { {TString("Write"), 0} };
  5447. VerifyProgram(res, elementStat, verifyLine);
  5448. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5449. }
  5450. Y_UNIT_TEST(CreateExternalDataSourceWithTablePrefix) {
  5451. NYql::TAstParseResult res = SqlToYql(R"sql(
  5452. USE plato;
  5453. pragma TablePathPrefix='/aba';
  5454. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5455. SOURCE_TYPE="ObjectStorage",
  5456. LOCATION="my-bucket",
  5457. AUTH_METHOD="NONE"
  5458. );
  5459. )sql");
  5460. UNIT_ASSERT(res.Root);
  5461. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5462. if (word == "Write") {
  5463. UNIT_ASSERT_STRING_CONTAINS(line, "/aba/MyDataSource");
  5464. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  5465. }
  5466. };
  5467. TWordCountHive elementStat = { {TString("Write"), 0} };
  5468. VerifyProgram(res, elementStat, verifyLine);
  5469. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5470. }
  5471. Y_UNIT_TEST(CreateExternalDataSourceIfNotExists) {
  5472. NYql::TAstParseResult res = SqlToYql(R"sql(
  5473. USE plato;
  5474. CREATE EXTERNAL DATA SOURCE IF NOT EXISTS MyDataSource WITH (
  5475. SOURCE_TYPE="ObjectStorage",
  5476. LOCATION="my-bucket",
  5477. AUTH_METHOD="NONE"
  5478. );
  5479. )sql");
  5480. UNIT_ASSERT(res.Root);
  5481. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5482. if (word == "Write") {
  5483. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"NONE") '('"location" '"my-bucket") '('"source_type" '"ObjectStorage"))#");
  5484. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObjectIfNotExists"));
  5485. }
  5486. };
  5487. TWordCountHive elementStat = { {TString("Write"), 0} };
  5488. VerifyProgram(res, elementStat, verifyLine);
  5489. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5490. }
  5491. Y_UNIT_TEST(AlterExternalDataSource) {
  5492. NYql::TAstParseResult res = SqlToYql(R"sql(
  5493. USE plato;
  5494. ALTER EXTERNAL DATA SOURCE MyDataSource
  5495. SET (SOURCE_TYPE = "ObjectStorage", Login = "Admin"),
  5496. SET Location "bucket",
  5497. RESET (Auth_Method, Service_Account_Id, Service_Account_Secret_Name);
  5498. )sql");
  5499. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  5500. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5501. if (word == "Write") {
  5502. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alterObject))#");
  5503. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('features '('('"location" '"bucket") '('"login" '"Admin") '('"source_type" '"ObjectStorage"))))#");
  5504. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('resetFeatures '('"auth_method" '"service_account_id" '"service_account_secret_name")))#");
  5505. }
  5506. };
  5507. TWordCountHive elementStat = { {TString("Write"), 0} };
  5508. VerifyProgram(res, elementStat, verifyLine);
  5509. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5510. }
  5511. Y_UNIT_TEST(CreateExternalDataSourceOrReplace) {
  5512. NYql::TAstParseResult res = SqlToYql(R"(
  5513. USE plato;
  5514. CREATE OR REPLACE EXTERNAL DATA SOURCE MyDataSource WITH (
  5515. SOURCE_TYPE="ObjectStorage",
  5516. LOCATION="my-bucket",
  5517. AUTH_METHOD="NONE"
  5518. );
  5519. )");
  5520. UNIT_ASSERT(res.Root);
  5521. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5522. if (word == "Write") {
  5523. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"auth_method" '"NONE") '('"location" '"my-bucket") '('"source_type" '"ObjectStorage"))#");
  5524. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObjectOrReplace"));
  5525. }
  5526. };
  5527. TWordCountHive elementStat = { {TString("Write"), 0} };
  5528. VerifyProgram(res, elementStat, verifyLine);
  5529. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5530. }
  5531. Y_UNIT_TEST(CreateOrReplaceForUnsupportedTableTypesShouldFail) {
  5532. ExpectFailWithError(R"sql(
  5533. USE plato;
  5534. CREATE OR REPLACE TABLE t (a int32 not null, primary key(a, a));
  5535. )sql" , "<main>:3:23: Error: OR REPLACE feature is supported only for EXTERNAL DATA SOURCE and EXTERNAL TABLE\n");
  5536. ExpectFailWithError(R"sql(
  5537. USE plato;
  5538. CREATE OR REPLACE TABLE t (
  5539. Key Uint64,
  5540. Value1 String,
  5541. PRIMARY KEY (Key)
  5542. )
  5543. WITH (
  5544. STORE = COLUMN,
  5545. AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 10
  5546. );
  5547. )sql" , "<main>:3:23: Error: OR REPLACE feature is supported only for EXTERNAL DATA SOURCE and EXTERNAL TABLE\n");
  5548. }
  5549. Y_UNIT_TEST(CreateExternalDataSourceWithBadArguments) {
  5550. ExpectFailWithError(R"sql(
  5551. USE plato;
  5552. CREATE EXTERNAL DATA SOURCE MyDataSource;
  5553. )sql" , "<main>:3:56: Error: mismatched input ';' expecting WITH\n");
  5554. ExpectFailWithError(R"sql(
  5555. USE plato;
  5556. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5557. LOCATION="my-bucket",
  5558. AUTH_METHOD="NONE"
  5559. );
  5560. )sql" , "<main>:5:33: Error: SOURCE_TYPE requires key\n");
  5561. ExpectFailWithError(R"sql(
  5562. USE plato;
  5563. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5564. SOURCE_TYPE="ObjectStorage",
  5565. LOCATION="my-bucket"
  5566. );
  5567. )sql" , "<main>:5:30: Error: AUTH_METHOD requires key\n");
  5568. ExpectFailWithError(R"sql(
  5569. USE plato;
  5570. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5571. SOURCE_TYPE="ObjectStorage",
  5572. LOCATION="my-bucket",
  5573. AUTH_METHOD="NONE1"
  5574. );
  5575. )sql" , "<main>:6:33: Error: Unknown AUTH_METHOD = NONE1\n");
  5576. ExpectFailWithError(R"sql(
  5577. USE plato;
  5578. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5579. SOURCE_TYPE="ObjectStorage",
  5580. LOCATION="my-bucket",
  5581. AUTH_METHOD="SERVICE_ACCOUNT"
  5582. );
  5583. )sql" , "<main>:6:33: Error: SERVICE_ACCOUNT_ID requires key\n");
  5584. ExpectFailWithError(R"sql(
  5585. USE plato;
  5586. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5587. SOURCE_TYPE="ObjectStorage",
  5588. LOCATION="my-bucket",
  5589. AUTH_METHOD="SERVICE_ACCOUNT",
  5590. SERVICE_ACCOUNT_ID="s1"
  5591. );
  5592. )sql" , "<main>:7:40: Error: SERVICE_ACCOUNT_SECRET_NAME requires key\n");
  5593. ExpectFailWithError(R"sql(
  5594. USE plato;
  5595. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5596. SOURCE_TYPE="ObjectStorage",
  5597. LOCATION="my-bucket",
  5598. AUTH_METHOD="SERVICE_ACCOUNT",
  5599. SERVICE_ACCOUNT_SECRET_NAME="s1"
  5600. );
  5601. )sql" , "<main>:7:49: Error: SERVICE_ACCOUNT_ID requires key\n");
  5602. ExpectFailWithError(R"sql(
  5603. USE plato;
  5604. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5605. SOURCE_TYPE="PostgreSQL",
  5606. LOCATION="protocol://host:port/",
  5607. AUTH_METHOD="BASIC",
  5608. LOGIN="admin"
  5609. );
  5610. )sql" , "<main>:7:27: Error: PASSWORD_SECRET_NAME requires key\n");
  5611. ExpectFailWithError(R"sql(
  5612. USE plato;
  5613. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5614. SOURCE_TYPE="PostgreSQL",
  5615. LOCATION="protocol://host:port/",
  5616. AUTH_METHOD="BASIC",
  5617. PASSWORD_SECRET_NAME="secret_name"
  5618. );
  5619. )sql" , "<main>:7:42: Error: LOGIN requires key\n");
  5620. ExpectFailWithError(R"sql(
  5621. USE plato;
  5622. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5623. SOURCE_TYPE="PostgreSQL",
  5624. LOCATION="protocol://host:port/",
  5625. AUTH_METHOD="MDB_BASIC",
  5626. SERVICE_ACCOUNT_SECRET_NAME="sa_secret_name",
  5627. LOGIN="admin",
  5628. PASSWORD_SECRET_NAME="secret_name"
  5629. );
  5630. )sql" , "<main>:9:42: Error: SERVICE_ACCOUNT_ID requires key\n");
  5631. ExpectFailWithError(R"sql(
  5632. USE plato;
  5633. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5634. SOURCE_TYPE="PostgreSQL",
  5635. LOCATION="protocol://host:port/",
  5636. AUTH_METHOD="MDB_BASIC",
  5637. SERVICE_ACCOUNT_ID="sa",
  5638. LOGIN="admin",
  5639. PASSWORD_SECRET_NAME="secret_name"
  5640. );
  5641. )sql" , "<main>:9:42: Error: SERVICE_ACCOUNT_SECRET_NAME requires key\n");
  5642. ExpectFailWithError(R"sql(
  5643. USE plato;
  5644. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5645. SOURCE_TYPE="PostgreSQL",
  5646. LOCATION="protocol://host:port/",
  5647. AUTH_METHOD="MDB_BASIC",
  5648. SERVICE_ACCOUNT_ID="sa",
  5649. SERVICE_ACCOUNT_SECRET_NAME="sa_secret_name",
  5650. PASSWORD_SECRET_NAME="secret_name"
  5651. );
  5652. )sql" , "<main>:9:42: Error: LOGIN requires key\n");
  5653. ExpectFailWithError(R"sql(
  5654. USE plato;
  5655. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5656. SOURCE_TYPE="PostgreSQL",
  5657. LOCATION="protocol://host:port/",
  5658. AUTH_METHOD="MDB_BASIC",
  5659. SERVICE_ACCOUNT_ID="sa",
  5660. SERVICE_ACCOUNT_SECRET_NAME="sa_secret_name",
  5661. LOGIN="admin"
  5662. );
  5663. )sql" , "<main>:9:27: Error: PASSWORD_SECRET_NAME requires key\n");
  5664. ExpectFailWithError(R"sql(
  5665. USE plato;
  5666. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5667. SOURCE_TYPE="PostgreSQL",
  5668. LOCATION="protocol://host:port/",
  5669. AUTH_METHOD="AWS",
  5670. AWS_SECRET_ACCESS_KEY_SECRET_NAME="secret_key_name",
  5671. AWS_REGION="ru-central-1"
  5672. );
  5673. )sql" , "<main>:8:32: Error: AWS_ACCESS_KEY_ID_SECRET_NAME requires key\n");
  5674. ExpectFailWithError(R"sql(
  5675. USE plato;
  5676. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5677. SOURCE_TYPE="PostgreSQL",
  5678. LOCATION="protocol://host:port/",
  5679. AUTH_METHOD="AWS",
  5680. AWS_ACCESS_KEY_ID_SECRET_NAME="secred_id_name",
  5681. AWS_REGION="ru-central-1"
  5682. );
  5683. )sql" , "<main>:8:32: Error: AWS_SECRET_ACCESS_KEY_SECRET_NAME requires key\n");
  5684. ExpectFailWithError(R"sql(
  5685. USE plato;
  5686. CREATE EXTERNAL DATA SOURCE MyDataSource WITH (
  5687. SOURCE_TYPE="PostgreSQL",
  5688. LOCATION="protocol://host:port/",
  5689. AUTH_METHOD="AWS",
  5690. AWS_SECRET_ACCESS_KEY_SECRET_NAME="secret_key_name",
  5691. AWS_ACCESS_KEY_ID_SECRET_NAME="secred_id_name"
  5692. );
  5693. )sql" , "<main>:8:51: Error: AWS_REGION requires key\n");
  5694. }
  5695. Y_UNIT_TEST(DropExternalDataSourceWithTablePrefix) {
  5696. NYql::TAstParseResult res = SqlToYql(R"sql(
  5697. USE plato;
  5698. DROP EXTERNAL DATA SOURCE MyDataSource;
  5699. )sql");
  5700. UNIT_ASSERT(res.Root);
  5701. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5702. if (word == "Write") {
  5703. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features"));
  5704. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  5705. }
  5706. };
  5707. TWordCountHive elementStat = { {TString("Write"), 0}};
  5708. VerifyProgram(res, elementStat, verifyLine);
  5709. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5710. }
  5711. Y_UNIT_TEST(DropExternalDataSource) {
  5712. NYql::TAstParseResult res = SqlToYql(R"sql(
  5713. USE plato;
  5714. pragma TablePathPrefix='/aba';
  5715. DROP EXTERNAL DATA SOURCE MyDataSource;
  5716. )sql");
  5717. UNIT_ASSERT(res.Root);
  5718. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5719. if (word == "Write") {
  5720. UNIT_ASSERT_STRING_CONTAINS(line, "/aba/MyDataSource");
  5721. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features"));
  5722. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  5723. }
  5724. };
  5725. TWordCountHive elementStat = { {TString("Write"), 0}};
  5726. VerifyProgram(res, elementStat, verifyLine);
  5727. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5728. }
  5729. Y_UNIT_TEST(DropExternalDataSourceIfExists) {
  5730. NYql::TAstParseResult res = SqlToYql(R"sql(
  5731. USE plato;
  5732. DROP EXTERNAL DATA SOURCE IF EXISTS MyDataSource;
  5733. )sql");
  5734. UNIT_ASSERT(res.Root);
  5735. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5736. if (word == "Write") {
  5737. UNIT_ASSERT_STRING_CONTAINS(line, "MyDataSource");
  5738. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObjectIfExists"));
  5739. }
  5740. };
  5741. TWordCountHive elementStat = { {TString("Write"), 0}};
  5742. VerifyProgram(res, elementStat, verifyLine);
  5743. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5744. }
  5745. }
  5746. Y_UNIT_TEST_SUITE(ExternalTable) {
  5747. Y_UNIT_TEST(CreateExternalTable) {
  5748. NYql::TAstParseResult res = SqlToYql(R"sql(
  5749. USE plato;
  5750. CREATE EXTERNAL TABLE mytable (
  5751. a int
  5752. ) WITH (
  5753. DATA_SOURCE="/Root/mydatasource",
  5754. LOCATION="/folder1/*"
  5755. );
  5756. )sql");
  5757. UNIT_ASSERT_C(res.Root, res.Issues.ToOneLineString());
  5758. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5759. if (word == "Write") {
  5760. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('data_source_path (String '"/Root/mydatasource")) '('location (String '"/folder1/*")))) '('tableType 'externalTable)))))#");
  5761. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tablescheme"));
  5762. }
  5763. };
  5764. TWordCountHive elementStat = { {TString("Write"), 0} };
  5765. VerifyProgram(res, elementStat, verifyLine);
  5766. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5767. }
  5768. Y_UNIT_TEST(CreateExternalTableWithTablePrefix) {
  5769. NYql::TAstParseResult res = SqlToYql(R"sql(
  5770. USE plato;
  5771. pragma TablePathPrefix='/aba';
  5772. CREATE EXTERNAL TABLE mytable (
  5773. a int
  5774. ) WITH (
  5775. DATA_SOURCE="mydatasource",
  5776. LOCATION="/folder1/*"
  5777. );
  5778. )sql");
  5779. UNIT_ASSERT_C(res.Root, res.Issues.ToOneLineString());
  5780. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5781. if (word == "Write") {
  5782. UNIT_ASSERT_STRING_CONTAINS(line, "/aba/mydatasource");
  5783. UNIT_ASSERT_STRING_CONTAINS(line, "/aba/mytable");
  5784. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("tablescheme"));
  5785. }
  5786. };
  5787. TWordCountHive elementStat = { {TString("Write"), 0} };
  5788. VerifyProgram(res, elementStat, verifyLine);
  5789. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5790. }
  5791. Y_UNIT_TEST(CreateExternalTableObjectStorage) {
  5792. auto res = SqlToYql(R"sql(
  5793. USE plato;
  5794. CREATE EXTERNAL TABLE mytable (
  5795. a int,
  5796. year Int
  5797. ) WITH (
  5798. DATA_SOURCE="/Root/mydatasource",
  5799. LOCATION="/folder1/*",
  5800. FORMAT="json_as_string",
  5801. `projection.enabled`="true",
  5802. `projection.year.type`="integer",
  5803. `projection.year.min`="2010",
  5804. `projection.year.max`="2022",
  5805. `projection.year.interval`="1",
  5806. `projection.month.type`="integer",
  5807. `projection.month.min`="1",
  5808. `projection.month.max`="12",
  5809. `projection.month.interval`="1",
  5810. `projection.month.digits`="2",
  5811. `storage.location.template`="${year}/${month}",
  5812. PARTITONED_BY = "[year, month]"
  5813. );
  5814. )sql");
  5815. UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString());
  5816. }
  5817. Y_UNIT_TEST(CreateExternalTableIfNotExists) {
  5818. NYql::TAstParseResult res = SqlToYql(R"sql(
  5819. USE plato;
  5820. CREATE EXTERNAL TABLE IF NOT EXISTS mytable (
  5821. a int
  5822. ) WITH (
  5823. DATA_SOURCE="/Root/mydatasource",
  5824. LOCATION="/folder1/*"
  5825. );
  5826. )sql");
  5827. UNIT_ASSERT_C(res.Root, res.Issues.ToOneLineString());
  5828. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5829. if (word == "Write") {
  5830. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('data_source_path (String '"/Root/mydatasource")) '('location (String '"/folder1/*")))) '('tableType 'externalTable)))))#");
  5831. UNIT_ASSERT_STRING_CONTAINS(line, "create_if_not_exists");
  5832. }
  5833. };
  5834. TWordCountHive elementStat = { {TString("Write"), 0} };
  5835. VerifyProgram(res, elementStat, verifyLine);
  5836. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5837. }
  5838. Y_UNIT_TEST(CreateExternalTableOrReplace) {
  5839. NYql::TAstParseResult res = SqlToYql(R"(
  5840. USE plato;
  5841. CREATE OR REPLACE EXTERNAL TABLE mytable (
  5842. a int
  5843. ) WITH (
  5844. DATA_SOURCE="/Root/mydatasource",
  5845. LOCATION="/folder1/*"
  5846. );
  5847. )");
  5848. UNIT_ASSERT_C(res.Root, res.Issues.ToOneLineString());
  5849. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5850. if (word == "Write") {
  5851. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('data_source_path (String '"/Root/mydatasource")) '('location (String '"/folder1/*")))) '('tableType 'externalTable)))))#");
  5852. UNIT_ASSERT_STRING_CONTAINS(line, "create_or_replace");
  5853. }
  5854. };
  5855. TWordCountHive elementStat = { {TString("Write"), 0} };
  5856. VerifyProgram(res, elementStat, verifyLine);
  5857. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5858. }
  5859. Y_UNIT_TEST(AlterExternalTableAddColumn) {
  5860. NYql::TAstParseResult res = SqlToYql(R"sql(
  5861. USE plato;
  5862. ALTER EXTERNAL TABLE mytable
  5863. ADD COLUMN my_column int32,
  5864. RESET (LOCATION);
  5865. )sql");
  5866. UNIT_ASSERT_C(res.Root, res.Issues.ToOneLineString());
  5867. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5868. if (word == "Write") {
  5869. UNIT_ASSERT_STRING_CONTAINS(line, R"#('actions '('('addColumns '('('"my_column" (AsOptionalType (DataType 'Int32))#");
  5870. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('setTableSettings '('('location)))#");
  5871. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('tableType 'externalTable))#");
  5872. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alter))#");
  5873. }
  5874. };
  5875. TWordCountHive elementStat = { {TString("Write"), 0} };
  5876. VerifyProgram(res, elementStat, verifyLine);
  5877. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5878. }
  5879. Y_UNIT_TEST(AlterExternalTableDropColumn) {
  5880. NYql::TAstParseResult res = SqlToYql(R"sql(
  5881. USE plato;
  5882. ALTER EXTERNAL TABLE mytable
  5883. DROP COLUMN my_column,
  5884. SET (Location = "abc", Other_Prop = "42"),
  5885. SET x 'y';
  5886. )sql");
  5887. UNIT_ASSERT_C(res.Root, res.Issues.ToOneLineString());
  5888. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5889. if (word == "Write") {
  5890. UNIT_ASSERT_STRING_CONTAINS(line, R"#('actions '('('dropColumns '('"my_column")#");
  5891. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('setTableSettings '('('location (String '"abc")) '('Other_Prop (String '"42")) '('x (String '"y")))))#");
  5892. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('tableType 'externalTable))#");
  5893. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alter))#");
  5894. }
  5895. };
  5896. TWordCountHive elementStat = { {TString("Write"), 0} };
  5897. VerifyProgram(res, elementStat, verifyLine);
  5898. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5899. }
  5900. Y_UNIT_TEST(CreateExternalTableWithBadArguments) {
  5901. ExpectFailWithError(R"sql(
  5902. USE plato;
  5903. CREATE EXTERNAL TABLE mytable;
  5904. )sql" , "<main>:3:45: Error: mismatched input ';' expecting '('\n");
  5905. ExpectFailWithError(R"sql(
  5906. USE plato;
  5907. CREATE EXTERNAL TABLE mytable (
  5908. a int
  5909. );
  5910. )sql" , "<main>:4:23: Error: DATA_SOURCE requires key\n");
  5911. ExpectFailWithError(R"sql(
  5912. USE plato;
  5913. CREATE EXTERNAL TABLE mytable (
  5914. a int
  5915. ) WITH (
  5916. DATA_SOURCE="/Root/mydatasource"
  5917. );
  5918. )sql" , "<main>:6:33: Error: LOCATION requires key\n");
  5919. ExpectFailWithError(R"sql(
  5920. USE plato;
  5921. CREATE EXTERNAL TABLE mytable (
  5922. a int
  5923. ) WITH (
  5924. LOCATION="/folder1/*"
  5925. );
  5926. )sql" , "<main>:6:30: Error: DATA_SOURCE requires key\n");
  5927. ExpectFailWithError(R"sql(
  5928. USE plato;
  5929. CREATE EXTERNAL TABLE mytable (
  5930. a int,
  5931. PRIMARY KEY(a)
  5932. ) WITH (
  5933. DATA_SOURCE="/Root/mydatasource",
  5934. LOCATION="/folder1/*"
  5935. );
  5936. )sql" , "<main>:8:30: Error: PRIMARY KEY is not supported for external table\n");
  5937. }
  5938. Y_UNIT_TEST(DropExternalTable) {
  5939. NYql::TAstParseResult res = SqlToYql(R"sql(
  5940. USE plato;
  5941. DROP EXTERNAL TABLE MyExternalTable;
  5942. )sql");
  5943. UNIT_ASSERT(res.Root);
  5944. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5945. if (word == "Write") {
  5946. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("tablescheme"));
  5947. }
  5948. };
  5949. TWordCountHive elementStat = { {TString("Write"), 0}};
  5950. VerifyProgram(res, elementStat, verifyLine);
  5951. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5952. }
  5953. Y_UNIT_TEST(DropExternalTableWithTablePrefix) {
  5954. NYql::TAstParseResult res = SqlToYql(R"sql(
  5955. USE plato;
  5956. pragma TablePathPrefix='/aba';
  5957. DROP EXTERNAL TABLE MyExternalTable;
  5958. )sql");
  5959. UNIT_ASSERT(res.Root);
  5960. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5961. if (word == "Write") {
  5962. UNIT_ASSERT_STRING_CONTAINS(line, "/aba/MyExternalTable");
  5963. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'tablescheme"));
  5964. }
  5965. };
  5966. TWordCountHive elementStat = { {TString("Write"), 0}};
  5967. VerifyProgram(res, elementStat, verifyLine);
  5968. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5969. }
  5970. Y_UNIT_TEST(DropExternalTableIfExists) {
  5971. NYql::TAstParseResult res = SqlToYql(R"sql(
  5972. USE plato;
  5973. DROP EXTERNAL TABLE IF EXISTS MyExternalTable;
  5974. )sql");
  5975. UNIT_ASSERT(res.Root);
  5976. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  5977. if (word == "Write") {
  5978. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("tablescheme"));
  5979. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("drop_if_exists"));
  5980. }
  5981. };
  5982. TWordCountHive elementStat = { {TString("Write"), 0}};
  5983. VerifyProgram(res, elementStat, verifyLine);
  5984. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  5985. }
  5986. }
  5987. Y_UNIT_TEST_SUITE(TopicsDDL) {
  5988. void TestQuery(const TString& query, bool expectOk = true) {
  5989. TStringBuilder finalQuery;
  5990. finalQuery << "use plato;" << Endl << query;
  5991. auto res = SqlToYql(finalQuery, 10, "kikimr");
  5992. if (expectOk) {
  5993. UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString());
  5994. } else {
  5995. UNIT_ASSERT(!res.IsOk());
  5996. }
  5997. }
  5998. Y_UNIT_TEST(CreateTopicSimple) {
  5999. TestQuery(R"(
  6000. CREATE TOPIC topic1;
  6001. )");
  6002. TestQuery(R"(
  6003. CREATE TOPIC `cluster1.topic1`;
  6004. )");
  6005. TestQuery(R"(
  6006. CREATE TOPIC topic1 WITH (metering_mode = "str_value", partition_count_limit = 123, retention_period = Interval('PT1H'));
  6007. )");
  6008. }
  6009. Y_UNIT_TEST(CreateTopicConsumer) {
  6010. TestQuery(R"(
  6011. CREATE TOPIC topic1 (CONSUMER cons1);
  6012. )");
  6013. TestQuery(R"(
  6014. CREATE TOPIC topic1 (CONSUMER cons1, CONSUMER cons2 WITH (important = false));
  6015. )");
  6016. TestQuery(R"(
  6017. CREATE TOPIC topic1 (CONSUMER cons1, CONSUMER cons2 WITH (important = false)) WITH (supported_codecs = "1,2,3");
  6018. )");
  6019. }
  6020. Y_UNIT_TEST(AlterTopicSimple) {
  6021. TestQuery(R"(
  6022. ALTER TOPIC topic1 SET (retention_period = Interval('PT1H'));
  6023. )");
  6024. TestQuery(R"(
  6025. ALTER TOPIC topic1 SET (retention_storage_mb = 3, partition_count_limit = 50);
  6026. )");
  6027. TestQuery(R"(
  6028. ALTER TOPIC topic1 RESET (supported_codecs, retention_period);
  6029. )");
  6030. TestQuery(R"(
  6031. ALTER TOPIC topic1 RESET (partition_write_speed_bytes_per_second),
  6032. SET (partition_write_burst_bytes = 11111, min_active_partitions = 1);
  6033. )");
  6034. }
  6035. Y_UNIT_TEST(AlterTopicConsumer) {
  6036. TestQuery(R"(
  6037. ALTER TOPIC topic1 ADD CONSUMER consumer1,
  6038. ADD CONSUMER consumer2 WITH (important = false, supported_codecs = "RAW"),
  6039. ALTER CONSUMER consumer3 SET (important = false, read_from = 1),
  6040. ALTER CONSUMER consumer3 RESET (supported_codecs),
  6041. DROP CONSUMER consumer4,
  6042. SET (partition_count_limit = 11, retention_period = Interval('PT1H')),
  6043. RESET(metering_mode)
  6044. )");
  6045. }
  6046. Y_UNIT_TEST(DropTopic) {
  6047. TestQuery(R"(
  6048. DROP TOPIC topic1;
  6049. )");
  6050. }
  6051. Y_UNIT_TEST(TopicBadRequests) {
  6052. TestQuery(R"(
  6053. CREATE TOPIC topic1();
  6054. )", false);
  6055. TestQuery(R"(
  6056. CREATE TOPIC topic1 SET setting1 = value1;
  6057. )", false);
  6058. TestQuery(R"(
  6059. ALTER TOPIC topic1 SET setting1 value1;
  6060. )", false);
  6061. TestQuery(R"(
  6062. ALTER TOPIC topic1 RESET setting1;
  6063. )", false);
  6064. TestQuery(R"(
  6065. ALTER TOPIC topic1 DROP CONSUMER consumer4 WITH (k1 = v1);
  6066. )", false);
  6067. TestQuery(R"(
  6068. CREATE TOPIC topic1 WITH (retention_period = 123);
  6069. )", false);
  6070. TestQuery(R"(
  6071. CREATE TOPIC topic1 (CONSUMER cons1, CONSUMER cons1 WITH (important = false));
  6072. )", false);
  6073. TestQuery(R"(
  6074. CREATE TOPIC topic1 (CONSUMER cons1 WITH (bad_option = false));
  6075. )", false);
  6076. TestQuery(R"(
  6077. ALTER TOPIC topic1 ADD CONSUMER cons1, ALTER CONSUMER cons1 RESET (important);
  6078. )", false);
  6079. TestQuery(R"(
  6080. ALTER TOPIC topic1 ADD CONSUMER consumer1,
  6081. ALTER CONSUMER consumer3 SET (supported_codecs = "RAW", read_from = 1),
  6082. ALTER CONSUMER consumer3 RESET (supported_codecs);
  6083. )", false);
  6084. TestQuery(R"(
  6085. ALTER TOPIC topic1 ADD CONSUMER consumer1,
  6086. ALTER CONSUMER consumer3 SET (supported_codecs = "RAW", read_from = 1),
  6087. ALTER CONSUMER consumer3 SET (read_from = 2);
  6088. )", false);
  6089. }
  6090. Y_UNIT_TEST(TopicWithPrefix) {
  6091. NYql::TAstParseResult res = SqlToYql(R"(
  6092. USE plato;
  6093. PRAGMA TablePathPrefix = '/database/path/to/tables';
  6094. ALTER TOPIC `my_table/my_feed` ADD CONSUMER `my_consumer`;
  6095. )");
  6096. UNIT_ASSERT(res.Root);
  6097. TWordCountHive elementStat = {{TString("/database/path/to/tables/my_table/my_feed"), 0}, {"topic", 0}};
  6098. VerifyProgram(res, elementStat);
  6099. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["topic"]);
  6100. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["/database/path/to/tables/my_table/my_feed"]);
  6101. }
  6102. }
  6103. Y_UNIT_TEST_SUITE(BlockEnginePragma) {
  6104. Y_UNIT_TEST(Basic) {
  6105. const TVector<TString> values = {"auto", "force", "disable"};
  6106. for (const auto& value : values) {
  6107. const auto query = TStringBuilder() << "pragma Blockengine='" << value << "'; select 1;";
  6108. NYql::TAstParseResult res = SqlToYql(query);
  6109. UNIT_ASSERT(res.Root);
  6110. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  6111. Y_UNUSED(word);
  6112. UNIT_ASSERT_STRING_CONTAINS(line, TStringBuilder() << R"(Configure! world (DataSource '"config") '"BlockEngine" '")" << value << "\"");
  6113. };
  6114. TWordCountHive elementStat({"BlockEngine"});
  6115. VerifyProgram(res, elementStat, verifyLine);
  6116. UNIT_ASSERT(elementStat["BlockEngine"] == ((value == "disable") ? 0 : 1));
  6117. }
  6118. }
  6119. Y_UNIT_TEST(UnknownSetting) {
  6120. ExpectFailWithError("use plato; pragma BlockEngine='foo';",
  6121. "<main>:1:31: Error: Expected `disable|auto|force' argument for: BlockEngine\n");
  6122. }
  6123. }
  6124. Y_UNIT_TEST_SUITE(TViewSyntaxTest) {
  6125. Y_UNIT_TEST(CreateViewSimple) {
  6126. NYql::TAstParseResult res = SqlToYql(R"(
  6127. USE plato;
  6128. CREATE VIEW TheView WITH (security_invoker = TRUE) AS SELECT 1;
  6129. )"
  6130. );
  6131. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6132. }
  6133. Y_UNIT_TEST(CreateViewIfNotExists) {
  6134. constexpr const char* name = "TheView";
  6135. NYql::TAstParseResult res = SqlToYql(std::format(R"(
  6136. USE plato;
  6137. CREATE VIEW IF NOT EXISTS {} AS SELECT 1;
  6138. )", name
  6139. ));
  6140. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6141. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  6142. if (word == "Write!") {
  6143. UNIT_ASSERT_STRING_CONTAINS(line, name);
  6144. UNIT_ASSERT_STRING_CONTAINS(line, "createObjectIfNotExists");
  6145. }
  6146. };
  6147. TWordCountHive elementStat = { {"Write!"} };
  6148. VerifyProgram(res, elementStat, verifyLine);
  6149. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6150. }
  6151. Y_UNIT_TEST(CreateViewFromTable) {
  6152. constexpr const char* path = "/PathPrefix/TheView";
  6153. constexpr const char* query = R"(
  6154. SELECT * FROM SomeTable
  6155. )";
  6156. NYql::TAstParseResult res = SqlToYql(std::format(R"(
  6157. USE plato;
  6158. CREATE VIEW `{}` WITH (security_invoker = TRUE) AS {};
  6159. )",
  6160. path,
  6161. query
  6162. )
  6163. );
  6164. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6165. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  6166. if (word == "Write!") {
  6167. UNIT_ASSERT_STRING_CONTAINS(line, path);
  6168. UNIT_ASSERT_STRING_CONTAINS(line, "createObject");
  6169. }
  6170. };
  6171. TWordCountHive elementStat = { {"Write!"} };
  6172. VerifyProgram(res, elementStat, verifyLine);
  6173. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6174. }
  6175. Y_UNIT_TEST(CheckReconstructedQuery) {
  6176. constexpr const char* path = "/PathPrefix/TheView";
  6177. constexpr const char* query = R"(
  6178. SELECT * FROM FirstTable JOIN SecondTable ON FirstTable.key == SecondTable.key
  6179. )";
  6180. NYql::TAstParseResult res = SqlToYql(std::format(R"(
  6181. USE plato;
  6182. CREATE VIEW `{}` WITH (security_invoker = TRUE) AS {};
  6183. )",
  6184. path,
  6185. query
  6186. )
  6187. );
  6188. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6189. TString reconstructedQuery = ToString(Tokenize(query));
  6190. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  6191. if (word == "query_text") {
  6192. UNIT_ASSERT_STRING_CONTAINS(line, reconstructedQuery);
  6193. }
  6194. };
  6195. TWordCountHive elementStat = { {"Write!"} };
  6196. VerifyProgram(res, elementStat, verifyLine);
  6197. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6198. }
  6199. Y_UNIT_TEST(DropView) {
  6200. constexpr const char* path = "/PathPrefix/TheView";
  6201. NYql::TAstParseResult res = SqlToYql(std::format(R"(
  6202. USE plato;
  6203. DROP VIEW `{}`;
  6204. )",
  6205. path
  6206. )
  6207. );
  6208. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6209. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  6210. if (word == "Write!") {
  6211. UNIT_ASSERT_STRING_CONTAINS(line, path);
  6212. UNIT_ASSERT_STRING_CONTAINS(line, "dropObject");
  6213. }
  6214. };
  6215. TWordCountHive elementStat = { {"Write!"} };
  6216. VerifyProgram(res, elementStat, verifyLine);
  6217. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6218. }
  6219. Y_UNIT_TEST(DropViewIfExists) {
  6220. constexpr const char* name = "TheView";
  6221. NYql::TAstParseResult res = SqlToYql(std::format(R"(
  6222. USE plato;
  6223. DROP VIEW IF EXISTS {};
  6224. )", name
  6225. ));
  6226. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6227. TVerifyLineFunc verifyLine = [&](const TString& word, const TString& line) {
  6228. if (word == "Write!") {
  6229. UNIT_ASSERT_STRING_CONTAINS(line, name);
  6230. UNIT_ASSERT_STRING_CONTAINS(line, "dropObjectIfExists");
  6231. }
  6232. };
  6233. TWordCountHive elementStat = { {"Write!"} };
  6234. VerifyProgram(res, elementStat, verifyLine);
  6235. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6236. }
  6237. Y_UNIT_TEST(CreateViewWithTablePrefix) {
  6238. NYql::TAstParseResult res = SqlToYql(R"(
  6239. USE plato;
  6240. PRAGMA TablePathPrefix='/PathPrefix';
  6241. CREATE VIEW TheView WITH (security_invoker = TRUE) AS SELECT 1;
  6242. )"
  6243. );
  6244. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6245. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6246. if (word == "Write!") {
  6247. UNIT_ASSERT_STRING_CONTAINS(line, "/PathPrefix/TheView");
  6248. UNIT_ASSERT_STRING_CONTAINS(line, "createObject");
  6249. }
  6250. };
  6251. TWordCountHive elementStat = { {"Write!"} };
  6252. VerifyProgram(res, elementStat, verifyLine);
  6253. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6254. }
  6255. Y_UNIT_TEST(DropViewWithTablePrefix) {
  6256. NYql::TAstParseResult res = SqlToYql(R"(
  6257. USE plato;
  6258. PRAGMA TablePathPrefix='/PathPrefix';
  6259. DROP VIEW TheView;
  6260. )"
  6261. );
  6262. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6263. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6264. if (word == "Write") {
  6265. UNIT_ASSERT_STRING_CONTAINS(line, "/PathPrefix/TheView");
  6266. UNIT_ASSERT_STRING_CONTAINS(line, "dropObject");
  6267. }
  6268. };
  6269. TWordCountHive elementStat = { {"Write!"} };
  6270. VerifyProgram(res, elementStat, verifyLine);
  6271. UNIT_ASSERT_VALUES_EQUAL(elementStat["Write!"], 1);
  6272. }
  6273. Y_UNIT_TEST(YtAlternativeSchemaSyntax) {
  6274. NYql::TAstParseResult res = SqlToYql(R"(
  6275. SELECT * FROM plato.Input WITH schema(y Int32, x String not null);
  6276. )");
  6277. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6278. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6279. if (word == "userschema") {
  6280. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos,
  6281. line.find(R"__('('('"userschema" (StructType '('"y" (AsOptionalType (DataType 'Int32))) '('"x" (DataType 'String))))))__"));
  6282. }
  6283. };
  6284. TWordCountHive elementStat = {{TString("userschema"), 0}};
  6285. VerifyProgram(res, elementStat, verifyLine);
  6286. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["userschema"]);
  6287. }
  6288. Y_UNIT_TEST(UseViewAndFullColumnId) {
  6289. NYql::TAstParseResult res = SqlToYql("USE plato; SELECT Input.x FROM Input VIEW uitzicht;");
  6290. UNIT_ASSERT(res.Root);
  6291. TWordCountHive elementStat = {{TString("SqlAccess"), 0}, {"SqlProjectItem", 0}, {"Read!", 0}};
  6292. VerifyProgram(res, elementStat);
  6293. UNIT_ASSERT_VALUES_EQUAL(0, elementStat["SqlAccess"]);
  6294. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["SqlProjectItem"]);
  6295. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Read!"]);
  6296. }
  6297. }
  6298. Y_UNIT_TEST_SUITE(CompactNamedExprs) {
  6299. Y_UNIT_TEST(SourceCallablesInWrongContext) {
  6300. TString query = R"(
  6301. pragma CompactNamedExprs;
  6302. $foo = %s();
  6303. select $foo from plato.Input;
  6304. )";
  6305. THashMap<TString, TString> errs = {
  6306. {"TableRow", "<main>:3:20: Error: TableRow requires data source\n"},
  6307. {"JoinTableRow", "<main>:3:20: Error: JoinTableRow requires data source\n"},
  6308. {"TableRecordIndex", "<main>:3:20: Error: Unable to use function: TableRecord without source\n"},
  6309. {"TablePath", "<main>:3:20: Error: Unable to use function: TablePath without source\n"},
  6310. {"SystemMetadata", "<main>:3:20: Error: Unable to use function: SystemMetadata without source\n"},
  6311. };
  6312. for (TString callable : { "TableRow", "JoinTableRow", "TableRecordIndex", "TablePath", "SystemMetadata"}) {
  6313. auto req = Sprintf(query.c_str(), callable.c_str());
  6314. ExpectFailWithError(req, errs[callable]);
  6315. }
  6316. }
  6317. Y_UNIT_TEST(ValidateUnusedExprs) {
  6318. TString query = R"(
  6319. pragma warning("disable", "4527");
  6320. pragma CompactNamedExprs;
  6321. pragma ValidateUnusedExprs;
  6322. $foo = count(1);
  6323. select 1;
  6324. )";
  6325. ExpectFailWithError(query, "<main>:6:20: Error: Aggregation is not allowed in this context\n");
  6326. query = R"(
  6327. pragma warning("disable", "4527");
  6328. pragma CompactNamedExprs;
  6329. pragma ValidateUnusedExprs;
  6330. define subquery $x() as
  6331. select count(1, 2);
  6332. end define;
  6333. select 1;
  6334. )";
  6335. ExpectFailWithError(query, "<main>:7:24: Error: Aggregation function Count requires exactly 1 argument(s), given: 2\n");
  6336. }
  6337. Y_UNIT_TEST(DisableValidateUnusedExprs) {
  6338. TString query = R"(
  6339. pragma warning("disable", "4527");
  6340. pragma CompactNamedExprs;
  6341. pragma DisableValidateUnusedExprs;
  6342. $foo = count(1);
  6343. select 1;
  6344. )";
  6345. SqlToYql(query).IsOk();
  6346. query = R"(
  6347. pragma warning("disable", "4527");
  6348. pragma CompactNamedExprs;
  6349. pragma DisableValidateUnusedExprs;
  6350. define subquery $x() as
  6351. select count(1, 2);
  6352. end define;
  6353. select 1;
  6354. )";
  6355. SqlToYql(query).IsOk();
  6356. }
  6357. }
  6358. Y_UNIT_TEST_SUITE(ResourcePool) {
  6359. Y_UNIT_TEST(CreateResourcePool) {
  6360. NYql::TAstParseResult res = SqlToYql(R"sql(
  6361. USE plato;
  6362. CREATE RESOURCE POOL MyResourcePool WITH (
  6363. CONCURRENT_QUERY_LIMIT=20,
  6364. QUERY_CANCEL_AFTER_SECONDS=86400,
  6365. QUEUE_TYPE="FIFO"
  6366. );
  6367. )sql");
  6368. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6369. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6370. if (word == "Write") {
  6371. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"concurrent_query_limit" (Int32 '"20")) '('"query_cancel_after_seconds" (Int32 '"86400")) '('"queue_type" '"FIFO"))#");
  6372. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  6373. }
  6374. };
  6375. TWordCountHive elementStat = { {TString("Write"), 0} };
  6376. VerifyProgram(res, elementStat, verifyLine);
  6377. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6378. }
  6379. Y_UNIT_TEST(CreateResourcePoolWithBadArguments) {
  6380. ExpectFailWithError(R"sql(
  6381. USE plato;
  6382. CREATE RESOURCE POOL MyResourcePool;
  6383. )sql" , "<main>:3:51: Error: mismatched input ';' expecting WITH\n");
  6384. ExpectFailWithError(R"sql(
  6385. USE plato;
  6386. CREATE RESOURCE POOL MyResourcePool WITH (
  6387. DUPLICATE_SETTING="first_value",
  6388. DUPLICATE_SETTING="second_value"
  6389. );
  6390. )sql" , "<main>:5:21: Error: DUPLICATE_SETTING duplicate keys\n");
  6391. }
  6392. Y_UNIT_TEST(AlterResourcePool) {
  6393. NYql::TAstParseResult res = SqlToYql(R"sql(
  6394. USE plato;
  6395. ALTER RESOURCE POOL MyResourcePool
  6396. SET (CONCURRENT_QUERY_LIMIT = 30, Weight = 5, QUEUE_TYPE = "UNORDERED"),
  6397. RESET (Query_Cancel_After_Seconds, Query_Count_Limit);
  6398. )sql");
  6399. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6400. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6401. if (word == "Write") {
  6402. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alterObject))#");
  6403. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('features '('('"concurrent_query_limit" (Int32 '"30")) '('"queue_type" '"UNORDERED") '('"weight" (Int32 '"5")))))#");
  6404. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('resetFeatures '('"query_cancel_after_seconds" '"query_count_limit")))#");
  6405. }
  6406. };
  6407. TWordCountHive elementStat = { {TString("Write"), 0} };
  6408. VerifyProgram(res, elementStat, verifyLine);
  6409. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6410. }
  6411. Y_UNIT_TEST(DropResourcePool) {
  6412. NYql::TAstParseResult res = SqlToYql(R"sql(
  6413. USE plato;
  6414. DROP RESOURCE POOL MyResourcePool;
  6415. )sql");
  6416. UNIT_ASSERT(res.Root);
  6417. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6418. if (word == "Write") {
  6419. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features"));
  6420. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  6421. }
  6422. };
  6423. TWordCountHive elementStat = { {TString("Write"), 0}};
  6424. VerifyProgram(res, elementStat, verifyLine);
  6425. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6426. }
  6427. }
  6428. Y_UNIT_TEST_SUITE(BackupCollection) {
  6429. Y_UNIT_TEST(CreateBackupCollection) {
  6430. NYql::TAstParseResult res = SqlToYql(R"sql(
  6431. USE plato;
  6432. CREATE BACKUP COLLECTION TestCollection WITH (
  6433. STORAGE="local",
  6434. TAG="test" -- for testing purposes, not a real thing
  6435. );
  6436. )sql");
  6437. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6438. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6439. if (word == "Write") {
  6440. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6441. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"storage" (String '"local")))#");
  6442. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"tag" (String '"test"))))#");
  6443. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('entries '()))#");
  6444. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'create"));
  6445. }
  6446. };
  6447. TWordCountHive elementStat = { {TString("Write"), 0} };
  6448. VerifyProgram(res, elementStat, verifyLine);
  6449. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6450. }
  6451. Y_UNIT_TEST(CreateBackupCollectionWithDatabase) {
  6452. NYql::TAstParseResult res = SqlToYql(R"sql(
  6453. USE plato;
  6454. CREATE BACKUP COLLECTION TestCollection DATABASE WITH (
  6455. STORAGE="local",
  6456. TAG="test" -- for testing purposes, not a real thing
  6457. );
  6458. )sql");
  6459. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6460. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6461. if (word == "Write") {
  6462. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6463. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"storage" (String '"local")))#");
  6464. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"tag" (String '"test"))))#");
  6465. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('entries '('('('type 'database)))))#");
  6466. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'create"));
  6467. }
  6468. };
  6469. TWordCountHive elementStat = { {TString("Write"), 0} };
  6470. VerifyProgram(res, elementStat, verifyLine);
  6471. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6472. }
  6473. Y_UNIT_TEST(CreateBackupCollectionWithTables) {
  6474. NYql::TAstParseResult res = SqlToYql(R"sql(
  6475. USE plato;
  6476. CREATE BACKUP COLLECTION TestCollection (
  6477. TABLE someTable,
  6478. TABLE `prefix/anotherTable`
  6479. ) WITH (
  6480. STORAGE="local",
  6481. TAG="test" -- for testing purposes, not a real thing
  6482. );
  6483. )sql");
  6484. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6485. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6486. if (word == "Write") {
  6487. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6488. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"storage" (String '"local")))#");
  6489. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"tag" (String '"test"))))#");
  6490. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('entries '('('('type 'table) '('path '"someTable")) '('('type 'table) '('path '"prefix/anotherTable")))))#");
  6491. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'create"));
  6492. }
  6493. };
  6494. TWordCountHive elementStat = { {TString("Write"), 0} };
  6495. VerifyProgram(res, elementStat, verifyLine);
  6496. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6497. }
  6498. Y_UNIT_TEST(CreateBackupCollectionWithBadArguments) {
  6499. ExpectFailWithError(R"sql(
  6500. USE plato;
  6501. CREATE BACKUP COLLECTION TestCollection;
  6502. )sql" , "<main>:3:55: Error: mismatched input ';' expecting {'(', DATABASE, WITH}\n");
  6503. ExpectFailWithError(R"sql(
  6504. USE plato;
  6505. CREATE BACKUP COLLECTION TABLE TestCollection;
  6506. )sql" , "<main>:3:47: Error: mismatched input 'TestCollection' expecting {'(', DATABASE, WITH}\n");
  6507. ExpectFailWithError(R"sql(
  6508. USE plato;
  6509. CREATE BACKUP COLLECTION DATABASE `test` TestCollection;
  6510. )sql" , "<main>:3:50: Error: mismatched input '`test`' expecting {'(', DATABASE, WITH}\n");
  6511. ExpectFailWithError(R"sql(
  6512. USE plato;
  6513. CREATE BACKUP COLLECTION TestCollection WITH (
  6514. DUPLICATE_SETTING="first_value",
  6515. DUPLICATE_SETTING="second_value"
  6516. );
  6517. )sql" , "<main>:5:21: Error: DUPLICATE_SETTING duplicate keys\n");
  6518. ExpectFailWithError(R"sql(
  6519. USE plato;
  6520. CREATE BACKUP COLLECTION TestCollection WITH (
  6521. INT_SETTING=1
  6522. );
  6523. )sql" , "<main>:4:21: Error: INT_SETTING value should be a string literal\n");
  6524. }
  6525. Y_UNIT_TEST(AlterBackupCollection) {
  6526. NYql::TAstParseResult res = SqlToYql(R"sql(
  6527. USE plato;
  6528. ALTER BACKUP COLLECTION TestCollection
  6529. SET (STORAGE="remote"), -- also just for test
  6530. SET (TAG1 = "123"),
  6531. RESET (TAG2, TAG3);
  6532. )sql");
  6533. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6534. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6535. if (word == "Write") {
  6536. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6537. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alter))#");
  6538. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"storage" (String '"remote")))#");
  6539. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('"tag1" (String '"123"))))#");
  6540. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('resetSettings '('"tag2" '"tag3")))#");
  6541. }
  6542. };
  6543. TWordCountHive elementStat = { {TString("Write"), 0} };
  6544. VerifyProgram(res, elementStat, verifyLine);
  6545. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6546. }
  6547. Y_UNIT_TEST(AlterBackupCollectionEntries) {
  6548. NYql::TAstParseResult res = SqlToYql(R"sql(
  6549. USE plato;
  6550. ALTER BACKUP COLLECTION TestCollection
  6551. DROP TABLE `test`,
  6552. ADD DATABASE;
  6553. )sql");
  6554. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6555. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6556. if (word == "Write") {
  6557. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6558. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alter))#");
  6559. UNIT_ASSERT_STRING_CONTAINS(line, R"#('alterEntries)#");
  6560. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('type 'table) '('path '"test") '('action 'drop)))#");
  6561. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('type 'database) '('action 'add)))#");
  6562. }
  6563. };
  6564. TWordCountHive elementStat = { {TString("Write"), 0} };
  6565. VerifyProgram(res, elementStat, verifyLine);
  6566. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6567. }
  6568. Y_UNIT_TEST(DropBackupCollection) {
  6569. NYql::TAstParseResult res = SqlToYql(R"sql(
  6570. USE plato;
  6571. DROP BACKUP COLLECTION TestCollection;
  6572. )sql");
  6573. UNIT_ASSERT(res.Root);
  6574. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6575. if (word == "Write") {
  6576. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6577. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("drop"));
  6578. }
  6579. };
  6580. TWordCountHive elementStat = { {TString("Write"), 0}};
  6581. VerifyProgram(res, elementStat, verifyLine);
  6582. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6583. }
  6584. }
  6585. Y_UNIT_TEST_SUITE(ResourcePoolClassifier) {
  6586. Y_UNIT_TEST(CreateResourcePoolClassifier) {
  6587. NYql::TAstParseResult res = SqlToYql(R"sql(
  6588. USE plato;
  6589. CREATE RESOURCE POOL CLASSIFIER MyResourcePoolClassifier WITH (
  6590. RANK=20,
  6591. RESOURCE_POOL='wgUserQueries',
  6592. MEMBER_NAME='yandex_query@abc'
  6593. );
  6594. )sql");
  6595. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6596. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6597. if (word == "Write") {
  6598. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('('"member_name" '"yandex_query@abc") '('"rank" (Int32 '"20")) '('"resource_pool" '"wgUserQueries"))#");
  6599. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("createObject"));
  6600. }
  6601. };
  6602. TWordCountHive elementStat = { {TString("Write"), 0} };
  6603. VerifyProgram(res, elementStat, verifyLine);
  6604. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6605. }
  6606. Y_UNIT_TEST(CreateResourcePoolClassifierWithBadArguments) {
  6607. ExpectFailWithError(R"sql(
  6608. USE plato;
  6609. CREATE RESOURCE POOL CLASSIFIER MyResourcePoolClassifier;
  6610. )sql" , "<main>:3:72: Error: mismatched input ';' expecting WITH\n");
  6611. ExpectFailWithError(R"sql(
  6612. USE plato;
  6613. CREATE RESOURCE POOL CLASSIFIER MyResourcePoolClassifier WITH (
  6614. DUPLICATE_SETTING="first_value",
  6615. DUPLICATE_SETTING="second_value"
  6616. );
  6617. )sql" , "<main>:5:21: Error: DUPLICATE_SETTING duplicate keys\n");
  6618. }
  6619. Y_UNIT_TEST(AlterResourcePoolClassifier) {
  6620. NYql::TAstParseResult res = SqlToYql(R"sql(
  6621. USE plato;
  6622. ALTER RESOURCE POOL CLASSIFIER MyResourcePoolClassifier
  6623. SET (RANK = 30, Weight = 5, MEMBER_NAME = "test@user"),
  6624. RESET (Resource_Pool);
  6625. )sql");
  6626. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6627. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6628. if (word == "Write") {
  6629. UNIT_ASSERT_STRING_CONTAINS(line, R"#(('mode 'alterObject))#");
  6630. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('features '('('"member_name" '"test@user") '('"rank" (Int32 '"30")) '('"weight" (Int32 '"5")))))#");
  6631. UNIT_ASSERT_STRING_CONTAINS(line, R"#('('resetFeatures '('"resource_pool")))#");
  6632. }
  6633. };
  6634. TWordCountHive elementStat = { {TString("Write"), 0} };
  6635. VerifyProgram(res, elementStat, verifyLine);
  6636. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6637. }
  6638. Y_UNIT_TEST(DropResourcePoolClassifier) {
  6639. NYql::TAstParseResult res = SqlToYql(R"sql(
  6640. USE plato;
  6641. DROP RESOURCE POOL CLASSIFIER MyResourcePoolClassifier;
  6642. )sql");
  6643. UNIT_ASSERT(res.Root);
  6644. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6645. if (word == "Write") {
  6646. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'features"));
  6647. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("dropObject"));
  6648. }
  6649. };
  6650. TWordCountHive elementStat = { {TString("Write"), 0}};
  6651. VerifyProgram(res, elementStat, verifyLine);
  6652. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6653. }
  6654. Y_UNIT_TEST(BacktickMatching) {
  6655. auto req = "select\n"
  6656. " 1 as `Schema has \\`RealCost\\``\n"
  6657. " -- foo`bar";
  6658. auto res = SqlToYql(req);
  6659. UNIT_ASSERT(res.Root);
  6660. UNIT_ASSERT(res.IsOk());
  6661. UNIT_ASSERT(res.Issues.Size() == 0);
  6662. res = SqlToYqlWithAnsiLexer(req);
  6663. UNIT_ASSERT(res.Root);
  6664. UNIT_ASSERT(res.IsOk());
  6665. UNIT_ASSERT(res.Issues.Size() == 0);
  6666. req = "select 1 as `a``b`, 2 as ````, 3 as `\\x60a\\x60`, 4 as ```b```, 5 as `\\`c\\``";
  6667. res = SqlToYql(req);
  6668. UNIT_ASSERT(res.Root);
  6669. UNIT_ASSERT(res.IsOk());
  6670. UNIT_ASSERT(res.Issues.Size() == 0);
  6671. res = SqlToYqlWithAnsiLexer(req);
  6672. UNIT_ASSERT(res.Root);
  6673. UNIT_ASSERT(res.IsOk());
  6674. UNIT_ASSERT(res.Issues.Size() == 0);
  6675. }
  6676. }
  6677. Y_UNIT_TEST_SUITE(Backup) {
  6678. Y_UNIT_TEST(Simple) {
  6679. NYql::TAstParseResult res = SqlToYql(R"sql(
  6680. USE plato;
  6681. BACKUP TestCollection;
  6682. )sql");
  6683. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6684. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6685. if (word == "Write") {
  6686. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6687. UNIT_ASSERT_VALUES_EQUAL(TString::npos, line.find("'Incremental"));
  6688. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'backup"));
  6689. }
  6690. };
  6691. TWordCountHive elementStat = { {TString("Write"), 0} };
  6692. VerifyProgram(res, elementStat, verifyLine);
  6693. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6694. }
  6695. Y_UNIT_TEST(Incremental) {
  6696. NYql::TAstParseResult res = SqlToYql(R"sql(
  6697. USE plato;
  6698. BACKUP TestCollection INCREMENTAL;
  6699. )sql");
  6700. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6701. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6702. if (word == "Write") {
  6703. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6704. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'backupIncremental"));
  6705. }
  6706. };
  6707. TWordCountHive elementStat = { {TString("Write"), 0} };
  6708. VerifyProgram(res, elementStat, verifyLine);
  6709. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6710. }
  6711. }
  6712. Y_UNIT_TEST_SUITE(Restore) {
  6713. Y_UNIT_TEST(Simple) {
  6714. NYql::TAstParseResult res = SqlToYql(R"sql(
  6715. USE plato;
  6716. RESTORE TestCollection;
  6717. )sql");
  6718. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6719. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6720. if (word == "Write") {
  6721. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6722. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'restore"));
  6723. }
  6724. };
  6725. TWordCountHive elementStat = { {TString("Write"), 0} };
  6726. VerifyProgram(res, elementStat, verifyLine);
  6727. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6728. }
  6729. Y_UNIT_TEST(AtPoint) {
  6730. NYql::TAstParseResult res = SqlToYql(R"sql(
  6731. USE plato;
  6732. RESTORE TestCollection AT '2024-06-16_20-14-02';
  6733. )sql");
  6734. UNIT_ASSERT_C(res.Root, res.Issues.ToString());
  6735. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6736. if (word == "Write") {
  6737. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find(R"#('"TestCollection")#"));
  6738. UNIT_ASSERT_STRING_CONTAINS(line, R"#('at '"2024-06-16_20-14-02")#");
  6739. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("'restore"));
  6740. }
  6741. };
  6742. TWordCountHive elementStat = { {TString("Write"), 0} };
  6743. VerifyProgram(res, elementStat, verifyLine);
  6744. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6745. }
  6746. }
  6747. Y_UNIT_TEST_SUITE(ColumnFamily) {
  6748. Y_UNIT_TEST(CompressionLevelCorrectUsage) {
  6749. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6750. CREATE TABLE tableName (
  6751. Key Uint32 FAMILY default,
  6752. Value String FAMILY family1,
  6753. PRIMARY KEY (Key),
  6754. FAMILY default (
  6755. DATA = "test",
  6756. COMPRESSION = "lz4",
  6757. COMPRESSION_LEVEL = 5
  6758. ),
  6759. FAMILY family1 (
  6760. DATA = "test",
  6761. COMPRESSION = "lz4",
  6762. COMPRESSION_LEVEL = 3
  6763. )
  6764. );
  6765. )");
  6766. UNIT_ASSERT(res.IsOk());
  6767. UNIT_ASSERT(res.Issues.Size() == 0);
  6768. TVerifyLineFunc verifyLine = [](const TString& word, const TString& line) {
  6769. if (word == "Write") {
  6770. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("compression_level"));
  6771. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("5"));
  6772. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, line.find("3"));
  6773. }
  6774. };
  6775. TWordCountHive elementStat = { { TString("Write"), 0 }, { TString("compression_level"), 0 } };
  6776. VerifyProgram(res, elementStat, verifyLine);
  6777. UNIT_ASSERT_VALUES_EQUAL(1, elementStat["Write"]);
  6778. UNIT_ASSERT_VALUES_EQUAL(2, elementStat["compression_level"]);
  6779. }
  6780. Y_UNIT_TEST(FieldDataIsNotString) {
  6781. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6782. CREATE TABLE tableName (
  6783. Key Uint32 FAMILY default,
  6784. PRIMARY KEY (Key),
  6785. FAMILY default (
  6786. DATA = 1,
  6787. COMPRESSION = "lz4",
  6788. COMPRESSION_LEVEL = 5
  6789. )
  6790. );
  6791. )");
  6792. UNIT_ASSERT(!res.IsOk());
  6793. UNIT_ASSERT(res.Issues.Size() == 1);
  6794. UNIT_ASSERT_STRING_CONTAINS(res.Issues.ToString(), "DATA value should be a string literal");
  6795. }
  6796. Y_UNIT_TEST(FieldCompressionIsNotString) {
  6797. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6798. CREATE TABLE tableName (
  6799. Key Uint32 FAMILY default,
  6800. PRIMARY KEY (Key),
  6801. FAMILY default (
  6802. DATA = "test",
  6803. COMPRESSION = 2,
  6804. COMPRESSION_LEVEL = 5
  6805. ),
  6806. );
  6807. )");
  6808. UNIT_ASSERT(!res.IsOk());
  6809. UNIT_ASSERT(res.Issues.Size() == 1);
  6810. UNIT_ASSERT_STRING_CONTAINS(res.Issues.ToString(), "COMPRESSION value should be a string literal");
  6811. }
  6812. Y_UNIT_TEST(FieldCompressionLevelIsNotInteger) {
  6813. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6814. CREATE TABLE tableName (
  6815. Key Uint32 FAMILY default,
  6816. PRIMARY KEY (Key),
  6817. FAMILY default (
  6818. DATA = "test",
  6819. COMPRESSION = "lz4",
  6820. COMPRESSION_LEVEL = "5"
  6821. )
  6822. );
  6823. )");
  6824. UNIT_ASSERT(!res.IsOk());
  6825. UNIT_ASSERT(res.Issues.Size() == 1);
  6826. UNIT_ASSERT_STRING_CONTAINS(res.Issues.ToString(), "COMPRESSION_LEVEL value should be an integer");
  6827. }
  6828. Y_UNIT_TEST(AlterCompressionCorrectUsage) {
  6829. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6830. ALTER TABLE tableName ALTER FAMILY default SET COMPRESSION "lz4";
  6831. )");
  6832. UNIT_ASSERT(res.IsOk());
  6833. UNIT_ASSERT(res.Issues.Size() == 0);
  6834. }
  6835. Y_UNIT_TEST(AlterCompressionFieldIsNotString) {
  6836. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6837. ALTER TABLE tableName ALTER FAMILY default SET COMPRESSION lz4;
  6838. )");
  6839. UNIT_ASSERT(!res.IsOk());
  6840. UNIT_ASSERT(res.Issues.Size() == 1);
  6841. UNIT_ASSERT_STRING_CONTAINS(res.Issues.ToString(), "mismatched input 'lz4' expecting {STRING_VALUE, DIGITS, INTEGER_VALUE}");
  6842. }
  6843. Y_UNIT_TEST(AlterCompressionLevelCorrectUsage) {
  6844. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6845. ALTER TABLE tableName ALTER FAMILY default SET COMPRESSION_LEVEL 5;
  6846. )");
  6847. UNIT_ASSERT(res.IsOk());
  6848. UNIT_ASSERT(res.Issues.Size() == 0);
  6849. }
  6850. Y_UNIT_TEST(AlterCompressionLevelFieldIsNotInteger) {
  6851. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6852. ALTER TABLE tableName ALTER FAMILY default SET COMPRESSION_LEVEL "5";
  6853. )");
  6854. UNIT_ASSERT(!res.IsOk());
  6855. UNIT_ASSERT(res.Issues.Size() == 1);
  6856. UNIT_ASSERT_STRING_CONTAINS(res.Issues.ToString(), "COMPRESSION_LEVEL value should be an integer");
  6857. }
  6858. }
  6859. Y_UNIT_TEST_SUITE(QuerySplit) {
  6860. Y_UNIT_TEST(Simple) {
  6861. TString query = R"(
  6862. ;
  6863. -- Comment 1
  6864. SELECT * From Input; -- Comment 2
  6865. -- Comment 3
  6866. $a = "a";
  6867. -- Comment 9
  6868. ;
  6869. -- Comment 10
  6870. -- Comment 8
  6871. $b = ($x) -> {
  6872. -- comment 4
  6873. return /* Comment 5 */ $x;
  6874. -- Comment 6
  6875. };
  6876. // Comment 7
  6877. )";
  6878. google::protobuf::Arena Arena;
  6879. NSQLTranslation::TTranslationSettings settings;
  6880. settings.AnsiLexer = false;
  6881. settings.Antlr4Parser = true;
  6882. settings.Arena = &Arena;
  6883. TVector<TString> statements;
  6884. NYql::TIssues issues;
  6885. NSQLTranslationV1::TLexers lexers;
  6886. lexers.Antlr4 = NSQLTranslationV1::MakeAntlr4LexerFactory();
  6887. NSQLTranslationV1::TParsers parsers;
  6888. parsers.Antlr4 = NSQLTranslationV1::MakeAntlr4ParserFactory();
  6889. UNIT_ASSERT(NSQLTranslationV1::SplitQueryToStatements(lexers, parsers, query, statements, issues, settings));
  6890. UNIT_ASSERT_VALUES_EQUAL(statements.size(), 3);
  6891. UNIT_ASSERT_VALUES_EQUAL(statements[0], "-- Comment 1\n SELECT * From Input; -- Comment 2\n");
  6892. UNIT_ASSERT_VALUES_EQUAL(statements[1], R"(-- Comment 3
  6893. $a = "a";)");
  6894. UNIT_ASSERT_VALUES_EQUAL(statements[2], R"(-- Comment 10
  6895. -- Comment 8
  6896. $b = ($x) -> {
  6897. -- comment 4
  6898. return /* Comment 5 */ $x;
  6899. -- Comment 6
  6900. };)");
  6901. }
  6902. }
  6903. Y_UNIT_TEST_SUITE(Transfer) {
  6904. Y_UNIT_TEST(Lambda) {
  6905. NYql::TAstParseResult res = SqlToYql(R"( use plato;
  6906. -- Русский коммент, empty statement
  6907. ;
  6908. -- befor comment
  6909. $a = "А";
  6910. SELECT * FROM Input;
  6911. $b = ($x) -> { return $a || $x; };
  6912. CREATE TRANSFER `TransferName`
  6913. FROM `TopicName` TO `TableName`
  6914. USING ($x) -> {
  6915. -- internal comment
  6916. return $b($x);
  6917. }
  6918. WITH (
  6919. CONNECTION_STRING = "grpc://localhost:2135/?database=/Root"
  6920. );
  6921. )");
  6922. UNIT_ASSERT_C(res.IsOk(), res.Issues.ToString());
  6923. UNIT_ASSERT_VALUES_EQUAL_C(res.Issues.Size(), 0, res.Issues.ToString());
  6924. const auto programm = GetPrettyPrint(res);
  6925. Cerr << ">>>>> Root " << programm << Endl;
  6926. auto expected = R"('transformLambda 'use plato;
  6927. -- befor comment
  6928. $a = "А";
  6929. $b = ($x) -> { return $a || $x; };
  6930. $__ydb_transfer_lambda = ($x) -> {
  6931. -- internal comment
  6932. return $b($x);
  6933. };
  6934. ))";
  6935. UNIT_ASSERT_VALUES_UNEQUAL(TString::npos, programm.find(expected));
  6936. }
  6937. }
  6938. Y_UNIT_TEST_SUITE(MatchRecognizeMeasuresAggregation) {
  6939. Y_UNIT_TEST(InsideSelect) {
  6940. ExpectFailWithError(R"sql(
  6941. SELECT FIRST(0), LAST(1);
  6942. )sql",
  6943. "<main>:2:20: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6944. "<main>:2:30: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6945. );
  6946. }
  6947. Y_UNIT_TEST(OutsideSelect) {
  6948. ExpectFailWithError(R"sql(
  6949. $lambda = ($x) -> (FIRST($x) + LAST($x));
  6950. SELECT $lambda(x) FROM plato.Input;
  6951. )sql",
  6952. "<main>:2:32: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6953. "<main>:2:44: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6954. );
  6955. }
  6956. Y_UNIT_TEST(AsAggregateFunction) {
  6957. ExpectFailWithError(R"sql(
  6958. SELECT FIRST(x), LAST(x) FROM plato.Input;
  6959. )sql",
  6960. "<main>:2:20: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6961. "<main>:2:30: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6962. );
  6963. }
  6964. Y_UNIT_TEST(AsWindowFunction) {
  6965. ExpectFailWithError(R"sql(
  6966. SELECT FIRST(x) OVER(), LAST(x) OVER() FROM plato.Input;
  6967. )sql",
  6968. "<main>:2:20: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6969. "<main>:2:37: Error: Cannot use FIRST and LAST outside the MATCH_RECOGNIZE context\n"
  6970. );
  6971. }
  6972. }