compiler.py 279 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081
  1. # sql/compiler.py
  2. # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
  3. # <see AUTHORS file>
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: https://www.opensource.org/licenses/mit-license.php
  7. # mypy: allow-untyped-defs, allow-untyped-calls
  8. """Base SQL and DDL compiler implementations.
  9. Classes provided include:
  10. :class:`.compiler.SQLCompiler` - renders SQL
  11. strings
  12. :class:`.compiler.DDLCompiler` - renders DDL
  13. (data definition language) strings
  14. :class:`.compiler.GenericTypeCompiler` - renders
  15. type specification strings.
  16. To generate user-defined SQL strings, see
  17. :doc:`/ext/compiler`.
  18. """
  19. from __future__ import annotations
  20. import collections
  21. import collections.abc as collections_abc
  22. import contextlib
  23. from enum import IntEnum
  24. import functools
  25. import itertools
  26. import operator
  27. import re
  28. from time import perf_counter
  29. import typing
  30. from typing import Any
  31. from typing import Callable
  32. from typing import cast
  33. from typing import ClassVar
  34. from typing import Dict
  35. from typing import FrozenSet
  36. from typing import Iterable
  37. from typing import Iterator
  38. from typing import List
  39. from typing import Mapping
  40. from typing import MutableMapping
  41. from typing import NamedTuple
  42. from typing import NoReturn
  43. from typing import Optional
  44. from typing import Pattern
  45. from typing import Sequence
  46. from typing import Set
  47. from typing import Tuple
  48. from typing import Type
  49. from typing import TYPE_CHECKING
  50. from typing import Union
  51. from . import base
  52. from . import coercions
  53. from . import crud
  54. from . import elements
  55. from . import functions
  56. from . import operators
  57. from . import roles
  58. from . import schema
  59. from . import selectable
  60. from . import sqltypes
  61. from . import util as sql_util
  62. from ._typing import is_column_element
  63. from ._typing import is_dml
  64. from .base import _de_clone
  65. from .base import _from_objects
  66. from .base import _NONE_NAME
  67. from .base import _SentinelDefaultCharacterization
  68. from .base import NO_ARG
  69. from .elements import quoted_name
  70. from .sqltypes import TupleType
  71. from .visitors import prefix_anon_map
  72. from .. import exc
  73. from .. import util
  74. from ..util import FastIntFlag
  75. from ..util.typing import Literal
  76. from ..util.typing import Protocol
  77. from ..util.typing import Self
  78. from ..util.typing import TypedDict
  79. if typing.TYPE_CHECKING:
  80. from .annotation import _AnnotationDict
  81. from .base import _AmbiguousTableNameMap
  82. from .base import CompileState
  83. from .base import Executable
  84. from .cache_key import CacheKey
  85. from .ddl import ExecutableDDLElement
  86. from .dml import Insert
  87. from .dml import Update
  88. from .dml import UpdateBase
  89. from .dml import UpdateDMLState
  90. from .dml import ValuesBase
  91. from .elements import _truncated_label
  92. from .elements import BinaryExpression
  93. from .elements import BindParameter
  94. from .elements import ClauseElement
  95. from .elements import ColumnClause
  96. from .elements import ColumnElement
  97. from .elements import False_
  98. from .elements import Label
  99. from .elements import Null
  100. from .elements import True_
  101. from .functions import Function
  102. from .schema import CheckConstraint
  103. from .schema import Column
  104. from .schema import Constraint
  105. from .schema import ForeignKeyConstraint
  106. from .schema import IdentityOptions
  107. from .schema import Index
  108. from .schema import PrimaryKeyConstraint
  109. from .schema import Table
  110. from .schema import UniqueConstraint
  111. from .selectable import _ColumnsClauseElement
  112. from .selectable import AliasedReturnsRows
  113. from .selectable import CompoundSelectState
  114. from .selectable import CTE
  115. from .selectable import FromClause
  116. from .selectable import NamedFromClause
  117. from .selectable import ReturnsRows
  118. from .selectable import Select
  119. from .selectable import SelectState
  120. from .type_api import _BindProcessorType
  121. from .type_api import TypeDecorator
  122. from .type_api import TypeEngine
  123. from .type_api import UserDefinedType
  124. from .visitors import Visitable
  125. from ..engine.cursor import CursorResultMetaData
  126. from ..engine.interfaces import _CoreSingleExecuteParams
  127. from ..engine.interfaces import _DBAPIAnyExecuteParams
  128. from ..engine.interfaces import _DBAPIMultiExecuteParams
  129. from ..engine.interfaces import _DBAPISingleExecuteParams
  130. from ..engine.interfaces import _ExecuteOptions
  131. from ..engine.interfaces import _GenericSetInputSizesType
  132. from ..engine.interfaces import _MutableCoreSingleExecuteParams
  133. from ..engine.interfaces import Dialect
  134. from ..engine.interfaces import SchemaTranslateMapType
  135. _FromHintsType = Dict["FromClause", str]
  136. RESERVED_WORDS = {
  137. "all",
  138. "analyse",
  139. "analyze",
  140. "and",
  141. "any",
  142. "array",
  143. "as",
  144. "asc",
  145. "asymmetric",
  146. "authorization",
  147. "between",
  148. "binary",
  149. "both",
  150. "case",
  151. "cast",
  152. "check",
  153. "collate",
  154. "column",
  155. "constraint",
  156. "create",
  157. "cross",
  158. "current_date",
  159. "current_role",
  160. "current_time",
  161. "current_timestamp",
  162. "current_user",
  163. "default",
  164. "deferrable",
  165. "desc",
  166. "distinct",
  167. "do",
  168. "else",
  169. "end",
  170. "except",
  171. "false",
  172. "for",
  173. "foreign",
  174. "freeze",
  175. "from",
  176. "full",
  177. "grant",
  178. "group",
  179. "having",
  180. "ilike",
  181. "in",
  182. "initially",
  183. "inner",
  184. "intersect",
  185. "into",
  186. "is",
  187. "isnull",
  188. "join",
  189. "leading",
  190. "left",
  191. "like",
  192. "limit",
  193. "localtime",
  194. "localtimestamp",
  195. "natural",
  196. "new",
  197. "not",
  198. "notnull",
  199. "null",
  200. "off",
  201. "offset",
  202. "old",
  203. "on",
  204. "only",
  205. "or",
  206. "order",
  207. "outer",
  208. "overlaps",
  209. "placing",
  210. "primary",
  211. "references",
  212. "right",
  213. "select",
  214. "session_user",
  215. "set",
  216. "similar",
  217. "some",
  218. "symmetric",
  219. "table",
  220. "then",
  221. "to",
  222. "trailing",
  223. "true",
  224. "union",
  225. "unique",
  226. "user",
  227. "using",
  228. "verbose",
  229. "when",
  230. "where",
  231. }
  232. LEGAL_CHARACTERS = re.compile(r"^[A-Z0-9_$]+$", re.I)
  233. LEGAL_CHARACTERS_PLUS_SPACE = re.compile(r"^[A-Z0-9_ $]+$", re.I)
  234. ILLEGAL_INITIAL_CHARACTERS = {str(x) for x in range(0, 10)}.union(["$"])
  235. FK_ON_DELETE = re.compile(
  236. r"^(?:RESTRICT|CASCADE|SET NULL|NO ACTION|SET DEFAULT)$", re.I
  237. )
  238. FK_ON_UPDATE = re.compile(
  239. r"^(?:RESTRICT|CASCADE|SET NULL|NO ACTION|SET DEFAULT)$", re.I
  240. )
  241. FK_INITIALLY = re.compile(r"^(?:DEFERRED|IMMEDIATE)$", re.I)
  242. BIND_PARAMS = re.compile(r"(?<![:\w\$\x5c]):([\w\$]+)(?![:\w\$])", re.UNICODE)
  243. BIND_PARAMS_ESC = re.compile(r"\x5c(:[\w\$]*)(?![:\w\$])", re.UNICODE)
  244. _pyformat_template = "%%(%(name)s)s"
  245. BIND_TEMPLATES = {
  246. "pyformat": _pyformat_template,
  247. "qmark": "?",
  248. "format": "%%s",
  249. "numeric": ":[_POSITION]",
  250. "numeric_dollar": "$[_POSITION]",
  251. "named": ":%(name)s",
  252. }
  253. OPERATORS = {
  254. # binary
  255. operators.and_: " AND ",
  256. operators.or_: " OR ",
  257. operators.add: " + ",
  258. operators.mul: " * ",
  259. operators.sub: " - ",
  260. operators.mod: " % ",
  261. operators.neg: "-",
  262. operators.lt: " < ",
  263. operators.le: " <= ",
  264. operators.ne: " != ",
  265. operators.gt: " > ",
  266. operators.ge: " >= ",
  267. operators.eq: " = ",
  268. operators.is_distinct_from: " IS DISTINCT FROM ",
  269. operators.is_not_distinct_from: " IS NOT DISTINCT FROM ",
  270. operators.concat_op: " || ",
  271. operators.match_op: " MATCH ",
  272. operators.not_match_op: " NOT MATCH ",
  273. operators.in_op: " IN ",
  274. operators.not_in_op: " NOT IN ",
  275. operators.comma_op: ", ",
  276. operators.from_: " FROM ",
  277. operators.as_: " AS ",
  278. operators.is_: " IS ",
  279. operators.is_not: " IS NOT ",
  280. operators.collate: " COLLATE ",
  281. # unary
  282. operators.exists: "EXISTS ",
  283. operators.distinct_op: "DISTINCT ",
  284. operators.inv: "NOT ",
  285. operators.any_op: "ANY ",
  286. operators.all_op: "ALL ",
  287. # modifiers
  288. operators.desc_op: " DESC",
  289. operators.asc_op: " ASC",
  290. operators.nulls_first_op: " NULLS FIRST",
  291. operators.nulls_last_op: " NULLS LAST",
  292. # bitwise
  293. operators.bitwise_xor_op: " ^ ",
  294. operators.bitwise_or_op: " | ",
  295. operators.bitwise_and_op: " & ",
  296. operators.bitwise_not_op: "~",
  297. operators.bitwise_lshift_op: " << ",
  298. operators.bitwise_rshift_op: " >> ",
  299. }
  300. FUNCTIONS: Dict[Type[Function[Any]], str] = {
  301. functions.coalesce: "coalesce",
  302. functions.current_date: "CURRENT_DATE",
  303. functions.current_time: "CURRENT_TIME",
  304. functions.current_timestamp: "CURRENT_TIMESTAMP",
  305. functions.current_user: "CURRENT_USER",
  306. functions.localtime: "LOCALTIME",
  307. functions.localtimestamp: "LOCALTIMESTAMP",
  308. functions.random: "random",
  309. functions.sysdate: "sysdate",
  310. functions.session_user: "SESSION_USER",
  311. functions.user: "USER",
  312. functions.cube: "CUBE",
  313. functions.rollup: "ROLLUP",
  314. functions.grouping_sets: "GROUPING SETS",
  315. }
  316. EXTRACT_MAP = {
  317. "month": "month",
  318. "day": "day",
  319. "year": "year",
  320. "second": "second",
  321. "hour": "hour",
  322. "doy": "doy",
  323. "minute": "minute",
  324. "quarter": "quarter",
  325. "dow": "dow",
  326. "week": "week",
  327. "epoch": "epoch",
  328. "milliseconds": "milliseconds",
  329. "microseconds": "microseconds",
  330. "timezone_hour": "timezone_hour",
  331. "timezone_minute": "timezone_minute",
  332. }
  333. COMPOUND_KEYWORDS = {
  334. selectable._CompoundSelectKeyword.UNION: "UNION",
  335. selectable._CompoundSelectKeyword.UNION_ALL: "UNION ALL",
  336. selectable._CompoundSelectKeyword.EXCEPT: "EXCEPT",
  337. selectable._CompoundSelectKeyword.EXCEPT_ALL: "EXCEPT ALL",
  338. selectable._CompoundSelectKeyword.INTERSECT: "INTERSECT",
  339. selectable._CompoundSelectKeyword.INTERSECT_ALL: "INTERSECT ALL",
  340. }
  341. class ResultColumnsEntry(NamedTuple):
  342. """Tracks a column expression that is expected to be represented
  343. in the result rows for this statement.
  344. This normally refers to the columns clause of a SELECT statement
  345. but may also refer to a RETURNING clause, as well as for dialect-specific
  346. emulations.
  347. """
  348. keyname: str
  349. """string name that's expected in cursor.description"""
  350. name: str
  351. """column name, may be labeled"""
  352. objects: Tuple[Any, ...]
  353. """sequence of objects that should be able to locate this column
  354. in a RowMapping. This is typically string names and aliases
  355. as well as Column objects.
  356. """
  357. type: TypeEngine[Any]
  358. """Datatype to be associated with this column. This is where
  359. the "result processing" logic directly links the compiled statement
  360. to the rows that come back from the cursor.
  361. """
  362. class _ResultMapAppender(Protocol):
  363. def __call__(
  364. self,
  365. keyname: str,
  366. name: str,
  367. objects: Sequence[Any],
  368. type_: TypeEngine[Any],
  369. ) -> None: ...
  370. # integer indexes into ResultColumnsEntry used by cursor.py.
  371. # some profiling showed integer access faster than named tuple
  372. RM_RENDERED_NAME: Literal[0] = 0
  373. RM_NAME: Literal[1] = 1
  374. RM_OBJECTS: Literal[2] = 2
  375. RM_TYPE: Literal[3] = 3
  376. class _BaseCompilerStackEntry(TypedDict):
  377. asfrom_froms: Set[FromClause]
  378. correlate_froms: Set[FromClause]
  379. selectable: ReturnsRows
  380. class _CompilerStackEntry(_BaseCompilerStackEntry, total=False):
  381. compile_state: CompileState
  382. need_result_map_for_nested: bool
  383. need_result_map_for_compound: bool
  384. select_0: ReturnsRows
  385. insert_from_select: Select[Any]
  386. class ExpandedState(NamedTuple):
  387. """represents state to use when producing "expanded" and
  388. "post compile" bound parameters for a statement.
  389. "expanded" parameters are parameters that are generated at
  390. statement execution time to suit a number of parameters passed, the most
  391. prominent example being the individual elements inside of an IN expression.
  392. "post compile" parameters are parameters where the SQL literal value
  393. will be rendered into the SQL statement at execution time, rather than
  394. being passed as separate parameters to the driver.
  395. To create an :class:`.ExpandedState` instance, use the
  396. :meth:`.SQLCompiler.construct_expanded_state` method on any
  397. :class:`.SQLCompiler` instance.
  398. """
  399. statement: str
  400. """String SQL statement with parameters fully expanded"""
  401. parameters: _CoreSingleExecuteParams
  402. """Parameter dictionary with parameters fully expanded.
  403. For a statement that uses named parameters, this dictionary will map
  404. exactly to the names in the statement. For a statement that uses
  405. positional parameters, the :attr:`.ExpandedState.positional_parameters`
  406. will yield a tuple with the positional parameter set.
  407. """
  408. processors: Mapping[str, _BindProcessorType[Any]]
  409. """mapping of bound value processors"""
  410. positiontup: Optional[Sequence[str]]
  411. """Sequence of string names indicating the order of positional
  412. parameters"""
  413. parameter_expansion: Mapping[str, List[str]]
  414. """Mapping representing the intermediary link from original parameter
  415. name to list of "expanded" parameter names, for those parameters that
  416. were expanded."""
  417. @property
  418. def positional_parameters(self) -> Tuple[Any, ...]:
  419. """Tuple of positional parameters, for statements that were compiled
  420. using a positional paramstyle.
  421. """
  422. if self.positiontup is None:
  423. raise exc.InvalidRequestError(
  424. "statement does not use a positional paramstyle"
  425. )
  426. return tuple(self.parameters[key] for key in self.positiontup)
  427. @property
  428. def additional_parameters(self) -> _CoreSingleExecuteParams:
  429. """synonym for :attr:`.ExpandedState.parameters`."""
  430. return self.parameters
  431. class _InsertManyValues(NamedTuple):
  432. """represents state to use for executing an "insertmanyvalues" statement.
  433. The primary consumers of this object are the
  434. :meth:`.SQLCompiler._deliver_insertmanyvalues_batches` and
  435. :meth:`.DefaultDialect._deliver_insertmanyvalues_batches` methods.
  436. .. versionadded:: 2.0
  437. """
  438. is_default_expr: bool
  439. """if True, the statement is of the form
  440. ``INSERT INTO TABLE DEFAULT VALUES``, and can't be rewritten as a "batch"
  441. """
  442. single_values_expr: str
  443. """The rendered "values" clause of the INSERT statement.
  444. This is typically the parenthesized section e.g. "(?, ?, ?)" or similar.
  445. The insertmanyvalues logic uses this string as a search and replace
  446. target.
  447. """
  448. insert_crud_params: List[crud._CrudParamElementStr]
  449. """List of Column / bind names etc. used while rewriting the statement"""
  450. num_positional_params_counted: int
  451. """the number of bound parameters in a single-row statement.
  452. This count may be larger or smaller than the actual number of columns
  453. targeted in the INSERT, as it accommodates for SQL expressions
  454. in the values list that may have zero or more parameters embedded
  455. within them.
  456. This count is part of what's used to organize rewritten parameter lists
  457. when batching.
  458. """
  459. sort_by_parameter_order: bool = False
  460. """if the deterministic_returnined_order parameter were used on the
  461. insert.
  462. All of the attributes following this will only be used if this is True.
  463. """
  464. includes_upsert_behaviors: bool = False
  465. """if True, we have to accommodate for upsert behaviors.
  466. This will in some cases downgrade "insertmanyvalues" that requests
  467. deterministic ordering.
  468. """
  469. sentinel_columns: Optional[Sequence[Column[Any]]] = None
  470. """List of sentinel columns that were located.
  471. This list is only here if the INSERT asked for
  472. sort_by_parameter_order=True,
  473. and dialect-appropriate sentinel columns were located.
  474. .. versionadded:: 2.0.10
  475. """
  476. num_sentinel_columns: int = 0
  477. """how many sentinel columns are in the above list, if any.
  478. This is the same as
  479. ``len(sentinel_columns) if sentinel_columns is not None else 0``
  480. """
  481. sentinel_param_keys: Optional[Sequence[str]] = None
  482. """parameter str keys in each param dictionary / tuple
  483. that would link to the client side "sentinel" values for that row, which
  484. we can use to match up parameter sets to result rows.
  485. This is only present if sentinel_columns is present and the INSERT
  486. statement actually refers to client side values for these sentinel
  487. columns.
  488. .. versionadded:: 2.0.10
  489. .. versionchanged:: 2.0.29 - the sequence is now string dictionary keys
  490. only, used against the "compiled parameteters" collection before
  491. the parameters were converted by bound parameter processors
  492. """
  493. implicit_sentinel: bool = False
  494. """if True, we have exactly one sentinel column and it uses a server side
  495. value, currently has to generate an incrementing integer value.
  496. The dialect in question would have asserted that it supports receiving
  497. these values back and sorting on that value as a means of guaranteeing
  498. correlation with the incoming parameter list.
  499. .. versionadded:: 2.0.10
  500. """
  501. has_upsert_bound_parameters: bool = False
  502. """if True, the upsert SET clause contains bound parameters that will
  503. receive their values from the parameters dict (i.e., parametrized
  504. bindparams where value is None and callable is None).
  505. This means we can't batch multiple rows in a single statement, since
  506. each row would need different values in the SET clause but there's only
  507. one SET clause per statement. See issue #13130.
  508. .. versionadded:: 2.0.37
  509. """
  510. embed_values_counter: bool = False
  511. """Whether to embed an incrementing integer counter in each parameter
  512. set within the VALUES clause as parameters are batched over.
  513. This is only used for a specific INSERT..SELECT..VALUES..RETURNING syntax
  514. where a subquery is used to produce value tuples. Current support
  515. includes PostgreSQL, Microsoft SQL Server.
  516. .. versionadded:: 2.0.10
  517. """
  518. class _InsertManyValuesBatch(NamedTuple):
  519. """represents an individual batch SQL statement for insertmanyvalues.
  520. This is passed through the
  521. :meth:`.SQLCompiler._deliver_insertmanyvalues_batches` and
  522. :meth:`.DefaultDialect._deliver_insertmanyvalues_batches` methods out
  523. to the :class:`.Connection` within the
  524. :meth:`.Connection._exec_insertmany_context` method.
  525. .. versionadded:: 2.0.10
  526. """
  527. replaced_statement: str
  528. replaced_parameters: _DBAPIAnyExecuteParams
  529. processed_setinputsizes: Optional[_GenericSetInputSizesType]
  530. batch: Sequence[_DBAPISingleExecuteParams]
  531. sentinel_values: Sequence[Tuple[Any, ...]]
  532. current_batch_size: int
  533. batchnum: int
  534. total_batches: int
  535. rows_sorted: bool
  536. is_downgraded: bool
  537. class InsertmanyvaluesSentinelOpts(FastIntFlag):
  538. """bitflag enum indicating styles of PK defaults
  539. which can work as implicit sentinel columns
  540. """
  541. NOT_SUPPORTED = 1
  542. AUTOINCREMENT = 2
  543. IDENTITY = 4
  544. SEQUENCE = 8
  545. ANY_AUTOINCREMENT = AUTOINCREMENT | IDENTITY | SEQUENCE
  546. _SUPPORTED_OR_NOT = NOT_SUPPORTED | ANY_AUTOINCREMENT
  547. USE_INSERT_FROM_SELECT = 16
  548. RENDER_SELECT_COL_CASTS = 64
  549. class CompilerState(IntEnum):
  550. COMPILING = 0
  551. """statement is present, compilation phase in progress"""
  552. STRING_APPLIED = 1
  553. """statement is present, string form of the statement has been applied.
  554. Additional processors by subclasses may still be pending.
  555. """
  556. NO_STATEMENT = 2
  557. """compiler does not have a statement to compile, is used
  558. for method access"""
  559. class Linting(IntEnum):
  560. """represent preferences for the 'SQL linting' feature.
  561. this feature currently includes support for flagging cartesian products
  562. in SQL statements.
  563. """
  564. NO_LINTING = 0
  565. "Disable all linting."
  566. COLLECT_CARTESIAN_PRODUCTS = 1
  567. """Collect data on FROMs and cartesian products and gather into
  568. 'self.from_linter'"""
  569. WARN_LINTING = 2
  570. "Emit warnings for linters that find problems"
  571. FROM_LINTING = COLLECT_CARTESIAN_PRODUCTS | WARN_LINTING
  572. """Warn for cartesian products; combines COLLECT_CARTESIAN_PRODUCTS
  573. and WARN_LINTING"""
  574. NO_LINTING, COLLECT_CARTESIAN_PRODUCTS, WARN_LINTING, FROM_LINTING = tuple(
  575. Linting
  576. )
  577. class FromLinter(collections.namedtuple("FromLinter", ["froms", "edges"])):
  578. """represents current state for the "cartesian product" detection
  579. feature."""
  580. def lint(self, start=None):
  581. froms = self.froms
  582. if not froms:
  583. return None, None
  584. edges = set(self.edges)
  585. the_rest = set(froms)
  586. if start is not None:
  587. start_with = start
  588. the_rest.remove(start_with)
  589. else:
  590. start_with = the_rest.pop()
  591. stack = collections.deque([start_with])
  592. while stack and the_rest:
  593. node = stack.popleft()
  594. the_rest.discard(node)
  595. # comparison of nodes in edges here is based on hash equality, as
  596. # there are "annotated" elements that match the non-annotated ones.
  597. # to remove the need for in-python hash() calls, use native
  598. # containment routines (e.g. "node in edge", "edge.index(node)")
  599. to_remove = {edge for edge in edges if node in edge}
  600. # appendleft the node in each edge that is not
  601. # the one that matched.
  602. stack.extendleft(edge[not edge.index(node)] for edge in to_remove)
  603. edges.difference_update(to_remove)
  604. # FROMS left over? boom
  605. if the_rest:
  606. return the_rest, start_with
  607. else:
  608. return None, None
  609. def warn(self, stmt_type="SELECT"):
  610. the_rest, start_with = self.lint()
  611. # FROMS left over? boom
  612. if the_rest:
  613. froms = the_rest
  614. if froms:
  615. template = (
  616. "{stmt_type} statement has a cartesian product between "
  617. "FROM element(s) {froms} and "
  618. 'FROM element "{start}". Apply join condition(s) '
  619. "between each element to resolve."
  620. )
  621. froms_str = ", ".join(
  622. f'"{self.froms[from_]}"' for from_ in froms
  623. )
  624. message = template.format(
  625. stmt_type=stmt_type,
  626. froms=froms_str,
  627. start=self.froms[start_with],
  628. )
  629. util.warn(message)
  630. class Compiled:
  631. """Represent a compiled SQL or DDL expression.
  632. The ``__str__`` method of the ``Compiled`` object should produce
  633. the actual text of the statement. ``Compiled`` objects are
  634. specific to their underlying database dialect, and also may
  635. or may not be specific to the columns referenced within a
  636. particular set of bind parameters. In no case should the
  637. ``Compiled`` object be dependent on the actual values of those
  638. bind parameters, even though it may reference those values as
  639. defaults.
  640. """
  641. statement: Optional[ClauseElement] = None
  642. "The statement to compile."
  643. string: str = ""
  644. "The string representation of the ``statement``"
  645. state: CompilerState
  646. """description of the compiler's state"""
  647. is_sql = False
  648. is_ddl = False
  649. _cached_metadata: Optional[CursorResultMetaData] = None
  650. _result_columns: Optional[List[ResultColumnsEntry]] = None
  651. schema_translate_map: Optional[SchemaTranslateMapType] = None
  652. execution_options: _ExecuteOptions = util.EMPTY_DICT
  653. """
  654. Execution options propagated from the statement. In some cases,
  655. sub-elements of the statement can modify these.
  656. """
  657. preparer: IdentifierPreparer
  658. _annotations: _AnnotationDict = util.EMPTY_DICT
  659. compile_state: Optional[CompileState] = None
  660. """Optional :class:`.CompileState` object that maintains additional
  661. state used by the compiler.
  662. Major executable objects such as :class:`_expression.Insert`,
  663. :class:`_expression.Update`, :class:`_expression.Delete`,
  664. :class:`_expression.Select` will generate this
  665. state when compiled in order to calculate additional information about the
  666. object. For the top level object that is to be executed, the state can be
  667. stored here where it can also have applicability towards result set
  668. processing.
  669. .. versionadded:: 1.4
  670. """
  671. dml_compile_state: Optional[CompileState] = None
  672. """Optional :class:`.CompileState` assigned at the same point that
  673. .isinsert, .isupdate, or .isdelete is assigned.
  674. This will normally be the same object as .compile_state, with the
  675. exception of cases like the :class:`.ORMFromStatementCompileState`
  676. object.
  677. .. versionadded:: 1.4.40
  678. """
  679. cache_key: Optional[CacheKey] = None
  680. """The :class:`.CacheKey` that was generated ahead of creating this
  681. :class:`.Compiled` object.
  682. This is used for routines that need access to the original
  683. :class:`.CacheKey` instance generated when the :class:`.Compiled`
  684. instance was first cached, typically in order to reconcile
  685. the original list of :class:`.BindParameter` objects with a
  686. per-statement list that's generated on each call.
  687. """
  688. _gen_time: float
  689. """Generation time of this :class:`.Compiled`, used for reporting
  690. cache stats."""
  691. def __init__(
  692. self,
  693. dialect: Dialect,
  694. statement: Optional[ClauseElement],
  695. schema_translate_map: Optional[SchemaTranslateMapType] = None,
  696. render_schema_translate: bool = False,
  697. compile_kwargs: Mapping[str, Any] = util.immutabledict(),
  698. ):
  699. """Construct a new :class:`.Compiled` object.
  700. :param dialect: :class:`.Dialect` to compile against.
  701. :param statement: :class:`_expression.ClauseElement` to be compiled.
  702. :param schema_translate_map: dictionary of schema names to be
  703. translated when forming the resultant SQL
  704. .. seealso::
  705. :ref:`schema_translating`
  706. :param compile_kwargs: additional kwargs that will be
  707. passed to the initial call to :meth:`.Compiled.process`.
  708. """
  709. self.dialect = dialect
  710. self.preparer = self.dialect.identifier_preparer
  711. if schema_translate_map:
  712. self.schema_translate_map = schema_translate_map
  713. self.preparer = self.preparer._with_schema_translate(
  714. schema_translate_map
  715. )
  716. if statement is not None:
  717. self.state = CompilerState.COMPILING
  718. self.statement = statement
  719. self.can_execute = statement.supports_execution
  720. self._annotations = statement._annotations
  721. if self.can_execute:
  722. if TYPE_CHECKING:
  723. assert isinstance(statement, Executable)
  724. self.execution_options = statement._execution_options
  725. self.string = self.process(self.statement, **compile_kwargs)
  726. if render_schema_translate:
  727. assert schema_translate_map is not None
  728. self.string = self.preparer._render_schema_translates(
  729. self.string, schema_translate_map
  730. )
  731. self.state = CompilerState.STRING_APPLIED
  732. else:
  733. self.state = CompilerState.NO_STATEMENT
  734. self._gen_time = perf_counter()
  735. def __init_subclass__(cls) -> None:
  736. cls._init_compiler_cls()
  737. return super().__init_subclass__()
  738. @classmethod
  739. def _init_compiler_cls(cls):
  740. pass
  741. def _execute_on_connection(
  742. self, connection, distilled_params, execution_options
  743. ):
  744. if self.can_execute:
  745. return connection._execute_compiled(
  746. self, distilled_params, execution_options
  747. )
  748. else:
  749. raise exc.ObjectNotExecutableError(self.statement)
  750. def visit_unsupported_compilation(self, element, err, **kw):
  751. raise exc.UnsupportedCompilationError(self, type(element)) from err
  752. @property
  753. def sql_compiler(self) -> SQLCompiler:
  754. """Return a Compiled that is capable of processing SQL expressions.
  755. If this compiler is one, it would likely just return 'self'.
  756. """
  757. raise NotImplementedError()
  758. def process(self, obj: Visitable, **kwargs: Any) -> str:
  759. return obj._compiler_dispatch(self, **kwargs)
  760. def __str__(self) -> str:
  761. """Return the string text of the generated SQL or DDL."""
  762. if self.state is CompilerState.STRING_APPLIED:
  763. return self.string
  764. else:
  765. return ""
  766. def construct_params(
  767. self,
  768. params: Optional[_CoreSingleExecuteParams] = None,
  769. extracted_parameters: Optional[Sequence[BindParameter[Any]]] = None,
  770. escape_names: bool = True,
  771. ) -> Optional[_MutableCoreSingleExecuteParams]:
  772. """Return the bind params for this compiled object.
  773. :param params: a dict of string/object pairs whose values will
  774. override bind values compiled in to the
  775. statement.
  776. """
  777. raise NotImplementedError()
  778. @property
  779. def params(self):
  780. """Return the bind params for this compiled object."""
  781. return self.construct_params()
  782. class TypeCompiler(util.EnsureKWArg):
  783. """Produces DDL specification for TypeEngine objects."""
  784. ensure_kwarg = r"visit_\w+"
  785. def __init__(self, dialect: Dialect):
  786. self.dialect = dialect
  787. def process(self, type_: TypeEngine[Any], **kw: Any) -> str:
  788. if (
  789. type_._variant_mapping
  790. and self.dialect.name in type_._variant_mapping
  791. ):
  792. type_ = type_._variant_mapping[self.dialect.name]
  793. return type_._compiler_dispatch(self, **kw)
  794. def visit_unsupported_compilation(
  795. self, element: Any, err: Exception, **kw: Any
  796. ) -> NoReturn:
  797. raise exc.UnsupportedCompilationError(self, element) from err
  798. # this was a Visitable, but to allow accurate detection of
  799. # column elements this is actually a column element
  800. class _CompileLabel(
  801. roles.BinaryElementRole[Any], elements.CompilerColumnElement
  802. ):
  803. """lightweight label object which acts as an expression.Label."""
  804. __visit_name__ = "label"
  805. __slots__ = "element", "name", "_alt_names"
  806. def __init__(self, col, name, alt_names=()):
  807. self.element = col
  808. self.name = name
  809. self._alt_names = (col,) + alt_names
  810. @property
  811. def proxy_set(self):
  812. return self.element.proxy_set
  813. @property
  814. def type(self):
  815. return self.element.type
  816. def self_group(self, **kw):
  817. return self
  818. class ilike_case_insensitive(
  819. roles.BinaryElementRole[Any], elements.CompilerColumnElement
  820. ):
  821. """produce a wrapping element for a case-insensitive portion of
  822. an ILIKE construct.
  823. The construct usually renders the ``lower()`` function, but on
  824. PostgreSQL will pass silently with the assumption that "ILIKE"
  825. is being used.
  826. .. versionadded:: 2.0
  827. """
  828. __visit_name__ = "ilike_case_insensitive_operand"
  829. __slots__ = "element", "comparator"
  830. def __init__(self, element):
  831. self.element = element
  832. self.comparator = element.comparator
  833. @property
  834. def proxy_set(self):
  835. return self.element.proxy_set
  836. @property
  837. def type(self):
  838. return self.element.type
  839. def self_group(self, **kw):
  840. return self
  841. def _with_binary_element_type(self, type_):
  842. return ilike_case_insensitive(
  843. self.element._with_binary_element_type(type_)
  844. )
  845. class SQLCompiler(Compiled):
  846. """Default implementation of :class:`.Compiled`.
  847. Compiles :class:`_expression.ClauseElement` objects into SQL strings.
  848. """
  849. extract_map = EXTRACT_MAP
  850. bindname_escape_characters: ClassVar[Mapping[str, str]] = (
  851. util.immutabledict(
  852. {
  853. "%": "P",
  854. "(": "A",
  855. ")": "Z",
  856. ":": "C",
  857. ".": "_",
  858. "[": "_",
  859. "]": "_",
  860. " ": "_",
  861. }
  862. )
  863. )
  864. """A mapping (e.g. dict or similar) containing a lookup of
  865. characters keyed to replacement characters which will be applied to all
  866. 'bind names' used in SQL statements as a form of 'escaping'; the given
  867. characters are replaced entirely with the 'replacement' character when
  868. rendered in the SQL statement, and a similar translation is performed
  869. on the incoming names used in parameter dictionaries passed to methods
  870. like :meth:`_engine.Connection.execute`.
  871. This allows bound parameter names used in :func:`_sql.bindparam` and
  872. other constructs to have any arbitrary characters present without any
  873. concern for characters that aren't allowed at all on the target database.
  874. Third party dialects can establish their own dictionary here to replace the
  875. default mapping, which will ensure that the particular characters in the
  876. mapping will never appear in a bound parameter name.
  877. The dictionary is evaluated at **class creation time**, so cannot be
  878. modified at runtime; it must be present on the class when the class
  879. is first declared.
  880. Note that for dialects that have additional bound parameter rules such
  881. as additional restrictions on leading characters, the
  882. :meth:`_sql.SQLCompiler.bindparam_string` method may need to be augmented.
  883. See the cx_Oracle compiler for an example of this.
  884. .. versionadded:: 2.0.0rc1
  885. """
  886. _bind_translate_re: ClassVar[Pattern[str]]
  887. _bind_translate_chars: ClassVar[Mapping[str, str]]
  888. is_sql = True
  889. compound_keywords = COMPOUND_KEYWORDS
  890. isdelete: bool = False
  891. isinsert: bool = False
  892. isupdate: bool = False
  893. """class-level defaults which can be set at the instance
  894. level to define if this Compiled instance represents
  895. INSERT/UPDATE/DELETE
  896. """
  897. postfetch: Optional[List[Column[Any]]]
  898. """list of columns that can be post-fetched after INSERT or UPDATE to
  899. receive server-updated values"""
  900. insert_prefetch: Sequence[Column[Any]] = ()
  901. """list of columns for which default values should be evaluated before
  902. an INSERT takes place"""
  903. update_prefetch: Sequence[Column[Any]] = ()
  904. """list of columns for which onupdate default values should be evaluated
  905. before an UPDATE takes place"""
  906. implicit_returning: Optional[Sequence[ColumnElement[Any]]] = None
  907. """list of "implicit" returning columns for a toplevel INSERT or UPDATE
  908. statement, used to receive newly generated values of columns.
  909. .. versionadded:: 2.0 ``implicit_returning`` replaces the previous
  910. ``returning`` collection, which was not a generalized RETURNING
  911. collection and instead was in fact specific to the "implicit returning"
  912. feature.
  913. """
  914. isplaintext: bool = False
  915. binds: Dict[str, BindParameter[Any]]
  916. """a dictionary of bind parameter keys to BindParameter instances."""
  917. bind_names: Dict[BindParameter[Any], str]
  918. """a dictionary of BindParameter instances to "compiled" names
  919. that are actually present in the generated SQL"""
  920. stack: List[_CompilerStackEntry]
  921. """major statements such as SELECT, INSERT, UPDATE, DELETE are
  922. tracked in this stack using an entry format."""
  923. returning_precedes_values: bool = False
  924. """set to True classwide to generate RETURNING
  925. clauses before the VALUES or WHERE clause (i.e. MSSQL)
  926. """
  927. render_table_with_column_in_update_from: bool = False
  928. """set to True classwide to indicate the SET clause
  929. in a multi-table UPDATE statement should qualify
  930. columns with the table name (i.e. MySQL only)
  931. """
  932. ansi_bind_rules: bool = False
  933. """SQL 92 doesn't allow bind parameters to be used
  934. in the columns clause of a SELECT, nor does it allow
  935. ambiguous expressions like "? = ?". A compiler
  936. subclass can set this flag to False if the target
  937. driver/DB enforces this
  938. """
  939. bindtemplate: str
  940. """template to render bound parameters based on paramstyle."""
  941. compilation_bindtemplate: str
  942. """template used by compiler to render parameters before positional
  943. paramstyle application"""
  944. _numeric_binds_identifier_char: str
  945. """Character that's used to as the identifier of a numerical bind param.
  946. For example if this char is set to ``$``, numerical binds will be rendered
  947. in the form ``$1, $2, $3``.
  948. """
  949. _result_columns: List[ResultColumnsEntry]
  950. """relates label names in the final SQL to a tuple of local
  951. column/label name, ColumnElement object (if any) and
  952. TypeEngine. CursorResult uses this for type processing and
  953. column targeting"""
  954. _textual_ordered_columns: bool = False
  955. """tell the result object that the column names as rendered are important,
  956. but they are also "ordered" vs. what is in the compiled object here.
  957. As of 1.4.42 this condition is only present when the statement is a
  958. TextualSelect, e.g. text("....").columns(...), where it is required
  959. that the columns are considered positionally and not by name.
  960. """
  961. _ad_hoc_textual: bool = False
  962. """tell the result that we encountered text() or '*' constructs in the
  963. middle of the result columns, but we also have compiled columns, so
  964. if the number of columns in cursor.description does not match how many
  965. expressions we have, that means we can't rely on positional at all and
  966. should match on name.
  967. """
  968. _ordered_columns: bool = True
  969. """
  970. if False, means we can't be sure the list of entries
  971. in _result_columns is actually the rendered order. Usually
  972. True unless using an unordered TextualSelect.
  973. """
  974. _loose_column_name_matching: bool = False
  975. """tell the result object that the SQL statement is textual, wants to match
  976. up to Column objects, and may be using the ._tq_label in the SELECT rather
  977. than the base name.
  978. """
  979. _numeric_binds: bool = False
  980. """
  981. True if paramstyle is "numeric". This paramstyle is trickier than
  982. all the others.
  983. """
  984. _render_postcompile: bool = False
  985. """
  986. whether to render out POSTCOMPILE params during the compile phase.
  987. This attribute is used only for end-user invocation of stmt.compile();
  988. it's never used for actual statement execution, where instead the
  989. dialect internals access and render the internal postcompile structure
  990. directly.
  991. """
  992. _post_compile_expanded_state: Optional[ExpandedState] = None
  993. """When render_postcompile is used, the ``ExpandedState`` used to create
  994. the "expanded" SQL is assigned here, and then used by the ``.params``
  995. accessor and ``.construct_params()`` methods for their return values.
  996. .. versionadded:: 2.0.0rc1
  997. """
  998. _pre_expanded_string: Optional[str] = None
  999. """Stores the original string SQL before 'post_compile' is applied,
  1000. for cases where 'post_compile' were used.
  1001. """
  1002. _pre_expanded_positiontup: Optional[List[str]] = None
  1003. _insertmanyvalues: Optional[_InsertManyValues] = None
  1004. _insert_crud_params: Optional[crud._CrudParamSequence] = None
  1005. literal_execute_params: FrozenSet[BindParameter[Any]] = frozenset()
  1006. """bindparameter objects that are rendered as literal values at statement
  1007. execution time.
  1008. """
  1009. post_compile_params: FrozenSet[BindParameter[Any]] = frozenset()
  1010. """bindparameter objects that are rendered as bound parameter placeholders
  1011. at statement execution time.
  1012. """
  1013. escaped_bind_names: util.immutabledict[str, str] = util.EMPTY_DICT
  1014. """Late escaping of bound parameter names that has to be converted
  1015. to the original name when looking in the parameter dictionary.
  1016. """
  1017. has_out_parameters = False
  1018. """if True, there are bindparam() objects that have the isoutparam
  1019. flag set."""
  1020. postfetch_lastrowid = False
  1021. """if True, and this in insert, use cursor.lastrowid to populate
  1022. result.inserted_primary_key. """
  1023. _cache_key_bind_match: Optional[
  1024. Tuple[
  1025. Dict[
  1026. BindParameter[Any],
  1027. List[BindParameter[Any]],
  1028. ],
  1029. Dict[
  1030. str,
  1031. BindParameter[Any],
  1032. ],
  1033. ]
  1034. ] = None
  1035. """a mapping that will relate the BindParameter object we compile
  1036. to those that are part of the extracted collection of parameters
  1037. in the cache key, if we were given a cache key.
  1038. """
  1039. positiontup: Optional[List[str]] = None
  1040. """for a compiled construct that uses a positional paramstyle, will be
  1041. a sequence of strings, indicating the names of bound parameters in order.
  1042. This is used in order to render bound parameters in their correct order,
  1043. and is combined with the :attr:`_sql.Compiled.params` dictionary to
  1044. render parameters.
  1045. This sequence always contains the unescaped name of the parameters.
  1046. .. seealso::
  1047. :ref:`faq_sql_expression_string` - includes a usage example for
  1048. debugging use cases.
  1049. """
  1050. _values_bindparam: Optional[List[str]] = None
  1051. _visited_bindparam: Optional[List[str]] = None
  1052. inline: bool = False
  1053. ctes: Optional[MutableMapping[CTE, str]]
  1054. # Detect same CTE references - Dict[(level, name), cte]
  1055. # Level is required for supporting nesting
  1056. ctes_by_level_name: Dict[Tuple[int, str], CTE]
  1057. # To retrieve key/level in ctes_by_level_name -
  1058. # Dict[cte_reference, (level, cte_name, cte_opts)]
  1059. level_name_by_cte: Dict[CTE, Tuple[int, str, selectable._CTEOpts]]
  1060. ctes_recursive: bool
  1061. _post_compile_pattern = re.compile(r"__\[POSTCOMPILE_(\S+?)(~~.+?~~)?\]")
  1062. _pyformat_pattern = re.compile(r"%\(([^)]+?)\)s")
  1063. _positional_pattern = re.compile(
  1064. f"{_pyformat_pattern.pattern}|{_post_compile_pattern.pattern}"
  1065. )
  1066. @classmethod
  1067. def _init_compiler_cls(cls):
  1068. cls._init_bind_translate()
  1069. @classmethod
  1070. def _init_bind_translate(cls):
  1071. reg = re.escape("".join(cls.bindname_escape_characters))
  1072. cls._bind_translate_re = re.compile(f"[{reg}]")
  1073. cls._bind_translate_chars = cls.bindname_escape_characters
  1074. def __init__(
  1075. self,
  1076. dialect: Dialect,
  1077. statement: Optional[ClauseElement],
  1078. cache_key: Optional[CacheKey] = None,
  1079. column_keys: Optional[Sequence[str]] = None,
  1080. for_executemany: bool = False,
  1081. linting: Linting = NO_LINTING,
  1082. _supporting_against: Optional[SQLCompiler] = None,
  1083. **kwargs: Any,
  1084. ):
  1085. """Construct a new :class:`.SQLCompiler` object.
  1086. :param dialect: :class:`.Dialect` to be used
  1087. :param statement: :class:`_expression.ClauseElement` to be compiled
  1088. :param column_keys: a list of column names to be compiled into an
  1089. INSERT or UPDATE statement.
  1090. :param for_executemany: whether INSERT / UPDATE statements should
  1091. expect that they are to be invoked in an "executemany" style,
  1092. which may impact how the statement will be expected to return the
  1093. values of defaults and autoincrement / sequences and similar.
  1094. Depending on the backend and driver in use, support for retrieving
  1095. these values may be disabled which means SQL expressions may
  1096. be rendered inline, RETURNING may not be rendered, etc.
  1097. :param kwargs: additional keyword arguments to be consumed by the
  1098. superclass.
  1099. """
  1100. self.column_keys = column_keys
  1101. self.cache_key = cache_key
  1102. if cache_key:
  1103. cksm = {b.key: b for b in cache_key[1]}
  1104. ckbm = {b: [b] for b in cache_key[1]}
  1105. self._cache_key_bind_match = (ckbm, cksm)
  1106. # compile INSERT/UPDATE defaults/sequences to expect executemany
  1107. # style execution, which may mean no pre-execute of defaults,
  1108. # or no RETURNING
  1109. self.for_executemany = for_executemany
  1110. self.linting = linting
  1111. # a dictionary of bind parameter keys to BindParameter
  1112. # instances.
  1113. self.binds = {}
  1114. # a dictionary of BindParameter instances to "compiled" names
  1115. # that are actually present in the generated SQL
  1116. self.bind_names = util.column_dict()
  1117. # stack which keeps track of nested SELECT statements
  1118. self.stack = []
  1119. self._result_columns = []
  1120. # true if the paramstyle is positional
  1121. self.positional = dialect.positional
  1122. if self.positional:
  1123. self._numeric_binds = nb = dialect.paramstyle.startswith("numeric")
  1124. if nb:
  1125. self._numeric_binds_identifier_char = (
  1126. "$" if dialect.paramstyle == "numeric_dollar" else ":"
  1127. )
  1128. self.compilation_bindtemplate = _pyformat_template
  1129. else:
  1130. self.compilation_bindtemplate = BIND_TEMPLATES[dialect.paramstyle]
  1131. self.ctes = None
  1132. self.label_length = (
  1133. dialect.label_length or dialect.max_identifier_length
  1134. )
  1135. # a map which tracks "anonymous" identifiers that are created on
  1136. # the fly here
  1137. self.anon_map = prefix_anon_map()
  1138. # a map which tracks "truncated" names based on
  1139. # dialect.label_length or dialect.max_identifier_length
  1140. self.truncated_names: Dict[Tuple[str, str], str] = {}
  1141. self._truncated_counters: Dict[str, int] = {}
  1142. Compiled.__init__(self, dialect, statement, **kwargs)
  1143. if self.isinsert or self.isupdate or self.isdelete:
  1144. if TYPE_CHECKING:
  1145. assert isinstance(statement, UpdateBase)
  1146. if self.isinsert or self.isupdate:
  1147. if TYPE_CHECKING:
  1148. assert isinstance(statement, ValuesBase)
  1149. if statement._inline:
  1150. self.inline = True
  1151. elif self.for_executemany and (
  1152. not self.isinsert
  1153. or (
  1154. self.dialect.insert_executemany_returning
  1155. and statement._return_defaults
  1156. )
  1157. ):
  1158. self.inline = True
  1159. self.bindtemplate = BIND_TEMPLATES[dialect.paramstyle]
  1160. if _supporting_against:
  1161. self.__dict__.update(
  1162. {
  1163. k: v
  1164. for k, v in _supporting_against.__dict__.items()
  1165. if k
  1166. not in {
  1167. "state",
  1168. "dialect",
  1169. "preparer",
  1170. "positional",
  1171. "_numeric_binds",
  1172. "compilation_bindtemplate",
  1173. "bindtemplate",
  1174. }
  1175. }
  1176. )
  1177. if self.state is CompilerState.STRING_APPLIED:
  1178. if self.positional:
  1179. if self._numeric_binds:
  1180. self._process_numeric()
  1181. else:
  1182. self._process_positional()
  1183. if self._render_postcompile:
  1184. parameters = self.construct_params(
  1185. escape_names=False,
  1186. _no_postcompile=True,
  1187. )
  1188. self._process_parameters_for_postcompile(
  1189. parameters, _populate_self=True
  1190. )
  1191. @property
  1192. def insert_single_values_expr(self) -> Optional[str]:
  1193. """When an INSERT is compiled with a single set of parameters inside
  1194. a VALUES expression, the string is assigned here, where it can be
  1195. used for insert batching schemes to rewrite the VALUES expression.
  1196. .. versionadded:: 1.3.8
  1197. .. versionchanged:: 2.0 This collection is no longer used by
  1198. SQLAlchemy's built-in dialects, in favor of the currently
  1199. internal ``_insertmanyvalues`` collection that is used only by
  1200. :class:`.SQLCompiler`.
  1201. """
  1202. if self._insertmanyvalues is None:
  1203. return None
  1204. else:
  1205. return self._insertmanyvalues.single_values_expr
  1206. @util.ro_memoized_property
  1207. def effective_returning(self) -> Optional[Sequence[ColumnElement[Any]]]:
  1208. """The effective "returning" columns for INSERT, UPDATE or DELETE.
  1209. This is either the so-called "implicit returning" columns which are
  1210. calculated by the compiler on the fly, or those present based on what's
  1211. present in ``self.statement._returning`` (expanded into individual
  1212. columns using the ``._all_selected_columns`` attribute) i.e. those set
  1213. explicitly using the :meth:`.UpdateBase.returning` method.
  1214. .. versionadded:: 2.0
  1215. """
  1216. if self.implicit_returning:
  1217. return self.implicit_returning
  1218. elif self.statement is not None and is_dml(self.statement):
  1219. return [
  1220. c
  1221. for c in self.statement._all_selected_columns
  1222. if is_column_element(c)
  1223. ]
  1224. else:
  1225. return None
  1226. @property
  1227. def returning(self):
  1228. """backwards compatibility; returns the
  1229. effective_returning collection.
  1230. """
  1231. return self.effective_returning
  1232. @property
  1233. def current_executable(self):
  1234. """Return the current 'executable' that is being compiled.
  1235. This is currently the :class:`_sql.Select`, :class:`_sql.Insert`,
  1236. :class:`_sql.Update`, :class:`_sql.Delete`,
  1237. :class:`_sql.CompoundSelect` object that is being compiled.
  1238. Specifically it's assigned to the ``self.stack`` list of elements.
  1239. When a statement like the above is being compiled, it normally
  1240. is also assigned to the ``.statement`` attribute of the
  1241. :class:`_sql.Compiler` object. However, all SQL constructs are
  1242. ultimately nestable, and this attribute should never be consulted
  1243. by a ``visit_`` method, as it is not guaranteed to be assigned
  1244. nor guaranteed to correspond to the current statement being compiled.
  1245. .. versionadded:: 1.3.21
  1246. For compatibility with previous versions, use the following
  1247. recipe::
  1248. statement = getattr(self, "current_executable", False)
  1249. if statement is False:
  1250. statement = self.stack[-1]["selectable"]
  1251. For versions 1.4 and above, ensure only .current_executable
  1252. is used; the format of "self.stack" may change.
  1253. """
  1254. try:
  1255. return self.stack[-1]["selectable"]
  1256. except IndexError as ie:
  1257. raise IndexError("Compiler does not have a stack entry") from ie
  1258. @property
  1259. def prefetch(self):
  1260. return list(self.insert_prefetch) + list(self.update_prefetch)
  1261. @util.memoized_property
  1262. def _global_attributes(self) -> Dict[Any, Any]:
  1263. return {}
  1264. @util.memoized_instancemethod
  1265. def _init_cte_state(self) -> MutableMapping[CTE, str]:
  1266. """Initialize collections related to CTEs only if
  1267. a CTE is located, to save on the overhead of
  1268. these collections otherwise.
  1269. """
  1270. # collect CTEs to tack on top of a SELECT
  1271. # To store the query to print - Dict[cte, text_query]
  1272. ctes: MutableMapping[CTE, str] = util.OrderedDict()
  1273. self.ctes = ctes
  1274. # Detect same CTE references - Dict[(level, name), cte]
  1275. # Level is required for supporting nesting
  1276. self.ctes_by_level_name = {}
  1277. # To retrieve key/level in ctes_by_level_name -
  1278. # Dict[cte_reference, (level, cte_name, cte_opts)]
  1279. self.level_name_by_cte = {}
  1280. self.ctes_recursive = False
  1281. return ctes
  1282. @contextlib.contextmanager
  1283. def _nested_result(self):
  1284. """special API to support the use case of 'nested result sets'"""
  1285. result_columns, ordered_columns = (
  1286. self._result_columns,
  1287. self._ordered_columns,
  1288. )
  1289. self._result_columns, self._ordered_columns = [], False
  1290. try:
  1291. if self.stack:
  1292. entry = self.stack[-1]
  1293. entry["need_result_map_for_nested"] = True
  1294. else:
  1295. entry = None
  1296. yield self._result_columns, self._ordered_columns
  1297. finally:
  1298. if entry:
  1299. entry.pop("need_result_map_for_nested")
  1300. self._result_columns, self._ordered_columns = (
  1301. result_columns,
  1302. ordered_columns,
  1303. )
  1304. def _process_positional(self):
  1305. assert not self.positiontup
  1306. assert self.state is CompilerState.STRING_APPLIED
  1307. assert not self._numeric_binds
  1308. if self.dialect.paramstyle == "format":
  1309. placeholder = "%s"
  1310. else:
  1311. assert self.dialect.paramstyle == "qmark"
  1312. placeholder = "?"
  1313. positions = []
  1314. def find_position(m: re.Match[str]) -> str:
  1315. normal_bind = m.group(1)
  1316. if normal_bind:
  1317. positions.append(normal_bind)
  1318. return placeholder
  1319. else:
  1320. # this a post-compile bind
  1321. positions.append(m.group(2))
  1322. return m.group(0)
  1323. self.string = re.sub(
  1324. self._positional_pattern, find_position, self.string
  1325. )
  1326. if self.escaped_bind_names:
  1327. reverse_escape = {v: k for k, v in self.escaped_bind_names.items()}
  1328. assert len(self.escaped_bind_names) == len(reverse_escape)
  1329. self.positiontup = [
  1330. reverse_escape.get(name, name) for name in positions
  1331. ]
  1332. else:
  1333. self.positiontup = positions
  1334. if self._insertmanyvalues:
  1335. positions = []
  1336. single_values_expr = re.sub(
  1337. self._positional_pattern,
  1338. find_position,
  1339. self._insertmanyvalues.single_values_expr,
  1340. )
  1341. insert_crud_params = [
  1342. (
  1343. v[0],
  1344. v[1],
  1345. re.sub(self._positional_pattern, find_position, v[2]),
  1346. v[3],
  1347. )
  1348. for v in self._insertmanyvalues.insert_crud_params
  1349. ]
  1350. self._insertmanyvalues = self._insertmanyvalues._replace(
  1351. single_values_expr=single_values_expr,
  1352. insert_crud_params=insert_crud_params,
  1353. )
  1354. def _process_numeric(self):
  1355. assert self._numeric_binds
  1356. assert self.state is CompilerState.STRING_APPLIED
  1357. num = 1
  1358. param_pos: Dict[str, str] = {}
  1359. order: Iterable[str]
  1360. if self._insertmanyvalues and self._values_bindparam is not None:
  1361. # bindparams that are not in values are always placed first.
  1362. # this avoids the need of changing them when using executemany
  1363. # values () ()
  1364. order = itertools.chain(
  1365. (
  1366. name
  1367. for name in self.bind_names.values()
  1368. if name not in self._values_bindparam
  1369. ),
  1370. self.bind_names.values(),
  1371. )
  1372. else:
  1373. order = self.bind_names.values()
  1374. for bind_name in order:
  1375. if bind_name in param_pos:
  1376. continue
  1377. bind = self.binds[bind_name]
  1378. if (
  1379. bind in self.post_compile_params
  1380. or bind in self.literal_execute_params
  1381. ):
  1382. # set to None to just mark the in positiontup, it will not
  1383. # be replaced below.
  1384. param_pos[bind_name] = None # type: ignore
  1385. else:
  1386. ph = f"{self._numeric_binds_identifier_char}{num}"
  1387. num += 1
  1388. param_pos[bind_name] = ph
  1389. self.next_numeric_pos = num
  1390. self.positiontup = list(param_pos)
  1391. if self.escaped_bind_names:
  1392. len_before = len(param_pos)
  1393. param_pos = {
  1394. self.escaped_bind_names.get(name, name): pos
  1395. for name, pos in param_pos.items()
  1396. }
  1397. assert len(param_pos) == len_before
  1398. # Can't use format here since % chars are not escaped.
  1399. self.string = self._pyformat_pattern.sub(
  1400. lambda m: param_pos[m.group(1)], self.string
  1401. )
  1402. if self._insertmanyvalues:
  1403. single_values_expr = (
  1404. # format is ok here since single_values_expr includes only
  1405. # place-holders
  1406. self._insertmanyvalues.single_values_expr
  1407. % param_pos
  1408. )
  1409. insert_crud_params = [
  1410. (v[0], v[1], "%s", v[3])
  1411. for v in self._insertmanyvalues.insert_crud_params
  1412. ]
  1413. self._insertmanyvalues = self._insertmanyvalues._replace(
  1414. # This has the numbers (:1, :2)
  1415. single_values_expr=single_values_expr,
  1416. # The single binds are instead %s so they can be formatted
  1417. insert_crud_params=insert_crud_params,
  1418. )
  1419. @util.memoized_property
  1420. def _bind_processors(
  1421. self,
  1422. ) -> MutableMapping[
  1423. str, Union[_BindProcessorType[Any], Sequence[_BindProcessorType[Any]]]
  1424. ]:
  1425. # mypy is not able to see the two value types as the above Union,
  1426. # it just sees "object". don't know how to resolve
  1427. return {
  1428. key: value # type: ignore
  1429. for key, value in (
  1430. (
  1431. self.bind_names[bindparam],
  1432. (
  1433. bindparam.type._cached_bind_processor(self.dialect)
  1434. if not bindparam.type._is_tuple_type
  1435. else tuple(
  1436. elem_type._cached_bind_processor(self.dialect)
  1437. for elem_type in cast(
  1438. TupleType, bindparam.type
  1439. ).types
  1440. )
  1441. ),
  1442. )
  1443. for bindparam in self.bind_names
  1444. )
  1445. if value is not None
  1446. }
  1447. def is_subquery(self):
  1448. return len(self.stack) > 1
  1449. @property
  1450. def sql_compiler(self) -> Self:
  1451. return self
  1452. def construct_expanded_state(
  1453. self,
  1454. params: Optional[_CoreSingleExecuteParams] = None,
  1455. escape_names: bool = True,
  1456. ) -> ExpandedState:
  1457. """Return a new :class:`.ExpandedState` for a given parameter set.
  1458. For queries that use "expanding" or other late-rendered parameters,
  1459. this method will provide for both the finalized SQL string as well
  1460. as the parameters that would be used for a particular parameter set.
  1461. .. versionadded:: 2.0.0rc1
  1462. """
  1463. parameters = self.construct_params(
  1464. params,
  1465. escape_names=escape_names,
  1466. _no_postcompile=True,
  1467. )
  1468. return self._process_parameters_for_postcompile(
  1469. parameters,
  1470. )
  1471. def construct_params(
  1472. self,
  1473. params: Optional[_CoreSingleExecuteParams] = None,
  1474. extracted_parameters: Optional[Sequence[BindParameter[Any]]] = None,
  1475. escape_names: bool = True,
  1476. _group_number: Optional[int] = None,
  1477. _check: bool = True,
  1478. _no_postcompile: bool = False,
  1479. ) -> _MutableCoreSingleExecuteParams:
  1480. """return a dictionary of bind parameter keys and values"""
  1481. if self._render_postcompile and not _no_postcompile:
  1482. assert self._post_compile_expanded_state is not None
  1483. if not params:
  1484. return dict(self._post_compile_expanded_state.parameters)
  1485. else:
  1486. raise exc.InvalidRequestError(
  1487. "can't construct new parameters when render_postcompile "
  1488. "is used; the statement is hard-linked to the original "
  1489. "parameters. Use construct_expanded_state to generate a "
  1490. "new statement and parameters."
  1491. )
  1492. has_escaped_names = escape_names and bool(self.escaped_bind_names)
  1493. if extracted_parameters:
  1494. # related the bound parameters collected in the original cache key
  1495. # to those collected in the incoming cache key. They will not have
  1496. # matching names but they will line up positionally in the same
  1497. # way. The parameters present in self.bind_names may be clones of
  1498. # these original cache key params in the case of DML but the .key
  1499. # will be guaranteed to match.
  1500. if self.cache_key is None:
  1501. raise exc.CompileError(
  1502. "This compiled object has no original cache key; "
  1503. "can't pass extracted_parameters to construct_params"
  1504. )
  1505. else:
  1506. orig_extracted = self.cache_key[1]
  1507. ckbm_tuple = self._cache_key_bind_match
  1508. assert ckbm_tuple is not None
  1509. ckbm, _ = ckbm_tuple
  1510. resolved_extracted = {
  1511. bind: extracted
  1512. for b, extracted in zip(orig_extracted, extracted_parameters)
  1513. for bind in ckbm[b]
  1514. }
  1515. else:
  1516. resolved_extracted = None
  1517. if params:
  1518. pd = {}
  1519. for bindparam, name in self.bind_names.items():
  1520. escaped_name = (
  1521. self.escaped_bind_names.get(name, name)
  1522. if has_escaped_names
  1523. else name
  1524. )
  1525. if bindparam.key in params:
  1526. pd[escaped_name] = params[bindparam.key]
  1527. elif name in params:
  1528. pd[escaped_name] = params[name]
  1529. elif _check and bindparam.required:
  1530. if _group_number:
  1531. raise exc.InvalidRequestError(
  1532. "A value is required for bind parameter %r, "
  1533. "in parameter group %d"
  1534. % (bindparam.key, _group_number),
  1535. code="cd3x",
  1536. )
  1537. else:
  1538. raise exc.InvalidRequestError(
  1539. "A value is required for bind parameter %r"
  1540. % bindparam.key,
  1541. code="cd3x",
  1542. )
  1543. else:
  1544. if resolved_extracted:
  1545. value_param = resolved_extracted.get(
  1546. bindparam, bindparam
  1547. )
  1548. else:
  1549. value_param = bindparam
  1550. if bindparam.callable:
  1551. pd[escaped_name] = value_param.effective_value
  1552. else:
  1553. pd[escaped_name] = value_param.value
  1554. return pd
  1555. else:
  1556. pd = {}
  1557. for bindparam, name in self.bind_names.items():
  1558. escaped_name = (
  1559. self.escaped_bind_names.get(name, name)
  1560. if has_escaped_names
  1561. else name
  1562. )
  1563. if _check and bindparam.required:
  1564. if _group_number:
  1565. raise exc.InvalidRequestError(
  1566. "A value is required for bind parameter %r, "
  1567. "in parameter group %d"
  1568. % (bindparam.key, _group_number),
  1569. code="cd3x",
  1570. )
  1571. else:
  1572. raise exc.InvalidRequestError(
  1573. "A value is required for bind parameter %r"
  1574. % bindparam.key,
  1575. code="cd3x",
  1576. )
  1577. if resolved_extracted:
  1578. value_param = resolved_extracted.get(bindparam, bindparam)
  1579. else:
  1580. value_param = bindparam
  1581. if bindparam.callable:
  1582. pd[escaped_name] = value_param.effective_value
  1583. else:
  1584. pd[escaped_name] = value_param.value
  1585. return pd
  1586. @util.memoized_instancemethod
  1587. def _get_set_input_sizes_lookup(self):
  1588. dialect = self.dialect
  1589. include_types = dialect.include_set_input_sizes
  1590. exclude_types = dialect.exclude_set_input_sizes
  1591. dbapi = dialect.dbapi
  1592. def lookup_type(typ):
  1593. dbtype = typ._unwrapped_dialect_impl(dialect).get_dbapi_type(dbapi)
  1594. if (
  1595. dbtype is not None
  1596. and (exclude_types is None or dbtype not in exclude_types)
  1597. and (include_types is None or dbtype in include_types)
  1598. ):
  1599. return dbtype
  1600. else:
  1601. return None
  1602. inputsizes = {}
  1603. literal_execute_params = self.literal_execute_params
  1604. for bindparam in self.bind_names:
  1605. if bindparam in literal_execute_params:
  1606. continue
  1607. if bindparam.type._is_tuple_type:
  1608. inputsizes[bindparam] = [
  1609. lookup_type(typ)
  1610. for typ in cast(TupleType, bindparam.type).types
  1611. ]
  1612. else:
  1613. inputsizes[bindparam] = lookup_type(bindparam.type)
  1614. return inputsizes
  1615. @property
  1616. def params(self):
  1617. """Return the bind param dictionary embedded into this
  1618. compiled object, for those values that are present.
  1619. .. seealso::
  1620. :ref:`faq_sql_expression_string` - includes a usage example for
  1621. debugging use cases.
  1622. """
  1623. return self.construct_params(_check=False)
  1624. def _process_parameters_for_postcompile(
  1625. self,
  1626. parameters: _MutableCoreSingleExecuteParams,
  1627. _populate_self: bool = False,
  1628. ) -> ExpandedState:
  1629. """handle special post compile parameters.
  1630. These include:
  1631. * "expanding" parameters -typically IN tuples that are rendered
  1632. on a per-parameter basis for an otherwise fixed SQL statement string.
  1633. * literal_binds compiled with the literal_execute flag. Used for
  1634. things like SQL Server "TOP N" where the driver does not accommodate
  1635. N as a bound parameter.
  1636. """
  1637. expanded_parameters = {}
  1638. new_positiontup: Optional[List[str]]
  1639. pre_expanded_string = self._pre_expanded_string
  1640. if pre_expanded_string is None:
  1641. pre_expanded_string = self.string
  1642. if self.positional:
  1643. new_positiontup = []
  1644. pre_expanded_positiontup = self._pre_expanded_positiontup
  1645. if pre_expanded_positiontup is None:
  1646. pre_expanded_positiontup = self.positiontup
  1647. else:
  1648. new_positiontup = pre_expanded_positiontup = None
  1649. processors = self._bind_processors
  1650. single_processors = cast(
  1651. "Mapping[str, _BindProcessorType[Any]]", processors
  1652. )
  1653. tuple_processors = cast(
  1654. "Mapping[str, Sequence[_BindProcessorType[Any]]]", processors
  1655. )
  1656. new_processors: Dict[str, _BindProcessorType[Any]] = {}
  1657. replacement_expressions: Dict[str, Any] = {}
  1658. to_update_sets: Dict[str, Any] = {}
  1659. # notes:
  1660. # *unescaped* parameter names in:
  1661. # self.bind_names, self.binds, self._bind_processors, self.positiontup
  1662. #
  1663. # *escaped* parameter names in:
  1664. # construct_params(), replacement_expressions
  1665. numeric_positiontup: Optional[List[str]] = None
  1666. if self.positional and pre_expanded_positiontup is not None:
  1667. names: Iterable[str] = pre_expanded_positiontup
  1668. if self._numeric_binds:
  1669. numeric_positiontup = []
  1670. else:
  1671. names = self.bind_names.values()
  1672. ebn = self.escaped_bind_names
  1673. for name in names:
  1674. escaped_name = ebn.get(name, name) if ebn else name
  1675. parameter = self.binds[name]
  1676. if parameter in self.literal_execute_params:
  1677. if escaped_name not in replacement_expressions:
  1678. replacement_expressions[escaped_name] = (
  1679. self.render_literal_bindparam(
  1680. parameter,
  1681. render_literal_value=parameters.pop(escaped_name),
  1682. )
  1683. )
  1684. continue
  1685. if parameter in self.post_compile_params:
  1686. if escaped_name in replacement_expressions:
  1687. to_update = to_update_sets[escaped_name]
  1688. values = None
  1689. else:
  1690. # we are removing the parameter from parameters
  1691. # because it is a list value, which is not expected by
  1692. # TypeEngine objects that would otherwise be asked to
  1693. # process it. the single name is being replaced with
  1694. # individual numbered parameters for each value in the
  1695. # param.
  1696. #
  1697. # note we are also inserting *escaped* parameter names
  1698. # into the given dictionary. default dialect will
  1699. # use these param names directly as they will not be
  1700. # in the escaped_bind_names dictionary.
  1701. values = parameters.pop(name)
  1702. leep_res = self._literal_execute_expanding_parameter(
  1703. escaped_name, parameter, values
  1704. )
  1705. (to_update, replacement_expr) = leep_res
  1706. to_update_sets[escaped_name] = to_update
  1707. replacement_expressions[escaped_name] = replacement_expr
  1708. if not parameter.literal_execute:
  1709. parameters.update(to_update)
  1710. if parameter.type._is_tuple_type:
  1711. assert values is not None
  1712. new_processors.update(
  1713. (
  1714. "%s_%s_%s" % (name, i, j),
  1715. tuple_processors[name][j - 1],
  1716. )
  1717. for i, tuple_element in enumerate(values, 1)
  1718. for j, _ in enumerate(tuple_element, 1)
  1719. if name in tuple_processors
  1720. and tuple_processors[name][j - 1] is not None
  1721. )
  1722. else:
  1723. new_processors.update(
  1724. (key, single_processors[name])
  1725. for key, _ in to_update
  1726. if name in single_processors
  1727. )
  1728. if numeric_positiontup is not None:
  1729. numeric_positiontup.extend(
  1730. name for name, _ in to_update
  1731. )
  1732. elif new_positiontup is not None:
  1733. # to_update has escaped names, but that's ok since
  1734. # these are new names, that aren't in the
  1735. # escaped_bind_names dict.
  1736. new_positiontup.extend(name for name, _ in to_update)
  1737. expanded_parameters[name] = [
  1738. expand_key for expand_key, _ in to_update
  1739. ]
  1740. elif new_positiontup is not None:
  1741. new_positiontup.append(name)
  1742. def process_expanding(m):
  1743. key = m.group(1)
  1744. expr = replacement_expressions[key]
  1745. # if POSTCOMPILE included a bind_expression, render that
  1746. # around each element
  1747. if m.group(2):
  1748. tok = m.group(2).split("~~")
  1749. be_left, be_right = tok[1], tok[3]
  1750. expr = ", ".join(
  1751. "%s%s%s" % (be_left, exp, be_right)
  1752. for exp in expr.split(", ")
  1753. )
  1754. return expr
  1755. statement = re.sub(
  1756. self._post_compile_pattern, process_expanding, pre_expanded_string
  1757. )
  1758. if numeric_positiontup is not None:
  1759. assert new_positiontup is not None
  1760. param_pos = {
  1761. key: f"{self._numeric_binds_identifier_char}{num}"
  1762. for num, key in enumerate(
  1763. numeric_positiontup, self.next_numeric_pos
  1764. )
  1765. }
  1766. # Can't use format here since % chars are not escaped.
  1767. statement = self._pyformat_pattern.sub(
  1768. lambda m: param_pos[m.group(1)], statement
  1769. )
  1770. new_positiontup.extend(numeric_positiontup)
  1771. expanded_state = ExpandedState(
  1772. statement,
  1773. parameters,
  1774. new_processors,
  1775. new_positiontup,
  1776. expanded_parameters,
  1777. )
  1778. if _populate_self:
  1779. # this is for the "render_postcompile" flag, which is not
  1780. # otherwise used internally and is for end-user debugging and
  1781. # special use cases.
  1782. self._pre_expanded_string = pre_expanded_string
  1783. self._pre_expanded_positiontup = pre_expanded_positiontup
  1784. self.string = expanded_state.statement
  1785. self.positiontup = (
  1786. list(expanded_state.positiontup or ())
  1787. if self.positional
  1788. else None
  1789. )
  1790. self._post_compile_expanded_state = expanded_state
  1791. return expanded_state
  1792. @util.preload_module("sqlalchemy.engine.cursor")
  1793. def _create_result_map(self):
  1794. """utility method used for unit tests only."""
  1795. cursor = util.preloaded.engine_cursor
  1796. return cursor.CursorResultMetaData._create_description_match_map(
  1797. self._result_columns
  1798. )
  1799. # assigned by crud.py for insert/update statements
  1800. _get_bind_name_for_col: _BindNameForColProtocol
  1801. @util.memoized_property
  1802. def _within_exec_param_key_getter(self) -> Callable[[Any], str]:
  1803. getter = self._get_bind_name_for_col
  1804. return getter
  1805. @util.memoized_property
  1806. @util.preload_module("sqlalchemy.engine.result")
  1807. def _inserted_primary_key_from_lastrowid_getter(self):
  1808. result = util.preloaded.engine_result
  1809. param_key_getter = self._within_exec_param_key_getter
  1810. assert self.compile_state is not None
  1811. statement = self.compile_state.statement
  1812. if TYPE_CHECKING:
  1813. assert isinstance(statement, Insert)
  1814. table = statement.table
  1815. getters = [
  1816. (operator.methodcaller("get", param_key_getter(col), None), col)
  1817. for col in table.primary_key
  1818. ]
  1819. autoinc_getter = None
  1820. autoinc_col = table._autoincrement_column
  1821. if autoinc_col is not None:
  1822. # apply type post processors to the lastrowid
  1823. lastrowid_processor = autoinc_col.type._cached_result_processor(
  1824. self.dialect, None
  1825. )
  1826. autoinc_key = param_key_getter(autoinc_col)
  1827. # if a bind value is present for the autoincrement column
  1828. # in the parameters, we need to do the logic dictated by
  1829. # #7998; honor a non-None user-passed parameter over lastrowid.
  1830. # previously in the 1.4 series we weren't fetching lastrowid
  1831. # at all if the key were present in the parameters
  1832. if autoinc_key in self.binds:
  1833. def _autoinc_getter(lastrowid, parameters):
  1834. param_value = parameters.get(autoinc_key, lastrowid)
  1835. if param_value is not None:
  1836. # they supplied non-None parameter, use that.
  1837. # SQLite at least is observed to return the wrong
  1838. # cursor.lastrowid for INSERT..ON CONFLICT so it
  1839. # can't be used in all cases
  1840. return param_value
  1841. else:
  1842. # use lastrowid
  1843. return lastrowid
  1844. # work around mypy https://github.com/python/mypy/issues/14027
  1845. autoinc_getter = _autoinc_getter
  1846. else:
  1847. lastrowid_processor = None
  1848. row_fn = result.result_tuple([col.key for col in table.primary_key])
  1849. def get(lastrowid, parameters):
  1850. """given cursor.lastrowid value and the parameters used for INSERT,
  1851. return a "row" that represents the primary key, either by
  1852. using the "lastrowid" or by extracting values from the parameters
  1853. that were sent along with the INSERT.
  1854. """
  1855. if lastrowid_processor is not None:
  1856. lastrowid = lastrowid_processor(lastrowid)
  1857. if lastrowid is None:
  1858. return row_fn(getter(parameters) for getter, col in getters)
  1859. else:
  1860. return row_fn(
  1861. (
  1862. (
  1863. autoinc_getter(lastrowid, parameters)
  1864. if autoinc_getter is not None
  1865. else lastrowid
  1866. )
  1867. if col is autoinc_col
  1868. else getter(parameters)
  1869. )
  1870. for getter, col in getters
  1871. )
  1872. return get
  1873. @util.memoized_property
  1874. @util.preload_module("sqlalchemy.engine.result")
  1875. def _inserted_primary_key_from_returning_getter(self):
  1876. result = util.preloaded.engine_result
  1877. assert self.compile_state is not None
  1878. statement = self.compile_state.statement
  1879. if TYPE_CHECKING:
  1880. assert isinstance(statement, Insert)
  1881. param_key_getter = self._within_exec_param_key_getter
  1882. table = statement.table
  1883. returning = self.implicit_returning
  1884. assert returning is not None
  1885. ret = {col: idx for idx, col in enumerate(returning)}
  1886. getters = cast(
  1887. "List[Tuple[Callable[[Any], Any], bool]]",
  1888. [
  1889. (
  1890. (operator.itemgetter(ret[col]), True)
  1891. if col in ret
  1892. else (
  1893. operator.methodcaller(
  1894. "get", param_key_getter(col), None
  1895. ),
  1896. False,
  1897. )
  1898. )
  1899. for col in table.primary_key
  1900. ],
  1901. )
  1902. row_fn = result.result_tuple([col.key for col in table.primary_key])
  1903. def get(row, parameters):
  1904. return row_fn(
  1905. getter(row) if use_row else getter(parameters)
  1906. for getter, use_row in getters
  1907. )
  1908. return get
  1909. def default_from(self) -> str:
  1910. """Called when a SELECT statement has no froms, and no FROM clause is
  1911. to be appended.
  1912. Gives Oracle Database a chance to tack on a ``FROM DUAL`` to the string
  1913. output.
  1914. """
  1915. return ""
  1916. def visit_override_binds(self, override_binds, **kw):
  1917. """SQL compile the nested element of an _OverrideBinds with
  1918. bindparams swapped out.
  1919. The _OverrideBinds is not normally expected to be compiled; it
  1920. is meant to be used when an already cached statement is to be used,
  1921. the compilation was already performed, and only the bound params should
  1922. be swapped in at execution time.
  1923. However, there are test cases that exericise this object, and
  1924. additionally the ORM subquery loader is known to feed in expressions
  1925. which include this construct into new queries (discovered in #11173),
  1926. so it has to do the right thing at compile time as well.
  1927. """
  1928. # get SQL text first
  1929. sqltext = override_binds.element._compiler_dispatch(self, **kw)
  1930. # for a test compile that is not for caching, change binds after the
  1931. # fact. note that we don't try to
  1932. # swap the bindparam as we compile, because our element may be
  1933. # elsewhere in the statement already (e.g. a subquery or perhaps a
  1934. # CTE) and was already visited / compiled. See
  1935. # test_relationship_criteria.py ->
  1936. # test_selectinload_local_criteria_subquery
  1937. for k in override_binds.translate:
  1938. if k not in self.binds:
  1939. continue
  1940. bp = self.binds[k]
  1941. # so this would work, just change the value of bp in place.
  1942. # but we dont want to mutate things outside.
  1943. # bp.value = override_binds.translate[bp.key]
  1944. # continue
  1945. # instead, need to replace bp with new_bp or otherwise accommodate
  1946. # in all internal collections
  1947. new_bp = bp._with_value(
  1948. override_binds.translate[bp.key],
  1949. maintain_key=True,
  1950. required=False,
  1951. )
  1952. name = self.bind_names[bp]
  1953. self.binds[k] = self.binds[name] = new_bp
  1954. self.bind_names[new_bp] = name
  1955. self.bind_names.pop(bp, None)
  1956. if bp in self.post_compile_params:
  1957. self.post_compile_params |= {new_bp}
  1958. if bp in self.literal_execute_params:
  1959. self.literal_execute_params |= {new_bp}
  1960. ckbm_tuple = self._cache_key_bind_match
  1961. if ckbm_tuple:
  1962. ckbm, cksm = ckbm_tuple
  1963. for bp in bp._cloned_set:
  1964. if bp.key in cksm:
  1965. cb = cksm[bp.key]
  1966. ckbm[cb].append(new_bp)
  1967. return sqltext
  1968. def visit_grouping(self, grouping, asfrom=False, **kwargs):
  1969. return "(" + grouping.element._compiler_dispatch(self, **kwargs) + ")"
  1970. def visit_select_statement_grouping(self, grouping, **kwargs):
  1971. return "(" + grouping.element._compiler_dispatch(self, **kwargs) + ")"
  1972. def visit_label_reference(
  1973. self, element, within_columns_clause=False, **kwargs
  1974. ):
  1975. if self.stack and self.dialect.supports_simple_order_by_label:
  1976. try:
  1977. compile_state = cast(
  1978. "Union[SelectState, CompoundSelectState]",
  1979. self.stack[-1]["compile_state"],
  1980. )
  1981. except KeyError as ke:
  1982. raise exc.CompileError(
  1983. "Can't resolve label reference for ORDER BY / "
  1984. "GROUP BY / DISTINCT etc."
  1985. ) from ke
  1986. (
  1987. with_cols,
  1988. only_froms,
  1989. only_cols,
  1990. ) = compile_state._label_resolve_dict
  1991. if within_columns_clause:
  1992. resolve_dict = only_froms
  1993. else:
  1994. resolve_dict = only_cols
  1995. # this can be None in the case that a _label_reference()
  1996. # were subject to a replacement operation, in which case
  1997. # the replacement of the Label element may have changed
  1998. # to something else like a ColumnClause expression.
  1999. order_by_elem = element.element._order_by_label_element
  2000. if (
  2001. order_by_elem is not None
  2002. and order_by_elem.name in resolve_dict
  2003. and order_by_elem.shares_lineage(
  2004. resolve_dict[order_by_elem.name]
  2005. )
  2006. ):
  2007. kwargs["render_label_as_label"] = (
  2008. element.element._order_by_label_element
  2009. )
  2010. return self.process(
  2011. element.element,
  2012. within_columns_clause=within_columns_clause,
  2013. **kwargs,
  2014. )
  2015. def visit_textual_label_reference(
  2016. self, element, within_columns_clause=False, **kwargs
  2017. ):
  2018. if not self.stack:
  2019. # compiling the element outside of the context of a SELECT
  2020. return self.process(element._text_clause)
  2021. try:
  2022. compile_state = cast(
  2023. "Union[SelectState, CompoundSelectState]",
  2024. self.stack[-1]["compile_state"],
  2025. )
  2026. except KeyError as ke:
  2027. coercions._no_text_coercion(
  2028. element.element,
  2029. extra=(
  2030. "Can't resolve label reference for ORDER BY / "
  2031. "GROUP BY / DISTINCT etc."
  2032. ),
  2033. exc_cls=exc.CompileError,
  2034. err=ke,
  2035. )
  2036. with_cols, only_froms, only_cols = compile_state._label_resolve_dict
  2037. try:
  2038. if within_columns_clause:
  2039. col = only_froms[element.element]
  2040. else:
  2041. col = with_cols[element.element]
  2042. except KeyError as err:
  2043. coercions._no_text_coercion(
  2044. element.element,
  2045. extra=(
  2046. "Can't resolve label reference for ORDER BY / "
  2047. "GROUP BY / DISTINCT etc."
  2048. ),
  2049. exc_cls=exc.CompileError,
  2050. err=err,
  2051. )
  2052. else:
  2053. kwargs["render_label_as_label"] = col
  2054. return self.process(
  2055. col, within_columns_clause=within_columns_clause, **kwargs
  2056. )
  2057. def visit_label(
  2058. self,
  2059. label,
  2060. add_to_result_map=None,
  2061. within_label_clause=False,
  2062. within_columns_clause=False,
  2063. render_label_as_label=None,
  2064. result_map_targets=(),
  2065. **kw,
  2066. ):
  2067. # only render labels within the columns clause
  2068. # or ORDER BY clause of a select. dialect-specific compilers
  2069. # can modify this behavior.
  2070. render_label_with_as = (
  2071. within_columns_clause and not within_label_clause
  2072. )
  2073. render_label_only = render_label_as_label is label
  2074. if render_label_only or render_label_with_as:
  2075. if isinstance(label.name, elements._truncated_label):
  2076. labelname = self._truncated_identifier("colident", label.name)
  2077. else:
  2078. labelname = label.name
  2079. if render_label_with_as:
  2080. if add_to_result_map is not None:
  2081. add_to_result_map(
  2082. labelname,
  2083. label.name,
  2084. (label, labelname) + label._alt_names + result_map_targets,
  2085. label.type,
  2086. )
  2087. return (
  2088. label.element._compiler_dispatch(
  2089. self,
  2090. within_columns_clause=True,
  2091. within_label_clause=True,
  2092. **kw,
  2093. )
  2094. + OPERATORS[operators.as_]
  2095. + self.preparer.format_label(label, labelname)
  2096. )
  2097. elif render_label_only:
  2098. return self.preparer.format_label(label, labelname)
  2099. else:
  2100. return label.element._compiler_dispatch(
  2101. self, within_columns_clause=False, **kw
  2102. )
  2103. def _fallback_column_name(self, column):
  2104. raise exc.CompileError(
  2105. "Cannot compile Column object until its 'name' is assigned."
  2106. )
  2107. def visit_lambda_element(self, element, **kw):
  2108. sql_element = element._resolved
  2109. return self.process(sql_element, **kw)
  2110. def visit_column(
  2111. self,
  2112. column: ColumnClause[Any],
  2113. add_to_result_map: Optional[_ResultMapAppender] = None,
  2114. include_table: bool = True,
  2115. result_map_targets: Tuple[Any, ...] = (),
  2116. ambiguous_table_name_map: Optional[_AmbiguousTableNameMap] = None,
  2117. **kwargs: Any,
  2118. ) -> str:
  2119. name = orig_name = column.name
  2120. if name is None:
  2121. name = self._fallback_column_name(column)
  2122. is_literal = column.is_literal
  2123. if not is_literal and isinstance(name, elements._truncated_label):
  2124. name = self._truncated_identifier("colident", name)
  2125. if add_to_result_map is not None:
  2126. targets = (column, name, column.key) + result_map_targets
  2127. if column._tq_label:
  2128. targets += (column._tq_label,)
  2129. add_to_result_map(name, orig_name, targets, column.type)
  2130. if is_literal:
  2131. # note we are not currently accommodating for
  2132. # literal_column(quoted_name('ident', True)) here
  2133. name = self.escape_literal_column(name)
  2134. else:
  2135. name = self.preparer.quote(name)
  2136. table = column.table
  2137. if table is None or not include_table or not table.named_with_column:
  2138. return name
  2139. else:
  2140. effective_schema = self.preparer.schema_for_object(table)
  2141. if effective_schema:
  2142. schema_prefix = (
  2143. self.preparer.quote_schema(effective_schema) + "."
  2144. )
  2145. else:
  2146. schema_prefix = ""
  2147. if TYPE_CHECKING:
  2148. assert isinstance(table, NamedFromClause)
  2149. tablename = table.name
  2150. if (
  2151. not effective_schema
  2152. and ambiguous_table_name_map
  2153. and tablename in ambiguous_table_name_map
  2154. ):
  2155. tablename = ambiguous_table_name_map[tablename]
  2156. if isinstance(tablename, elements._truncated_label):
  2157. tablename = self._truncated_identifier("alias", tablename)
  2158. return schema_prefix + self.preparer.quote(tablename) + "." + name
  2159. def visit_collation(self, element, **kw):
  2160. return self.preparer.format_collation(element.collation)
  2161. def visit_fromclause(self, fromclause, **kwargs):
  2162. return fromclause.name
  2163. def visit_index(self, index, **kwargs):
  2164. return index.name
  2165. def visit_typeclause(self, typeclause, **kw):
  2166. kw["type_expression"] = typeclause
  2167. kw["identifier_preparer"] = self.preparer
  2168. return self.dialect.type_compiler_instance.process(
  2169. typeclause.type, **kw
  2170. )
  2171. def post_process_text(self, text):
  2172. if self.preparer._double_percents:
  2173. text = text.replace("%", "%%")
  2174. return text
  2175. def escape_literal_column(self, text):
  2176. if self.preparer._double_percents:
  2177. text = text.replace("%", "%%")
  2178. return text
  2179. def visit_textclause(self, textclause, add_to_result_map=None, **kw):
  2180. def do_bindparam(m):
  2181. name = m.group(1)
  2182. if name in textclause._bindparams:
  2183. return self.process(textclause._bindparams[name], **kw)
  2184. else:
  2185. return self.bindparam_string(name, **kw)
  2186. if not self.stack:
  2187. self.isplaintext = True
  2188. if add_to_result_map:
  2189. # text() object is present in the columns clause of a
  2190. # select(). Add a no-name entry to the result map so that
  2191. # row[text()] produces a result
  2192. add_to_result_map(None, None, (textclause,), sqltypes.NULLTYPE)
  2193. # un-escape any \:params
  2194. return BIND_PARAMS_ESC.sub(
  2195. lambda m: m.group(1),
  2196. BIND_PARAMS.sub(
  2197. do_bindparam, self.post_process_text(textclause.text)
  2198. ),
  2199. )
  2200. def visit_textual_select(
  2201. self, taf, compound_index=None, asfrom=False, **kw
  2202. ):
  2203. toplevel = not self.stack
  2204. entry = self._default_stack_entry if toplevel else self.stack[-1]
  2205. new_entry: _CompilerStackEntry = {
  2206. "correlate_froms": set(),
  2207. "asfrom_froms": set(),
  2208. "selectable": taf,
  2209. }
  2210. self.stack.append(new_entry)
  2211. if taf._independent_ctes:
  2212. self._dispatch_independent_ctes(taf, kw)
  2213. populate_result_map = (
  2214. toplevel
  2215. or (
  2216. compound_index == 0
  2217. and entry.get("need_result_map_for_compound", False)
  2218. )
  2219. or entry.get("need_result_map_for_nested", False)
  2220. )
  2221. if populate_result_map:
  2222. self._ordered_columns = self._textual_ordered_columns = (
  2223. taf.positional
  2224. )
  2225. # enable looser result column matching when the SQL text links to
  2226. # Column objects by name only
  2227. self._loose_column_name_matching = not taf.positional and bool(
  2228. taf.column_args
  2229. )
  2230. for c in taf.column_args:
  2231. self.process(
  2232. c,
  2233. within_columns_clause=True,
  2234. add_to_result_map=self._add_to_result_map,
  2235. )
  2236. text = self.process(taf.element, **kw)
  2237. if self.ctes:
  2238. nesting_level = len(self.stack) if not toplevel else None
  2239. text = self._render_cte_clause(nesting_level=nesting_level) + text
  2240. self.stack.pop(-1)
  2241. return text
  2242. def visit_null(self, expr: Null, **kw: Any) -> str:
  2243. return "NULL"
  2244. def visit_true(self, expr: True_, **kw: Any) -> str:
  2245. if self.dialect.supports_native_boolean:
  2246. return "true"
  2247. else:
  2248. return "1"
  2249. def visit_false(self, expr: False_, **kw: Any) -> str:
  2250. if self.dialect.supports_native_boolean:
  2251. return "false"
  2252. else:
  2253. return "0"
  2254. def _generate_delimited_list(self, elements, separator, **kw):
  2255. return separator.join(
  2256. s
  2257. for s in (c._compiler_dispatch(self, **kw) for c in elements)
  2258. if s
  2259. )
  2260. def _generate_delimited_and_list(self, clauses, **kw):
  2261. lcc, clauses = elements.BooleanClauseList._process_clauses_for_boolean(
  2262. operators.and_,
  2263. elements.True_._singleton,
  2264. elements.False_._singleton,
  2265. clauses,
  2266. )
  2267. if lcc == 1:
  2268. return clauses[0]._compiler_dispatch(self, **kw)
  2269. else:
  2270. separator = OPERATORS[operators.and_]
  2271. return separator.join(
  2272. s
  2273. for s in (c._compiler_dispatch(self, **kw) for c in clauses)
  2274. if s
  2275. )
  2276. def visit_tuple(self, clauselist, **kw):
  2277. return "(%s)" % self.visit_clauselist(clauselist, **kw)
  2278. def visit_clauselist(self, clauselist, **kw):
  2279. sep = clauselist.operator
  2280. if sep is None:
  2281. sep = " "
  2282. else:
  2283. sep = OPERATORS[clauselist.operator]
  2284. return self._generate_delimited_list(clauselist.clauses, sep, **kw)
  2285. def visit_expression_clauselist(self, clauselist, **kw):
  2286. operator_ = clauselist.operator
  2287. disp = self._get_operator_dispatch(
  2288. operator_, "expression_clauselist", None
  2289. )
  2290. if disp:
  2291. return disp(clauselist, operator_, **kw)
  2292. try:
  2293. opstring = OPERATORS[operator_]
  2294. except KeyError as err:
  2295. raise exc.UnsupportedCompilationError(self, operator_) from err
  2296. else:
  2297. kw["_in_operator_expression"] = True
  2298. return self._generate_delimited_list(
  2299. clauselist.clauses, opstring, **kw
  2300. )
  2301. def visit_case(self, clause, **kwargs):
  2302. x = "CASE "
  2303. if clause.value is not None:
  2304. x += clause.value._compiler_dispatch(self, **kwargs) + " "
  2305. for cond, result in clause.whens:
  2306. x += (
  2307. "WHEN "
  2308. + cond._compiler_dispatch(self, **kwargs)
  2309. + " THEN "
  2310. + result._compiler_dispatch(self, **kwargs)
  2311. + " "
  2312. )
  2313. if clause.else_ is not None:
  2314. x += (
  2315. "ELSE " + clause.else_._compiler_dispatch(self, **kwargs) + " "
  2316. )
  2317. x += "END"
  2318. return x
  2319. def visit_type_coerce(self, type_coerce, **kw):
  2320. return type_coerce.typed_expression._compiler_dispatch(self, **kw)
  2321. def visit_cast(self, cast, **kwargs):
  2322. type_clause = cast.typeclause._compiler_dispatch(self, **kwargs)
  2323. match = re.match("(.*)( COLLATE .*)", type_clause)
  2324. return "CAST(%s AS %s)%s" % (
  2325. cast.clause._compiler_dispatch(self, **kwargs),
  2326. match.group(1) if match else type_clause,
  2327. match.group(2) if match else "",
  2328. )
  2329. def _format_frame_clause(self, range_, **kw):
  2330. return "%s AND %s" % (
  2331. (
  2332. "UNBOUNDED PRECEDING"
  2333. if range_[0] is elements.RANGE_UNBOUNDED
  2334. else (
  2335. "CURRENT ROW"
  2336. if range_[0] is elements.RANGE_CURRENT
  2337. else (
  2338. "%s PRECEDING"
  2339. % (
  2340. self.process(
  2341. elements.literal(abs(range_[0])), **kw
  2342. ),
  2343. )
  2344. if range_[0] < 0
  2345. else "%s FOLLOWING"
  2346. % (self.process(elements.literal(range_[0]), **kw),)
  2347. )
  2348. )
  2349. ),
  2350. (
  2351. "UNBOUNDED FOLLOWING"
  2352. if range_[1] is elements.RANGE_UNBOUNDED
  2353. else (
  2354. "CURRENT ROW"
  2355. if range_[1] is elements.RANGE_CURRENT
  2356. else (
  2357. "%s PRECEDING"
  2358. % (
  2359. self.process(
  2360. elements.literal(abs(range_[1])), **kw
  2361. ),
  2362. )
  2363. if range_[1] < 0
  2364. else "%s FOLLOWING"
  2365. % (self.process(elements.literal(range_[1]), **kw),)
  2366. )
  2367. )
  2368. ),
  2369. )
  2370. def visit_over(self, over, **kwargs):
  2371. text = over.element._compiler_dispatch(self, **kwargs)
  2372. if over.range_ is not None:
  2373. range_ = "RANGE BETWEEN %s" % self._format_frame_clause(
  2374. over.range_, **kwargs
  2375. )
  2376. elif over.rows is not None:
  2377. range_ = "ROWS BETWEEN %s" % self._format_frame_clause(
  2378. over.rows, **kwargs
  2379. )
  2380. elif over.groups is not None:
  2381. range_ = "GROUPS BETWEEN %s" % self._format_frame_clause(
  2382. over.groups, **kwargs
  2383. )
  2384. else:
  2385. range_ = None
  2386. return "%s OVER (%s)" % (
  2387. text,
  2388. " ".join(
  2389. [
  2390. "%s BY %s"
  2391. % (word, clause._compiler_dispatch(self, **kwargs))
  2392. for word, clause in (
  2393. ("PARTITION", over.partition_by),
  2394. ("ORDER", over.order_by),
  2395. )
  2396. if clause is not None and len(clause)
  2397. ]
  2398. + ([range_] if range_ else [])
  2399. ),
  2400. )
  2401. def visit_withingroup(self, withingroup, **kwargs):
  2402. return "%s WITHIN GROUP (ORDER BY %s)" % (
  2403. withingroup.element._compiler_dispatch(self, **kwargs),
  2404. withingroup.order_by._compiler_dispatch(self, **kwargs),
  2405. )
  2406. def visit_funcfilter(self, funcfilter, **kwargs):
  2407. return "%s FILTER (WHERE %s)" % (
  2408. funcfilter.func._compiler_dispatch(self, **kwargs),
  2409. funcfilter.criterion._compiler_dispatch(self, **kwargs),
  2410. )
  2411. def visit_extract(self, extract, **kwargs):
  2412. field = self.extract_map.get(extract.field, extract.field)
  2413. return "EXTRACT(%s FROM %s)" % (
  2414. field,
  2415. extract.expr._compiler_dispatch(self, **kwargs),
  2416. )
  2417. def visit_scalar_function_column(self, element, **kw):
  2418. compiled_fn = self.visit_function(element.fn, **kw)
  2419. compiled_col = self.visit_column(element, **kw)
  2420. return "(%s).%s" % (compiled_fn, compiled_col)
  2421. def visit_function(
  2422. self,
  2423. func: Function[Any],
  2424. add_to_result_map: Optional[_ResultMapAppender] = None,
  2425. **kwargs: Any,
  2426. ) -> str:
  2427. if add_to_result_map is not None:
  2428. add_to_result_map(func.name, func.name, (func.name,), func.type)
  2429. disp = getattr(self, "visit_%s_func" % func.name.lower(), None)
  2430. text: str
  2431. if disp:
  2432. text = disp(func, **kwargs)
  2433. else:
  2434. name = FUNCTIONS.get(func._deannotate().__class__, None)
  2435. if name:
  2436. if func._has_args:
  2437. name += "%(expr)s"
  2438. else:
  2439. name = func.name
  2440. name = (
  2441. self.preparer.quote(name)
  2442. if self.preparer._requires_quotes_illegal_chars(name)
  2443. or isinstance(name, elements.quoted_name)
  2444. else name
  2445. )
  2446. name = name + "%(expr)s"
  2447. text = ".".join(
  2448. [
  2449. (
  2450. self.preparer.quote(tok)
  2451. if self.preparer._requires_quotes_illegal_chars(tok)
  2452. or isinstance(name, elements.quoted_name)
  2453. else tok
  2454. )
  2455. for tok in func.packagenames
  2456. ]
  2457. + [name]
  2458. ) % {"expr": self.function_argspec(func, **kwargs)}
  2459. if func._with_ordinality:
  2460. text += " WITH ORDINALITY"
  2461. return text
  2462. def visit_next_value_func(self, next_value, **kw):
  2463. return self.visit_sequence(next_value.sequence)
  2464. def visit_sequence(self, sequence, **kw):
  2465. raise NotImplementedError(
  2466. "Dialect '%s' does not support sequence increments."
  2467. % self.dialect.name
  2468. )
  2469. def function_argspec(self, func: Function[Any], **kwargs: Any) -> str:
  2470. return func.clause_expr._compiler_dispatch(self, **kwargs)
  2471. def visit_compound_select(
  2472. self, cs, asfrom=False, compound_index=None, **kwargs
  2473. ):
  2474. toplevel = not self.stack
  2475. compile_state = cs._compile_state_factory(cs, self, **kwargs)
  2476. if toplevel and not self.compile_state:
  2477. self.compile_state = compile_state
  2478. compound_stmt = compile_state.statement
  2479. entry = self._default_stack_entry if toplevel else self.stack[-1]
  2480. need_result_map = toplevel or (
  2481. not compound_index
  2482. and entry.get("need_result_map_for_compound", False)
  2483. )
  2484. # indicates there is already a CompoundSelect in play
  2485. if compound_index == 0:
  2486. entry["select_0"] = cs
  2487. self.stack.append(
  2488. {
  2489. "correlate_froms": entry["correlate_froms"],
  2490. "asfrom_froms": entry["asfrom_froms"],
  2491. "selectable": cs,
  2492. "compile_state": compile_state,
  2493. "need_result_map_for_compound": need_result_map,
  2494. }
  2495. )
  2496. if compound_stmt._independent_ctes:
  2497. self._dispatch_independent_ctes(compound_stmt, kwargs)
  2498. keyword = self.compound_keywords[cs.keyword]
  2499. text = (" " + keyword + " ").join(
  2500. (
  2501. c._compiler_dispatch(
  2502. self, asfrom=asfrom, compound_index=i, **kwargs
  2503. )
  2504. for i, c in enumerate(cs.selects)
  2505. )
  2506. )
  2507. kwargs["include_table"] = False
  2508. text += self.group_by_clause(cs, **dict(asfrom=asfrom, **kwargs))
  2509. text += self.order_by_clause(cs, **kwargs)
  2510. if cs._has_row_limiting_clause:
  2511. text += self._row_limit_clause(cs, **kwargs)
  2512. if self.ctes:
  2513. nesting_level = len(self.stack) if not toplevel else None
  2514. text = (
  2515. self._render_cte_clause(
  2516. nesting_level=nesting_level,
  2517. include_following_stack=True,
  2518. )
  2519. + text
  2520. )
  2521. self.stack.pop(-1)
  2522. return text
  2523. def _row_limit_clause(self, cs, **kwargs):
  2524. if cs._fetch_clause is not None:
  2525. return self.fetch_clause(cs, **kwargs)
  2526. else:
  2527. return self.limit_clause(cs, **kwargs)
  2528. def _get_operator_dispatch(self, operator_, qualifier1, qualifier2):
  2529. attrname = "visit_%s_%s%s" % (
  2530. operator_.__name__,
  2531. qualifier1,
  2532. "_" + qualifier2 if qualifier2 else "",
  2533. )
  2534. return getattr(self, attrname, None)
  2535. def visit_unary(
  2536. self, unary, add_to_result_map=None, result_map_targets=(), **kw
  2537. ):
  2538. if add_to_result_map is not None:
  2539. result_map_targets += (unary,)
  2540. kw["add_to_result_map"] = add_to_result_map
  2541. kw["result_map_targets"] = result_map_targets
  2542. if unary.operator:
  2543. if unary.modifier:
  2544. raise exc.CompileError(
  2545. "Unary expression does not support operator "
  2546. "and modifier simultaneously"
  2547. )
  2548. disp = self._get_operator_dispatch(
  2549. unary.operator, "unary", "operator"
  2550. )
  2551. if disp:
  2552. return disp(unary, unary.operator, **kw)
  2553. else:
  2554. return self._generate_generic_unary_operator(
  2555. unary, OPERATORS[unary.operator], **kw
  2556. )
  2557. elif unary.modifier:
  2558. disp = self._get_operator_dispatch(
  2559. unary.modifier, "unary", "modifier"
  2560. )
  2561. if disp:
  2562. return disp(unary, unary.modifier, **kw)
  2563. else:
  2564. return self._generate_generic_unary_modifier(
  2565. unary, OPERATORS[unary.modifier], **kw
  2566. )
  2567. else:
  2568. raise exc.CompileError(
  2569. "Unary expression has no operator or modifier"
  2570. )
  2571. def visit_truediv_binary(self, binary, operator, **kw):
  2572. if self.dialect.div_is_floordiv:
  2573. return (
  2574. self.process(binary.left, **kw)
  2575. + " / "
  2576. # TODO: would need a fast cast again here,
  2577. # unless we want to use an implicit cast like "+ 0.0"
  2578. + self.process(
  2579. elements.Cast(
  2580. binary.right,
  2581. (
  2582. binary.right.type
  2583. if binary.right.type._type_affinity
  2584. is sqltypes.Numeric
  2585. else sqltypes.Numeric()
  2586. ),
  2587. ),
  2588. **kw,
  2589. )
  2590. )
  2591. else:
  2592. return (
  2593. self.process(binary.left, **kw)
  2594. + " / "
  2595. + self.process(binary.right, **kw)
  2596. )
  2597. def visit_floordiv_binary(self, binary, operator, **kw):
  2598. if (
  2599. self.dialect.div_is_floordiv
  2600. and binary.right.type._type_affinity is sqltypes.Integer
  2601. ):
  2602. return (
  2603. self.process(binary.left, **kw)
  2604. + " / "
  2605. + self.process(binary.right, **kw)
  2606. )
  2607. else:
  2608. return "FLOOR(%s)" % (
  2609. self.process(binary.left, **kw)
  2610. + " / "
  2611. + self.process(binary.right, **kw)
  2612. )
  2613. def visit_is_true_unary_operator(self, element, operator, **kw):
  2614. if (
  2615. element._is_implicitly_boolean
  2616. or self.dialect.supports_native_boolean
  2617. ):
  2618. return self.process(element.element, **kw)
  2619. else:
  2620. return "%s = 1" % self.process(element.element, **kw)
  2621. def visit_is_false_unary_operator(self, element, operator, **kw):
  2622. if (
  2623. element._is_implicitly_boolean
  2624. or self.dialect.supports_native_boolean
  2625. ):
  2626. return "NOT %s" % self.process(element.element, **kw)
  2627. else:
  2628. return "%s = 0" % self.process(element.element, **kw)
  2629. def visit_not_match_op_binary(self, binary, operator, **kw):
  2630. return "NOT %s" % self.visit_binary(
  2631. binary, override_operator=operators.match_op
  2632. )
  2633. def visit_not_in_op_binary(self, binary, operator, **kw):
  2634. # The brackets are required in the NOT IN operation because the empty
  2635. # case is handled using the form "(col NOT IN (null) OR 1 = 1)".
  2636. # The presence of the OR makes the brackets required.
  2637. return "(%s)" % self._generate_generic_binary(
  2638. binary, OPERATORS[operator], **kw
  2639. )
  2640. def visit_empty_set_op_expr(self, type_, expand_op, **kw):
  2641. if expand_op is operators.not_in_op:
  2642. if len(type_) > 1:
  2643. return "(%s)) OR (1 = 1" % (
  2644. ", ".join("NULL" for element in type_)
  2645. )
  2646. else:
  2647. return "NULL) OR (1 = 1"
  2648. elif expand_op is operators.in_op:
  2649. if len(type_) > 1:
  2650. return "(%s)) AND (1 != 1" % (
  2651. ", ".join("NULL" for element in type_)
  2652. )
  2653. else:
  2654. return "NULL) AND (1 != 1"
  2655. else:
  2656. return self.visit_empty_set_expr(type_)
  2657. def visit_empty_set_expr(self, element_types, **kw):
  2658. raise NotImplementedError(
  2659. "Dialect '%s' does not support empty set expression."
  2660. % self.dialect.name
  2661. )
  2662. def _literal_execute_expanding_parameter_literal_binds(
  2663. self, parameter, values, bind_expression_template=None
  2664. ):
  2665. typ_dialect_impl = parameter.type._unwrapped_dialect_impl(self.dialect)
  2666. if not values:
  2667. # empty IN expression. note we don't need to use
  2668. # bind_expression_template here because there are no
  2669. # expressions to render.
  2670. if typ_dialect_impl._is_tuple_type:
  2671. replacement_expression = (
  2672. "VALUES " if self.dialect.tuple_in_values else ""
  2673. ) + self.visit_empty_set_op_expr(
  2674. parameter.type.types, parameter.expand_op
  2675. )
  2676. else:
  2677. replacement_expression = self.visit_empty_set_op_expr(
  2678. [parameter.type], parameter.expand_op
  2679. )
  2680. elif typ_dialect_impl._is_tuple_type or (
  2681. typ_dialect_impl._isnull
  2682. and isinstance(values[0], collections_abc.Sequence)
  2683. and not isinstance(values[0], (str, bytes))
  2684. ):
  2685. if typ_dialect_impl._has_bind_expression:
  2686. raise NotImplementedError(
  2687. "bind_expression() on TupleType not supported with "
  2688. "literal_binds"
  2689. )
  2690. replacement_expression = (
  2691. "VALUES " if self.dialect.tuple_in_values else ""
  2692. ) + ", ".join(
  2693. "(%s)"
  2694. % (
  2695. ", ".join(
  2696. self.render_literal_value(value, param_type)
  2697. for value, param_type in zip(
  2698. tuple_element, parameter.type.types
  2699. )
  2700. )
  2701. )
  2702. for i, tuple_element in enumerate(values)
  2703. )
  2704. else:
  2705. if bind_expression_template:
  2706. post_compile_pattern = self._post_compile_pattern
  2707. m = post_compile_pattern.search(bind_expression_template)
  2708. assert m and m.group(
  2709. 2
  2710. ), "unexpected format for expanding parameter"
  2711. tok = m.group(2).split("~~")
  2712. be_left, be_right = tok[1], tok[3]
  2713. replacement_expression = ", ".join(
  2714. "%s%s%s"
  2715. % (
  2716. be_left,
  2717. self.render_literal_value(value, parameter.type),
  2718. be_right,
  2719. )
  2720. for value in values
  2721. )
  2722. else:
  2723. replacement_expression = ", ".join(
  2724. self.render_literal_value(value, parameter.type)
  2725. for value in values
  2726. )
  2727. return (), replacement_expression
  2728. def _literal_execute_expanding_parameter(self, name, parameter, values):
  2729. if parameter.literal_execute:
  2730. return self._literal_execute_expanding_parameter_literal_binds(
  2731. parameter, values
  2732. )
  2733. dialect = self.dialect
  2734. typ_dialect_impl = parameter.type._unwrapped_dialect_impl(dialect)
  2735. if self._numeric_binds:
  2736. bind_template = self.compilation_bindtemplate
  2737. else:
  2738. bind_template = self.bindtemplate
  2739. if (
  2740. self.dialect._bind_typing_render_casts
  2741. and typ_dialect_impl.render_bind_cast
  2742. ):
  2743. def _render_bindtemplate(name):
  2744. return self.render_bind_cast(
  2745. parameter.type,
  2746. typ_dialect_impl,
  2747. bind_template % {"name": name},
  2748. )
  2749. else:
  2750. def _render_bindtemplate(name):
  2751. return bind_template % {"name": name}
  2752. if not values:
  2753. to_update = []
  2754. if typ_dialect_impl._is_tuple_type:
  2755. replacement_expression = self.visit_empty_set_op_expr(
  2756. parameter.type.types, parameter.expand_op
  2757. )
  2758. else:
  2759. replacement_expression = self.visit_empty_set_op_expr(
  2760. [parameter.type], parameter.expand_op
  2761. )
  2762. elif typ_dialect_impl._is_tuple_type or (
  2763. typ_dialect_impl._isnull
  2764. and isinstance(values[0], collections_abc.Sequence)
  2765. and not isinstance(values[0], (str, bytes))
  2766. ):
  2767. assert not typ_dialect_impl._is_array
  2768. to_update = [
  2769. ("%s_%s_%s" % (name, i, j), value)
  2770. for i, tuple_element in enumerate(values, 1)
  2771. for j, value in enumerate(tuple_element, 1)
  2772. ]
  2773. replacement_expression = (
  2774. "VALUES " if dialect.tuple_in_values else ""
  2775. ) + ", ".join(
  2776. "(%s)"
  2777. % (
  2778. ", ".join(
  2779. _render_bindtemplate(
  2780. to_update[i * len(tuple_element) + j][0]
  2781. )
  2782. for j, value in enumerate(tuple_element)
  2783. )
  2784. )
  2785. for i, tuple_element in enumerate(values)
  2786. )
  2787. else:
  2788. to_update = [
  2789. ("%s_%s" % (name, i), value)
  2790. for i, value in enumerate(values, 1)
  2791. ]
  2792. replacement_expression = ", ".join(
  2793. _render_bindtemplate(key) for key, value in to_update
  2794. )
  2795. return to_update, replacement_expression
  2796. def visit_binary(
  2797. self,
  2798. binary,
  2799. override_operator=None,
  2800. eager_grouping=False,
  2801. from_linter=None,
  2802. lateral_from_linter=None,
  2803. **kw,
  2804. ):
  2805. if from_linter and operators.is_comparison(binary.operator):
  2806. if lateral_from_linter is not None:
  2807. enclosing_lateral = kw["enclosing_lateral"]
  2808. lateral_from_linter.edges.update(
  2809. itertools.product(
  2810. _de_clone(
  2811. binary.left._from_objects + [enclosing_lateral]
  2812. ),
  2813. _de_clone(
  2814. binary.right._from_objects + [enclosing_lateral]
  2815. ),
  2816. )
  2817. )
  2818. else:
  2819. from_linter.edges.update(
  2820. itertools.product(
  2821. _de_clone(binary.left._from_objects),
  2822. _de_clone(binary.right._from_objects),
  2823. )
  2824. )
  2825. # don't allow "? = ?" to render
  2826. if (
  2827. self.ansi_bind_rules
  2828. and isinstance(binary.left, elements.BindParameter)
  2829. and isinstance(binary.right, elements.BindParameter)
  2830. ):
  2831. kw["literal_execute"] = True
  2832. operator_ = override_operator or binary.operator
  2833. disp = self._get_operator_dispatch(operator_, "binary", None)
  2834. if disp:
  2835. return disp(binary, operator_, **kw)
  2836. else:
  2837. try:
  2838. opstring = OPERATORS[operator_]
  2839. except KeyError as err:
  2840. raise exc.UnsupportedCompilationError(self, operator_) from err
  2841. else:
  2842. return self._generate_generic_binary(
  2843. binary,
  2844. opstring,
  2845. from_linter=from_linter,
  2846. lateral_from_linter=lateral_from_linter,
  2847. **kw,
  2848. )
  2849. def visit_function_as_comparison_op_binary(self, element, operator, **kw):
  2850. return self.process(element.sql_function, **kw)
  2851. def visit_mod_binary(self, binary, operator, **kw):
  2852. if self.preparer._double_percents:
  2853. return (
  2854. self.process(binary.left, **kw)
  2855. + " %% "
  2856. + self.process(binary.right, **kw)
  2857. )
  2858. else:
  2859. return (
  2860. self.process(binary.left, **kw)
  2861. + " % "
  2862. + self.process(binary.right, **kw)
  2863. )
  2864. def visit_custom_op_binary(self, element, operator, **kw):
  2865. kw["eager_grouping"] = operator.eager_grouping
  2866. return self._generate_generic_binary(
  2867. element,
  2868. " " + self.escape_literal_column(operator.opstring) + " ",
  2869. **kw,
  2870. )
  2871. def visit_custom_op_unary_operator(self, element, operator, **kw):
  2872. return self._generate_generic_unary_operator(
  2873. element, self.escape_literal_column(operator.opstring) + " ", **kw
  2874. )
  2875. def visit_custom_op_unary_modifier(self, element, operator, **kw):
  2876. return self._generate_generic_unary_modifier(
  2877. element, " " + self.escape_literal_column(operator.opstring), **kw
  2878. )
  2879. def _generate_generic_binary(
  2880. self,
  2881. binary: BinaryExpression[Any],
  2882. opstring: str,
  2883. eager_grouping: bool = False,
  2884. **kw: Any,
  2885. ) -> str:
  2886. _in_operator_expression = kw.get("_in_operator_expression", False)
  2887. kw["_in_operator_expression"] = True
  2888. kw["_binary_op"] = binary.operator
  2889. text = (
  2890. binary.left._compiler_dispatch(
  2891. self, eager_grouping=eager_grouping, **kw
  2892. )
  2893. + opstring
  2894. + binary.right._compiler_dispatch(
  2895. self, eager_grouping=eager_grouping, **kw
  2896. )
  2897. )
  2898. if _in_operator_expression and eager_grouping:
  2899. text = "(%s)" % text
  2900. return text
  2901. def _generate_generic_unary_operator(self, unary, opstring, **kw):
  2902. return opstring + unary.element._compiler_dispatch(self, **kw)
  2903. def _generate_generic_unary_modifier(self, unary, opstring, **kw):
  2904. return unary.element._compiler_dispatch(self, **kw) + opstring
  2905. @util.memoized_property
  2906. def _like_percent_literal(self):
  2907. return elements.literal_column("'%'", type_=sqltypes.STRINGTYPE)
  2908. def visit_ilike_case_insensitive_operand(self, element, **kw):
  2909. return f"lower({element.element._compiler_dispatch(self, **kw)})"
  2910. def visit_contains_op_binary(self, binary, operator, **kw):
  2911. binary = binary._clone()
  2912. percent = self._like_percent_literal
  2913. binary.right = percent.concat(binary.right).concat(percent)
  2914. return self.visit_like_op_binary(binary, operator, **kw)
  2915. def visit_not_contains_op_binary(self, binary, operator, **kw):
  2916. binary = binary._clone()
  2917. percent = self._like_percent_literal
  2918. binary.right = percent.concat(binary.right).concat(percent)
  2919. return self.visit_not_like_op_binary(binary, operator, **kw)
  2920. def visit_icontains_op_binary(self, binary, operator, **kw):
  2921. binary = binary._clone()
  2922. percent = self._like_percent_literal
  2923. binary.left = ilike_case_insensitive(binary.left)
  2924. binary.right = percent.concat(
  2925. ilike_case_insensitive(binary.right)
  2926. ).concat(percent)
  2927. return self.visit_ilike_op_binary(binary, operator, **kw)
  2928. def visit_not_icontains_op_binary(self, binary, operator, **kw):
  2929. binary = binary._clone()
  2930. percent = self._like_percent_literal
  2931. binary.left = ilike_case_insensitive(binary.left)
  2932. binary.right = percent.concat(
  2933. ilike_case_insensitive(binary.right)
  2934. ).concat(percent)
  2935. return self.visit_not_ilike_op_binary(binary, operator, **kw)
  2936. def visit_startswith_op_binary(self, binary, operator, **kw):
  2937. binary = binary._clone()
  2938. percent = self._like_percent_literal
  2939. binary.right = percent._rconcat(binary.right)
  2940. return self.visit_like_op_binary(binary, operator, **kw)
  2941. def visit_not_startswith_op_binary(self, binary, operator, **kw):
  2942. binary = binary._clone()
  2943. percent = self._like_percent_literal
  2944. binary.right = percent._rconcat(binary.right)
  2945. return self.visit_not_like_op_binary(binary, operator, **kw)
  2946. def visit_istartswith_op_binary(self, binary, operator, **kw):
  2947. binary = binary._clone()
  2948. percent = self._like_percent_literal
  2949. binary.left = ilike_case_insensitive(binary.left)
  2950. binary.right = percent._rconcat(ilike_case_insensitive(binary.right))
  2951. return self.visit_ilike_op_binary(binary, operator, **kw)
  2952. def visit_not_istartswith_op_binary(self, binary, operator, **kw):
  2953. binary = binary._clone()
  2954. percent = self._like_percent_literal
  2955. binary.left = ilike_case_insensitive(binary.left)
  2956. binary.right = percent._rconcat(ilike_case_insensitive(binary.right))
  2957. return self.visit_not_ilike_op_binary(binary, operator, **kw)
  2958. def visit_endswith_op_binary(self, binary, operator, **kw):
  2959. binary = binary._clone()
  2960. percent = self._like_percent_literal
  2961. binary.right = percent.concat(binary.right)
  2962. return self.visit_like_op_binary(binary, operator, **kw)
  2963. def visit_not_endswith_op_binary(self, binary, operator, **kw):
  2964. binary = binary._clone()
  2965. percent = self._like_percent_literal
  2966. binary.right = percent.concat(binary.right)
  2967. return self.visit_not_like_op_binary(binary, operator, **kw)
  2968. def visit_iendswith_op_binary(self, binary, operator, **kw):
  2969. binary = binary._clone()
  2970. percent = self._like_percent_literal
  2971. binary.left = ilike_case_insensitive(binary.left)
  2972. binary.right = percent.concat(ilike_case_insensitive(binary.right))
  2973. return self.visit_ilike_op_binary(binary, operator, **kw)
  2974. def visit_not_iendswith_op_binary(self, binary, operator, **kw):
  2975. binary = binary._clone()
  2976. percent = self._like_percent_literal
  2977. binary.left = ilike_case_insensitive(binary.left)
  2978. binary.right = percent.concat(ilike_case_insensitive(binary.right))
  2979. return self.visit_not_ilike_op_binary(binary, operator, **kw)
  2980. def visit_like_op_binary(self, binary, operator, **kw):
  2981. escape = binary.modifiers.get("escape", None)
  2982. return "%s LIKE %s" % (
  2983. binary.left._compiler_dispatch(self, **kw),
  2984. binary.right._compiler_dispatch(self, **kw),
  2985. ) + (
  2986. " ESCAPE " + self.render_literal_value(escape, sqltypes.STRINGTYPE)
  2987. if escape is not None
  2988. else ""
  2989. )
  2990. def visit_not_like_op_binary(self, binary, operator, **kw):
  2991. escape = binary.modifiers.get("escape", None)
  2992. return "%s NOT LIKE %s" % (
  2993. binary.left._compiler_dispatch(self, **kw),
  2994. binary.right._compiler_dispatch(self, **kw),
  2995. ) + (
  2996. " ESCAPE " + self.render_literal_value(escape, sqltypes.STRINGTYPE)
  2997. if escape is not None
  2998. else ""
  2999. )
  3000. def visit_ilike_op_binary(self, binary, operator, **kw):
  3001. if operator is operators.ilike_op:
  3002. binary = binary._clone()
  3003. binary.left = ilike_case_insensitive(binary.left)
  3004. binary.right = ilike_case_insensitive(binary.right)
  3005. # else we assume ilower() has been applied
  3006. return self.visit_like_op_binary(binary, operator, **kw)
  3007. def visit_not_ilike_op_binary(self, binary, operator, **kw):
  3008. if operator is operators.not_ilike_op:
  3009. binary = binary._clone()
  3010. binary.left = ilike_case_insensitive(binary.left)
  3011. binary.right = ilike_case_insensitive(binary.right)
  3012. # else we assume ilower() has been applied
  3013. return self.visit_not_like_op_binary(binary, operator, **kw)
  3014. def visit_between_op_binary(self, binary, operator, **kw):
  3015. symmetric = binary.modifiers.get("symmetric", False)
  3016. return self._generate_generic_binary(
  3017. binary, " BETWEEN SYMMETRIC " if symmetric else " BETWEEN ", **kw
  3018. )
  3019. def visit_not_between_op_binary(self, binary, operator, **kw):
  3020. symmetric = binary.modifiers.get("symmetric", False)
  3021. return self._generate_generic_binary(
  3022. binary,
  3023. " NOT BETWEEN SYMMETRIC " if symmetric else " NOT BETWEEN ",
  3024. **kw,
  3025. )
  3026. def visit_regexp_match_op_binary(
  3027. self, binary: BinaryExpression[Any], operator: Any, **kw: Any
  3028. ) -> str:
  3029. raise exc.CompileError(
  3030. "%s dialect does not support regular expressions"
  3031. % self.dialect.name
  3032. )
  3033. def visit_not_regexp_match_op_binary(
  3034. self, binary: BinaryExpression[Any], operator: Any, **kw: Any
  3035. ) -> str:
  3036. raise exc.CompileError(
  3037. "%s dialect does not support regular expressions"
  3038. % self.dialect.name
  3039. )
  3040. def visit_regexp_replace_op_binary(
  3041. self, binary: BinaryExpression[Any], operator: Any, **kw: Any
  3042. ) -> str:
  3043. raise exc.CompileError(
  3044. "%s dialect does not support regular expression replacements"
  3045. % self.dialect.name
  3046. )
  3047. def visit_bindparam(
  3048. self,
  3049. bindparam,
  3050. within_columns_clause=False,
  3051. literal_binds=False,
  3052. skip_bind_expression=False,
  3053. literal_execute=False,
  3054. render_postcompile=False,
  3055. is_upsert_set=False,
  3056. **kwargs,
  3057. ):
  3058. # Detect parametrized bindparams in upsert SET clause for issue #13130
  3059. if (
  3060. is_upsert_set
  3061. and bindparam.value is None
  3062. and bindparam.callable is None
  3063. and self._insertmanyvalues is not None
  3064. ):
  3065. self._insertmanyvalues = self._insertmanyvalues._replace(
  3066. has_upsert_bound_parameters=True
  3067. )
  3068. if not skip_bind_expression:
  3069. impl = bindparam.type.dialect_impl(self.dialect)
  3070. if impl._has_bind_expression:
  3071. bind_expression = impl.bind_expression(bindparam)
  3072. wrapped = self.process(
  3073. bind_expression,
  3074. skip_bind_expression=True,
  3075. within_columns_clause=within_columns_clause,
  3076. literal_binds=literal_binds and not bindparam.expanding,
  3077. literal_execute=literal_execute,
  3078. render_postcompile=render_postcompile,
  3079. **kwargs,
  3080. )
  3081. if bindparam.expanding:
  3082. # for postcompile w/ expanding, move the "wrapped" part
  3083. # of this into the inside
  3084. m = re.match(
  3085. r"^(.*)\(__\[POSTCOMPILE_(\S+?)\]\)(.*)$", wrapped
  3086. )
  3087. assert m, "unexpected format for expanding parameter"
  3088. wrapped = "(__[POSTCOMPILE_%s~~%s~~REPL~~%s~~])" % (
  3089. m.group(2),
  3090. m.group(1),
  3091. m.group(3),
  3092. )
  3093. if literal_binds:
  3094. ret = self.render_literal_bindparam(
  3095. bindparam,
  3096. within_columns_clause=True,
  3097. bind_expression_template=wrapped,
  3098. **kwargs,
  3099. )
  3100. return "(%s)" % ret
  3101. return wrapped
  3102. if not literal_binds:
  3103. literal_execute = (
  3104. literal_execute
  3105. or bindparam.literal_execute
  3106. or (within_columns_clause and self.ansi_bind_rules)
  3107. )
  3108. post_compile = literal_execute or bindparam.expanding
  3109. else:
  3110. post_compile = False
  3111. if literal_binds:
  3112. ret = self.render_literal_bindparam(
  3113. bindparam, within_columns_clause=True, **kwargs
  3114. )
  3115. if bindparam.expanding:
  3116. ret = "(%s)" % ret
  3117. return ret
  3118. name = self._truncate_bindparam(bindparam)
  3119. if name in self.binds:
  3120. existing = self.binds[name]
  3121. if existing is not bindparam:
  3122. if (
  3123. (existing.unique or bindparam.unique)
  3124. and not existing.proxy_set.intersection(
  3125. bindparam.proxy_set
  3126. )
  3127. and not existing._cloned_set.intersection(
  3128. bindparam._cloned_set
  3129. )
  3130. ):
  3131. raise exc.CompileError(
  3132. "Bind parameter '%s' conflicts with "
  3133. "unique bind parameter of the same name" % name
  3134. )
  3135. elif existing.expanding != bindparam.expanding:
  3136. raise exc.CompileError(
  3137. "Can't reuse bound parameter name '%s' in both "
  3138. "'expanding' (e.g. within an IN expression) and "
  3139. "non-expanding contexts. If this parameter is to "
  3140. "receive a list/array value, set 'expanding=True' on "
  3141. "it for expressions that aren't IN, otherwise use "
  3142. "a different parameter name." % (name,)
  3143. )
  3144. elif existing._is_crud or bindparam._is_crud:
  3145. if existing._is_crud and bindparam._is_crud:
  3146. # TODO: this condition is not well understood.
  3147. # see tests in test/sql/test_update.py
  3148. raise exc.CompileError(
  3149. "Encountered unsupported case when compiling an "
  3150. "INSERT or UPDATE statement. If this is a "
  3151. "multi-table "
  3152. "UPDATE statement, please provide string-named "
  3153. "arguments to the "
  3154. "values() method with distinct names; support for "
  3155. "multi-table UPDATE statements that "
  3156. "target multiple tables for UPDATE is very "
  3157. "limited",
  3158. )
  3159. else:
  3160. raise exc.CompileError(
  3161. f"bindparam() name '{bindparam.key}' is reserved "
  3162. "for automatic usage in the VALUES or SET "
  3163. "clause of this "
  3164. "insert/update statement. Please use a "
  3165. "name other than column name when using "
  3166. "bindparam() "
  3167. "with insert() or update() (for example, "
  3168. f"'b_{bindparam.key}')."
  3169. )
  3170. self.binds[bindparam.key] = self.binds[name] = bindparam
  3171. # if we are given a cache key that we're going to match against,
  3172. # relate the bindparam here to one that is most likely present
  3173. # in the "extracted params" portion of the cache key. this is used
  3174. # to set up a positional mapping that is used to determine the
  3175. # correct parameters for a subsequent use of this compiled with
  3176. # a different set of parameter values. here, we accommodate for
  3177. # parameters that may have been cloned both before and after the cache
  3178. # key was been generated.
  3179. ckbm_tuple = self._cache_key_bind_match
  3180. if ckbm_tuple:
  3181. ckbm, cksm = ckbm_tuple
  3182. for bp in bindparam._cloned_set:
  3183. if bp.key in cksm:
  3184. cb = cksm[bp.key]
  3185. ckbm[cb].append(bindparam)
  3186. if bindparam.isoutparam:
  3187. self.has_out_parameters = True
  3188. if post_compile:
  3189. if render_postcompile:
  3190. self._render_postcompile = True
  3191. if literal_execute:
  3192. self.literal_execute_params |= {bindparam}
  3193. else:
  3194. self.post_compile_params |= {bindparam}
  3195. ret = self.bindparam_string(
  3196. name,
  3197. post_compile=post_compile,
  3198. expanding=bindparam.expanding,
  3199. bindparam_type=bindparam.type,
  3200. **kwargs,
  3201. )
  3202. if bindparam.expanding:
  3203. ret = "(%s)" % ret
  3204. return ret
  3205. def render_bind_cast(self, type_, dbapi_type, sqltext):
  3206. raise NotImplementedError()
  3207. def render_literal_bindparam(
  3208. self,
  3209. bindparam,
  3210. render_literal_value=NO_ARG,
  3211. bind_expression_template=None,
  3212. **kw,
  3213. ):
  3214. if render_literal_value is not NO_ARG:
  3215. value = render_literal_value
  3216. else:
  3217. if bindparam.value is None and bindparam.callable is None:
  3218. op = kw.get("_binary_op", None)
  3219. if op and op not in (operators.is_, operators.is_not):
  3220. util.warn_limited(
  3221. "Bound parameter '%s' rendering literal NULL in a SQL "
  3222. "expression; comparisons to NULL should not use "
  3223. "operators outside of 'is' or 'is not'",
  3224. (bindparam.key,),
  3225. )
  3226. return self.process(sqltypes.NULLTYPE, **kw)
  3227. value = bindparam.effective_value
  3228. if bindparam.expanding:
  3229. leep = self._literal_execute_expanding_parameter_literal_binds
  3230. to_update, replacement_expr = leep(
  3231. bindparam,
  3232. value,
  3233. bind_expression_template=bind_expression_template,
  3234. )
  3235. return replacement_expr
  3236. else:
  3237. return self.render_literal_value(value, bindparam.type)
  3238. def render_literal_value(
  3239. self, value: Any, type_: sqltypes.TypeEngine[Any]
  3240. ) -> str:
  3241. """Render the value of a bind parameter as a quoted literal.
  3242. This is used for statement sections that do not accept bind parameters
  3243. on the target driver/database.
  3244. This should be implemented by subclasses using the quoting services
  3245. of the DBAPI.
  3246. """
  3247. if value is None and not type_.should_evaluate_none:
  3248. # issue #10535 - handle NULL in the compiler without placing
  3249. # this onto each type, except for "evaluate None" types
  3250. # (e.g. JSON)
  3251. return self.process(elements.Null._instance())
  3252. processor = type_._cached_literal_processor(self.dialect)
  3253. if processor:
  3254. try:
  3255. return processor(value)
  3256. except Exception as e:
  3257. raise exc.CompileError(
  3258. f"Could not render literal value "
  3259. f'"{sql_util._repr_single_value(value)}" '
  3260. f"with datatype "
  3261. f"{type_}; see parent stack trace for "
  3262. "more detail."
  3263. ) from e
  3264. else:
  3265. raise exc.CompileError(
  3266. f"No literal value renderer is available for literal value "
  3267. f'"{sql_util._repr_single_value(value)}" '
  3268. f"with datatype {type_}"
  3269. )
  3270. def _truncate_bindparam(self, bindparam):
  3271. if bindparam in self.bind_names:
  3272. return self.bind_names[bindparam]
  3273. bind_name = bindparam.key
  3274. if isinstance(bind_name, elements._truncated_label):
  3275. bind_name = self._truncated_identifier("bindparam", bind_name)
  3276. # add to bind_names for translation
  3277. self.bind_names[bindparam] = bind_name
  3278. return bind_name
  3279. def _truncated_identifier(
  3280. self, ident_class: str, name: _truncated_label
  3281. ) -> str:
  3282. if (ident_class, name) in self.truncated_names:
  3283. return self.truncated_names[(ident_class, name)]
  3284. anonname = name.apply_map(self.anon_map)
  3285. if len(anonname) > self.label_length - 6:
  3286. counter = self._truncated_counters.get(ident_class, 1)
  3287. truncname = (
  3288. anonname[0 : max(self.label_length - 6, 0)]
  3289. + "_"
  3290. + hex(counter)[2:]
  3291. )
  3292. self._truncated_counters[ident_class] = counter + 1
  3293. else:
  3294. truncname = anonname
  3295. self.truncated_names[(ident_class, name)] = truncname
  3296. return truncname
  3297. def _anonymize(self, name: str) -> str:
  3298. return name % self.anon_map
  3299. def bindparam_string(
  3300. self,
  3301. name: str,
  3302. post_compile: bool = False,
  3303. expanding: bool = False,
  3304. escaped_from: Optional[str] = None,
  3305. bindparam_type: Optional[TypeEngine[Any]] = None,
  3306. accumulate_bind_names: Optional[Set[str]] = None,
  3307. visited_bindparam: Optional[List[str]] = None,
  3308. **kw: Any,
  3309. ) -> str:
  3310. # TODO: accumulate_bind_names is passed by crud.py to gather
  3311. # names on a per-value basis, visited_bindparam is passed by
  3312. # visit_insert() to collect all parameters in the statement.
  3313. # see if this gathering can be simplified somehow
  3314. if accumulate_bind_names is not None:
  3315. accumulate_bind_names.add(name)
  3316. if visited_bindparam is not None:
  3317. visited_bindparam.append(name)
  3318. if not escaped_from:
  3319. if self._bind_translate_re.search(name):
  3320. # not quite the translate use case as we want to
  3321. # also get a quick boolean if we even found
  3322. # unusual characters in the name
  3323. new_name = self._bind_translate_re.sub(
  3324. lambda m: self._bind_translate_chars[m.group(0)],
  3325. name,
  3326. )
  3327. escaped_from = name
  3328. name = new_name
  3329. if escaped_from:
  3330. self.escaped_bind_names = self.escaped_bind_names.union(
  3331. {escaped_from: name}
  3332. )
  3333. if post_compile:
  3334. ret = "__[POSTCOMPILE_%s]" % name
  3335. if expanding:
  3336. # for expanding, bound parameters or literal values will be
  3337. # rendered per item
  3338. return ret
  3339. # otherwise, for non-expanding "literal execute", apply
  3340. # bind casts as determined by the datatype
  3341. if bindparam_type is not None:
  3342. type_impl = bindparam_type._unwrapped_dialect_impl(
  3343. self.dialect
  3344. )
  3345. if type_impl.render_literal_cast:
  3346. ret = self.render_bind_cast(bindparam_type, type_impl, ret)
  3347. return ret
  3348. elif self.state is CompilerState.COMPILING:
  3349. ret = self.compilation_bindtemplate % {"name": name}
  3350. else:
  3351. ret = self.bindtemplate % {"name": name}
  3352. if (
  3353. bindparam_type is not None
  3354. and self.dialect._bind_typing_render_casts
  3355. ):
  3356. type_impl = bindparam_type._unwrapped_dialect_impl(self.dialect)
  3357. if type_impl.render_bind_cast:
  3358. ret = self.render_bind_cast(bindparam_type, type_impl, ret)
  3359. return ret
  3360. def _dispatch_independent_ctes(self, stmt, kw):
  3361. local_kw = kw.copy()
  3362. local_kw.pop("cte_opts", None)
  3363. for cte, opt in zip(
  3364. stmt._independent_ctes, stmt._independent_ctes_opts
  3365. ):
  3366. cte._compiler_dispatch(self, cte_opts=opt, **local_kw)
  3367. def visit_cte(
  3368. self,
  3369. cte: CTE,
  3370. asfrom: bool = False,
  3371. ashint: bool = False,
  3372. fromhints: Optional[_FromHintsType] = None,
  3373. visiting_cte: Optional[CTE] = None,
  3374. from_linter: Optional[FromLinter] = None,
  3375. cte_opts: selectable._CTEOpts = selectable._CTEOpts(False),
  3376. **kwargs: Any,
  3377. ) -> Optional[str]:
  3378. self_ctes = self._init_cte_state()
  3379. assert self_ctes is self.ctes
  3380. kwargs["visiting_cte"] = cte
  3381. cte_name = cte.name
  3382. if isinstance(cte_name, elements._truncated_label):
  3383. cte_name = self._truncated_identifier("alias", cte_name)
  3384. is_new_cte = True
  3385. embedded_in_current_named_cte = False
  3386. _reference_cte = cte._get_reference_cte()
  3387. nesting = cte.nesting or cte_opts.nesting
  3388. # check for CTE already encountered
  3389. if _reference_cte in self.level_name_by_cte:
  3390. cte_level, _, existing_cte_opts = self.level_name_by_cte[
  3391. _reference_cte
  3392. ]
  3393. assert _ == cte_name
  3394. cte_level_name = (cte_level, cte_name)
  3395. existing_cte = self.ctes_by_level_name[cte_level_name]
  3396. # check if we are receiving it here with a specific
  3397. # "nest_here" location; if so, move it to this location
  3398. if cte_opts.nesting:
  3399. if existing_cte_opts.nesting:
  3400. raise exc.CompileError(
  3401. "CTE is stated as 'nest_here' in "
  3402. "more than one location"
  3403. )
  3404. old_level_name = (cte_level, cte_name)
  3405. cte_level = len(self.stack) if nesting else 1
  3406. cte_level_name = new_level_name = (cte_level, cte_name)
  3407. del self.ctes_by_level_name[old_level_name]
  3408. self.ctes_by_level_name[new_level_name] = existing_cte
  3409. self.level_name_by_cte[_reference_cte] = new_level_name + (
  3410. cte_opts,
  3411. )
  3412. else:
  3413. cte_level = len(self.stack) if nesting else 1
  3414. cte_level_name = (cte_level, cte_name)
  3415. if cte_level_name in self.ctes_by_level_name:
  3416. existing_cte = self.ctes_by_level_name[cte_level_name]
  3417. else:
  3418. existing_cte = None
  3419. if existing_cte is not None:
  3420. embedded_in_current_named_cte = visiting_cte is existing_cte
  3421. # we've generated a same-named CTE that we are enclosed in,
  3422. # or this is the same CTE. just return the name.
  3423. if cte is existing_cte._restates or cte is existing_cte:
  3424. is_new_cte = False
  3425. elif existing_cte is cte._restates:
  3426. # we've generated a same-named CTE that is
  3427. # enclosed in us - we take precedence, so
  3428. # discard the text for the "inner".
  3429. del self_ctes[existing_cte]
  3430. existing_cte_reference_cte = existing_cte._get_reference_cte()
  3431. assert existing_cte_reference_cte is _reference_cte
  3432. assert existing_cte_reference_cte is existing_cte
  3433. del self.level_name_by_cte[existing_cte_reference_cte]
  3434. else:
  3435. if (
  3436. # if the two CTEs have the same hash, which we expect
  3437. # here means that one/both is an annotated of the other
  3438. (hash(cte) == hash(existing_cte))
  3439. # or...
  3440. or (
  3441. (
  3442. # if they are clones, i.e. they came from the ORM
  3443. # or some other visit method
  3444. cte._is_clone_of is not None
  3445. or existing_cte._is_clone_of is not None
  3446. )
  3447. # and are deep-copy identical
  3448. and cte.compare(existing_cte)
  3449. )
  3450. ):
  3451. # then consider these two CTEs the same
  3452. is_new_cte = False
  3453. else:
  3454. # otherwise these are two CTEs that either will render
  3455. # differently, or were indicated separately by the user,
  3456. # with the same name
  3457. raise exc.CompileError(
  3458. "Multiple, unrelated CTEs found with "
  3459. "the same name: %r" % cte_name
  3460. )
  3461. if not asfrom and not is_new_cte:
  3462. return None
  3463. if cte._cte_alias is not None:
  3464. pre_alias_cte = cte._cte_alias
  3465. cte_pre_alias_name = cte._cte_alias.name
  3466. if isinstance(cte_pre_alias_name, elements._truncated_label):
  3467. cte_pre_alias_name = self._truncated_identifier(
  3468. "alias", cte_pre_alias_name
  3469. )
  3470. else:
  3471. pre_alias_cte = cte
  3472. cte_pre_alias_name = None
  3473. if is_new_cte:
  3474. self.ctes_by_level_name[cte_level_name] = cte
  3475. self.level_name_by_cte[_reference_cte] = cte_level_name + (
  3476. cte_opts,
  3477. )
  3478. if pre_alias_cte not in self.ctes:
  3479. self.visit_cte(pre_alias_cte, **kwargs)
  3480. if not cte_pre_alias_name and cte not in self_ctes:
  3481. if cte.recursive:
  3482. self.ctes_recursive = True
  3483. text = self.preparer.format_alias(cte, cte_name)
  3484. if cte.recursive or cte.element.name_cte_columns:
  3485. col_source = cte.element
  3486. # TODO: can we get at the .columns_plus_names collection
  3487. # that is already (or will be?) generated for the SELECT
  3488. # rather than calling twice?
  3489. recur_cols = [
  3490. # TODO: proxy_name is not technically safe,
  3491. # see test_cte->
  3492. # test_with_recursive_no_name_currently_buggy. not
  3493. # clear what should be done with such a case
  3494. fallback_label_name or proxy_name
  3495. for (
  3496. _,
  3497. proxy_name,
  3498. fallback_label_name,
  3499. c,
  3500. repeated,
  3501. ) in (col_source._generate_columns_plus_names(True))
  3502. if not repeated
  3503. ]
  3504. text += "(%s)" % (
  3505. ", ".join(
  3506. self.preparer.format_label_name(
  3507. ident, anon_map=self.anon_map
  3508. )
  3509. for ident in recur_cols
  3510. )
  3511. )
  3512. assert kwargs.get("subquery", False) is False
  3513. if not self.stack:
  3514. # toplevel, this is a stringify of the
  3515. # cte directly. just compile the inner
  3516. # the way alias() does.
  3517. return cte.element._compiler_dispatch(
  3518. self, asfrom=asfrom, **kwargs
  3519. )
  3520. else:
  3521. prefixes = self._generate_prefixes(
  3522. cte, cte._prefixes, **kwargs
  3523. )
  3524. inner = cte.element._compiler_dispatch(
  3525. self, asfrom=True, **kwargs
  3526. )
  3527. text += " AS %s\n(%s)" % (prefixes, inner)
  3528. if cte._suffixes:
  3529. text += " " + self._generate_prefixes(
  3530. cte, cte._suffixes, **kwargs
  3531. )
  3532. self_ctes[cte] = text
  3533. if asfrom:
  3534. if from_linter:
  3535. from_linter.froms[cte._de_clone()] = cte_name
  3536. if not is_new_cte and embedded_in_current_named_cte:
  3537. return self.preparer.format_alias(cte, cte_name)
  3538. if cte_pre_alias_name:
  3539. text = self.preparer.format_alias(cte, cte_pre_alias_name)
  3540. if self.preparer._requires_quotes(cte_name):
  3541. cte_name = self.preparer.quote(cte_name)
  3542. text += self.get_render_as_alias_suffix(cte_name)
  3543. return text # type: ignore[no-any-return]
  3544. else:
  3545. return self.preparer.format_alias(cte, cte_name)
  3546. return None
  3547. def visit_table_valued_alias(self, element, **kw):
  3548. if element.joins_implicitly:
  3549. kw["from_linter"] = None
  3550. if element._is_lateral:
  3551. return self.visit_lateral(element, **kw)
  3552. else:
  3553. return self.visit_alias(element, **kw)
  3554. def visit_table_valued_column(self, element, **kw):
  3555. return self.visit_column(element, **kw)
  3556. def visit_alias(
  3557. self,
  3558. alias,
  3559. asfrom=False,
  3560. ashint=False,
  3561. iscrud=False,
  3562. fromhints=None,
  3563. subquery=False,
  3564. lateral=False,
  3565. enclosing_alias=None,
  3566. from_linter=None,
  3567. **kwargs,
  3568. ):
  3569. if lateral:
  3570. if "enclosing_lateral" not in kwargs:
  3571. # if lateral is set and enclosing_lateral is not
  3572. # present, we assume we are being called directly
  3573. # from visit_lateral() and we need to set enclosing_lateral.
  3574. assert alias._is_lateral
  3575. kwargs["enclosing_lateral"] = alias
  3576. # for lateral objects, we track a second from_linter that is...
  3577. # lateral! to the level above us.
  3578. if (
  3579. from_linter
  3580. and "lateral_from_linter" not in kwargs
  3581. and "enclosing_lateral" in kwargs
  3582. ):
  3583. kwargs["lateral_from_linter"] = from_linter
  3584. if enclosing_alias is not None and enclosing_alias.element is alias:
  3585. inner = alias.element._compiler_dispatch(
  3586. self,
  3587. asfrom=asfrom,
  3588. ashint=ashint,
  3589. iscrud=iscrud,
  3590. fromhints=fromhints,
  3591. lateral=lateral,
  3592. enclosing_alias=alias,
  3593. **kwargs,
  3594. )
  3595. if subquery and (asfrom or lateral):
  3596. inner = "(%s)" % (inner,)
  3597. return inner
  3598. else:
  3599. kwargs["enclosing_alias"] = alias
  3600. if asfrom or ashint:
  3601. if isinstance(alias.name, elements._truncated_label):
  3602. alias_name = self._truncated_identifier("alias", alias.name)
  3603. else:
  3604. alias_name = alias.name
  3605. if ashint:
  3606. return self.preparer.format_alias(alias, alias_name)
  3607. elif asfrom:
  3608. if from_linter:
  3609. from_linter.froms[alias._de_clone()] = alias_name
  3610. inner = alias.element._compiler_dispatch(
  3611. self, asfrom=True, lateral=lateral, **kwargs
  3612. )
  3613. if subquery:
  3614. inner = "(%s)" % (inner,)
  3615. ret = inner + self.get_render_as_alias_suffix(
  3616. self.preparer.format_alias(alias, alias_name)
  3617. )
  3618. if alias._supports_derived_columns and alias._render_derived:
  3619. ret += "(%s)" % (
  3620. ", ".join(
  3621. "%s%s"
  3622. % (
  3623. self.preparer.quote(col.name),
  3624. (
  3625. " %s"
  3626. % self.dialect.type_compiler_instance.process(
  3627. col.type, **kwargs
  3628. )
  3629. if alias._render_derived_w_types
  3630. else ""
  3631. ),
  3632. )
  3633. for col in alias.c
  3634. )
  3635. )
  3636. if fromhints and alias in fromhints:
  3637. ret = self.format_from_hint_text(
  3638. ret, alias, fromhints[alias], iscrud
  3639. )
  3640. return ret
  3641. else:
  3642. # note we cancel the "subquery" flag here as well
  3643. return alias.element._compiler_dispatch(
  3644. self, lateral=lateral, **kwargs
  3645. )
  3646. def visit_subquery(self, subquery, **kw):
  3647. kw["subquery"] = True
  3648. return self.visit_alias(subquery, **kw)
  3649. def visit_lateral(self, lateral_, **kw):
  3650. kw["lateral"] = True
  3651. return "LATERAL %s" % self.visit_alias(lateral_, **kw)
  3652. def visit_tablesample(self, tablesample, asfrom=False, **kw):
  3653. text = "%s TABLESAMPLE %s" % (
  3654. self.visit_alias(tablesample, asfrom=True, **kw),
  3655. tablesample._get_method()._compiler_dispatch(self, **kw),
  3656. )
  3657. if tablesample.seed is not None:
  3658. text += " REPEATABLE (%s)" % (
  3659. tablesample.seed._compiler_dispatch(self, **kw)
  3660. )
  3661. return text
  3662. def _render_values(self, element, **kw):
  3663. kw.setdefault("literal_binds", element.literal_binds)
  3664. tuples = ", ".join(
  3665. self.process(
  3666. elements.Tuple(
  3667. types=element._column_types, *elem
  3668. ).self_group(),
  3669. **kw,
  3670. )
  3671. for chunk in element._data
  3672. for elem in chunk
  3673. )
  3674. return f"VALUES {tuples}"
  3675. def visit_values(
  3676. self, element, asfrom=False, from_linter=None, visiting_cte=None, **kw
  3677. ):
  3678. if element._independent_ctes:
  3679. self._dispatch_independent_ctes(element, kw)
  3680. v = self._render_values(element, **kw)
  3681. if element._unnamed:
  3682. name = None
  3683. elif isinstance(element.name, elements._truncated_label):
  3684. name = self._truncated_identifier("values", element.name)
  3685. else:
  3686. name = element.name
  3687. if element._is_lateral:
  3688. lateral = "LATERAL "
  3689. else:
  3690. lateral = ""
  3691. if asfrom:
  3692. if from_linter:
  3693. from_linter.froms[element._de_clone()] = (
  3694. name if name is not None else "(unnamed VALUES element)"
  3695. )
  3696. if visiting_cte is not None and visiting_cte.element is element:
  3697. if element._is_lateral:
  3698. raise exc.CompileError(
  3699. "Can't use a LATERAL VALUES expression inside of a CTE"
  3700. )
  3701. elif name:
  3702. kw["include_table"] = False
  3703. v = "%s(%s)%s (%s)" % (
  3704. lateral,
  3705. v,
  3706. self.get_render_as_alias_suffix(self.preparer.quote(name)),
  3707. (
  3708. ", ".join(
  3709. c._compiler_dispatch(self, **kw)
  3710. for c in element.columns
  3711. )
  3712. ),
  3713. )
  3714. else:
  3715. v = "%s(%s)" % (lateral, v)
  3716. return v
  3717. def visit_scalar_values(self, element, **kw):
  3718. return f"({self._render_values(element, **kw)})"
  3719. def get_render_as_alias_suffix(self, alias_name_text):
  3720. return " AS " + alias_name_text
  3721. def _add_to_result_map(
  3722. self,
  3723. keyname: str,
  3724. name: str,
  3725. objects: Tuple[Any, ...],
  3726. type_: TypeEngine[Any],
  3727. ) -> None:
  3728. # note objects must be non-empty for cursor.py to handle the
  3729. # collection properly
  3730. assert objects
  3731. if keyname is None or keyname == "*":
  3732. self._ordered_columns = False
  3733. self._ad_hoc_textual = True
  3734. if type_._is_tuple_type:
  3735. raise exc.CompileError(
  3736. "Most backends don't support SELECTing "
  3737. "from a tuple() object. If this is an ORM query, "
  3738. "consider using the Bundle object."
  3739. )
  3740. self._result_columns.append(
  3741. ResultColumnsEntry(keyname, name, objects, type_)
  3742. )
  3743. def _label_returning_column(
  3744. self, stmt, column, populate_result_map, column_clause_args=None, **kw
  3745. ):
  3746. """Render a column with necessary labels inside of a RETURNING clause.
  3747. This method is provided for individual dialects in place of calling
  3748. the _label_select_column method directly, so that the two use cases
  3749. of RETURNING vs. SELECT can be disambiguated going forward.
  3750. .. versionadded:: 1.4.21
  3751. """
  3752. return self._label_select_column(
  3753. None,
  3754. column,
  3755. populate_result_map,
  3756. False,
  3757. {} if column_clause_args is None else column_clause_args,
  3758. **kw,
  3759. )
  3760. def _label_select_column(
  3761. self,
  3762. select,
  3763. column,
  3764. populate_result_map,
  3765. asfrom,
  3766. column_clause_args,
  3767. name=None,
  3768. proxy_name=None,
  3769. fallback_label_name=None,
  3770. within_columns_clause=True,
  3771. column_is_repeated=False,
  3772. need_column_expressions=False,
  3773. include_table=True,
  3774. ):
  3775. """produce labeled columns present in a select()."""
  3776. impl = column.type.dialect_impl(self.dialect)
  3777. if impl._has_column_expression and (
  3778. need_column_expressions or populate_result_map
  3779. ):
  3780. col_expr = impl.column_expression(column)
  3781. else:
  3782. col_expr = column
  3783. if populate_result_map:
  3784. # pass an "add_to_result_map" callable into the compilation
  3785. # of embedded columns. this collects information about the
  3786. # column as it will be fetched in the result and is coordinated
  3787. # with cursor.description when the query is executed.
  3788. add_to_result_map = self._add_to_result_map
  3789. # if the SELECT statement told us this column is a repeat,
  3790. # wrap the callable with one that prevents the addition of the
  3791. # targets
  3792. if column_is_repeated:
  3793. _add_to_result_map = add_to_result_map
  3794. def add_to_result_map(keyname, name, objects, type_):
  3795. _add_to_result_map(keyname, name, (keyname,), type_)
  3796. # if we redefined col_expr for type expressions, wrap the
  3797. # callable with one that adds the original column to the targets
  3798. elif col_expr is not column:
  3799. _add_to_result_map = add_to_result_map
  3800. def add_to_result_map(keyname, name, objects, type_):
  3801. _add_to_result_map(
  3802. keyname, name, (column,) + objects, type_
  3803. )
  3804. else:
  3805. add_to_result_map = None
  3806. # this method is used by some of the dialects for RETURNING,
  3807. # which has different inputs. _label_returning_column was added
  3808. # as the better target for this now however for 1.4 we will keep
  3809. # _label_select_column directly compatible with this use case.
  3810. # these assertions right now set up the current expected inputs
  3811. assert within_columns_clause, (
  3812. "_label_select_column is only relevant within "
  3813. "the columns clause of a SELECT or RETURNING"
  3814. )
  3815. if isinstance(column, elements.Label):
  3816. if col_expr is not column:
  3817. result_expr = _CompileLabel(
  3818. col_expr, column.name, alt_names=(column.element,)
  3819. )
  3820. else:
  3821. result_expr = col_expr
  3822. elif name:
  3823. # here, _columns_plus_names has determined there's an explicit
  3824. # label name we need to use. this is the default for
  3825. # tablenames_plus_columnnames as well as when columns are being
  3826. # deduplicated on name
  3827. assert (
  3828. proxy_name is not None
  3829. ), "proxy_name is required if 'name' is passed"
  3830. result_expr = _CompileLabel(
  3831. col_expr,
  3832. name,
  3833. alt_names=(
  3834. proxy_name,
  3835. # this is a hack to allow legacy result column lookups
  3836. # to work as they did before; this goes away in 2.0.
  3837. # TODO: this only seems to be tested indirectly
  3838. # via test/orm/test_deprecations.py. should be a
  3839. # resultset test for this
  3840. column._tq_label,
  3841. ),
  3842. )
  3843. else:
  3844. # determine here whether this column should be rendered in
  3845. # a labelled context or not, as we were given no required label
  3846. # name from the caller. Here we apply heuristics based on the kind
  3847. # of SQL expression involved.
  3848. if col_expr is not column:
  3849. # type-specific expression wrapping the given column,
  3850. # so we render a label
  3851. render_with_label = True
  3852. elif isinstance(column, elements.ColumnClause):
  3853. # table-bound column, we render its name as a label if we are
  3854. # inside of a subquery only
  3855. render_with_label = (
  3856. asfrom
  3857. and not column.is_literal
  3858. and column.table is not None
  3859. )
  3860. elif isinstance(column, elements.TextClause):
  3861. render_with_label = False
  3862. elif isinstance(column, elements.UnaryExpression):
  3863. # unary expression. notes added as of #12681
  3864. #
  3865. # By convention, the visit_unary() method
  3866. # itself does not add an entry to the result map, and relies
  3867. # upon either the inner expression creating a result map
  3868. # entry, or if not, by creating a label here that produces
  3869. # the result map entry. Where that happens is based on whether
  3870. # or not the element immediately inside the unary is a
  3871. # NamedColumn subclass or not.
  3872. #
  3873. # Now, this also impacts how the SELECT is written; if
  3874. # we decide to generate a label here, we get the usual
  3875. # "~(x+y) AS anon_1" thing in the columns clause. If we
  3876. # don't, we don't get an AS at all, we get like
  3877. # "~table.column".
  3878. #
  3879. # But here is the important thing as of modernish (like 1.4)
  3880. # versions of SQLAlchemy - **whether or not the AS <label>
  3881. # is present in the statement is not actually important**.
  3882. # We target result columns **positionally** for a fully
  3883. # compiled ``Select()`` object; before 1.4 we needed those
  3884. # labels to match in cursor.description etc etc but now it
  3885. # really doesn't matter.
  3886. # So really, we could set render_with_label True in all cases.
  3887. # Or we could just have visit_unary() populate the result map
  3888. # in all cases.
  3889. #
  3890. # What we're doing here is strictly trying to not rock the
  3891. # boat too much with when we do/don't render "AS label";
  3892. # labels being present helps in the edge cases that we
  3893. # "fall back" to named cursor.description matching, labels
  3894. # not being present for columns keeps us from having awkward
  3895. # phrases like "SELECT DISTINCT table.x AS x".
  3896. render_with_label = (
  3897. (
  3898. # exception case to detect if we render "not boolean"
  3899. # as "not <col>" for native boolean or "<col> = 1"
  3900. # for non-native boolean. this is controlled by
  3901. # visit_is_<true|false>_unary_operator
  3902. column.operator
  3903. in (operators.is_false, operators.is_true)
  3904. and not self.dialect.supports_native_boolean
  3905. )
  3906. or column._wraps_unnamed_column()
  3907. or asfrom
  3908. )
  3909. elif (
  3910. # general class of expressions that don't have a SQL-column
  3911. # addressable name. includes scalar selects, bind parameters,
  3912. # SQL functions, others
  3913. not isinstance(column, elements.NamedColumn)
  3914. # deeper check that indicates there's no natural "name" to
  3915. # this element, which accommodates for custom SQL constructs
  3916. # that might have a ".name" attribute (but aren't SQL
  3917. # functions) but are not implementing this more recently added
  3918. # base class. in theory the "NamedColumn" check should be
  3919. # enough, however here we seek to maintain legacy behaviors
  3920. # as well.
  3921. and column._non_anon_label is None
  3922. ):
  3923. render_with_label = True
  3924. else:
  3925. render_with_label = False
  3926. if render_with_label:
  3927. if not fallback_label_name:
  3928. # used by the RETURNING case right now. we generate it
  3929. # here as 3rd party dialects may be referring to
  3930. # _label_select_column method directly instead of the
  3931. # just-added _label_returning_column method
  3932. assert not column_is_repeated
  3933. fallback_label_name = column._anon_name_label
  3934. fallback_label_name = (
  3935. elements._truncated_label(fallback_label_name)
  3936. if not isinstance(
  3937. fallback_label_name, elements._truncated_label
  3938. )
  3939. else fallback_label_name
  3940. )
  3941. result_expr = _CompileLabel(
  3942. col_expr, fallback_label_name, alt_names=(proxy_name,)
  3943. )
  3944. else:
  3945. result_expr = col_expr
  3946. column_clause_args.update(
  3947. within_columns_clause=within_columns_clause,
  3948. add_to_result_map=add_to_result_map,
  3949. include_table=include_table,
  3950. )
  3951. return result_expr._compiler_dispatch(self, **column_clause_args)
  3952. def format_from_hint_text(self, sqltext, table, hint, iscrud):
  3953. hinttext = self.get_from_hint_text(table, hint)
  3954. if hinttext:
  3955. sqltext += " " + hinttext
  3956. return sqltext
  3957. def get_select_hint_text(self, byfroms):
  3958. return None
  3959. def get_from_hint_text(
  3960. self, table: FromClause, text: Optional[str]
  3961. ) -> Optional[str]:
  3962. return None
  3963. def get_crud_hint_text(self, table, text):
  3964. return None
  3965. def get_statement_hint_text(self, hint_texts):
  3966. return " ".join(hint_texts)
  3967. _default_stack_entry: _CompilerStackEntry
  3968. if not typing.TYPE_CHECKING:
  3969. _default_stack_entry = util.immutabledict(
  3970. [("correlate_froms", frozenset()), ("asfrom_froms", frozenset())]
  3971. )
  3972. def _display_froms_for_select(
  3973. self, select_stmt, asfrom, lateral=False, **kw
  3974. ):
  3975. # utility method to help external dialects
  3976. # get the correct from list for a select.
  3977. # specifically the oracle dialect needs this feature
  3978. # right now.
  3979. toplevel = not self.stack
  3980. entry = self._default_stack_entry if toplevel else self.stack[-1]
  3981. compile_state = select_stmt._compile_state_factory(select_stmt, self)
  3982. correlate_froms = entry["correlate_froms"]
  3983. asfrom_froms = entry["asfrom_froms"]
  3984. if asfrom and not lateral:
  3985. froms = compile_state._get_display_froms(
  3986. explicit_correlate_froms=correlate_froms.difference(
  3987. asfrom_froms
  3988. ),
  3989. implicit_correlate_froms=(),
  3990. )
  3991. else:
  3992. froms = compile_state._get_display_froms(
  3993. explicit_correlate_froms=correlate_froms,
  3994. implicit_correlate_froms=asfrom_froms,
  3995. )
  3996. return froms
  3997. translate_select_structure: Any = None
  3998. """if not ``None``, should be a callable which accepts ``(select_stmt,
  3999. **kw)`` and returns a select object. this is used for structural changes
  4000. mostly to accommodate for LIMIT/OFFSET schemes
  4001. """
  4002. def visit_select(
  4003. self,
  4004. select_stmt,
  4005. asfrom=False,
  4006. insert_into=False,
  4007. fromhints=None,
  4008. compound_index=None,
  4009. select_wraps_for=None,
  4010. lateral=False,
  4011. from_linter=None,
  4012. **kwargs,
  4013. ):
  4014. assert select_wraps_for is None, (
  4015. "SQLAlchemy 1.4 requires use of "
  4016. "the translate_select_structure hook for structural "
  4017. "translations of SELECT objects"
  4018. )
  4019. # initial setup of SELECT. the compile_state_factory may now
  4020. # be creating a totally different SELECT from the one that was
  4021. # passed in. for ORM use this will convert from an ORM-state
  4022. # SELECT to a regular "Core" SELECT. other composed operations
  4023. # such as computation of joins will be performed.
  4024. kwargs["within_columns_clause"] = False
  4025. compile_state = select_stmt._compile_state_factory(
  4026. select_stmt, self, **kwargs
  4027. )
  4028. kwargs["ambiguous_table_name_map"] = (
  4029. compile_state._ambiguous_table_name_map
  4030. )
  4031. select_stmt = compile_state.statement
  4032. toplevel = not self.stack
  4033. if toplevel and not self.compile_state:
  4034. self.compile_state = compile_state
  4035. is_embedded_select = compound_index is not None or insert_into
  4036. # translate step for Oracle, SQL Server which often need to
  4037. # restructure the SELECT to allow for LIMIT/OFFSET and possibly
  4038. # other conditions
  4039. if self.translate_select_structure:
  4040. new_select_stmt = self.translate_select_structure(
  4041. select_stmt, asfrom=asfrom, **kwargs
  4042. )
  4043. # if SELECT was restructured, maintain a link to the originals
  4044. # and assemble a new compile state
  4045. if new_select_stmt is not select_stmt:
  4046. compile_state_wraps_for = compile_state
  4047. select_wraps_for = select_stmt
  4048. select_stmt = new_select_stmt
  4049. compile_state = select_stmt._compile_state_factory(
  4050. select_stmt, self, **kwargs
  4051. )
  4052. select_stmt = compile_state.statement
  4053. entry = self._default_stack_entry if toplevel else self.stack[-1]
  4054. populate_result_map = need_column_expressions = (
  4055. toplevel
  4056. or entry.get("need_result_map_for_compound", False)
  4057. or entry.get("need_result_map_for_nested", False)
  4058. )
  4059. # indicates there is a CompoundSelect in play and we are not the
  4060. # first select
  4061. if compound_index:
  4062. populate_result_map = False
  4063. # this was first proposed as part of #3372; however, it is not
  4064. # reached in current tests and could possibly be an assertion
  4065. # instead.
  4066. if not populate_result_map and "add_to_result_map" in kwargs:
  4067. del kwargs["add_to_result_map"]
  4068. froms = self._setup_select_stack(
  4069. select_stmt, compile_state, entry, asfrom, lateral, compound_index
  4070. )
  4071. column_clause_args = kwargs.copy()
  4072. column_clause_args.update(
  4073. {"within_label_clause": False, "within_columns_clause": False}
  4074. )
  4075. text = "SELECT " # we're off to a good start !
  4076. if select_stmt._hints:
  4077. hint_text, byfrom = self._setup_select_hints(select_stmt)
  4078. if hint_text:
  4079. text += hint_text + " "
  4080. else:
  4081. byfrom = None
  4082. if select_stmt._independent_ctes:
  4083. self._dispatch_independent_ctes(select_stmt, kwargs)
  4084. if select_stmt._prefixes:
  4085. text += self._generate_prefixes(
  4086. select_stmt, select_stmt._prefixes, **kwargs
  4087. )
  4088. text += self.get_select_precolumns(select_stmt, **kwargs)
  4089. # the actual list of columns to print in the SELECT column list.
  4090. inner_columns = [
  4091. c
  4092. for c in [
  4093. self._label_select_column(
  4094. select_stmt,
  4095. column,
  4096. populate_result_map,
  4097. asfrom,
  4098. column_clause_args,
  4099. name=name,
  4100. proxy_name=proxy_name,
  4101. fallback_label_name=fallback_label_name,
  4102. column_is_repeated=repeated,
  4103. need_column_expressions=need_column_expressions,
  4104. )
  4105. for (
  4106. name,
  4107. proxy_name,
  4108. fallback_label_name,
  4109. column,
  4110. repeated,
  4111. ) in compile_state.columns_plus_names
  4112. ]
  4113. if c is not None
  4114. ]
  4115. if populate_result_map and select_wraps_for is not None:
  4116. # if this select was generated from translate_select,
  4117. # rewrite the targeted columns in the result map
  4118. translate = dict(
  4119. zip(
  4120. [
  4121. name
  4122. for (
  4123. key,
  4124. proxy_name,
  4125. fallback_label_name,
  4126. name,
  4127. repeated,
  4128. ) in compile_state.columns_plus_names
  4129. ],
  4130. [
  4131. name
  4132. for (
  4133. key,
  4134. proxy_name,
  4135. fallback_label_name,
  4136. name,
  4137. repeated,
  4138. ) in compile_state_wraps_for.columns_plus_names
  4139. ],
  4140. )
  4141. )
  4142. self._result_columns = [
  4143. ResultColumnsEntry(
  4144. key, name, tuple(translate.get(o, o) for o in obj), type_
  4145. )
  4146. for key, name, obj, type_ in self._result_columns
  4147. ]
  4148. text = self._compose_select_body(
  4149. text,
  4150. select_stmt,
  4151. compile_state,
  4152. inner_columns,
  4153. froms,
  4154. byfrom,
  4155. toplevel,
  4156. kwargs,
  4157. )
  4158. if select_stmt._statement_hints:
  4159. per_dialect = [
  4160. ht
  4161. for (dialect_name, ht) in select_stmt._statement_hints
  4162. if dialect_name in ("*", self.dialect.name)
  4163. ]
  4164. if per_dialect:
  4165. text += " " + self.get_statement_hint_text(per_dialect)
  4166. # In compound query, CTEs are shared at the compound level
  4167. if self.ctes and (not is_embedded_select or toplevel):
  4168. nesting_level = len(self.stack) if not toplevel else None
  4169. text = self._render_cte_clause(nesting_level=nesting_level) + text
  4170. if select_stmt._suffixes:
  4171. text += " " + self._generate_prefixes(
  4172. select_stmt, select_stmt._suffixes, **kwargs
  4173. )
  4174. self.stack.pop(-1)
  4175. return text
  4176. def _setup_select_hints(
  4177. self, select: Select[Any]
  4178. ) -> Tuple[str, _FromHintsType]:
  4179. byfrom = {
  4180. from_: hinttext
  4181. % {"name": from_._compiler_dispatch(self, ashint=True)}
  4182. for (from_, dialect), hinttext in select._hints.items()
  4183. if dialect in ("*", self.dialect.name)
  4184. }
  4185. hint_text = self.get_select_hint_text(byfrom)
  4186. return hint_text, byfrom
  4187. def _setup_select_stack(
  4188. self, select, compile_state, entry, asfrom, lateral, compound_index
  4189. ):
  4190. correlate_froms = entry["correlate_froms"]
  4191. asfrom_froms = entry["asfrom_froms"]
  4192. if compound_index == 0:
  4193. entry["select_0"] = select
  4194. elif compound_index:
  4195. select_0 = entry["select_0"]
  4196. numcols = len(select_0._all_selected_columns)
  4197. if len(compile_state.columns_plus_names) != numcols:
  4198. raise exc.CompileError(
  4199. "All selectables passed to "
  4200. "CompoundSelect must have identical numbers of "
  4201. "columns; select #%d has %d columns, select "
  4202. "#%d has %d"
  4203. % (
  4204. 1,
  4205. numcols,
  4206. compound_index + 1,
  4207. len(select._all_selected_columns),
  4208. )
  4209. )
  4210. if asfrom and not lateral:
  4211. froms = compile_state._get_display_froms(
  4212. explicit_correlate_froms=correlate_froms.difference(
  4213. asfrom_froms
  4214. ),
  4215. implicit_correlate_froms=(),
  4216. )
  4217. else:
  4218. froms = compile_state._get_display_froms(
  4219. explicit_correlate_froms=correlate_froms,
  4220. implicit_correlate_froms=asfrom_froms,
  4221. )
  4222. new_correlate_froms = set(_from_objects(*froms))
  4223. all_correlate_froms = new_correlate_froms.union(correlate_froms)
  4224. new_entry: _CompilerStackEntry = {
  4225. "asfrom_froms": new_correlate_froms,
  4226. "correlate_froms": all_correlate_froms,
  4227. "selectable": select,
  4228. "compile_state": compile_state,
  4229. }
  4230. self.stack.append(new_entry)
  4231. return froms
  4232. def _compose_select_body(
  4233. self,
  4234. text,
  4235. select,
  4236. compile_state,
  4237. inner_columns,
  4238. froms,
  4239. byfrom,
  4240. toplevel,
  4241. kwargs,
  4242. ):
  4243. text += ", ".join(inner_columns)
  4244. if self.linting & COLLECT_CARTESIAN_PRODUCTS:
  4245. from_linter = FromLinter({}, set())
  4246. warn_linting = self.linting & WARN_LINTING
  4247. if toplevel:
  4248. self.from_linter = from_linter
  4249. else:
  4250. from_linter = None
  4251. warn_linting = False
  4252. # adjust the whitespace for no inner columns, part of #9440,
  4253. # so that a no-col SELECT comes out as "SELECT WHERE..." or
  4254. # "SELECT FROM ...".
  4255. # while it would be better to have built the SELECT starting string
  4256. # without trailing whitespace first, then add whitespace only if inner
  4257. # cols were present, this breaks compatibility with various custom
  4258. # compilation schemes that are currently being tested.
  4259. if not inner_columns:
  4260. text = text.rstrip()
  4261. if froms:
  4262. text += " \nFROM "
  4263. if select._hints:
  4264. text += ", ".join(
  4265. [
  4266. f._compiler_dispatch(
  4267. self,
  4268. asfrom=True,
  4269. fromhints=byfrom,
  4270. from_linter=from_linter,
  4271. **kwargs,
  4272. )
  4273. for f in froms
  4274. ]
  4275. )
  4276. else:
  4277. text += ", ".join(
  4278. [
  4279. f._compiler_dispatch(
  4280. self,
  4281. asfrom=True,
  4282. from_linter=from_linter,
  4283. **kwargs,
  4284. )
  4285. for f in froms
  4286. ]
  4287. )
  4288. else:
  4289. text += self.default_from()
  4290. if select._where_criteria:
  4291. t = self._generate_delimited_and_list(
  4292. select._where_criteria, from_linter=from_linter, **kwargs
  4293. )
  4294. if t:
  4295. text += " \nWHERE " + t
  4296. if warn_linting:
  4297. assert from_linter is not None
  4298. from_linter.warn()
  4299. if select._group_by_clauses:
  4300. text += self.group_by_clause(select, **kwargs)
  4301. if select._having_criteria:
  4302. t = self._generate_delimited_and_list(
  4303. select._having_criteria, **kwargs
  4304. )
  4305. if t:
  4306. text += " \nHAVING " + t
  4307. if select._order_by_clauses:
  4308. text += self.order_by_clause(select, **kwargs)
  4309. if select._has_row_limiting_clause:
  4310. text += self._row_limit_clause(select, **kwargs)
  4311. if select._for_update_arg is not None:
  4312. text += self.for_update_clause(select, **kwargs)
  4313. return text
  4314. def _generate_prefixes(self, stmt, prefixes, **kw):
  4315. clause = " ".join(
  4316. prefix._compiler_dispatch(self, **kw)
  4317. for prefix, dialect_name in prefixes
  4318. if dialect_name in (None, "*") or dialect_name == self.dialect.name
  4319. )
  4320. if clause:
  4321. clause += " "
  4322. return clause
  4323. def _render_cte_clause(
  4324. self,
  4325. nesting_level=None,
  4326. include_following_stack=False,
  4327. ):
  4328. """
  4329. include_following_stack
  4330. Also render the nesting CTEs on the next stack. Useful for
  4331. SQL structures like UNION or INSERT that can wrap SELECT
  4332. statements containing nesting CTEs.
  4333. """
  4334. if not self.ctes:
  4335. return ""
  4336. ctes: MutableMapping[CTE, str]
  4337. if nesting_level and nesting_level > 1:
  4338. ctes = util.OrderedDict()
  4339. for cte in list(self.ctes.keys()):
  4340. cte_level, cte_name, cte_opts = self.level_name_by_cte[
  4341. cte._get_reference_cte()
  4342. ]
  4343. nesting = cte.nesting or cte_opts.nesting
  4344. is_rendered_level = cte_level == nesting_level or (
  4345. include_following_stack and cte_level == nesting_level + 1
  4346. )
  4347. if not (nesting and is_rendered_level):
  4348. continue
  4349. ctes[cte] = self.ctes[cte]
  4350. else:
  4351. ctes = self.ctes
  4352. if not ctes:
  4353. return ""
  4354. ctes_recursive = any([cte.recursive for cte in ctes])
  4355. cte_text = self.get_cte_preamble(ctes_recursive) + " "
  4356. cte_text += ", \n".join([txt for txt in ctes.values()])
  4357. cte_text += "\n "
  4358. if nesting_level and nesting_level > 1:
  4359. for cte in list(ctes.keys()):
  4360. cte_level, cte_name, cte_opts = self.level_name_by_cte[
  4361. cte._get_reference_cte()
  4362. ]
  4363. del self.ctes[cte]
  4364. del self.ctes_by_level_name[(cte_level, cte_name)]
  4365. del self.level_name_by_cte[cte._get_reference_cte()]
  4366. return cte_text
  4367. def get_cte_preamble(self, recursive):
  4368. if recursive:
  4369. return "WITH RECURSIVE"
  4370. else:
  4371. return "WITH"
  4372. def get_select_precolumns(self, select: Select[Any], **kw: Any) -> str:
  4373. """Called when building a ``SELECT`` statement, position is just
  4374. before column list.
  4375. """
  4376. if select._distinct_on:
  4377. util.warn_deprecated(
  4378. "DISTINCT ON is currently supported only by the PostgreSQL "
  4379. "dialect. Use of DISTINCT ON for other backends is currently "
  4380. "silently ignored, however this usage is deprecated, and will "
  4381. "raise CompileError in a future release for all backends "
  4382. "that do not support this syntax.",
  4383. version="1.4",
  4384. )
  4385. return "DISTINCT " if select._distinct else ""
  4386. def group_by_clause(self, select, **kw):
  4387. """allow dialects to customize how GROUP BY is rendered."""
  4388. group_by = self._generate_delimited_list(
  4389. select._group_by_clauses, OPERATORS[operators.comma_op], **kw
  4390. )
  4391. if group_by:
  4392. return " GROUP BY " + group_by
  4393. else:
  4394. return ""
  4395. def order_by_clause(self, select, **kw):
  4396. """allow dialects to customize how ORDER BY is rendered."""
  4397. order_by = self._generate_delimited_list(
  4398. select._order_by_clauses, OPERATORS[operators.comma_op], **kw
  4399. )
  4400. if order_by:
  4401. return " ORDER BY " + order_by
  4402. else:
  4403. return ""
  4404. def for_update_clause(self, select, **kw):
  4405. return " FOR UPDATE"
  4406. def returning_clause(
  4407. self,
  4408. stmt: UpdateBase,
  4409. returning_cols: Sequence[_ColumnsClauseElement],
  4410. *,
  4411. populate_result_map: bool,
  4412. **kw: Any,
  4413. ) -> str:
  4414. columns = [
  4415. self._label_returning_column(
  4416. stmt,
  4417. column,
  4418. populate_result_map,
  4419. fallback_label_name=fallback_label_name,
  4420. column_is_repeated=repeated,
  4421. name=name,
  4422. proxy_name=proxy_name,
  4423. **kw,
  4424. )
  4425. for (
  4426. name,
  4427. proxy_name,
  4428. fallback_label_name,
  4429. column,
  4430. repeated,
  4431. ) in stmt._generate_columns_plus_names(
  4432. True, cols=base._select_iterables(returning_cols)
  4433. )
  4434. ]
  4435. return "RETURNING " + ", ".join(columns)
  4436. def limit_clause(self, select, **kw):
  4437. text = ""
  4438. if select._limit_clause is not None:
  4439. text += "\n LIMIT " + self.process(select._limit_clause, **kw)
  4440. if select._offset_clause is not None:
  4441. if select._limit_clause is None:
  4442. text += "\n LIMIT -1"
  4443. text += " OFFSET " + self.process(select._offset_clause, **kw)
  4444. return text
  4445. def fetch_clause(
  4446. self,
  4447. select,
  4448. fetch_clause=None,
  4449. require_offset=False,
  4450. use_literal_execute_for_simple_int=False,
  4451. **kw,
  4452. ):
  4453. if fetch_clause is None:
  4454. fetch_clause = select._fetch_clause
  4455. fetch_clause_options = select._fetch_clause_options
  4456. else:
  4457. fetch_clause_options = {"percent": False, "with_ties": False}
  4458. text = ""
  4459. if select._offset_clause is not None:
  4460. offset_clause = select._offset_clause
  4461. if (
  4462. use_literal_execute_for_simple_int
  4463. and select._simple_int_clause(offset_clause)
  4464. ):
  4465. offset_clause = offset_clause.render_literal_execute()
  4466. offset_str = self.process(offset_clause, **kw)
  4467. text += "\n OFFSET %s ROWS" % offset_str
  4468. elif require_offset:
  4469. text += "\n OFFSET 0 ROWS"
  4470. if fetch_clause is not None:
  4471. if (
  4472. use_literal_execute_for_simple_int
  4473. and select._simple_int_clause(fetch_clause)
  4474. ):
  4475. fetch_clause = fetch_clause.render_literal_execute()
  4476. text += "\n FETCH FIRST %s%s ROWS %s" % (
  4477. self.process(fetch_clause, **kw),
  4478. " PERCENT" if fetch_clause_options["percent"] else "",
  4479. "WITH TIES" if fetch_clause_options["with_ties"] else "ONLY",
  4480. )
  4481. return text
  4482. def visit_table(
  4483. self,
  4484. table,
  4485. asfrom=False,
  4486. iscrud=False,
  4487. ashint=False,
  4488. fromhints=None,
  4489. use_schema=True,
  4490. from_linter=None,
  4491. ambiguous_table_name_map=None,
  4492. enclosing_alias=None,
  4493. **kwargs,
  4494. ):
  4495. if from_linter:
  4496. from_linter.froms[table] = table.fullname
  4497. if asfrom or ashint:
  4498. effective_schema = self.preparer.schema_for_object(table)
  4499. if use_schema and effective_schema:
  4500. ret = (
  4501. self.preparer.quote_schema(effective_schema)
  4502. + "."
  4503. + self.preparer.quote(table.name)
  4504. )
  4505. else:
  4506. ret = self.preparer.quote(table.name)
  4507. if (
  4508. (
  4509. enclosing_alias is None
  4510. or enclosing_alias.element is not table
  4511. )
  4512. and not effective_schema
  4513. and ambiguous_table_name_map
  4514. and table.name in ambiguous_table_name_map
  4515. ):
  4516. anon_name = self._truncated_identifier(
  4517. "alias", ambiguous_table_name_map[table.name]
  4518. )
  4519. ret = ret + self.get_render_as_alias_suffix(
  4520. self.preparer.format_alias(None, anon_name)
  4521. )
  4522. if fromhints and table in fromhints:
  4523. ret = self.format_from_hint_text(
  4524. ret, table, fromhints[table], iscrud
  4525. )
  4526. return ret
  4527. else:
  4528. return ""
  4529. def visit_join(self, join, asfrom=False, from_linter=None, **kwargs):
  4530. if from_linter:
  4531. from_linter.edges.update(
  4532. itertools.product(
  4533. _de_clone(join.left._from_objects),
  4534. _de_clone(join.right._from_objects),
  4535. )
  4536. )
  4537. if join.full:
  4538. join_type = " FULL OUTER JOIN "
  4539. elif join.isouter:
  4540. join_type = " LEFT OUTER JOIN "
  4541. else:
  4542. join_type = " JOIN "
  4543. return (
  4544. join.left._compiler_dispatch(
  4545. self, asfrom=True, from_linter=from_linter, **kwargs
  4546. )
  4547. + join_type
  4548. + join.right._compiler_dispatch(
  4549. self, asfrom=True, from_linter=from_linter, **kwargs
  4550. )
  4551. + " ON "
  4552. # TODO: likely need asfrom=True here?
  4553. + join.onclause._compiler_dispatch(
  4554. self, from_linter=from_linter, **kwargs
  4555. )
  4556. )
  4557. def _setup_crud_hints(self, stmt, table_text):
  4558. dialect_hints = {
  4559. table: hint_text
  4560. for (table, dialect), hint_text in stmt._hints.items()
  4561. if dialect in ("*", self.dialect.name)
  4562. }
  4563. if stmt.table in dialect_hints:
  4564. table_text = self.format_from_hint_text(
  4565. table_text, stmt.table, dialect_hints[stmt.table], True
  4566. )
  4567. return dialect_hints, table_text
  4568. # within the realm of "insertmanyvalues sentinel columns",
  4569. # these lookups match different kinds of Column() configurations
  4570. # to specific backend capabilities. they are broken into two
  4571. # lookups, one for autoincrement columns and the other for non
  4572. # autoincrement columns
  4573. _sentinel_col_non_autoinc_lookup = util.immutabledict(
  4574. {
  4575. _SentinelDefaultCharacterization.CLIENTSIDE: (
  4576. InsertmanyvaluesSentinelOpts._SUPPORTED_OR_NOT
  4577. ),
  4578. _SentinelDefaultCharacterization.SENTINEL_DEFAULT: (
  4579. InsertmanyvaluesSentinelOpts._SUPPORTED_OR_NOT
  4580. ),
  4581. _SentinelDefaultCharacterization.NONE: (
  4582. InsertmanyvaluesSentinelOpts._SUPPORTED_OR_NOT
  4583. ),
  4584. _SentinelDefaultCharacterization.IDENTITY: (
  4585. InsertmanyvaluesSentinelOpts.IDENTITY
  4586. ),
  4587. _SentinelDefaultCharacterization.SEQUENCE: (
  4588. InsertmanyvaluesSentinelOpts.SEQUENCE
  4589. ),
  4590. }
  4591. )
  4592. _sentinel_col_autoinc_lookup = _sentinel_col_non_autoinc_lookup.union(
  4593. {
  4594. _SentinelDefaultCharacterization.NONE: (
  4595. InsertmanyvaluesSentinelOpts.AUTOINCREMENT
  4596. ),
  4597. }
  4598. )
  4599. def _get_sentinel_column_for_table(
  4600. self, table: Table
  4601. ) -> Optional[Sequence[Column[Any]]]:
  4602. """given a :class:`.Table`, return a usable sentinel column or
  4603. columns for this dialect if any.
  4604. Return None if no sentinel columns could be identified, or raise an
  4605. error if a column was marked as a sentinel explicitly but isn't
  4606. compatible with this dialect.
  4607. """
  4608. sentinel_opts = self.dialect.insertmanyvalues_implicit_sentinel
  4609. sentinel_characteristics = table._sentinel_column_characteristics
  4610. sent_cols = sentinel_characteristics.columns
  4611. if sent_cols is None:
  4612. return None
  4613. if sentinel_characteristics.is_autoinc:
  4614. bitmask = self._sentinel_col_autoinc_lookup.get(
  4615. sentinel_characteristics.default_characterization, 0
  4616. )
  4617. else:
  4618. bitmask = self._sentinel_col_non_autoinc_lookup.get(
  4619. sentinel_characteristics.default_characterization, 0
  4620. )
  4621. if sentinel_opts & bitmask:
  4622. return sent_cols
  4623. if sentinel_characteristics.is_explicit:
  4624. # a column was explicitly marked as insert_sentinel=True,
  4625. # however it is not compatible with this dialect. they should
  4626. # not indicate this column as a sentinel if they need to include
  4627. # this dialect.
  4628. # TODO: do we want non-primary key explicit sentinel cols
  4629. # that can gracefully degrade for some backends?
  4630. # insert_sentinel="degrade" perhaps. not for the initial release.
  4631. # I am hoping people are generally not dealing with this sentinel
  4632. # business at all.
  4633. # if is_explicit is True, there will be only one sentinel column.
  4634. raise exc.InvalidRequestError(
  4635. f"Column {sent_cols[0]} can't be explicitly "
  4636. "marked as a sentinel column when using the "
  4637. f"{self.dialect.name} dialect, as the "
  4638. "particular type of default generation on this column is "
  4639. "not currently compatible with this dialect's specific "
  4640. f"INSERT..RETURNING syntax which can receive the "
  4641. "server-generated value in "
  4642. "a deterministic way. To remove this error, remove "
  4643. "insert_sentinel=True from primary key autoincrement "
  4644. "columns; these columns are automatically used as "
  4645. "sentinels for supported dialects in any case."
  4646. )
  4647. return None
  4648. def _deliver_insertmanyvalues_batches(
  4649. self,
  4650. statement: str,
  4651. parameters: _DBAPIMultiExecuteParams,
  4652. compiled_parameters: List[_MutableCoreSingleExecuteParams],
  4653. generic_setinputsizes: Optional[_GenericSetInputSizesType],
  4654. batch_size: int,
  4655. sort_by_parameter_order: bool,
  4656. schema_translate_map: Optional[SchemaTranslateMapType],
  4657. ) -> Iterator[_InsertManyValuesBatch]:
  4658. imv = self._insertmanyvalues
  4659. assert imv is not None
  4660. if not imv.sentinel_param_keys:
  4661. _sentinel_from_params = None
  4662. else:
  4663. _sentinel_from_params = operator.itemgetter(
  4664. *imv.sentinel_param_keys
  4665. )
  4666. lenparams = len(parameters)
  4667. if imv.is_default_expr and not self.dialect.supports_default_metavalue:
  4668. # backend doesn't support
  4669. # INSERT INTO table (pk_col) VALUES (DEFAULT), (DEFAULT), ...
  4670. # at the moment this is basically SQL Server due to
  4671. # not being able to use DEFAULT for identity column
  4672. # just yield out that many single statements! still
  4673. # faster than a whole connection.execute() call ;)
  4674. #
  4675. # note we still are taking advantage of the fact that we know
  4676. # we are using RETURNING. The generalized approach of fetching
  4677. # cursor.lastrowid etc. still goes through the more heavyweight
  4678. # "ExecutionContext per statement" system as it isn't usable
  4679. # as a generic "RETURNING" approach
  4680. use_row_at_a_time = True
  4681. downgraded = False
  4682. elif not self.dialect.supports_multivalues_insert or (
  4683. sort_by_parameter_order
  4684. and self._result_columns
  4685. and (
  4686. imv.sentinel_columns is None
  4687. or (
  4688. imv.includes_upsert_behaviors
  4689. and not imv.embed_values_counter
  4690. )
  4691. )
  4692. ):
  4693. # deterministic order was requested and the compiler could
  4694. # not organize sentinel columns for this dialect/statement.
  4695. # use row at a time. Note: if embed_values_counter is True,
  4696. # the counter itself provides the ordering capability we need,
  4697. # so we can use batch mode even with upsert behaviors.
  4698. use_row_at_a_time = True
  4699. downgraded = True
  4700. elif (
  4701. imv.has_upsert_bound_parameters
  4702. and not imv.embed_values_counter
  4703. and self._result_columns
  4704. ):
  4705. # For upsert behaviors (ON CONFLICT DO UPDATE, etc.) with RETURNING
  4706. # and parametrized bindparams in the SET clause, we must use
  4707. # row-at-a-time. Batching multiple rows in a single statement
  4708. # doesn't work when the SET clause contains bound parameters that
  4709. # will receive different values per row, as there's only one SET
  4710. # clause per statement. See issue #13130.
  4711. use_row_at_a_time = True
  4712. downgraded = True
  4713. else:
  4714. use_row_at_a_time = False
  4715. downgraded = False
  4716. if use_row_at_a_time:
  4717. for batchnum, (param, compiled_param) in enumerate(
  4718. cast(
  4719. "Sequence[Tuple[_DBAPISingleExecuteParams, _MutableCoreSingleExecuteParams]]", # noqa: E501
  4720. zip(parameters, compiled_parameters),
  4721. ),
  4722. 1,
  4723. ):
  4724. yield _InsertManyValuesBatch(
  4725. statement,
  4726. param,
  4727. generic_setinputsizes,
  4728. [param],
  4729. (
  4730. [_sentinel_from_params(compiled_param)]
  4731. if _sentinel_from_params
  4732. else []
  4733. ),
  4734. 1,
  4735. batchnum,
  4736. lenparams,
  4737. sort_by_parameter_order,
  4738. downgraded,
  4739. )
  4740. return
  4741. if schema_translate_map:
  4742. rst = functools.partial(
  4743. self.preparer._render_schema_translates,
  4744. schema_translate_map=schema_translate_map,
  4745. )
  4746. else:
  4747. rst = None
  4748. imv_single_values_expr = imv.single_values_expr
  4749. if rst:
  4750. imv_single_values_expr = rst(imv_single_values_expr)
  4751. executemany_values = f"({imv_single_values_expr})"
  4752. statement = statement.replace(executemany_values, "__EXECMANY_TOKEN__")
  4753. # Use optional insertmanyvalues_max_parameters
  4754. # to further shrink the batch size so that there are no more than
  4755. # insertmanyvalues_max_parameters params.
  4756. # Currently used by SQL Server, which limits statements to 2100 bound
  4757. # parameters (actually 2099).
  4758. max_params = self.dialect.insertmanyvalues_max_parameters
  4759. if max_params:
  4760. total_num_of_params = len(self.bind_names)
  4761. num_params_per_batch = len(imv.insert_crud_params)
  4762. num_params_outside_of_batch = (
  4763. total_num_of_params - num_params_per_batch
  4764. )
  4765. batch_size = min(
  4766. batch_size,
  4767. (
  4768. (max_params - num_params_outside_of_batch)
  4769. // num_params_per_batch
  4770. ),
  4771. )
  4772. batches = cast("List[Sequence[Any]]", list(parameters))
  4773. compiled_batches = cast(
  4774. "List[Sequence[Any]]", list(compiled_parameters)
  4775. )
  4776. processed_setinputsizes: Optional[_GenericSetInputSizesType] = None
  4777. batchnum = 1
  4778. total_batches = lenparams // batch_size + (
  4779. 1 if lenparams % batch_size else 0
  4780. )
  4781. insert_crud_params = imv.insert_crud_params
  4782. assert insert_crud_params is not None
  4783. if rst:
  4784. insert_crud_params = [
  4785. (col, key, rst(expr), st)
  4786. for col, key, expr, st in insert_crud_params
  4787. ]
  4788. escaped_bind_names: Mapping[str, str]
  4789. expand_pos_lower_index = expand_pos_upper_index = 0
  4790. if not self.positional:
  4791. if self.escaped_bind_names:
  4792. escaped_bind_names = self.escaped_bind_names
  4793. else:
  4794. escaped_bind_names = {}
  4795. all_keys = set(parameters[0])
  4796. def apply_placeholders(keys, formatted):
  4797. for key in keys:
  4798. key = escaped_bind_names.get(key, key)
  4799. formatted = formatted.replace(
  4800. self.bindtemplate % {"name": key},
  4801. self.bindtemplate
  4802. % {"name": f"{key}__EXECMANY_INDEX__"},
  4803. )
  4804. return formatted
  4805. if imv.embed_values_counter:
  4806. imv_values_counter = ", _IMV_VALUES_COUNTER"
  4807. else:
  4808. imv_values_counter = ""
  4809. formatted_values_clause = f"""({', '.join(
  4810. apply_placeholders(bind_keys, formatted)
  4811. for _, _, formatted, bind_keys in insert_crud_params
  4812. )}{imv_values_counter})"""
  4813. keys_to_replace = all_keys.intersection(
  4814. escaped_bind_names.get(key, key)
  4815. for _, _, _, bind_keys in insert_crud_params
  4816. for key in bind_keys
  4817. )
  4818. base_parameters = {
  4819. key: parameters[0][key]
  4820. for key in all_keys.difference(keys_to_replace)
  4821. }
  4822. executemany_values_w_comma = ""
  4823. else:
  4824. formatted_values_clause = ""
  4825. keys_to_replace = set()
  4826. base_parameters = {}
  4827. if imv.embed_values_counter:
  4828. executemany_values_w_comma = (
  4829. f"({imv_single_values_expr}, _IMV_VALUES_COUNTER), "
  4830. )
  4831. else:
  4832. executemany_values_w_comma = f"({imv_single_values_expr}), "
  4833. all_names_we_will_expand: Set[str] = set()
  4834. for elem in imv.insert_crud_params:
  4835. all_names_we_will_expand.update(elem[3])
  4836. # get the start and end position in a particular list
  4837. # of parameters where we will be doing the "expanding".
  4838. # statements can have params on either side or both sides,
  4839. # given RETURNING and CTEs
  4840. if all_names_we_will_expand:
  4841. positiontup = self.positiontup
  4842. assert positiontup is not None
  4843. all_expand_positions = {
  4844. idx
  4845. for idx, name in enumerate(positiontup)
  4846. if name in all_names_we_will_expand
  4847. }
  4848. expand_pos_lower_index = min(all_expand_positions)
  4849. expand_pos_upper_index = max(all_expand_positions) + 1
  4850. assert (
  4851. len(all_expand_positions)
  4852. == expand_pos_upper_index - expand_pos_lower_index
  4853. )
  4854. if self._numeric_binds:
  4855. escaped = re.escape(self._numeric_binds_identifier_char)
  4856. executemany_values_w_comma = re.sub(
  4857. rf"{escaped}\d+", "%s", executemany_values_w_comma
  4858. )
  4859. while batches:
  4860. batch = batches[0:batch_size]
  4861. compiled_batch = compiled_batches[0:batch_size]
  4862. batches[0:batch_size] = []
  4863. compiled_batches[0:batch_size] = []
  4864. if batches:
  4865. current_batch_size = batch_size
  4866. else:
  4867. current_batch_size = len(batch)
  4868. if generic_setinputsizes:
  4869. # if setinputsizes is present, expand this collection to
  4870. # suit the batch length as well
  4871. # currently this will be mssql+pyodbc for internal dialects
  4872. processed_setinputsizes = [
  4873. (new_key, len_, typ)
  4874. for new_key, len_, typ in (
  4875. (f"{key}_{index}", len_, typ)
  4876. for index in range(current_batch_size)
  4877. for key, len_, typ in generic_setinputsizes
  4878. )
  4879. ]
  4880. replaced_parameters: Any
  4881. if self.positional:
  4882. num_ins_params = imv.num_positional_params_counted
  4883. batch_iterator: Iterable[Sequence[Any]]
  4884. extra_params_left: Sequence[Any]
  4885. extra_params_right: Sequence[Any]
  4886. if num_ins_params == len(batch[0]):
  4887. extra_params_left = extra_params_right = ()
  4888. batch_iterator = batch
  4889. else:
  4890. extra_params_left = batch[0][:expand_pos_lower_index]
  4891. extra_params_right = batch[0][expand_pos_upper_index:]
  4892. batch_iterator = (
  4893. b[expand_pos_lower_index:expand_pos_upper_index]
  4894. for b in batch
  4895. )
  4896. if imv.embed_values_counter:
  4897. expanded_values_string = (
  4898. "".join(
  4899. executemany_values_w_comma.replace(
  4900. "_IMV_VALUES_COUNTER", str(i)
  4901. )
  4902. for i, _ in enumerate(batch)
  4903. )
  4904. )[:-2]
  4905. else:
  4906. expanded_values_string = (
  4907. (executemany_values_w_comma * current_batch_size)
  4908. )[:-2]
  4909. if self._numeric_binds and num_ins_params > 0:
  4910. # numeric will always number the parameters inside of
  4911. # VALUES (and thus order self.positiontup) to be higher
  4912. # than non-VALUES parameters, no matter where in the
  4913. # statement those non-VALUES parameters appear (this is
  4914. # ensured in _process_numeric by numbering first all
  4915. # params that are not in _values_bindparam)
  4916. # therefore all extra params are always
  4917. # on the left side and numbered lower than the VALUES
  4918. # parameters
  4919. assert not extra_params_right
  4920. start = expand_pos_lower_index + 1
  4921. end = num_ins_params * (current_batch_size) + start
  4922. # need to format here, since statement may contain
  4923. # unescaped %, while values_string contains just (%s, %s)
  4924. positions = tuple(
  4925. f"{self._numeric_binds_identifier_char}{i}"
  4926. for i in range(start, end)
  4927. )
  4928. expanded_values_string = expanded_values_string % positions
  4929. replaced_statement = statement.replace(
  4930. "__EXECMANY_TOKEN__", expanded_values_string
  4931. )
  4932. replaced_parameters = tuple(
  4933. itertools.chain.from_iterable(batch_iterator)
  4934. )
  4935. replaced_parameters = (
  4936. extra_params_left
  4937. + replaced_parameters
  4938. + extra_params_right
  4939. )
  4940. else:
  4941. replaced_values_clauses = []
  4942. replaced_parameters = base_parameters.copy()
  4943. for i, param in enumerate(batch):
  4944. fmv = formatted_values_clause.replace(
  4945. "EXECMANY_INDEX__", str(i)
  4946. )
  4947. if imv.embed_values_counter:
  4948. fmv = fmv.replace("_IMV_VALUES_COUNTER", str(i))
  4949. replaced_values_clauses.append(fmv)
  4950. replaced_parameters.update(
  4951. {f"{key}__{i}": param[key] for key in keys_to_replace}
  4952. )
  4953. replaced_statement = statement.replace(
  4954. "__EXECMANY_TOKEN__",
  4955. ", ".join(replaced_values_clauses),
  4956. )
  4957. yield _InsertManyValuesBatch(
  4958. replaced_statement,
  4959. replaced_parameters,
  4960. processed_setinputsizes,
  4961. batch,
  4962. (
  4963. [_sentinel_from_params(cb) for cb in compiled_batch]
  4964. if _sentinel_from_params
  4965. else []
  4966. ),
  4967. current_batch_size,
  4968. batchnum,
  4969. total_batches,
  4970. sort_by_parameter_order,
  4971. False,
  4972. )
  4973. batchnum += 1
  4974. def visit_insert(
  4975. self, insert_stmt, visited_bindparam=None, visiting_cte=None, **kw
  4976. ):
  4977. compile_state = insert_stmt._compile_state_factory(
  4978. insert_stmt, self, **kw
  4979. )
  4980. insert_stmt = compile_state.statement
  4981. if visiting_cte is not None:
  4982. kw["visiting_cte"] = visiting_cte
  4983. toplevel = False
  4984. else:
  4985. toplevel = not self.stack
  4986. if toplevel:
  4987. self.isinsert = True
  4988. if not self.dml_compile_state:
  4989. self.dml_compile_state = compile_state
  4990. if not self.compile_state:
  4991. self.compile_state = compile_state
  4992. self.stack.append(
  4993. {
  4994. "correlate_froms": set(),
  4995. "asfrom_froms": set(),
  4996. "selectable": insert_stmt,
  4997. }
  4998. )
  4999. counted_bindparam = 0
  5000. # reset any incoming "visited_bindparam" collection
  5001. visited_bindparam = None
  5002. # for positional, insertmanyvalues needs to know how many
  5003. # bound parameters are in the VALUES sequence; there's no simple
  5004. # rule because default expressions etc. can have zero or more
  5005. # params inside them. After multiple attempts to figure this out,
  5006. # this very simplistic "count after" works and is
  5007. # likely the least amount of callcounts, though looks clumsy
  5008. if self.positional and visiting_cte is None:
  5009. # if we are inside a CTE, don't count parameters
  5010. # here since they won't be for insertmanyvalues. keep
  5011. # visited_bindparam at None so no counting happens.
  5012. # see #9173
  5013. visited_bindparam = []
  5014. crud_params_struct = crud._get_crud_params(
  5015. self,
  5016. insert_stmt,
  5017. compile_state,
  5018. toplevel,
  5019. visited_bindparam=visited_bindparam,
  5020. **kw,
  5021. )
  5022. if self.positional and visited_bindparam is not None:
  5023. counted_bindparam = len(visited_bindparam)
  5024. if self._numeric_binds:
  5025. if self._values_bindparam is not None:
  5026. self._values_bindparam += visited_bindparam
  5027. else:
  5028. self._values_bindparam = visited_bindparam
  5029. crud_params_single = crud_params_struct.single_params
  5030. if (
  5031. not crud_params_single
  5032. and not self.dialect.supports_default_values
  5033. and not self.dialect.supports_default_metavalue
  5034. and not self.dialect.supports_empty_insert
  5035. ):
  5036. raise exc.CompileError(
  5037. "The '%s' dialect with current database "
  5038. "version settings does not support empty "
  5039. "inserts." % self.dialect.name
  5040. )
  5041. if compile_state._has_multi_parameters:
  5042. if not self.dialect.supports_multivalues_insert:
  5043. raise exc.CompileError(
  5044. "The '%s' dialect with current database "
  5045. "version settings does not support "
  5046. "in-place multirow inserts." % self.dialect.name
  5047. )
  5048. elif (
  5049. self.implicit_returning or insert_stmt._returning
  5050. ) and insert_stmt._sort_by_parameter_order:
  5051. raise exc.CompileError(
  5052. "RETURNING cannot be deterministically sorted when "
  5053. "using an INSERT which includes multi-row values()."
  5054. )
  5055. crud_params_single = crud_params_struct.single_params
  5056. else:
  5057. crud_params_single = crud_params_struct.single_params
  5058. preparer = self.preparer
  5059. supports_default_values = self.dialect.supports_default_values
  5060. text = "INSERT "
  5061. if insert_stmt._prefixes:
  5062. text += self._generate_prefixes(
  5063. insert_stmt, insert_stmt._prefixes, **kw
  5064. )
  5065. text += "INTO "
  5066. table_text = preparer.format_table(insert_stmt.table)
  5067. if insert_stmt._hints:
  5068. _, table_text = self._setup_crud_hints(insert_stmt, table_text)
  5069. if insert_stmt._independent_ctes:
  5070. self._dispatch_independent_ctes(insert_stmt, kw)
  5071. text += table_text
  5072. if crud_params_single or not supports_default_values:
  5073. text += " (%s)" % ", ".join(
  5074. [expr for _, expr, _, _ in crud_params_single]
  5075. )
  5076. # look for insertmanyvalues attributes that would have been configured
  5077. # by crud.py as it scanned through the columns to be part of the
  5078. # INSERT
  5079. use_insertmanyvalues = crud_params_struct.use_insertmanyvalues
  5080. named_sentinel_params: Optional[Sequence[str]] = None
  5081. add_sentinel_cols = None
  5082. implicit_sentinel = False
  5083. returning_cols = self.implicit_returning or insert_stmt._returning
  5084. if returning_cols:
  5085. add_sentinel_cols = crud_params_struct.use_sentinel_columns
  5086. if add_sentinel_cols is not None:
  5087. assert use_insertmanyvalues
  5088. # search for the sentinel column explicitly present
  5089. # in the INSERT columns list, and additionally check that
  5090. # this column has a bound parameter name set up that's in the
  5091. # parameter list. If both of these cases are present, it means
  5092. # we will have a client side value for the sentinel in each
  5093. # parameter set.
  5094. _params_by_col = {
  5095. col: param_names
  5096. for col, _, _, param_names in crud_params_single
  5097. }
  5098. named_sentinel_params = []
  5099. for _add_sentinel_col in add_sentinel_cols:
  5100. if _add_sentinel_col not in _params_by_col:
  5101. named_sentinel_params = None
  5102. break
  5103. param_name = self._within_exec_param_key_getter(
  5104. _add_sentinel_col
  5105. )
  5106. if param_name not in _params_by_col[_add_sentinel_col]:
  5107. named_sentinel_params = None
  5108. break
  5109. named_sentinel_params.append(param_name)
  5110. if named_sentinel_params is None:
  5111. # if we are not going to have a client side value for
  5112. # the sentinel in the parameter set, that means it's
  5113. # an autoincrement, an IDENTITY, or a server-side SQL
  5114. # expression like nextval('seqname'). So this is
  5115. # an "implicit" sentinel; we will look for it in
  5116. # RETURNING
  5117. # only, and then sort on it. For this case on PG,
  5118. # SQL Server we have to use a special INSERT form
  5119. # that guarantees the server side function lines up with
  5120. # the entries in the VALUES.
  5121. if (
  5122. self.dialect.insertmanyvalues_implicit_sentinel
  5123. & InsertmanyvaluesSentinelOpts.ANY_AUTOINCREMENT
  5124. ):
  5125. implicit_sentinel = True
  5126. else:
  5127. # here, we are not using a sentinel at all
  5128. # and we are likely the SQLite dialect.
  5129. # The first add_sentinel_col that we have should not
  5130. # be marked as "insert_sentinel=True". if it was,
  5131. # an error should have been raised in
  5132. # _get_sentinel_column_for_table.
  5133. assert not add_sentinel_cols[0]._insert_sentinel, (
  5134. "sentinel selection rules should have prevented "
  5135. "us from getting here for this dialect"
  5136. )
  5137. # always put the sentinel columns last. even if they are
  5138. # in the returning list already, they will be there twice
  5139. # then.
  5140. returning_cols = list(returning_cols) + list(add_sentinel_cols)
  5141. returning_clause = self.returning_clause(
  5142. insert_stmt,
  5143. returning_cols,
  5144. populate_result_map=toplevel,
  5145. )
  5146. if self.returning_precedes_values:
  5147. text += " " + returning_clause
  5148. else:
  5149. returning_clause = None
  5150. if insert_stmt.select is not None:
  5151. # placed here by crud.py
  5152. select_text = self.process(
  5153. self.stack[-1]["insert_from_select"], insert_into=True, **kw
  5154. )
  5155. if self.ctes and self.dialect.cte_follows_insert:
  5156. nesting_level = len(self.stack) if not toplevel else None
  5157. text += " %s%s" % (
  5158. self._render_cte_clause(
  5159. nesting_level=nesting_level,
  5160. include_following_stack=True,
  5161. ),
  5162. select_text,
  5163. )
  5164. else:
  5165. text += " %s" % select_text
  5166. elif not crud_params_single and supports_default_values:
  5167. text += " DEFAULT VALUES"
  5168. if use_insertmanyvalues:
  5169. self._insertmanyvalues = _InsertManyValues(
  5170. True,
  5171. self.dialect.default_metavalue_token,
  5172. crud_params_single,
  5173. counted_bindparam,
  5174. sort_by_parameter_order=(
  5175. insert_stmt._sort_by_parameter_order
  5176. ),
  5177. includes_upsert_behaviors=(
  5178. insert_stmt._post_values_clause is not None
  5179. ),
  5180. sentinel_columns=add_sentinel_cols,
  5181. num_sentinel_columns=(
  5182. len(add_sentinel_cols) if add_sentinel_cols else 0
  5183. ),
  5184. implicit_sentinel=implicit_sentinel,
  5185. )
  5186. elif compile_state._has_multi_parameters:
  5187. text += " VALUES %s" % (
  5188. ", ".join(
  5189. "(%s)"
  5190. % (", ".join(value for _, _, value, _ in crud_param_set))
  5191. for crud_param_set in crud_params_struct.all_multi_params
  5192. ),
  5193. )
  5194. elif use_insertmanyvalues:
  5195. if (
  5196. implicit_sentinel
  5197. and (
  5198. self.dialect.insertmanyvalues_implicit_sentinel
  5199. & InsertmanyvaluesSentinelOpts.USE_INSERT_FROM_SELECT
  5200. )
  5201. # this is checking if we have
  5202. # INSERT INTO table (id) VALUES (DEFAULT).
  5203. and not (crud_params_struct.is_default_metavalue_only)
  5204. ):
  5205. # if we have a sentinel column that is server generated,
  5206. # then for selected backends render the VALUES list as a
  5207. # subquery. This is the orderable form supported by
  5208. # PostgreSQL and in fewer cases SQL Server
  5209. embed_sentinel_value = True
  5210. render_bind_casts = (
  5211. self.dialect.insertmanyvalues_implicit_sentinel
  5212. & InsertmanyvaluesSentinelOpts.RENDER_SELECT_COL_CASTS
  5213. )
  5214. add_sentinel_set = add_sentinel_cols or ()
  5215. insert_single_values_expr = ", ".join(
  5216. [
  5217. value
  5218. for col, _, value, _ in crud_params_single
  5219. if col not in add_sentinel_set
  5220. ]
  5221. )
  5222. colnames = ", ".join(
  5223. f"p{i}"
  5224. for i, cp in enumerate(crud_params_single)
  5225. if cp[0] not in add_sentinel_set
  5226. )
  5227. if render_bind_casts:
  5228. # render casts for the SELECT list. For PG, we are
  5229. # already rendering bind casts in the parameter list,
  5230. # selectively for the more "tricky" types like ARRAY.
  5231. # however, even for the "easy" types, if the parameter
  5232. # is NULL for every entry, PG gives up and says
  5233. # "it must be TEXT", which fails for other easy types
  5234. # like ints. So we cast on this side too.
  5235. colnames_w_cast = ", ".join(
  5236. (
  5237. self.render_bind_cast(
  5238. col.type,
  5239. col.type._unwrapped_dialect_impl(self.dialect),
  5240. f"p{i}",
  5241. )
  5242. if col not in add_sentinel_set
  5243. else expr
  5244. )
  5245. for i, (col, _, expr, _) in enumerate(
  5246. crud_params_single
  5247. )
  5248. )
  5249. else:
  5250. colnames_w_cast = ", ".join(
  5251. (f"p{i}" if col not in add_sentinel_set else expr)
  5252. for i, (col, _, expr, _) in enumerate(
  5253. crud_params_single
  5254. )
  5255. )
  5256. insert_crud_params = [
  5257. elem
  5258. for elem in crud_params_single
  5259. if elem[0] not in add_sentinel_set
  5260. ]
  5261. text += (
  5262. f" SELECT {colnames_w_cast} FROM "
  5263. f"(VALUES ({insert_single_values_expr})) "
  5264. f"AS imp_sen({colnames}, sen_counter) "
  5265. "ORDER BY sen_counter"
  5266. )
  5267. else:
  5268. # otherwise, if no sentinel or backend doesn't support
  5269. # orderable subquery form, use a plain VALUES list
  5270. embed_sentinel_value = False
  5271. insert_crud_params = crud_params_single
  5272. insert_single_values_expr = ", ".join(
  5273. [value for _, _, value, _ in crud_params_single]
  5274. )
  5275. text += f" VALUES ({insert_single_values_expr})"
  5276. self._insertmanyvalues = _InsertManyValues(
  5277. is_default_expr=False,
  5278. single_values_expr=insert_single_values_expr,
  5279. insert_crud_params=insert_crud_params,
  5280. num_positional_params_counted=counted_bindparam,
  5281. sort_by_parameter_order=(insert_stmt._sort_by_parameter_order),
  5282. includes_upsert_behaviors=(
  5283. insert_stmt._post_values_clause is not None
  5284. ),
  5285. sentinel_columns=add_sentinel_cols,
  5286. num_sentinel_columns=(
  5287. len(add_sentinel_cols) if add_sentinel_cols else 0
  5288. ),
  5289. sentinel_param_keys=named_sentinel_params,
  5290. implicit_sentinel=implicit_sentinel,
  5291. embed_values_counter=embed_sentinel_value,
  5292. )
  5293. else:
  5294. insert_single_values_expr = ", ".join(
  5295. [value for _, _, value, _ in crud_params_single]
  5296. )
  5297. text += f" VALUES ({insert_single_values_expr})"
  5298. if insert_stmt._post_values_clause is not None:
  5299. post_values_clause = self.process(
  5300. insert_stmt._post_values_clause, **kw
  5301. )
  5302. if post_values_clause:
  5303. text += " " + post_values_clause
  5304. if returning_clause and not self.returning_precedes_values:
  5305. text += " " + returning_clause
  5306. if self.ctes and not self.dialect.cte_follows_insert:
  5307. nesting_level = len(self.stack) if not toplevel else None
  5308. text = (
  5309. self._render_cte_clause(
  5310. nesting_level=nesting_level,
  5311. include_following_stack=True,
  5312. )
  5313. + text
  5314. )
  5315. self.stack.pop(-1)
  5316. return text
  5317. def update_limit_clause(self, update_stmt):
  5318. """Provide a hook for MySQL to add LIMIT to the UPDATE"""
  5319. return None
  5320. def delete_limit_clause(self, delete_stmt):
  5321. """Provide a hook for MySQL to add LIMIT to the DELETE"""
  5322. return None
  5323. def update_tables_clause(self, update_stmt, from_table, extra_froms, **kw):
  5324. """Provide a hook to override the initial table clause
  5325. in an UPDATE statement.
  5326. MySQL overrides this.
  5327. """
  5328. kw["asfrom"] = True
  5329. return from_table._compiler_dispatch(self, iscrud=True, **kw)
  5330. def update_from_clause(
  5331. self, update_stmt, from_table, extra_froms, from_hints, **kw
  5332. ):
  5333. """Provide a hook to override the generation of an
  5334. UPDATE..FROM clause.
  5335. MySQL and MSSQL override this.
  5336. """
  5337. raise NotImplementedError(
  5338. "This backend does not support multiple-table "
  5339. "criteria within UPDATE"
  5340. )
  5341. def visit_update(
  5342. self,
  5343. update_stmt: Update,
  5344. visiting_cte: Optional[CTE] = None,
  5345. **kw: Any,
  5346. ) -> str:
  5347. compile_state = update_stmt._compile_state_factory(
  5348. update_stmt, self, **kw
  5349. )
  5350. if TYPE_CHECKING:
  5351. assert isinstance(compile_state, UpdateDMLState)
  5352. update_stmt = compile_state.statement # type: ignore[assignment]
  5353. if visiting_cte is not None:
  5354. kw["visiting_cte"] = visiting_cte
  5355. toplevel = False
  5356. else:
  5357. toplevel = not self.stack
  5358. if toplevel:
  5359. self.isupdate = True
  5360. if not self.dml_compile_state:
  5361. self.dml_compile_state = compile_state
  5362. if not self.compile_state:
  5363. self.compile_state = compile_state
  5364. if self.linting & COLLECT_CARTESIAN_PRODUCTS:
  5365. from_linter = FromLinter({}, set())
  5366. warn_linting = self.linting & WARN_LINTING
  5367. if toplevel:
  5368. self.from_linter = from_linter
  5369. else:
  5370. from_linter = None
  5371. warn_linting = False
  5372. extra_froms = compile_state._extra_froms
  5373. is_multitable = bool(extra_froms)
  5374. if is_multitable:
  5375. # main table might be a JOIN
  5376. main_froms = set(_from_objects(update_stmt.table))
  5377. render_extra_froms = [
  5378. f for f in extra_froms if f not in main_froms
  5379. ]
  5380. correlate_froms = main_froms.union(extra_froms)
  5381. else:
  5382. render_extra_froms = []
  5383. correlate_froms = {update_stmt.table}
  5384. self.stack.append(
  5385. {
  5386. "correlate_froms": correlate_froms,
  5387. "asfrom_froms": correlate_froms,
  5388. "selectable": update_stmt,
  5389. }
  5390. )
  5391. text = "UPDATE "
  5392. if update_stmt._prefixes:
  5393. text += self._generate_prefixes(
  5394. update_stmt, update_stmt._prefixes, **kw
  5395. )
  5396. table_text = self.update_tables_clause(
  5397. update_stmt,
  5398. update_stmt.table,
  5399. render_extra_froms,
  5400. from_linter=from_linter,
  5401. **kw,
  5402. )
  5403. crud_params_struct = crud._get_crud_params(
  5404. self, update_stmt, compile_state, toplevel, **kw
  5405. )
  5406. crud_params = crud_params_struct.single_params
  5407. if update_stmt._hints:
  5408. dialect_hints, table_text = self._setup_crud_hints(
  5409. update_stmt, table_text
  5410. )
  5411. else:
  5412. dialect_hints = None
  5413. if update_stmt._independent_ctes:
  5414. self._dispatch_independent_ctes(update_stmt, kw)
  5415. text += table_text
  5416. text += " SET "
  5417. text += ", ".join(
  5418. expr + "=" + value
  5419. for _, expr, value, _ in cast(
  5420. "List[Tuple[Any, str, str, Any]]", crud_params
  5421. )
  5422. )
  5423. if self.implicit_returning or update_stmt._returning:
  5424. if self.returning_precedes_values:
  5425. text += " " + self.returning_clause(
  5426. update_stmt,
  5427. self.implicit_returning or update_stmt._returning,
  5428. populate_result_map=toplevel,
  5429. )
  5430. if extra_froms:
  5431. extra_from_text = self.update_from_clause(
  5432. update_stmt,
  5433. update_stmt.table,
  5434. render_extra_froms,
  5435. dialect_hints,
  5436. from_linter=from_linter,
  5437. **kw,
  5438. )
  5439. if extra_from_text:
  5440. text += " " + extra_from_text
  5441. if update_stmt._where_criteria:
  5442. t = self._generate_delimited_and_list(
  5443. update_stmt._where_criteria, from_linter=from_linter, **kw
  5444. )
  5445. if t:
  5446. text += " WHERE " + t
  5447. limit_clause = self.update_limit_clause(update_stmt)
  5448. if limit_clause:
  5449. text += " " + limit_clause
  5450. if (
  5451. self.implicit_returning or update_stmt._returning
  5452. ) and not self.returning_precedes_values:
  5453. text += " " + self.returning_clause(
  5454. update_stmt,
  5455. self.implicit_returning or update_stmt._returning,
  5456. populate_result_map=toplevel,
  5457. )
  5458. if self.ctes:
  5459. nesting_level = len(self.stack) if not toplevel else None
  5460. text = self._render_cte_clause(nesting_level=nesting_level) + text
  5461. if warn_linting:
  5462. assert from_linter is not None
  5463. from_linter.warn(stmt_type="UPDATE")
  5464. self.stack.pop(-1)
  5465. return text # type: ignore[no-any-return]
  5466. def delete_extra_from_clause(
  5467. self, delete_stmt, from_table, extra_froms, from_hints, **kw
  5468. ):
  5469. """Provide a hook to override the generation of an
  5470. DELETE..FROM clause.
  5471. This can be used to implement DELETE..USING for example.
  5472. MySQL and MSSQL override this.
  5473. """
  5474. raise NotImplementedError(
  5475. "This backend does not support multiple-table "
  5476. "criteria within DELETE"
  5477. )
  5478. def delete_table_clause(self, delete_stmt, from_table, extra_froms, **kw):
  5479. return from_table._compiler_dispatch(
  5480. self, asfrom=True, iscrud=True, **kw
  5481. )
  5482. def visit_delete(self, delete_stmt, visiting_cte=None, **kw):
  5483. compile_state = delete_stmt._compile_state_factory(
  5484. delete_stmt, self, **kw
  5485. )
  5486. delete_stmt = compile_state.statement
  5487. if visiting_cte is not None:
  5488. kw["visiting_cte"] = visiting_cte
  5489. toplevel = False
  5490. else:
  5491. toplevel = not self.stack
  5492. if toplevel:
  5493. self.isdelete = True
  5494. if not self.dml_compile_state:
  5495. self.dml_compile_state = compile_state
  5496. if not self.compile_state:
  5497. self.compile_state = compile_state
  5498. if self.linting & COLLECT_CARTESIAN_PRODUCTS:
  5499. from_linter = FromLinter({}, set())
  5500. warn_linting = self.linting & WARN_LINTING
  5501. if toplevel:
  5502. self.from_linter = from_linter
  5503. else:
  5504. from_linter = None
  5505. warn_linting = False
  5506. extra_froms = compile_state._extra_froms
  5507. correlate_froms = {delete_stmt.table}.union(extra_froms)
  5508. self.stack.append(
  5509. {
  5510. "correlate_froms": correlate_froms,
  5511. "asfrom_froms": correlate_froms,
  5512. "selectable": delete_stmt,
  5513. }
  5514. )
  5515. text = "DELETE "
  5516. if delete_stmt._prefixes:
  5517. text += self._generate_prefixes(
  5518. delete_stmt, delete_stmt._prefixes, **kw
  5519. )
  5520. text += "FROM "
  5521. try:
  5522. table_text = self.delete_table_clause(
  5523. delete_stmt,
  5524. delete_stmt.table,
  5525. extra_froms,
  5526. from_linter=from_linter,
  5527. )
  5528. except TypeError:
  5529. # anticipate 3rd party dialects that don't include **kw
  5530. # TODO: remove in 2.1
  5531. table_text = self.delete_table_clause(
  5532. delete_stmt, delete_stmt.table, extra_froms
  5533. )
  5534. if from_linter:
  5535. _ = self.process(delete_stmt.table, from_linter=from_linter)
  5536. crud._get_crud_params(self, delete_stmt, compile_state, toplevel, **kw)
  5537. if delete_stmt._hints:
  5538. dialect_hints, table_text = self._setup_crud_hints(
  5539. delete_stmt, table_text
  5540. )
  5541. else:
  5542. dialect_hints = None
  5543. if delete_stmt._independent_ctes:
  5544. self._dispatch_independent_ctes(delete_stmt, kw)
  5545. text += table_text
  5546. if (
  5547. self.implicit_returning or delete_stmt._returning
  5548. ) and self.returning_precedes_values:
  5549. text += " " + self.returning_clause(
  5550. delete_stmt,
  5551. self.implicit_returning or delete_stmt._returning,
  5552. populate_result_map=toplevel,
  5553. )
  5554. if extra_froms:
  5555. extra_from_text = self.delete_extra_from_clause(
  5556. delete_stmt,
  5557. delete_stmt.table,
  5558. extra_froms,
  5559. dialect_hints,
  5560. from_linter=from_linter,
  5561. **kw,
  5562. )
  5563. if extra_from_text:
  5564. text += " " + extra_from_text
  5565. if delete_stmt._where_criteria:
  5566. t = self._generate_delimited_and_list(
  5567. delete_stmt._where_criteria, from_linter=from_linter, **kw
  5568. )
  5569. if t:
  5570. text += " WHERE " + t
  5571. limit_clause = self.delete_limit_clause(delete_stmt)
  5572. if limit_clause:
  5573. text += " " + limit_clause
  5574. if (
  5575. self.implicit_returning or delete_stmt._returning
  5576. ) and not self.returning_precedes_values:
  5577. text += " " + self.returning_clause(
  5578. delete_stmt,
  5579. self.implicit_returning or delete_stmt._returning,
  5580. populate_result_map=toplevel,
  5581. )
  5582. if self.ctes:
  5583. nesting_level = len(self.stack) if not toplevel else None
  5584. text = self._render_cte_clause(nesting_level=nesting_level) + text
  5585. if warn_linting:
  5586. assert from_linter is not None
  5587. from_linter.warn(stmt_type="DELETE")
  5588. self.stack.pop(-1)
  5589. return text
  5590. def visit_savepoint(self, savepoint_stmt, **kw):
  5591. return "SAVEPOINT %s" % self.preparer.format_savepoint(savepoint_stmt)
  5592. def visit_rollback_to_savepoint(self, savepoint_stmt, **kw):
  5593. return "ROLLBACK TO SAVEPOINT %s" % self.preparer.format_savepoint(
  5594. savepoint_stmt
  5595. )
  5596. def visit_release_savepoint(self, savepoint_stmt, **kw):
  5597. return "RELEASE SAVEPOINT %s" % self.preparer.format_savepoint(
  5598. savepoint_stmt
  5599. )
  5600. class StrSQLCompiler(SQLCompiler):
  5601. """A :class:`.SQLCompiler` subclass which allows a small selection
  5602. of non-standard SQL features to render into a string value.
  5603. The :class:`.StrSQLCompiler` is invoked whenever a Core expression
  5604. element is directly stringified without calling upon the
  5605. :meth:`_expression.ClauseElement.compile` method.
  5606. It can render a limited set
  5607. of non-standard SQL constructs to assist in basic stringification,
  5608. however for more substantial custom or dialect-specific SQL constructs,
  5609. it will be necessary to make use of
  5610. :meth:`_expression.ClauseElement.compile`
  5611. directly.
  5612. .. seealso::
  5613. :ref:`faq_sql_expression_string`
  5614. """
  5615. def _fallback_column_name(self, column):
  5616. return "<name unknown>"
  5617. @util.preload_module("sqlalchemy.engine.url")
  5618. def visit_unsupported_compilation(self, element, err, **kw):
  5619. if element.stringify_dialect != "default":
  5620. url = util.preloaded.engine_url
  5621. dialect = url.URL.create(element.stringify_dialect).get_dialect()()
  5622. compiler = dialect.statement_compiler(
  5623. dialect, None, _supporting_against=self
  5624. )
  5625. if not isinstance(compiler, StrSQLCompiler):
  5626. return compiler.process(element, **kw)
  5627. return super().visit_unsupported_compilation(element, err)
  5628. def visit_getitem_binary(self, binary, operator, **kw):
  5629. return "%s[%s]" % (
  5630. self.process(binary.left, **kw),
  5631. self.process(binary.right, **kw),
  5632. )
  5633. def visit_json_getitem_op_binary(self, binary, operator, **kw):
  5634. return self.visit_getitem_binary(binary, operator, **kw)
  5635. def visit_json_path_getitem_op_binary(self, binary, operator, **kw):
  5636. return self.visit_getitem_binary(binary, operator, **kw)
  5637. def visit_sequence(self, sequence, **kw):
  5638. return (
  5639. f"<next sequence value: {self.preparer.format_sequence(sequence)}>"
  5640. )
  5641. def returning_clause(
  5642. self,
  5643. stmt: UpdateBase,
  5644. returning_cols: Sequence[_ColumnsClauseElement],
  5645. *,
  5646. populate_result_map: bool,
  5647. **kw: Any,
  5648. ) -> str:
  5649. columns = [
  5650. self._label_select_column(None, c, True, False, {})
  5651. for c in base._select_iterables(returning_cols)
  5652. ]
  5653. return "RETURNING " + ", ".join(columns)
  5654. def update_from_clause(
  5655. self, update_stmt, from_table, extra_froms, from_hints, **kw
  5656. ):
  5657. kw["asfrom"] = True
  5658. return "FROM " + ", ".join(
  5659. t._compiler_dispatch(self, fromhints=from_hints, **kw)
  5660. for t in extra_froms
  5661. )
  5662. def delete_extra_from_clause(
  5663. self, delete_stmt, from_table, extra_froms, from_hints, **kw
  5664. ):
  5665. kw["asfrom"] = True
  5666. return ", " + ", ".join(
  5667. t._compiler_dispatch(self, fromhints=from_hints, **kw)
  5668. for t in extra_froms
  5669. )
  5670. def visit_empty_set_expr(self, element_types, **kw):
  5671. return "SELECT 1 WHERE 1!=1"
  5672. def get_from_hint_text(self, table, text):
  5673. return "[%s]" % text
  5674. def visit_regexp_match_op_binary(self, binary, operator, **kw):
  5675. return self._generate_generic_binary(binary, " <regexp> ", **kw)
  5676. def visit_not_regexp_match_op_binary(self, binary, operator, **kw):
  5677. return self._generate_generic_binary(binary, " <not regexp> ", **kw)
  5678. def visit_regexp_replace_op_binary(self, binary, operator, **kw):
  5679. return "<regexp replace>(%s, %s)" % (
  5680. binary.left._compiler_dispatch(self, **kw),
  5681. binary.right._compiler_dispatch(self, **kw),
  5682. )
  5683. def visit_try_cast(self, cast, **kwargs):
  5684. return "TRY_CAST(%s AS %s)" % (
  5685. cast.clause._compiler_dispatch(self, **kwargs),
  5686. cast.typeclause._compiler_dispatch(self, **kwargs),
  5687. )
  5688. class DDLCompiler(Compiled):
  5689. is_ddl = True
  5690. if TYPE_CHECKING:
  5691. def __init__(
  5692. self,
  5693. dialect: Dialect,
  5694. statement: ExecutableDDLElement,
  5695. schema_translate_map: Optional[SchemaTranslateMapType] = ...,
  5696. render_schema_translate: bool = ...,
  5697. compile_kwargs: Mapping[str, Any] = ...,
  5698. ): ...
  5699. @util.ro_memoized_property
  5700. def sql_compiler(self) -> SQLCompiler:
  5701. return self.dialect.statement_compiler(
  5702. self.dialect, None, schema_translate_map=self.schema_translate_map
  5703. )
  5704. @util.memoized_property
  5705. def type_compiler(self):
  5706. return self.dialect.type_compiler_instance
  5707. def construct_params(
  5708. self,
  5709. params: Optional[_CoreSingleExecuteParams] = None,
  5710. extracted_parameters: Optional[Sequence[BindParameter[Any]]] = None,
  5711. escape_names: bool = True,
  5712. ) -> Optional[_MutableCoreSingleExecuteParams]:
  5713. return None
  5714. def visit_ddl(self, ddl, **kwargs):
  5715. # table events can substitute table and schema name
  5716. context = ddl.context
  5717. if isinstance(ddl.target, schema.Table):
  5718. context = context.copy()
  5719. preparer = self.preparer
  5720. path = preparer.format_table_seq(ddl.target)
  5721. if len(path) == 1:
  5722. table, sch = path[0], ""
  5723. else:
  5724. table, sch = path[-1], path[0]
  5725. context.setdefault("table", table)
  5726. context.setdefault("schema", sch)
  5727. context.setdefault("fullname", preparer.format_table(ddl.target))
  5728. return self.sql_compiler.post_process_text(ddl.statement % context)
  5729. def visit_create_schema(self, create, **kw):
  5730. text = "CREATE SCHEMA "
  5731. if create.if_not_exists:
  5732. text += "IF NOT EXISTS "
  5733. return text + self.preparer.format_schema(create.element)
  5734. def visit_drop_schema(self, drop, **kw):
  5735. text = "DROP SCHEMA "
  5736. if drop.if_exists:
  5737. text += "IF EXISTS "
  5738. text += self.preparer.format_schema(drop.element)
  5739. if drop.cascade:
  5740. text += " CASCADE"
  5741. return text
  5742. def visit_create_table(self, create, **kw):
  5743. table = create.element
  5744. preparer = self.preparer
  5745. text = "\nCREATE "
  5746. if table._prefixes:
  5747. text += " ".join(table._prefixes) + " "
  5748. text += "TABLE "
  5749. if create.if_not_exists:
  5750. text += "IF NOT EXISTS "
  5751. text += preparer.format_table(table) + " "
  5752. create_table_suffix = self.create_table_suffix(table)
  5753. if create_table_suffix:
  5754. text += create_table_suffix + " "
  5755. text += "("
  5756. separator = "\n"
  5757. # if only one primary key, specify it along with the column
  5758. first_pk = False
  5759. for create_column in create.columns:
  5760. column = create_column.element
  5761. try:
  5762. processed = self.process(
  5763. create_column, first_pk=column.primary_key and not first_pk
  5764. )
  5765. if processed is not None:
  5766. text += separator
  5767. separator = ", \n"
  5768. text += "\t" + processed
  5769. if column.primary_key:
  5770. first_pk = True
  5771. except exc.CompileError as ce:
  5772. raise exc.CompileError(
  5773. "(in table '%s', column '%s'): %s"
  5774. % (table.description, column.name, ce.args[0])
  5775. ) from ce
  5776. const = self.create_table_constraints(
  5777. table,
  5778. _include_foreign_key_constraints=create.include_foreign_key_constraints, # noqa
  5779. )
  5780. if const:
  5781. text += separator + "\t" + const
  5782. text += "\n)%s\n\n" % self.post_create_table(table)
  5783. return text
  5784. def visit_create_column(self, create, first_pk=False, **kw):
  5785. column = create.element
  5786. if column.system:
  5787. return None
  5788. text = self.get_column_specification(column, first_pk=first_pk)
  5789. const = " ".join(
  5790. self.process(constraint) for constraint in column.constraints
  5791. )
  5792. if const:
  5793. text += " " + const
  5794. return text
  5795. def create_table_constraints(
  5796. self, table, _include_foreign_key_constraints=None, **kw
  5797. ):
  5798. # On some DB order is significant: visit PK first, then the
  5799. # other constraints (engine.ReflectionTest.testbasic failed on FB2)
  5800. constraints = []
  5801. if table.primary_key:
  5802. constraints.append(table.primary_key)
  5803. all_fkcs = table.foreign_key_constraints
  5804. if _include_foreign_key_constraints is not None:
  5805. omit_fkcs = all_fkcs.difference(_include_foreign_key_constraints)
  5806. else:
  5807. omit_fkcs = set()
  5808. constraints.extend(
  5809. [
  5810. c
  5811. for c in table._sorted_constraints
  5812. if c is not table.primary_key and c not in omit_fkcs
  5813. ]
  5814. )
  5815. return ", \n\t".join(
  5816. p
  5817. for p in (
  5818. self.process(constraint)
  5819. for constraint in constraints
  5820. if (constraint._should_create_for_compiler(self))
  5821. and (
  5822. not self.dialect.supports_alter
  5823. or not getattr(constraint, "use_alter", False)
  5824. )
  5825. )
  5826. if p is not None
  5827. )
  5828. def visit_drop_table(self, drop, **kw):
  5829. text = "\nDROP TABLE "
  5830. if drop.if_exists:
  5831. text += "IF EXISTS "
  5832. return text + self.preparer.format_table(drop.element)
  5833. def visit_drop_view(self, drop, **kw):
  5834. return "\nDROP VIEW " + self.preparer.format_table(drop.element)
  5835. def _verify_index_table(self, index: Index) -> None:
  5836. if index.table is None:
  5837. raise exc.CompileError(
  5838. "Index '%s' is not associated with any table." % index.name
  5839. )
  5840. def visit_create_index(
  5841. self, create, include_schema=False, include_table_schema=True, **kw
  5842. ):
  5843. index = create.element
  5844. self._verify_index_table(index)
  5845. preparer = self.preparer
  5846. text = "CREATE "
  5847. if index.unique:
  5848. text += "UNIQUE "
  5849. if index.name is None:
  5850. raise exc.CompileError(
  5851. "CREATE INDEX requires that the index have a name"
  5852. )
  5853. text += "INDEX "
  5854. if create.if_not_exists:
  5855. text += "IF NOT EXISTS "
  5856. text += "%s ON %s (%s)" % (
  5857. self._prepared_index_name(index, include_schema=include_schema),
  5858. preparer.format_table(
  5859. index.table, use_schema=include_table_schema
  5860. ),
  5861. ", ".join(
  5862. self.sql_compiler.process(
  5863. expr, include_table=False, literal_binds=True
  5864. )
  5865. for expr in index.expressions
  5866. ),
  5867. )
  5868. return text
  5869. def visit_drop_index(self, drop, **kw):
  5870. index = drop.element
  5871. if index.name is None:
  5872. raise exc.CompileError(
  5873. "DROP INDEX requires that the index have a name"
  5874. )
  5875. text = "\nDROP INDEX "
  5876. if drop.if_exists:
  5877. text += "IF EXISTS "
  5878. return text + self._prepared_index_name(index, include_schema=True)
  5879. def _prepared_index_name(
  5880. self, index: Index, include_schema: bool = False
  5881. ) -> str:
  5882. if index.table is not None:
  5883. effective_schema = self.preparer.schema_for_object(index.table)
  5884. else:
  5885. effective_schema = None
  5886. if include_schema and effective_schema:
  5887. schema_name = self.preparer.quote_schema(effective_schema)
  5888. else:
  5889. schema_name = None
  5890. index_name: str = self.preparer.format_index(index)
  5891. if schema_name:
  5892. index_name = schema_name + "." + index_name
  5893. return index_name
  5894. def visit_add_constraint(self, create, **kw):
  5895. return "ALTER TABLE %s ADD %s" % (
  5896. self.preparer.format_table(create.element.table),
  5897. self.process(create.element),
  5898. )
  5899. def visit_set_table_comment(self, create, **kw):
  5900. return "COMMENT ON TABLE %s IS %s" % (
  5901. self.preparer.format_table(create.element),
  5902. self.sql_compiler.render_literal_value(
  5903. create.element.comment, sqltypes.String()
  5904. ),
  5905. )
  5906. def visit_drop_table_comment(self, drop, **kw):
  5907. return "COMMENT ON TABLE %s IS NULL" % self.preparer.format_table(
  5908. drop.element
  5909. )
  5910. def visit_set_column_comment(self, create, **kw):
  5911. return "COMMENT ON COLUMN %s IS %s" % (
  5912. self.preparer.format_column(
  5913. create.element, use_table=True, use_schema=True
  5914. ),
  5915. self.sql_compiler.render_literal_value(
  5916. create.element.comment, sqltypes.String()
  5917. ),
  5918. )
  5919. def visit_drop_column_comment(self, drop, **kw):
  5920. return "COMMENT ON COLUMN %s IS NULL" % self.preparer.format_column(
  5921. drop.element, use_table=True
  5922. )
  5923. def visit_set_constraint_comment(self, create, **kw):
  5924. raise exc.UnsupportedCompilationError(self, type(create))
  5925. def visit_drop_constraint_comment(self, drop, **kw):
  5926. raise exc.UnsupportedCompilationError(self, type(drop))
  5927. def get_identity_options(self, identity_options: IdentityOptions) -> str:
  5928. text = []
  5929. if identity_options.increment is not None:
  5930. text.append("INCREMENT BY %d" % identity_options.increment)
  5931. if identity_options.start is not None:
  5932. text.append("START WITH %d" % identity_options.start)
  5933. if identity_options.minvalue is not None:
  5934. text.append("MINVALUE %d" % identity_options.minvalue)
  5935. if identity_options.maxvalue is not None:
  5936. text.append("MAXVALUE %d" % identity_options.maxvalue)
  5937. if identity_options.nominvalue is not None:
  5938. text.append("NO MINVALUE")
  5939. if identity_options.nomaxvalue is not None:
  5940. text.append("NO MAXVALUE")
  5941. if identity_options.cache is not None:
  5942. text.append("CACHE %d" % identity_options.cache)
  5943. if identity_options.cycle is not None:
  5944. text.append("CYCLE" if identity_options.cycle else "NO CYCLE")
  5945. return " ".join(text)
  5946. def visit_create_sequence(self, create, prefix=None, **kw):
  5947. text = "CREATE SEQUENCE "
  5948. if create.if_not_exists:
  5949. text += "IF NOT EXISTS "
  5950. text += self.preparer.format_sequence(create.element)
  5951. if prefix:
  5952. text += prefix
  5953. options = self.get_identity_options(create.element)
  5954. if options:
  5955. text += " " + options
  5956. return text
  5957. def visit_drop_sequence(self, drop, **kw):
  5958. text = "DROP SEQUENCE "
  5959. if drop.if_exists:
  5960. text += "IF EXISTS "
  5961. return text + self.preparer.format_sequence(drop.element)
  5962. def visit_drop_constraint(self, drop, **kw):
  5963. constraint = drop.element
  5964. if constraint.name is not None:
  5965. formatted_name = self.preparer.format_constraint(constraint)
  5966. else:
  5967. formatted_name = None
  5968. if formatted_name is None:
  5969. raise exc.CompileError(
  5970. "Can't emit DROP CONSTRAINT for constraint %r; "
  5971. "it has no name" % drop.element
  5972. )
  5973. return "ALTER TABLE %s DROP CONSTRAINT %s%s%s" % (
  5974. self.preparer.format_table(drop.element.table),
  5975. "IF EXISTS " if drop.if_exists else "",
  5976. formatted_name,
  5977. " CASCADE" if drop.cascade else "",
  5978. )
  5979. def get_column_specification(self, column, **kwargs):
  5980. colspec = (
  5981. self.preparer.format_column(column)
  5982. + " "
  5983. + self.dialect.type_compiler_instance.process(
  5984. column.type, type_expression=column
  5985. )
  5986. )
  5987. default = self.get_column_default_string(column)
  5988. if default is not None:
  5989. colspec += " DEFAULT " + default
  5990. if column.computed is not None:
  5991. colspec += " " + self.process(column.computed)
  5992. if (
  5993. column.identity is not None
  5994. and self.dialect.supports_identity_columns
  5995. ):
  5996. colspec += " " + self.process(column.identity)
  5997. if not column.nullable and (
  5998. not column.identity or not self.dialect.supports_identity_columns
  5999. ):
  6000. colspec += " NOT NULL"
  6001. return colspec
  6002. def create_table_suffix(self, table):
  6003. return ""
  6004. def post_create_table(self, table):
  6005. return ""
  6006. def get_column_default_string(self, column: Column[Any]) -> Optional[str]:
  6007. if isinstance(column.server_default, schema.DefaultClause):
  6008. return self.render_default_string(column.server_default.arg)
  6009. else:
  6010. return None
  6011. def render_default_string(self, default: Union[Visitable, str]) -> str:
  6012. if isinstance(default, str):
  6013. return self.sql_compiler.render_literal_value(
  6014. default, sqltypes.STRINGTYPE
  6015. )
  6016. else:
  6017. return self.sql_compiler.process(default, literal_binds=True)
  6018. def visit_table_or_column_check_constraint(self, constraint, **kw):
  6019. if constraint.is_column_level:
  6020. return self.visit_column_check_constraint(constraint)
  6021. else:
  6022. return self.visit_check_constraint(constraint)
  6023. def visit_check_constraint(self, constraint, **kw):
  6024. text = self.define_constraint_preamble(constraint, **kw)
  6025. text += self.define_check_body(constraint, **kw)
  6026. text += self.define_constraint_deferrability(constraint)
  6027. return text
  6028. def visit_column_check_constraint(self, constraint, **kw):
  6029. text = self.define_constraint_preamble(constraint, **kw)
  6030. text += self.define_check_body(constraint, **kw)
  6031. text += self.define_constraint_deferrability(constraint)
  6032. return text
  6033. def visit_primary_key_constraint(
  6034. self, constraint: PrimaryKeyConstraint, **kw: Any
  6035. ) -> str:
  6036. if len(constraint) == 0:
  6037. return ""
  6038. text = self.define_constraint_preamble(constraint, **kw)
  6039. text += self.define_primary_key_body(constraint, **kw)
  6040. text += self.define_constraint_deferrability(constraint)
  6041. return text
  6042. def visit_foreign_key_constraint(
  6043. self, constraint: ForeignKeyConstraint, **kw: Any
  6044. ) -> str:
  6045. text = self.define_constraint_preamble(constraint, **kw)
  6046. text += self.define_foreign_key_body(constraint, **kw)
  6047. text += self.define_constraint_match(constraint)
  6048. text += self.define_constraint_cascades(constraint)
  6049. text += self.define_constraint_deferrability(constraint)
  6050. return text
  6051. def define_constraint_remote_table(self, constraint, table, preparer):
  6052. """Format the remote table clause of a CREATE CONSTRAINT clause."""
  6053. return preparer.format_table(table)
  6054. def visit_unique_constraint(
  6055. self, constraint: UniqueConstraint, **kw: Any
  6056. ) -> str:
  6057. if len(constraint) == 0:
  6058. return ""
  6059. text = self.define_constraint_preamble(constraint, **kw)
  6060. text += self.define_unique_body(constraint, **kw)
  6061. text += self.define_constraint_deferrability(constraint)
  6062. return text
  6063. def define_constraint_preamble(
  6064. self, constraint: Constraint, **kw: Any
  6065. ) -> str:
  6066. text = ""
  6067. if constraint.name is not None:
  6068. formatted_name = self.preparer.format_constraint(constraint)
  6069. if formatted_name is not None:
  6070. text += "CONSTRAINT %s " % formatted_name
  6071. return text
  6072. def define_primary_key_body(
  6073. self, constraint: PrimaryKeyConstraint, **kw: Any
  6074. ) -> str:
  6075. text = ""
  6076. text += "PRIMARY KEY "
  6077. text += "(%s)" % ", ".join(
  6078. self.preparer.quote(c.name)
  6079. for c in (
  6080. constraint.columns_autoinc_first
  6081. if constraint._implicit_generated
  6082. else constraint.columns
  6083. )
  6084. )
  6085. return text
  6086. def define_foreign_key_body(
  6087. self, constraint: ForeignKeyConstraint, **kw: Any
  6088. ) -> str:
  6089. preparer = self.preparer
  6090. remote_table = list(constraint.elements)[0].column.table
  6091. text = "FOREIGN KEY(%s) REFERENCES %s (%s)" % (
  6092. ", ".join(
  6093. preparer.quote(f.parent.name) for f in constraint.elements
  6094. ),
  6095. self.define_constraint_remote_table(
  6096. constraint, remote_table, preparer
  6097. ),
  6098. ", ".join(
  6099. preparer.quote(f.column.name) for f in constraint.elements
  6100. ),
  6101. )
  6102. return text
  6103. def define_unique_body(
  6104. self, constraint: UniqueConstraint, **kw: Any
  6105. ) -> str:
  6106. text = "UNIQUE %s(%s)" % (
  6107. self.define_unique_constraint_distinct(constraint, **kw),
  6108. ", ".join(self.preparer.quote(c.name) for c in constraint),
  6109. )
  6110. return text
  6111. def define_check_body(self, constraint: CheckConstraint, **kw: Any) -> str:
  6112. text = "CHECK (%s)" % self.sql_compiler.process(
  6113. constraint.sqltext, include_table=False, literal_binds=True
  6114. )
  6115. return text
  6116. def define_unique_constraint_distinct(
  6117. self, constraint: UniqueConstraint, **kw: Any
  6118. ) -> str:
  6119. return ""
  6120. def define_constraint_cascades(
  6121. self, constraint: ForeignKeyConstraint
  6122. ) -> str:
  6123. text = ""
  6124. if constraint.ondelete is not None:
  6125. text += self.define_constraint_ondelete_cascade(constraint)
  6126. if constraint.onupdate is not None:
  6127. text += self.define_constraint_onupdate_cascade(constraint)
  6128. return text
  6129. def define_constraint_ondelete_cascade(
  6130. self, constraint: ForeignKeyConstraint
  6131. ) -> str:
  6132. return " ON DELETE %s" % self.preparer.validate_sql_phrase(
  6133. constraint.ondelete, FK_ON_DELETE
  6134. )
  6135. def define_constraint_onupdate_cascade(
  6136. self, constraint: ForeignKeyConstraint
  6137. ) -> str:
  6138. return " ON UPDATE %s" % self.preparer.validate_sql_phrase(
  6139. constraint.onupdate, FK_ON_UPDATE
  6140. )
  6141. def define_constraint_deferrability(self, constraint: Constraint) -> str:
  6142. text = ""
  6143. if constraint.deferrable is not None:
  6144. if constraint.deferrable:
  6145. text += " DEFERRABLE"
  6146. else:
  6147. text += " NOT DEFERRABLE"
  6148. if constraint.initially is not None:
  6149. text += " INITIALLY %s" % self.preparer.validate_sql_phrase(
  6150. constraint.initially, FK_INITIALLY
  6151. )
  6152. return text
  6153. def define_constraint_match(self, constraint: ForeignKeyConstraint) -> str:
  6154. text = ""
  6155. if constraint.match is not None:
  6156. text += " MATCH %s" % constraint.match
  6157. return text
  6158. def visit_computed_column(self, generated, **kw):
  6159. text = "GENERATED ALWAYS AS (%s)" % self.sql_compiler.process(
  6160. generated.sqltext, include_table=False, literal_binds=True
  6161. )
  6162. if generated.persisted is True:
  6163. text += " STORED"
  6164. elif generated.persisted is False:
  6165. text += " VIRTUAL"
  6166. return text
  6167. def visit_identity_column(self, identity, **kw):
  6168. text = "GENERATED %s AS IDENTITY" % (
  6169. "ALWAYS" if identity.always else "BY DEFAULT",
  6170. )
  6171. options = self.get_identity_options(identity)
  6172. if options:
  6173. text += " (%s)" % options
  6174. return text
  6175. class GenericTypeCompiler(TypeCompiler):
  6176. def visit_FLOAT(self, type_: sqltypes.Float[Any], **kw: Any) -> str:
  6177. return "FLOAT"
  6178. def visit_DOUBLE(self, type_: sqltypes.Double[Any], **kw: Any) -> str:
  6179. return "DOUBLE"
  6180. def visit_DOUBLE_PRECISION(
  6181. self, type_: sqltypes.DOUBLE_PRECISION[Any], **kw: Any
  6182. ) -> str:
  6183. return "DOUBLE PRECISION"
  6184. def visit_REAL(self, type_: sqltypes.REAL[Any], **kw: Any) -> str:
  6185. return "REAL"
  6186. def visit_NUMERIC(self, type_: sqltypes.Numeric[Any], **kw: Any) -> str:
  6187. if type_.precision is None:
  6188. return "NUMERIC"
  6189. elif type_.scale is None:
  6190. return "NUMERIC(%(precision)s)" % {"precision": type_.precision}
  6191. else:
  6192. return "NUMERIC(%(precision)s, %(scale)s)" % {
  6193. "precision": type_.precision,
  6194. "scale": type_.scale,
  6195. }
  6196. def visit_DECIMAL(self, type_: sqltypes.DECIMAL[Any], **kw: Any) -> str:
  6197. if type_.precision is None:
  6198. return "DECIMAL"
  6199. elif type_.scale is None:
  6200. return "DECIMAL(%(precision)s)" % {"precision": type_.precision}
  6201. else:
  6202. return "DECIMAL(%(precision)s, %(scale)s)" % {
  6203. "precision": type_.precision,
  6204. "scale": type_.scale,
  6205. }
  6206. def visit_INTEGER(self, type_: sqltypes.Integer, **kw: Any) -> str:
  6207. return "INTEGER"
  6208. def visit_SMALLINT(self, type_: sqltypes.SmallInteger, **kw: Any) -> str:
  6209. return "SMALLINT"
  6210. def visit_BIGINT(self, type_: sqltypes.BigInteger, **kw: Any) -> str:
  6211. return "BIGINT"
  6212. def visit_TIMESTAMP(self, type_: sqltypes.TIMESTAMP, **kw: Any) -> str:
  6213. return "TIMESTAMP"
  6214. def visit_DATETIME(self, type_: sqltypes.DateTime, **kw: Any) -> str:
  6215. return "DATETIME"
  6216. def visit_DATE(self, type_: sqltypes.Date, **kw: Any) -> str:
  6217. return "DATE"
  6218. def visit_TIME(self, type_: sqltypes.Time, **kw: Any) -> str:
  6219. return "TIME"
  6220. def visit_CLOB(self, type_: sqltypes.CLOB, **kw: Any) -> str:
  6221. return "CLOB"
  6222. def visit_NCLOB(self, type_: sqltypes.Text, **kw: Any) -> str:
  6223. return "NCLOB"
  6224. def _render_string_type(
  6225. self, name: str, length: Optional[int], collation: Optional[str]
  6226. ) -> str:
  6227. text = name
  6228. if length:
  6229. text += f"({length})"
  6230. if collation:
  6231. text += f' COLLATE "{collation}"'
  6232. return text
  6233. def visit_CHAR(self, type_: sqltypes.CHAR, **kw: Any) -> str:
  6234. return self._render_string_type("CHAR", type_.length, type_.collation)
  6235. def visit_NCHAR(self, type_: sqltypes.NCHAR, **kw: Any) -> str:
  6236. return self._render_string_type("NCHAR", type_.length, type_.collation)
  6237. def visit_VARCHAR(self, type_: sqltypes.String, **kw: Any) -> str:
  6238. return self._render_string_type(
  6239. "VARCHAR", type_.length, type_.collation
  6240. )
  6241. def visit_NVARCHAR(self, type_: sqltypes.NVARCHAR, **kw: Any) -> str:
  6242. return self._render_string_type(
  6243. "NVARCHAR", type_.length, type_.collation
  6244. )
  6245. def visit_TEXT(self, type_: sqltypes.Text, **kw: Any) -> str:
  6246. return self._render_string_type("TEXT", type_.length, type_.collation)
  6247. def visit_UUID(self, type_: sqltypes.Uuid[Any], **kw: Any) -> str:
  6248. return "UUID"
  6249. def visit_BLOB(self, type_: sqltypes.LargeBinary, **kw: Any) -> str:
  6250. return "BLOB"
  6251. def visit_BINARY(self, type_: sqltypes.BINARY, **kw: Any) -> str:
  6252. return "BINARY" + (type_.length and "(%d)" % type_.length or "")
  6253. def visit_VARBINARY(self, type_: sqltypes.VARBINARY, **kw: Any) -> str:
  6254. return "VARBINARY" + (type_.length and "(%d)" % type_.length or "")
  6255. def visit_BOOLEAN(self, type_: sqltypes.Boolean, **kw: Any) -> str:
  6256. return "BOOLEAN"
  6257. def visit_uuid(self, type_: sqltypes.Uuid[Any], **kw: Any) -> str:
  6258. if not type_.native_uuid or not self.dialect.supports_native_uuid:
  6259. return self._render_string_type("CHAR", length=32, collation=None)
  6260. else:
  6261. return self.visit_UUID(type_, **kw)
  6262. def visit_large_binary(
  6263. self, type_: sqltypes.LargeBinary, **kw: Any
  6264. ) -> str:
  6265. return self.visit_BLOB(type_, **kw)
  6266. def visit_boolean(self, type_: sqltypes.Boolean, **kw: Any) -> str:
  6267. return self.visit_BOOLEAN(type_, **kw)
  6268. def visit_time(self, type_: sqltypes.Time, **kw: Any) -> str:
  6269. return self.visit_TIME(type_, **kw)
  6270. def visit_datetime(self, type_: sqltypes.DateTime, **kw: Any) -> str:
  6271. return self.visit_DATETIME(type_, **kw)
  6272. def visit_date(self, type_: sqltypes.Date, **kw: Any) -> str:
  6273. return self.visit_DATE(type_, **kw)
  6274. def visit_big_integer(self, type_: sqltypes.BigInteger, **kw: Any) -> str:
  6275. return self.visit_BIGINT(type_, **kw)
  6276. def visit_small_integer(
  6277. self, type_: sqltypes.SmallInteger, **kw: Any
  6278. ) -> str:
  6279. return self.visit_SMALLINT(type_, **kw)
  6280. def visit_integer(self, type_: sqltypes.Integer, **kw: Any) -> str:
  6281. return self.visit_INTEGER(type_, **kw)
  6282. def visit_real(self, type_: sqltypes.REAL[Any], **kw: Any) -> str:
  6283. return self.visit_REAL(type_, **kw)
  6284. def visit_float(self, type_: sqltypes.Float[Any], **kw: Any) -> str:
  6285. return self.visit_FLOAT(type_, **kw)
  6286. def visit_double(self, type_: sqltypes.Double[Any], **kw: Any) -> str:
  6287. return self.visit_DOUBLE(type_, **kw)
  6288. def visit_numeric(self, type_: sqltypes.Numeric[Any], **kw: Any) -> str:
  6289. return self.visit_NUMERIC(type_, **kw)
  6290. def visit_string(self, type_: sqltypes.String, **kw: Any) -> str:
  6291. return self.visit_VARCHAR(type_, **kw)
  6292. def visit_unicode(self, type_: sqltypes.Unicode, **kw: Any) -> str:
  6293. return self.visit_VARCHAR(type_, **kw)
  6294. def visit_text(self, type_: sqltypes.Text, **kw: Any) -> str:
  6295. return self.visit_TEXT(type_, **kw)
  6296. def visit_unicode_text(
  6297. self, type_: sqltypes.UnicodeText, **kw: Any
  6298. ) -> str:
  6299. return self.visit_TEXT(type_, **kw)
  6300. def visit_enum(self, type_: sqltypes.Enum, **kw: Any) -> str:
  6301. return self.visit_VARCHAR(type_, **kw)
  6302. def visit_null(self, type_, **kw):
  6303. raise exc.CompileError(
  6304. "Can't generate DDL for %r; "
  6305. "did you forget to specify a "
  6306. "type on this Column?" % type_
  6307. )
  6308. def visit_type_decorator(
  6309. self, type_: TypeDecorator[Any], **kw: Any
  6310. ) -> str:
  6311. return self.process(type_.type_engine(self.dialect), **kw)
  6312. def visit_user_defined(
  6313. self, type_: UserDefinedType[Any], **kw: Any
  6314. ) -> str:
  6315. return type_.get_col_spec(**kw)
  6316. class StrSQLTypeCompiler(GenericTypeCompiler):
  6317. def process(self, type_, **kw):
  6318. try:
  6319. _compiler_dispatch = type_._compiler_dispatch
  6320. except AttributeError:
  6321. return self._visit_unknown(type_, **kw)
  6322. else:
  6323. return _compiler_dispatch(self, **kw)
  6324. def __getattr__(self, key):
  6325. if key.startswith("visit_"):
  6326. return self._visit_unknown
  6327. else:
  6328. raise AttributeError(key)
  6329. def _visit_unknown(self, type_, **kw):
  6330. if type_.__class__.__name__ == type_.__class__.__name__.upper():
  6331. return type_.__class__.__name__
  6332. else:
  6333. return repr(type_)
  6334. def visit_null(self, type_, **kw):
  6335. return "NULL"
  6336. def visit_user_defined(self, type_, **kw):
  6337. try:
  6338. get_col_spec = type_.get_col_spec
  6339. except AttributeError:
  6340. return repr(type_)
  6341. else:
  6342. return get_col_spec(**kw)
  6343. class _SchemaForObjectCallable(Protocol):
  6344. def __call__(self, __obj: Any) -> str: ...
  6345. class _BindNameForColProtocol(Protocol):
  6346. def __call__(self, col: ColumnClause[Any]) -> str: ...
  6347. class IdentifierPreparer:
  6348. """Handle quoting and case-folding of identifiers based on options."""
  6349. reserved_words = RESERVED_WORDS
  6350. legal_characters = LEGAL_CHARACTERS
  6351. illegal_initial_characters = ILLEGAL_INITIAL_CHARACTERS
  6352. initial_quote: str
  6353. final_quote: str
  6354. _strings: MutableMapping[str, str]
  6355. schema_for_object: _SchemaForObjectCallable = operator.attrgetter("schema")
  6356. """Return the .schema attribute for an object.
  6357. For the default IdentifierPreparer, the schema for an object is always
  6358. the value of the ".schema" attribute. if the preparer is replaced
  6359. with one that has a non-empty schema_translate_map, the value of the
  6360. ".schema" attribute is rendered a symbol that will be converted to a
  6361. real schema name from the mapping post-compile.
  6362. """
  6363. _includes_none_schema_translate: bool = False
  6364. def __init__(
  6365. self,
  6366. dialect: Dialect,
  6367. initial_quote: str = '"',
  6368. final_quote: Optional[str] = None,
  6369. escape_quote: str = '"',
  6370. quote_case_sensitive_collations: bool = True,
  6371. omit_schema: bool = False,
  6372. ):
  6373. """Construct a new ``IdentifierPreparer`` object.
  6374. initial_quote
  6375. Character that begins a delimited identifier.
  6376. final_quote
  6377. Character that ends a delimited identifier. Defaults to
  6378. `initial_quote`.
  6379. omit_schema
  6380. Prevent prepending schema name. Useful for databases that do
  6381. not support schemae.
  6382. """
  6383. self.dialect = dialect
  6384. self.initial_quote = initial_quote
  6385. self.final_quote = final_quote or self.initial_quote
  6386. self.escape_quote = escape_quote
  6387. self.escape_to_quote = self.escape_quote * 2
  6388. self.omit_schema = omit_schema
  6389. self.quote_case_sensitive_collations = quote_case_sensitive_collations
  6390. self._strings = {}
  6391. self._double_percents = self.dialect.paramstyle in (
  6392. "format",
  6393. "pyformat",
  6394. )
  6395. def _with_schema_translate(self, schema_translate_map):
  6396. prep = self.__class__.__new__(self.__class__)
  6397. prep.__dict__.update(self.__dict__)
  6398. includes_none = None in schema_translate_map
  6399. def symbol_getter(obj):
  6400. name = obj.schema
  6401. if obj._use_schema_map and (name is not None or includes_none):
  6402. if name is not None and ("[" in name or "]" in name):
  6403. raise exc.CompileError(
  6404. "Square bracket characters ([]) not supported "
  6405. "in schema translate name '%s'" % name
  6406. )
  6407. return quoted_name(
  6408. "__[SCHEMA_%s]" % (name or "_none"), quote=False
  6409. )
  6410. else:
  6411. return obj.schema
  6412. prep.schema_for_object = symbol_getter
  6413. prep._includes_none_schema_translate = includes_none
  6414. return prep
  6415. def _render_schema_translates(
  6416. self, statement: str, schema_translate_map: SchemaTranslateMapType
  6417. ) -> str:
  6418. d = schema_translate_map
  6419. if None in d:
  6420. if not self._includes_none_schema_translate:
  6421. raise exc.InvalidRequestError(
  6422. "schema translate map which previously did not have "
  6423. "`None` present as a key now has `None` present; compiled "
  6424. "statement may lack adequate placeholders. Please use "
  6425. "consistent keys in successive "
  6426. "schema_translate_map dictionaries."
  6427. )
  6428. d["_none"] = d[None] # type: ignore[index]
  6429. def replace(m):
  6430. name = m.group(2)
  6431. if name in d:
  6432. effective_schema = d[name]
  6433. else:
  6434. if name in (None, "_none"):
  6435. raise exc.InvalidRequestError(
  6436. "schema translate map which previously had `None` "
  6437. "present as a key now no longer has it present; don't "
  6438. "know how to apply schema for compiled statement. "
  6439. "Please use consistent keys in successive "
  6440. "schema_translate_map dictionaries."
  6441. )
  6442. effective_schema = name
  6443. if not effective_schema:
  6444. effective_schema = self.dialect.default_schema_name
  6445. if not effective_schema:
  6446. # TODO: no coverage here
  6447. raise exc.CompileError(
  6448. "Dialect has no default schema name; can't "
  6449. "use None as dynamic schema target."
  6450. )
  6451. return self.quote_schema(effective_schema)
  6452. return re.sub(r"(__\[SCHEMA_([^\]]+)\])", replace, statement)
  6453. def _escape_identifier(self, value: str) -> str:
  6454. """Escape an identifier.
  6455. Subclasses should override this to provide database-dependent
  6456. escaping behavior.
  6457. """
  6458. value = value.replace(self.escape_quote, self.escape_to_quote)
  6459. if self._double_percents:
  6460. value = value.replace("%", "%%")
  6461. return value
  6462. def _unescape_identifier(self, value: str) -> str:
  6463. """Canonicalize an escaped identifier.
  6464. Subclasses should override this to provide database-dependent
  6465. unescaping behavior that reverses _escape_identifier.
  6466. """
  6467. return value.replace(self.escape_to_quote, self.escape_quote)
  6468. def validate_sql_phrase(self, element, reg):
  6469. """keyword sequence filter.
  6470. a filter for elements that are intended to represent keyword sequences,
  6471. such as "INITIALLY", "INITIALLY DEFERRED", etc. no special characters
  6472. should be present.
  6473. .. versionadded:: 1.3
  6474. """
  6475. if element is not None and not reg.match(element):
  6476. raise exc.CompileError(
  6477. "Unexpected SQL phrase: %r (matching against %r)"
  6478. % (element, reg.pattern)
  6479. )
  6480. return element
  6481. def quote_identifier(self, value: str) -> str:
  6482. """Quote an identifier.
  6483. Subclasses should override this to provide database-dependent
  6484. quoting behavior.
  6485. """
  6486. return (
  6487. self.initial_quote
  6488. + self._escape_identifier(value)
  6489. + self.final_quote
  6490. )
  6491. def _requires_quotes(self, value: str) -> bool:
  6492. """Return True if the given identifier requires quoting."""
  6493. lc_value = value.lower()
  6494. return (
  6495. lc_value in self.reserved_words
  6496. or value[0] in self.illegal_initial_characters
  6497. or not self.legal_characters.match(str(value))
  6498. or (lc_value != value)
  6499. )
  6500. def _requires_quotes_illegal_chars(self, value):
  6501. """Return True if the given identifier requires quoting, but
  6502. not taking case convention into account."""
  6503. return not self.legal_characters.match(str(value))
  6504. def quote_schema(self, schema: str, force: Any = None) -> str:
  6505. """Conditionally quote a schema name.
  6506. The name is quoted if it is a reserved word, contains quote-necessary
  6507. characters, or is an instance of :class:`.quoted_name` which includes
  6508. ``quote`` set to ``True``.
  6509. Subclasses can override this to provide database-dependent
  6510. quoting behavior for schema names.
  6511. :param schema: string schema name
  6512. :param force: unused
  6513. .. deprecated:: 0.9
  6514. The :paramref:`.IdentifierPreparer.quote_schema.force`
  6515. parameter is deprecated and will be removed in a future
  6516. release. This flag has no effect on the behavior of the
  6517. :meth:`.IdentifierPreparer.quote` method; please refer to
  6518. :class:`.quoted_name`.
  6519. """
  6520. if force is not None:
  6521. # not using the util.deprecated_params() decorator in this
  6522. # case because of the additional function call overhead on this
  6523. # very performance-critical spot.
  6524. util.warn_deprecated(
  6525. "The IdentifierPreparer.quote_schema.force parameter is "
  6526. "deprecated and will be removed in a future release. This "
  6527. "flag has no effect on the behavior of the "
  6528. "IdentifierPreparer.quote method; please refer to "
  6529. "quoted_name().",
  6530. # deprecated 0.9. warning from 1.3
  6531. version="0.9",
  6532. )
  6533. return self.quote(schema)
  6534. def quote(self, ident: str, force: Any = None) -> str:
  6535. """Conditionally quote an identifier.
  6536. The identifier is quoted if it is a reserved word, contains
  6537. quote-necessary characters, or is an instance of
  6538. :class:`.quoted_name` which includes ``quote`` set to ``True``.
  6539. Subclasses can override this to provide database-dependent
  6540. quoting behavior for identifier names.
  6541. :param ident: string identifier
  6542. :param force: unused
  6543. .. deprecated:: 0.9
  6544. The :paramref:`.IdentifierPreparer.quote.force`
  6545. parameter is deprecated and will be removed in a future
  6546. release. This flag has no effect on the behavior of the
  6547. :meth:`.IdentifierPreparer.quote` method; please refer to
  6548. :class:`.quoted_name`.
  6549. """
  6550. if force is not None:
  6551. # not using the util.deprecated_params() decorator in this
  6552. # case because of the additional function call overhead on this
  6553. # very performance-critical spot.
  6554. util.warn_deprecated(
  6555. "The IdentifierPreparer.quote.force parameter is "
  6556. "deprecated and will be removed in a future release. This "
  6557. "flag has no effect on the behavior of the "
  6558. "IdentifierPreparer.quote method; please refer to "
  6559. "quoted_name().",
  6560. # deprecated 0.9. warning from 1.3
  6561. version="0.9",
  6562. )
  6563. force = getattr(ident, "quote", None)
  6564. if force is None:
  6565. if ident in self._strings:
  6566. return self._strings[ident]
  6567. else:
  6568. if self._requires_quotes(ident):
  6569. self._strings[ident] = self.quote_identifier(ident)
  6570. else:
  6571. self._strings[ident] = ident
  6572. return self._strings[ident]
  6573. elif force:
  6574. return self.quote_identifier(ident)
  6575. else:
  6576. return ident
  6577. def format_collation(self, collation_name):
  6578. if self.quote_case_sensitive_collations:
  6579. return self.quote(collation_name)
  6580. else:
  6581. return collation_name
  6582. def format_sequence(
  6583. self, sequence: schema.Sequence, use_schema: bool = True
  6584. ) -> str:
  6585. name = self.quote(sequence.name)
  6586. effective_schema = self.schema_for_object(sequence)
  6587. if (
  6588. not self.omit_schema
  6589. and use_schema
  6590. and effective_schema is not None
  6591. ):
  6592. name = self.quote_schema(effective_schema) + "." + name
  6593. return name
  6594. def format_label(
  6595. self, label: Label[Any], name: Optional[str] = None
  6596. ) -> str:
  6597. return self.quote(name or label.name)
  6598. def format_alias(
  6599. self, alias: Optional[AliasedReturnsRows], name: Optional[str] = None
  6600. ) -> str:
  6601. if name is None:
  6602. assert alias is not None
  6603. return self.quote(alias.name)
  6604. else:
  6605. return self.quote(name)
  6606. def format_savepoint(self, savepoint, name=None):
  6607. # Running the savepoint name through quoting is unnecessary
  6608. # for all known dialects. This is here to support potential
  6609. # third party use cases
  6610. ident = name or savepoint.ident
  6611. if self._requires_quotes(ident):
  6612. ident = self.quote_identifier(ident)
  6613. return ident
  6614. @util.preload_module("sqlalchemy.sql.naming")
  6615. def format_constraint(
  6616. self, constraint: Union[Constraint, Index], _alembic_quote: bool = True
  6617. ) -> Optional[str]:
  6618. naming = util.preloaded.sql_naming
  6619. if constraint.name is _NONE_NAME:
  6620. name = naming._constraint_name_for_table(
  6621. constraint, constraint.table
  6622. )
  6623. if name is None:
  6624. return None
  6625. else:
  6626. name = constraint.name
  6627. assert name is not None
  6628. if constraint.__visit_name__ == "index":
  6629. return self.truncate_and_render_index_name(
  6630. name, _alembic_quote=_alembic_quote
  6631. )
  6632. else:
  6633. return self.truncate_and_render_constraint_name(
  6634. name, _alembic_quote=_alembic_quote
  6635. )
  6636. def truncate_and_render_index_name(
  6637. self, name: str, _alembic_quote: bool = True
  6638. ) -> str:
  6639. # calculate these at format time so that ad-hoc changes
  6640. # to dialect.max_identifier_length etc. can be reflected
  6641. # as IdentifierPreparer is long lived
  6642. max_ = (
  6643. self.dialect.max_index_name_length
  6644. or self.dialect.max_identifier_length
  6645. )
  6646. return self._truncate_and_render_maxlen_name(
  6647. name, max_, _alembic_quote
  6648. )
  6649. def truncate_and_render_constraint_name(
  6650. self, name: str, _alembic_quote: bool = True
  6651. ) -> str:
  6652. # calculate these at format time so that ad-hoc changes
  6653. # to dialect.max_identifier_length etc. can be reflected
  6654. # as IdentifierPreparer is long lived
  6655. max_ = (
  6656. self.dialect.max_constraint_name_length
  6657. or self.dialect.max_identifier_length
  6658. )
  6659. return self._truncate_and_render_maxlen_name(
  6660. name, max_, _alembic_quote
  6661. )
  6662. def _truncate_and_render_maxlen_name(
  6663. self, name: str, max_: int, _alembic_quote: bool
  6664. ) -> str:
  6665. if isinstance(name, elements._truncated_label):
  6666. if len(name) > max_:
  6667. name = name[0 : max_ - 8] + "_" + util.md5_hex(name)[-4:]
  6668. else:
  6669. self.dialect.validate_identifier(name)
  6670. if not _alembic_quote:
  6671. return name
  6672. else:
  6673. return self.quote(name)
  6674. def format_index(self, index: Index) -> str:
  6675. name = self.format_constraint(index)
  6676. assert name is not None
  6677. return name
  6678. def format_table(
  6679. self,
  6680. table: FromClause,
  6681. use_schema: bool = True,
  6682. name: Optional[str] = None,
  6683. ) -> str:
  6684. """Prepare a quoted table and schema name."""
  6685. if name is None:
  6686. if TYPE_CHECKING:
  6687. assert isinstance(table, NamedFromClause)
  6688. name = table.name
  6689. result = self.quote(name)
  6690. effective_schema = self.schema_for_object(table)
  6691. if not self.omit_schema and use_schema and effective_schema:
  6692. result = self.quote_schema(effective_schema) + "." + result
  6693. return result
  6694. def format_schema(self, name):
  6695. """Prepare a quoted schema name."""
  6696. return self.quote(name)
  6697. def format_label_name(
  6698. self,
  6699. name,
  6700. anon_map=None,
  6701. ):
  6702. """Prepare a quoted column name."""
  6703. if anon_map is not None and isinstance(
  6704. name, elements._truncated_label
  6705. ):
  6706. name = name.apply_map(anon_map)
  6707. return self.quote(name)
  6708. def format_column(
  6709. self,
  6710. column: ColumnElement[Any],
  6711. use_table: bool = False,
  6712. name: Optional[str] = None,
  6713. table_name: Optional[str] = None,
  6714. use_schema: bool = False,
  6715. anon_map: Optional[Mapping[str, Any]] = None,
  6716. ) -> str:
  6717. """Prepare a quoted column name."""
  6718. if name is None:
  6719. name = column.name
  6720. assert name is not None
  6721. if anon_map is not None and isinstance(
  6722. name, elements._truncated_label
  6723. ):
  6724. name = name.apply_map(anon_map)
  6725. if not getattr(column, "is_literal", False):
  6726. if use_table:
  6727. return (
  6728. self.format_table(
  6729. column.table, use_schema=use_schema, name=table_name
  6730. )
  6731. + "."
  6732. + self.quote(name)
  6733. )
  6734. else:
  6735. return self.quote(name)
  6736. else:
  6737. # literal textual elements get stuck into ColumnClause a lot,
  6738. # which shouldn't get quoted
  6739. if use_table:
  6740. return (
  6741. self.format_table(
  6742. column.table, use_schema=use_schema, name=table_name
  6743. )
  6744. + "."
  6745. + name
  6746. )
  6747. else:
  6748. return name
  6749. def format_table_seq(self, table, use_schema=True):
  6750. """Format table name and schema as a tuple."""
  6751. # Dialects with more levels in their fully qualified references
  6752. # ('database', 'owner', etc.) could override this and return
  6753. # a longer sequence.
  6754. effective_schema = self.schema_for_object(table)
  6755. if not self.omit_schema and use_schema and effective_schema:
  6756. return (
  6757. self.quote_schema(effective_schema),
  6758. self.format_table(table, use_schema=False),
  6759. )
  6760. else:
  6761. return (self.format_table(table, use_schema=False),)
  6762. @util.memoized_property
  6763. def _r_identifiers(self):
  6764. initial, final, escaped_final = (
  6765. re.escape(s)
  6766. for s in (
  6767. self.initial_quote,
  6768. self.final_quote,
  6769. self._escape_identifier(self.final_quote),
  6770. )
  6771. )
  6772. r = re.compile(
  6773. r"(?:"
  6774. r"(?:%(initial)s((?:%(escaped)s|[^%(final)s])+)%(final)s"
  6775. r"|([^\.]+))(?=\.|$))+"
  6776. % {"initial": initial, "final": final, "escaped": escaped_final}
  6777. )
  6778. return r
  6779. def unformat_identifiers(self, identifiers: str) -> Sequence[str]:
  6780. """Unpack 'schema.table.column'-like strings into components."""
  6781. r = self._r_identifiers
  6782. return [
  6783. self._unescape_identifier(i)
  6784. for i in [a or b for a, b in r.findall(identifiers)]
  6785. ]