sql_ut.cpp 350 KB

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