sql_ut_antlr4.cpp 347 KB

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