pg_catalog.go 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851
  1. package executor
  2. import (
  3. "fmt"
  4. "sort"
  5. "strconv"
  6. "strings"
  7. "github.com/danfragoso/pizzasql-next/pkg/parser"
  8. "github.com/danfragoso/pizzasql-next/pkg/pgerror"
  9. "github.com/danfragoso/pizzasql-next/pkg/storage"
  10. )
  11. // PostgreSQL catalog emulation.
  12. //
  13. // pg_catalog and information_schema are synthesized from the durable schema the
  14. // connection's session observes (including DDL staged by an open transaction).
  15. // Nothing is persisted and no virtual relation accepts writes. OIDs are
  16. // deterministic: a 32-bit FNV-1a hash of the namespace-qualified name, lifted
  17. // above PostgreSQL's FirstNormalObjectId and collision-probed in sorted order.
  18. // The same allocator feeds pg_class, pg_attribute, pg_type, pg_index, and
  19. // pg_constraint, so catalog joins agree.
  20. //
  21. // The emulated schemas are pg_catalog (OID 11), public (OID 2200), and
  22. // information_schema (OID 13207). User relations always live in public.
  23. const (
  24. pgCatalogSchemaName = "pg_catalog"
  25. informationSchemaName = "information_schema"
  26. publicSchemaName = "public"
  27. pgCatalogNamespaceOID = int64(11)
  28. publicNamespaceOID = int64(2200)
  29. infoSchemaNamespaceOID = int64(13207)
  30. firstNormalObjectID = int64(16384)
  31. // Built-in OIDs the emulation refers to.
  32. pgDefaultTablespaceOID = int64(1663)
  33. pgGlobalTablespaceOID = int64(1664)
  34. pgBtreeAMOID = int64(403)
  35. pgHeapAMOID = int64(2)
  36. catalogOwnerOID = int64(10)
  37. )
  38. // catalogRelationDef declares a virtual relation's column list.
  39. type catalogRelationDef struct {
  40. schema string
  41. name string
  42. columns []catalogColumnDef
  43. }
  44. type catalogColumnDef struct {
  45. name string
  46. typ string
  47. }
  48. // pgCatalogRelationDefs lists the read-only pg_catalog relations.
  49. var pgCatalogRelationDefs = []catalogRelationDef{
  50. {schema: pgCatalogSchemaName, name: "pg_namespace", columns: []catalogColumnDef{
  51. {"oid", "OID"}, {"nspname", "NAME"}, {"nspowner", "OID"}, {"nspacl", "TEXT"},
  52. }},
  53. {schema: pgCatalogSchemaName, name: "pg_class", columns: []catalogColumnDef{
  54. {"oid", "OID"}, {"relname", "NAME"}, {"relnamespace", "OID"}, {"reltype", "OID"},
  55. {"reloftype", "OID"}, {"relowner", "OID"}, {"relam", "OID"}, {"relfilenode", "OID"},
  56. {"reltablespace", "OID"}, {"relpages", "INT4"}, {"reltuples", "FLOAT4"},
  57. {"relallvisible", "INT4"}, {"reltoastrelid", "OID"}, {"relhasindex", "BOOL"},
  58. {"relisshared", "BOOL"}, {"relpersistence", "CHAR"}, {"relkind", "CHAR"},
  59. {"relnatts", "INT2"}, {"relchecks", "INT2"}, {"relhasrules", "BOOL"},
  60. {"relhastriggers", "BOOL"}, {"relhassubclass", "BOOL"}, {"relrowsecurity", "BOOL"},
  61. {"relforcerowsecurity", "BOOL"}, {"relispopulated", "BOOL"}, {"relreplident", "CHAR"},
  62. {"relispartition", "BOOL"}, {"relrewrite", "OID"}, {"relfrozenxid", "OID"},
  63. {"relminmxid", "OID"}, {"relacl", "TEXT"}, {"reloptions", "TEXT"},
  64. {"relpartbound", "TEXT"},
  65. }},
  66. {schema: pgCatalogSchemaName, name: "pg_attribute", columns: []catalogColumnDef{
  67. {"attrelid", "OID"}, {"attname", "NAME"}, {"atttypid", "OID"},
  68. {"attstattarget", "INT4"}, {"attlen", "INT2"}, {"attnum", "INT2"},
  69. {"attndims", "INT4"}, {"attcacheoff", "INT4"}, {"atttypmod", "INT4"},
  70. {"attbyval", "BOOL"}, {"attalign", "CHAR"}, {"attstorage", "CHAR"},
  71. {"attcompression", "CHAR"}, {"attnotnull", "BOOL"}, {"atthasdef", "BOOL"},
  72. {"atthasmissing", "BOOL"}, {"attidentity", "CHAR"}, {"attgenerated", "CHAR"},
  73. {"attisdropped", "BOOL"}, {"attislocal", "BOOL"}, {"attinhcount", "INT2"},
  74. {"attcollation", "OID"}, {"attacl", "TEXT"}, {"attoptions", "TEXT"},
  75. {"attfdwoptions", "TEXT"}, {"attmissingval", "TEXT"},
  76. }},
  77. {schema: pgCatalogSchemaName, name: "pg_type", columns: []catalogColumnDef{
  78. {"oid", "OID"}, {"typname", "NAME"}, {"typnamespace", "OID"},
  79. {"typowner", "OID"}, {"typlen", "INT2"}, {"typbyval", "BOOL"},
  80. {"typtype", "CHAR"}, {"typcategory", "CHAR"}, {"typispreferred", "BOOL"},
  81. {"typisdefined", "BOOL"}, {"typdelim", "CHAR"}, {"typrelid", "OID"},
  82. {"typsubscript", "REGPROC"}, {"typelem", "OID"}, {"typarray", "OID"},
  83. {"typinput", "REGPROC"}, {"typoutput", "REGPROC"}, {"typreceive", "REGPROC"},
  84. {"typsend", "REGPROC"}, {"typmodin", "REGPROC"}, {"typmodout", "REGPROC"},
  85. {"typanalyze", "REGPROC"}, {"typalign", "CHAR"}, {"typstorage", "CHAR"},
  86. {"typnotnull", "BOOL"}, {"typbasetype", "OID"}, {"typtypmod", "INT4"},
  87. {"typndims", "INT4"}, {"typcollation", "OID"}, {"typdefaultbin", "TEXT"},
  88. {"typdefault", "TEXT"}, {"typacl", "TEXT"},
  89. }},
  90. {schema: pgCatalogSchemaName, name: "pg_index", columns: []catalogColumnDef{
  91. {"indexrelid", "OID"}, {"indrelid", "OID"}, {"indnatts", "INT2"},
  92. {"indnkeyatts", "INT2"}, {"indisunique", "BOOL"}, {"indisprimary", "BOOL"},
  93. {"indisexclusion", "BOOL"}, {"indimmediate", "BOOL"}, {"indisclustered", "BOOL"},
  94. {"indisvalid", "BOOL"}, {"indcheckxmin", "BOOL"}, {"indisready", "BOOL"},
  95. {"indislive", "BOOL"}, {"indisreplident", "BOOL"}, {"indkey", "INT2[]"},
  96. {"indcollation", "TEXT"}, {"indclass", "TEXT"}, {"indoption", "INT2[]"},
  97. {"indexprs", "TEXT"}, {"indpred", "TEXT"},
  98. }},
  99. {schema: pgCatalogSchemaName, name: "pg_constraint", columns: []catalogColumnDef{
  100. {"oid", "OID"}, {"conname", "NAME"}, {"connamespace", "OID"},
  101. {"contype", "CHAR"}, {"condeferrable", "BOOL"}, {"condeferred", "BOOL"},
  102. {"convalidated", "BOOL"}, {"conrelid", "OID"}, {"contypid", "OID"},
  103. {"conindid", "OID"}, {"conparentid", "OID"}, {"confrelid", "OID"},
  104. {"confupdtype", "CHAR"}, {"confdeltype", "CHAR"}, {"confmatchtype", "CHAR"},
  105. {"conislocal", "BOOL"}, {"coninhcount", "INT2"}, {"connoinherit", "BOOL"},
  106. {"conkey", "INT2[]"}, {"confkey", "INT2[]"}, {"conpfeqop", "TEXT"},
  107. {"conppeqop", "TEXT"}, {"conffeqop", "TEXT"}, {"conexclop", "TEXT"},
  108. {"conbin", "TEXT"}, {"consrc", "TEXT"},
  109. }},
  110. {schema: pgCatalogSchemaName, name: "pg_attrdef", columns: []catalogColumnDef{
  111. {"oid", "OID"}, {"adrelid", "OID"}, {"adnum", "INT2"}, {"adbin", "TEXT"},
  112. }},
  113. {schema: pgCatalogSchemaName, name: "pg_database", columns: []catalogColumnDef{
  114. {"oid", "OID"}, {"datname", "NAME"}, {"datdba", "OID"}, {"encoding", "INT4"},
  115. {"datlocprovider", "CHAR"}, {"datistemplate", "BOOL"}, {"datallowconn", "BOOL"},
  116. {"datconnlimit", "INT4"}, {"datlastsysoid", "OID"}, {"datfrozenxid", "OID"},
  117. {"datminmxid", "OID"}, {"dattablespace", "OID"}, {"datcollate", "TEXT"},
  118. {"datctype", "TEXT"}, {"datlocale", "TEXT"}, {"daticurules", "TEXT"},
  119. {"datcollversion", "TEXT"}, {"datacl", "TEXT"},
  120. }},
  121. {schema: pgCatalogSchemaName, name: "pg_tablespace", columns: []catalogColumnDef{
  122. {"oid", "OID"}, {"spcname", "NAME"}, {"spcowner", "OID"}, {"spcacl", "TEXT"},
  123. {"spcoptions", "TEXT"},
  124. }},
  125. {schema: pgCatalogSchemaName, name: "pg_proc", columns: []catalogColumnDef{
  126. {"oid", "OID"}, {"proname", "NAME"}, {"pronamespace", "OID"},
  127. {"proowner", "OID"}, {"prolang", "OID"}, {"procost", "FLOAT4"},
  128. {"prorows", "FLOAT4"}, {"provariadic", "OID"}, {"prosupport", "REGPROC"},
  129. {"prokind", "CHAR"}, {"prosecdef", "BOOL"}, {"proleakproof", "BOOL"},
  130. {"proisstrict", "BOOL"}, {"proretset", "BOOL"}, {"provolatile", "CHAR"},
  131. {"proparallel", "CHAR"}, {"pronargs", "INT2"}, {"pronargdefaults", "INT2"},
  132. {"prorettype", "OID"}, {"proargtypes", "TEXT"}, {"proallargtypes", "TEXT"},
  133. {"proargmodes", "TEXT"}, {"proargnames", "TEXT"}, {"proargdefaults", "TEXT"},
  134. {"protrftypes", "TEXT"}, {"prosrc", "TEXT"}, {"probin", "TEXT"},
  135. {"prosqlbody", "TEXT"}, {"proconfig", "TEXT"}, {"proacl", "TEXT"},
  136. }},
  137. {schema: pgCatalogSchemaName, name: "pg_am", columns: []catalogColumnDef{
  138. {"oid", "OID"}, {"amname", "NAME"}, {"amhandler", "OID"}, {"amtype", "CHAR"},
  139. }},
  140. {schema: pgCatalogSchemaName, name: "pg_description", columns: []catalogColumnDef{
  141. {"objoid", "OID"}, {"classoid", "OID"}, {"objsubid", "INT4"}, {"description", "TEXT"},
  142. }},
  143. {schema: pgCatalogSchemaName, name: "pg_tables", columns: []catalogColumnDef{
  144. {"schemaname", "NAME"}, {"tablename", "NAME"}, {"tableowner", "NAME"},
  145. {"tablespace", "NAME"}, {"hasindexes", "BOOL"}, {"hasrules", "BOOL"},
  146. {"hastriggers", "BOOL"}, {"rowsecurity", "BOOL"},
  147. }},
  148. {schema: pgCatalogSchemaName, name: "pg_indexes", columns: []catalogColumnDef{
  149. {"schemaname", "NAME"}, {"tablename", "NAME"}, {"indexname", "NAME"},
  150. {"tablespace", "NAME"}, {"indexdef", "TEXT"},
  151. }},
  152. }
  153. // informationSchemaRelationDefs lists the read-only information_schema views.
  154. var informationSchemaRelationDefs = []catalogRelationDef{
  155. {schema: informationSchemaName, name: "tables", columns: []catalogColumnDef{
  156. {"table_catalog", "TEXT"}, {"table_schema", "TEXT"}, {"table_name", "TEXT"},
  157. {"table_type", "TEXT"}, {"self_referencing_column_name", "TEXT"},
  158. {"reference_generation", "TEXT"}, {"user_defined_type_catalog", "TEXT"},
  159. {"user_defined_type_schema", "TEXT"}, {"user_defined_type_name", "TEXT"},
  160. {"is_insertable_into", "TEXT"}, {"is_typed", "TEXT"}, {"commit_action", "TEXT"},
  161. }},
  162. {schema: informationSchemaName, name: "columns", columns: []catalogColumnDef{
  163. {"table_catalog", "TEXT"}, {"table_schema", "TEXT"}, {"table_name", "TEXT"},
  164. {"column_name", "TEXT"}, {"ordinal_position", "INT4"}, {"column_default", "TEXT"},
  165. {"is_nullable", "TEXT"}, {"data_type", "TEXT"}, {"character_maximum_length", "INT4"},
  166. {"character_octet_length", "INT4"}, {"numeric_precision", "INT4"},
  167. {"numeric_precision_radix", "INT4"}, {"numeric_scale", "INT4"},
  168. {"datetime_precision", "INT4"}, {"interval_type", "TEXT"},
  169. {"interval_precision", "INT4"}, {"character_set_catalog", "TEXT"},
  170. {"character_set_schema", "TEXT"}, {"character_set_name", "TEXT"},
  171. {"collation_catalog", "TEXT"}, {"collation_schema", "TEXT"},
  172. {"collation_name", "TEXT"}, {"domain_catalog", "TEXT"}, {"domain_schema", "TEXT"},
  173. {"domain_name", "TEXT"}, {"udt_catalog", "TEXT"}, {"udt_schema", "TEXT"},
  174. {"udt_name", "TEXT"}, {"scope_catalog", "TEXT"}, {"scope_schema", "TEXT"},
  175. {"scope_name", "TEXT"}, {"maximum_cardinality", "INT4"}, {"dtd_identifier", "TEXT"},
  176. {"is_self_referencing", "TEXT"}, {"is_identity", "TEXT"},
  177. {"identity_generation", "TEXT"}, {"identity_start", "TEXT"},
  178. {"identity_increment", "TEXT"}, {"identity_maximum", "TEXT"},
  179. {"identity_minimum", "TEXT"}, {"identity_cycle", "TEXT"},
  180. {"is_generated", "TEXT"}, {"generation_expression", "TEXT"},
  181. {"is_updatable", "TEXT"},
  182. }},
  183. {schema: informationSchemaName, name: "table_constraints", columns: []catalogColumnDef{
  184. {"constraint_catalog", "TEXT"}, {"constraint_schema", "TEXT"},
  185. {"constraint_name", "TEXT"}, {"table_catalog", "TEXT"}, {"table_schema", "TEXT"},
  186. {"table_name", "TEXT"}, {"constraint_type", "TEXT"}, {"is_deferrable", "TEXT"},
  187. {"initially_deferred", "TEXT"}, {"enforced", "TEXT"}, {"nulls_distinct", "TEXT"},
  188. }},
  189. {schema: informationSchemaName, name: "key_column_usage", columns: []catalogColumnDef{
  190. {"constraint_catalog", "TEXT"}, {"constraint_schema", "TEXT"},
  191. {"constraint_name", "TEXT"}, {"table_catalog", "TEXT"}, {"table_schema", "TEXT"},
  192. {"table_name", "TEXT"}, {"column_name", "TEXT"}, {"ordinal_position", "INT4"},
  193. {"position_in_unique_constraint", "INT4"},
  194. }},
  195. {schema: informationSchemaName, name: "referential_constraints", columns: []catalogColumnDef{
  196. {"constraint_catalog", "TEXT"}, {"constraint_schema", "TEXT"},
  197. {"constraint_name", "TEXT"}, {"unique_constraint_catalog", "TEXT"},
  198. {"unique_constraint_schema", "TEXT"}, {"unique_constraint_name", "TEXT"},
  199. {"match_option", "TEXT"}, {"update_rule", "TEXT"}, {"delete_rule", "TEXT"},
  200. {"is_deferrable", "TEXT"}, {"initially_deferred", "TEXT"}, {"enforced", "TEXT"},
  201. }},
  202. {schema: informationSchemaName, name: "constraint_column_usage", columns: []catalogColumnDef{
  203. {"table_catalog", "TEXT"}, {"table_schema", "TEXT"}, {"table_name", "TEXT"},
  204. {"constraint_catalog", "TEXT"}, {"constraint_schema", "TEXT"},
  205. {"constraint_name", "TEXT"}, {"column_name", "TEXT"},
  206. }},
  207. {schema: informationSchemaName, name: "schemata", columns: []catalogColumnDef{
  208. {"catalog_name", "TEXT"}, {"schema_name", "TEXT"}, {"schema_owner", "TEXT"},
  209. {"default_character_set_catalog", "TEXT"},
  210. {"default_character_set_schema", "TEXT"},
  211. {"default_character_set_name", "TEXT"}, {"sql_path", "TEXT"},
  212. }},
  213. {schema: informationSchemaName, name: "sequences", columns: []catalogColumnDef{
  214. {"sequence_catalog", "TEXT"}, {"sequence_schema", "TEXT"},
  215. {"sequence_name", "TEXT"}, {"data_type", "TEXT"},
  216. {"numeric_precision", "INT4"}, {"numeric_precision_radix", "INT4"},
  217. {"numeric_scale", "INT4"}, {"start_value", "TEXT"}, {"minimum_value", "TEXT"},
  218. {"maximum_value", "TEXT"}, {"increment", "TEXT"}, {"cycle_option", "TEXT"},
  219. }},
  220. {schema: informationSchemaName, name: "views", columns: []catalogColumnDef{
  221. {"table_catalog", "TEXT"}, {"table_schema", "TEXT"}, {"table_name", "TEXT"},
  222. {"view_definition", "TEXT"}, {"check_option", "TEXT"}, {"is_updatable", "TEXT"},
  223. {"is_insertable_into", "TEXT"}, {"is_trigger_updatable", "TEXT"},
  224. {"is_trigger_deletable", "TEXT"}, {"is_trigger_insertable_into", "TEXT"},
  225. }},
  226. }
  227. // catalogRelationSchema builds the storage schema that the analyzer and the
  228. // materialized SELECT path use for a virtual relation.
  229. func catalogRelationSchema(def catalogRelationDef) *storage.Schema {
  230. schema := &storage.Schema{Name: def.name, Columns: make([]storage.Column, len(def.columns))}
  231. for i, column := range def.columns {
  232. schema.Columns[i] = storage.Column{Name: column.name, Type: column.typ, Nullable: true}
  233. }
  234. return schema
  235. }
  236. var pgCatalogRelationIndex = buildCatalogRelationIndex()
  237. type catalogRelationEntry struct {
  238. def catalogRelationDef
  239. schema *storage.Schema
  240. }
  241. func buildCatalogRelationIndex() map[string]catalogRelationEntry {
  242. index := make(map[string]catalogRelationEntry, len(pgCatalogRelationDefs)+len(informationSchemaRelationDefs))
  243. for _, def := range append(append([]catalogRelationDef(nil), pgCatalogRelationDefs...), informationSchemaRelationDefs...) {
  244. index[def.schema+"."+strings.ToLower(def.name)] = catalogRelationEntry{def: def, schema: catalogRelationSchema(def)}
  245. }
  246. return index
  247. }
  248. // catalogRelationFor resolves a possibly schema-qualified table reference to a
  249. // virtual catalog relation. A CTE in scope shadows every relation name, and an
  250. // unqualified name resolves to pg_catalog only when no durable table shadows it,
  251. // matching PostgreSQL's implicit search_path.
  252. func (e *Executor) catalogRelationFor(ref parser.TableRef) (catalogRelationEntry, bool) {
  253. if ref.Subquery != nil || ref.Function != nil {
  254. return catalogRelationEntry{}, false
  255. }
  256. if e.cteTableExists(ref.Name) {
  257. return catalogRelationEntry{}, false
  258. }
  259. name := strings.ToLower(ref.Name)
  260. switch strings.ToLower(ref.Schema) {
  261. case pgCatalogSchemaName:
  262. entry, ok := pgCatalogRelationIndex[pgCatalogSchemaName+"."+name]
  263. return entry, ok
  264. case informationSchemaName:
  265. entry, ok := pgCatalogRelationIndex[informationSchemaName+"."+name]
  266. return entry, ok
  267. case "":
  268. // Resolve the catalog name first: an ordinary table name then needs no
  269. // session lookup, and a locked scan only asks the session whether a
  270. // catalog-named relation is shadowed by a durable table.
  271. entry, ok := pgCatalogRelationIndex[pgCatalogSchemaName+"."+name]
  272. if !ok || e.catalogTableExists(ref.Name) {
  273. return catalogRelationEntry{}, false
  274. }
  275. return entry, true
  276. default:
  277. // The emulated schemas are distinct: public.<name> names a durable
  278. // relation, never pg_catalog.<name>, so a qualified miss falls through to
  279. // the durable-schema path and is reported as an undefined table.
  280. return catalogRelationEntry{}, false
  281. }
  282. }
  283. // isCatalogRelationRef reports whether a FROM entry names a virtual relation.
  284. func (e *Executor) isCatalogRelationRef(ref parser.TableRef) bool {
  285. _, ok := e.catalogRelationFor(ref)
  286. return ok
  287. }
  288. // fromReferencesCatalogRelation walks a FROM clause, including JOIN chains.
  289. func (e *Executor) fromReferencesCatalogRelation(from []parser.TableRef) bool {
  290. for _, ref := range from {
  291. cur := ref
  292. for {
  293. if e.isCatalogRelationRef(cur) {
  294. return true
  295. }
  296. if cur.Join == nil || cur.Join.Table == nil {
  297. break
  298. }
  299. cur = *cur.Join.Table
  300. }
  301. }
  302. return false
  303. }
  304. // ---------------------------------------------------------------------------
  305. // Deterministic OIDs
  306. func fnv1a32(text string) uint32 {
  307. hash := uint32(2166136261)
  308. for i := 0; i < len(text); i++ {
  309. hash ^= uint32(text[i])
  310. hash *= 16777619
  311. }
  312. return hash
  313. }
  314. // catalogRelationKey identifies a relation row. relkind is part of the identity:
  315. // the engine lets an index share its table's name, and both rows must keep their
  316. // own OID so pg_class, pg_attribute, and pg_index agree, exactly as relname plus
  317. // relkind identifies a pg_class row in PostgreSQL.
  318. func catalogRelationKey(relation *catalogRelation) string {
  319. return strings.ToLower(relation.schemaName+"."+relation.name) + "#" + string(relation.kind)
  320. }
  321. // allocateOID maps a kind and fully qualified name to a stable, positive OID.
  322. // The first probe is the FNV-1a hash lifted into [firstNormalObjectID,
  323. // MaxInt32]; collisions are resolved by linear probing in the caller's sorted
  324. // order, so the assignment is deterministic for a given schema.
  325. func (s *catalogSnapshot) allocateOID(kind, key string) int64 {
  326. owner := kind + ":" + key
  327. oid := int64(fnv1a32("pizzasql:" + owner))
  328. oid &= 0x7fffffff
  329. if oid < firstNormalObjectID {
  330. oid += firstNormalObjectID
  331. }
  332. for {
  333. if existing, used := s.oidOwners[oid]; !used || existing == owner {
  334. s.oidOwners[oid] = owner
  335. return oid
  336. }
  337. oid++
  338. if oid > 0x7fffffff {
  339. oid = firstNormalObjectID
  340. }
  341. }
  342. }
  343. // ---------------------------------------------------------------------------
  344. // Built-in type table
  345. type pgBuiltinType struct {
  346. oid int64
  347. name string // pg_type.typname
  348. sqlName string // format_type / information_schema spelling
  349. length int64
  350. byval bool
  351. category string
  352. delim string
  353. elem int64
  354. array int64
  355. align string
  356. storage string
  357. }
  358. func (t pgBuiltinType) isArray() bool { return t.category == "A" }
  359. var pgBuiltinTypes = []pgBuiltinType{
  360. {oid: 16, name: "bool", sqlName: "boolean", length: 1, byval: true, category: "B", delim: ",", array: 1000, align: "c", storage: "p"},
  361. {oid: 17, name: "bytea", sqlName: "bytea", length: -1, category: "U", delim: ",", array: 1001, align: "i", storage: "x"},
  362. {oid: 18, name: "char", sqlName: "\"char\"", length: 1, byval: true, category: "S", delim: ",", array: 1002, align: "c", storage: "p"},
  363. {oid: 19, name: "name", sqlName: "name", length: 64, category: "S", delim: ",", array: 1003, align: "c", storage: "p"},
  364. {oid: 20, name: "int8", sqlName: "bigint", length: 8, byval: true, category: "N", delim: ",", array: 1016, align: "d", storage: "p"},
  365. {oid: 21, name: "int2", sqlName: "smallint", length: 2, byval: true, category: "N", delim: ",", array: 1005, align: "s", storage: "p"},
  366. {oid: 23, name: "int4", sqlName: "integer", length: 4, byval: true, category: "N", delim: ",", array: 1007, align: "i", storage: "p"},
  367. {oid: 25, name: "text", sqlName: "text", length: -1, category: "S", delim: ",", array: 1009, align: "i", storage: "x"},
  368. {oid: 26, name: "oid", sqlName: "oid", length: 4, byval: true, category: "N", delim: ",", array: 1028, align: "i", storage: "p"},
  369. {oid: 114, name: "json", sqlName: "json", length: -1, category: "U", delim: ",", array: 199, align: "i", storage: "x"},
  370. {oid: 700, name: "float4", sqlName: "real", length: 4, byval: true, category: "N", delim: ",", array: 1021, align: "i", storage: "p"},
  371. {oid: 701, name: "float8", sqlName: "double precision", length: 8, byval: true, category: "N", delim: ",", array: 1022, align: "d", storage: "p"},
  372. {oid: 1042, name: "bpchar", sqlName: "character", length: -1, category: "S", delim: ",", array: 1014, align: "i", storage: "x"},
  373. {oid: 1043, name: "varchar", sqlName: "character varying", length: -1, category: "S", delim: ",", array: 1015, align: "i", storage: "x"},
  374. {oid: 1082, name: "date", sqlName: "date", length: 4, byval: true, category: "D", delim: ",", array: 1182, align: "i", storage: "p"},
  375. {oid: 1083, name: "time", sqlName: "time without time zone", length: 8, byval: true, category: "D", delim: ",", array: 1183, align: "d", storage: "p"},
  376. {oid: 1184, name: "timestamptz", sqlName: "timestamp with time zone", length: 8, byval: true, category: "D", delim: ",", array: 1185, align: "d", storage: "p"},
  377. {oid: 1700, name: "numeric", sqlName: "numeric", length: -1, category: "N", delim: ",", array: 1231, align: "i", storage: "x"},
  378. {oid: 2205, name: "regclass", sqlName: "regclass", length: 4, byval: true, category: "N", delim: ",", array: 2210, align: "i", storage: "p"},
  379. {oid: 2206, name: "regtype", sqlName: "regtype", length: 4, byval: true, category: "N", delim: ",", array: 2211, align: "i", storage: "p"},
  380. {oid: 2950, name: "uuid", sqlName: "uuid", length: 16, category: "U", delim: ",", array: 2951, align: "c", storage: "p"},
  381. {oid: 3802, name: "jsonb", sqlName: "jsonb", length: -1, category: "U", delim: ",", array: 3807, align: "i", storage: "x"},
  382. // Array types for the supported element types.
  383. {oid: 199, name: "_json", sqlName: "json[]", length: -1, category: "A", delim: ",", elem: 114, align: "i", storage: "x"},
  384. {oid: 1000, name: "_bool", sqlName: "boolean[]", length: -1, category: "A", delim: ",", elem: 16, align: "i", storage: "x"},
  385. {oid: 1001, name: "_bytea", sqlName: "bytea[]", length: -1, category: "A", delim: ",", elem: 17, align: "i", storage: "x"},
  386. {oid: 1002, name: "_char", sqlName: "\"char\"[]", length: -1, category: "A", delim: ",", elem: 18, align: "i", storage: "x"},
  387. {oid: 1003, name: "_name", sqlName: "name[]", length: -1, category: "A", delim: ",", elem: 19, align: "i", storage: "x"},
  388. {oid: 1005, name: "_int2", sqlName: "smallint[]", length: -1, category: "A", delim: ",", elem: 21, align: "i", storage: "x"},
  389. {oid: 1007, name: "_int4", sqlName: "integer[]", length: -1, category: "A", delim: ",", elem: 23, align: "i", storage: "x"},
  390. {oid: 1009, name: "_text", sqlName: "text[]", length: -1, category: "A", delim: ",", elem: 25, align: "i", storage: "x"},
  391. {oid: 1014, name: "_bpchar", sqlName: "character[]", length: -1, category: "A", delim: ",", elem: 1042, align: "i", storage: "x"},
  392. {oid: 1015, name: "_varchar", sqlName: "character varying[]", length: -1, category: "A", delim: ",", elem: 1043, align: "i", storage: "x"},
  393. {oid: 1016, name: "_int8", sqlName: "bigint[]", length: -1, category: "A", delim: ",", elem: 20, align: "i", storage: "x"},
  394. {oid: 1021, name: "_float4", sqlName: "real[]", length: -1, category: "A", delim: ",", elem: 700, align: "i", storage: "x"},
  395. {oid: 1022, name: "_float8", sqlName: "double precision[]", length: -1, category: "A", delim: ",", elem: 701, align: "i", storage: "x"},
  396. {oid: 1028, name: "_oid", sqlName: "oid[]", length: -1, category: "A", delim: ",", elem: 26, align: "i", storage: "x"},
  397. {oid: 1182, name: "_date", sqlName: "date[]", length: -1, category: "A", delim: ",", elem: 1082, align: "i", storage: "x"},
  398. {oid: 1183, name: "_time", sqlName: "time without time zone[]", length: -1, category: "A", delim: ",", elem: 1083, align: "i", storage: "x"},
  399. {oid: 1185, name: "_timestamptz", sqlName: "timestamp with time zone[]", length: -1, category: "A", delim: ",", elem: 1184, align: "i", storage: "x"},
  400. {oid: 1231, name: "_numeric", sqlName: "numeric[]", length: -1, category: "A", delim: ",", elem: 1700, align: "i", storage: "x"},
  401. {oid: 2210, name: "_regclass", sqlName: "regclass[]", length: -1, category: "A", delim: ",", elem: 2205, align: "i", storage: "x"},
  402. {oid: 2211, name: "_regtype", sqlName: "regtype[]", length: -1, category: "A", delim: ",", elem: 2206, align: "i", storage: "x"},
  403. {oid: 2951, name: "_uuid", sqlName: "uuid[]", length: -1, category: "A", delim: ",", elem: 2950, align: "i", storage: "x"},
  404. {oid: 3807, name: "_jsonb", sqlName: "jsonb[]", length: -1, category: "A", delim: ",", elem: 3802, align: "i", storage: "x"},
  405. }
  406. var pgBuiltinTypeByOID = func() map[int64]pgBuiltinType {
  407. index := make(map[int64]pgBuiltinType, len(pgBuiltinTypes))
  408. for _, t := range pgBuiltinTypes {
  409. index[t.oid] = t
  410. }
  411. return index
  412. }()
  413. var pgBuiltinTypeByName = func() map[string]pgBuiltinType {
  414. index := make(map[string]pgBuiltinType, len(pgBuiltinTypes))
  415. for _, t := range pgBuiltinTypes {
  416. index[t.name] = t
  417. }
  418. return index
  419. }()
  420. // pgTypeForDeclaredName maps an engine column type ("INTEGER", "TEXT[]", ...)
  421. // to its PostgreSQL type row. Unknown names report TEXT rather than claiming a
  422. // type the engine does not have.
  423. func pgTypeForDeclaredName(name string) pgBuiltinType {
  424. upper := strings.ToUpper(strings.TrimSpace(name))
  425. if idx := strings.IndexByte(upper, '('); idx >= 0 {
  426. upper = strings.TrimSpace(upper[:idx])
  427. }
  428. if strings.HasSuffix(upper, "[]") {
  429. element := strings.TrimSpace(strings.TrimSuffix(upper, "[]"))
  430. base := pgTypeForDeclaredName(element)
  431. if array, ok := pgBuiltinTypeByOID[base.array]; ok && base.array != 0 {
  432. return array
  433. }
  434. if fallback, ok := pgBuiltinTypeByOID[1009]; ok {
  435. return fallback
  436. }
  437. }
  438. switch upper {
  439. case "INTEGER", "INT", "INT4":
  440. return pgBuiltinTypeByOID[23]
  441. case "BIGINT", "INT8":
  442. return pgBuiltinTypeByOID[20]
  443. case "SMALLINT", "INT2", "TINYINT", "MEDIUMINT":
  444. return pgBuiltinTypeByOID[21]
  445. case "TEXT", "CLOB", "NCHAR", "NVARCHAR":
  446. return pgBuiltinTypeByOID[25]
  447. case "VARCHAR", "CHARACTER VARYING":
  448. return pgBuiltinTypeByOID[1043]
  449. case "CHAR", "CHARACTER":
  450. return pgBuiltinTypeByOID[1042]
  451. case "BOOLEAN", "BOOL":
  452. return pgBuiltinTypeByOID[16]
  453. case "REAL", "FLOAT", "FLOAT4":
  454. return pgBuiltinTypeByOID[700]
  455. case "DOUBLE", "DOUBLE PRECISION", "FLOAT8":
  456. return pgBuiltinTypeByOID[701]
  457. case "NUMERIC", "DECIMAL":
  458. return pgBuiltinTypeByOID[1700]
  459. case "JSONB":
  460. return pgBuiltinTypeByOID[3802]
  461. case "JSON":
  462. return pgBuiltinTypeByOID[114]
  463. case "BLOB", "BYTEA":
  464. return pgBuiltinTypeByOID[17]
  465. case "DATETIME", "TIMESTAMP", "TIMESTAMPTZ", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITHOUT TIME ZONE":
  466. return pgBuiltinTypeByOID[1184]
  467. case "DATE":
  468. return pgBuiltinTypeByOID[1082]
  469. case "TIME", "TIME WITHOUT TIME ZONE", "TIME WITH TIME ZONE":
  470. return pgBuiltinTypeByOID[1083]
  471. case "UUID":
  472. return pgBuiltinTypeByOID[2950]
  473. case "OID":
  474. return pgBuiltinTypeByOID[26]
  475. case "NAME":
  476. return pgBuiltinTypeByOID[19]
  477. case "REGCLASS":
  478. return pgBuiltinTypeByOID[2205]
  479. case "REGTYPE":
  480. return pgBuiltinTypeByOID[2206]
  481. default:
  482. return pgBuiltinTypeByOID[25]
  483. }
  484. }
  485. // ---------------------------------------------------------------------------
  486. // Snapshot
  487. type catalogRelation struct {
  488. schemaName string
  489. name string
  490. oid int64
  491. kind byte // 'r' table, 'i' index, 'v' view / virtual relation
  492. columns []storage.Column
  493. table *storage.Schema
  494. index *storage.Index
  495. // virtual marks a synthesized pg_catalog/information_schema relation. User
  496. // tables, indexes, and session views are the durable/session schema.
  497. virtual bool
  498. // primaryIndex marks the synthetic index that backs a PRIMARY KEY. The
  499. // engine does not persist an index object for the key, but PostgreSQL tools
  500. // expect pg_index/pg_constraint to point at one.
  501. primaryIndex bool
  502. }
  503. type catalogConstraint struct {
  504. oid int64
  505. name string
  506. table *catalogRelation
  507. contype byte
  508. indexOID int64
  509. columns []string // child columns (PK/UNIQUE/FK) or empty for CHECK
  510. fk *storage.ForeignKeyConstraint
  511. check *storage.CheckConstraint
  512. }
  513. type catalogSnapshot struct {
  514. database string
  515. relations []*catalogRelation
  516. relationByKey map[string]*catalogRelation
  517. relationByOID map[int64]*catalogRelation
  518. tableByName map[string]*catalogRelation
  519. tableIndexes map[string][]*catalogRelation
  520. constraints []*catalogConstraint
  521. constraintByOID map[int64]*catalogConstraint
  522. rows map[string][]storage.Row
  523. // Preallocated OIDs keep every catalog relation deterministic regardless of
  524. // the order in which row sets are materialized.
  525. attrdefOIDs map[string]int64
  526. databaseOID int64
  527. procOIDs map[string]int64
  528. oidOwners map[int64]string
  529. }
  530. // catalogSnapshotForQuery builds (once per statement) and returns the catalog
  531. // snapshot the statement observes.
  532. func (e *Executor) catalogSnapshotForQuery() (*catalogSnapshot, error) {
  533. if e.schema == nil || e.session == nil {
  534. return nil, pgerror.Unsupported("catalog introspection is not available in a stored expression")
  535. }
  536. if e.pgCatalog != nil {
  537. return e.pgCatalog, nil
  538. }
  539. if e.lockedScanDepth > 0 {
  540. // Building a snapshot reads the session catalog, which takes the session
  541. // lock; that lock is already held by the scan this predicate runs inside,
  542. // so continuing would deadlock the connection and leak the table lock.
  543. // Statements that can reach this point prime the snapshot before scanning
  544. // (see primeCatalogSnapshot), so this is a guard, not a policy.
  545. return nil, pgerror.Unsupported("catalog relations cannot be resolved inside a locked table scan")
  546. }
  547. snapshot, err := buildCatalogSnapshot(e)
  548. if err != nil {
  549. return nil, err
  550. }
  551. e.pgCatalog = snapshot
  552. return snapshot, nil
  553. }
  554. // catalogSnapshotFunctionNames lists the catalog functions whose value is
  555. // resolved through the statement's virtual catalog snapshot.
  556. var catalogSnapshotFunctionNames = map[string]bool{
  557. "FORMAT_TYPE": true,
  558. "PG_TABLE_IS_VISIBLE": true,
  559. "PG_GET_INDEXDEF": true,
  560. "PG_GET_CONSTRAINTDEF": true,
  561. "HAS_TABLE_PRIVILEGE": true,
  562. "TO_REGCLASS": true,
  563. "TO_REGTYPE": true,
  564. }
  565. // catalogSnapshotExprNeeded reports whether evaluating expr reads the virtual
  566. // catalog at value time: a regclass/regtype cast, a catalog function that
  567. // resolves names through the snapshot, or a subquery containing either.
  568. // AST fields are often typed nil pointers inside an interface, so every pointer
  569. // case checks for nil before reading it.
  570. func catalogSnapshotExprNeeded(expr parser.Expr) bool {
  571. switch n := expr.(type) {
  572. case nil, *parser.ColumnRef, *parser.LiteralExpr:
  573. return false
  574. case *parser.CastExpr:
  575. if n == nil {
  576. return false
  577. }
  578. switch strings.ToUpper(strings.TrimSpace(n.Type.SQLTypeName())) {
  579. case "REGCLASS", "REGTYPE":
  580. return true
  581. }
  582. return catalogSnapshotExprNeeded(n.Expr)
  583. case *parser.FunctionCall:
  584. if n == nil {
  585. return false
  586. }
  587. if catalogSnapshotFunctionNames[strings.ToUpper(n.Name)] {
  588. return true
  589. }
  590. for _, arg := range n.Args {
  591. if catalogSnapshotExprNeeded(arg) {
  592. return true
  593. }
  594. }
  595. return false
  596. case *parser.BinaryExpr:
  597. return n != nil && (catalogSnapshotExprNeeded(n.Left) || catalogSnapshotExprNeeded(n.Right))
  598. case *parser.UnaryExpr:
  599. return n != nil && catalogSnapshotExprNeeded(n.Operand)
  600. case *parser.BetweenExpr:
  601. return n != nil && (catalogSnapshotExprNeeded(n.Left) || catalogSnapshotExprNeeded(n.Low) || catalogSnapshotExprNeeded(n.High))
  602. case *parser.LikeExpr:
  603. return n != nil && (catalogSnapshotExprNeeded(n.Left) || catalogSnapshotExprNeeded(n.Pattern) || catalogSnapshotExprNeeded(n.Escape))
  604. case *parser.IsNullExpr:
  605. return n != nil && catalogSnapshotExprNeeded(n.Left)
  606. case *parser.IsDistinctExpr:
  607. return n != nil && (catalogSnapshotExprNeeded(n.Left) || catalogSnapshotExprNeeded(n.Right))
  608. case *parser.CaseExpr:
  609. if n == nil {
  610. return false
  611. }
  612. if catalogSnapshotExprNeeded(n.Operand) || catalogSnapshotExprNeeded(n.Else) {
  613. return true
  614. }
  615. for _, when := range n.Whens {
  616. if catalogSnapshotExprNeeded(when.Condition) || catalogSnapshotExprNeeded(when.Result) {
  617. return true
  618. }
  619. }
  620. return false
  621. case *parser.ArrayExpr:
  622. if n == nil {
  623. return false
  624. }
  625. for _, element := range n.Elements {
  626. if catalogSnapshotExprNeeded(element) {
  627. return true
  628. }
  629. }
  630. return false
  631. case *parser.SubscriptExpr:
  632. return n != nil && (catalogSnapshotExprNeeded(n.Expr) || catalogSnapshotExprNeeded(n.Index))
  633. case *parser.AnyAllExpr:
  634. return n != nil && (catalogSnapshotExprNeeded(n.Left) || catalogSnapshotExprNeeded(n.Array))
  635. case *parser.InExpr:
  636. if n == nil {
  637. return false
  638. }
  639. if catalogSnapshotExprNeeded(n.Left) || catalogSnapshotSelectNeeded(n.Subquery) {
  640. return true
  641. }
  642. for _, value := range n.Values {
  643. if catalogSnapshotExprNeeded(value) {
  644. return true
  645. }
  646. }
  647. return false
  648. case *parser.SubqueryExpr:
  649. return n != nil && catalogSnapshotSelectNeeded(n.Query)
  650. case *parser.ExistsExpr:
  651. return n != nil && catalogSnapshotSelectNeeded(n.Subquery)
  652. case *parser.ParenExpr:
  653. return n != nil && catalogSnapshotExprNeeded(n.Expr)
  654. default:
  655. return false
  656. }
  657. }
  658. // catalogSnapshotSelectNeeded reports whether a SELECT evaluates a catalog-backed
  659. // expression in any of its clauses or nested relations.
  660. func catalogSnapshotSelectNeeded(sel *parser.SelectStmt) bool {
  661. if sel == nil {
  662. return false
  663. }
  664. for _, cte := range sel.With {
  665. if catalogSnapshotSelectNeeded(cte.Query) {
  666. return true
  667. }
  668. }
  669. if sel.Compound != nil && (catalogSnapshotSelectNeeded(sel.Compound.Left) || catalogSnapshotSelectNeeded(sel.Compound.Right)) {
  670. return true
  671. }
  672. for _, column := range sel.Columns {
  673. if catalogSnapshotExprNeeded(column.Expr) {
  674. return true
  675. }
  676. }
  677. for i := range sel.From {
  678. if catalogSnapshotTableRefNeeded(&sel.From[i]) {
  679. return true
  680. }
  681. }
  682. for _, expr := range sel.GroupBy {
  683. if catalogSnapshotExprNeeded(expr) {
  684. return true
  685. }
  686. }
  687. for _, item := range sel.OrderBy {
  688. if catalogSnapshotExprNeeded(item.Expr) {
  689. return true
  690. }
  691. }
  692. return catalogSnapshotExprNeeded(sel.Where) ||
  693. catalogSnapshotExprNeeded(sel.Having) ||
  694. catalogSnapshotExprNeeded(sel.Limit) ||
  695. catalogSnapshotExprNeeded(sel.Offset)
  696. }
  697. // catalogSnapshotTableRefNeeded reports whether a FROM entry evaluates a
  698. // catalog-backed expression in a derived table, table function, or join.
  699. func catalogSnapshotTableRefNeeded(ref *parser.TableRef) bool {
  700. if ref == nil {
  701. return false
  702. }
  703. if catalogSnapshotSelectNeeded(ref.Subquery) || catalogSnapshotExprNeeded(ref.Function) {
  704. return true
  705. }
  706. if ref.Join != nil {
  707. return catalogSnapshotTableRefNeeded(ref.Join.Table) || catalogSnapshotExprNeeded(ref.Join.Condition)
  708. }
  709. return false
  710. }
  711. // catalogSnapshotStatementNeeded reports whether the statement evaluates a
  712. // catalog-backed expression anywhere it can run during the statement.
  713. func catalogSnapshotStatementNeeded(stmt parser.Statement) bool {
  714. switch s := stmt.(type) {
  715. case *parser.SelectStmt:
  716. return catalogSnapshotSelectNeeded(s)
  717. case *parser.UpdateStmt:
  718. for i := range s.From {
  719. if catalogSnapshotTableRefNeeded(&s.From[i]) {
  720. return true
  721. }
  722. }
  723. for _, assignment := range s.Set {
  724. if catalogSnapshotExprNeeded(assignment.Value) {
  725. return true
  726. }
  727. }
  728. return catalogSnapshotExprNeeded(s.Where) || catalogSnapshotReturningNeeded(s.Returning)
  729. case *parser.DeleteStmt:
  730. return catalogSnapshotExprNeeded(s.Where) || catalogSnapshotReturningNeeded(s.Returning)
  731. case *parser.InsertStmt:
  732. for _, row := range s.Values {
  733. for _, value := range row {
  734. if catalogSnapshotExprNeeded(value) {
  735. return true
  736. }
  737. }
  738. }
  739. for _, assignment := range s.ConflictUpdate {
  740. if catalogSnapshotExprNeeded(assignment.Value) {
  741. return true
  742. }
  743. }
  744. return catalogSnapshotSelectNeeded(s.Select) || catalogSnapshotReturningNeeded(s.Returning)
  745. default:
  746. return false
  747. }
  748. }
  749. func catalogSnapshotReturningNeeded(columns []parser.SelectColumn) bool {
  750. for _, column := range columns {
  751. if catalogSnapshotExprNeeded(column.Expr) {
  752. return true
  753. }
  754. }
  755. return false
  756. }
  757. // primeCatalogSnapshot builds the statement's virtual catalog snapshot before a
  758. // scan can take the session lock. A regclass/regtype cast or catalog function
  759. // evaluated inside a locked scan would otherwise call back into the session while
  760. // the scan holds its lock, which deadlocks the connection and leaks the table
  761. // lock to every other session. Statements whose value-time expressions cannot
  762. // reach the catalog skip the build entirely.
  763. func (e *Executor) primeCatalogSnapshot(stmt parser.Statement) error {
  764. if e.pgCatalog != nil || !catalogSnapshotStatementNeeded(stmt) {
  765. return nil
  766. }
  767. _, err := e.catalogSnapshotForQuery()
  768. return err
  769. }
  770. // enterLockedScan marks the start of row-filter or update evaluation that runs
  771. // inside a session scan, where the session lock is already held.
  772. func (e *Executor) enterLockedScan() { e.lockedScanDepth++ }
  773. // exitLockedScan marks the end of one such evaluation.
  774. func (e *Executor) exitLockedScan() { e.lockedScanDepth-- }
  775. // visibleCatalogColumns drops the engine's hidden synthetic rowid column, which
  776. // is not a user-visible PostgreSQL attribute.
  777. func visibleCatalogColumns(schema *storage.Schema) []storage.Column {
  778. columns := make([]storage.Column, 0, len(schema.Columns))
  779. for _, column := range schema.Columns {
  780. if schema.UsesSyntheticRowID() && column.Name == "_rowid_" {
  781. continue
  782. }
  783. columns = append(columns, column)
  784. }
  785. return columns
  786. }
  787. func indexCatalogColumns(index *storage.Index) []storage.Column {
  788. columns := make([]storage.Column, len(index.Columns))
  789. for i, column := range index.Columns {
  790. name := column.Name
  791. if name == "" {
  792. name = fmt.Sprintf("expr%d", i+1)
  793. }
  794. columns[i] = storage.Column{Name: name, Type: "TEXT", Nullable: true}
  795. }
  796. return columns
  797. }
  798. func relationNamespaceOID(schemaName string) int64 {
  799. switch schemaName {
  800. case pgCatalogSchemaName:
  801. return pgCatalogNamespaceOID
  802. case informationSchemaName:
  803. return infoSchemaNamespaceOID
  804. default:
  805. return publicNamespaceOID
  806. }
  807. }
  808. // uniqueCatalogName returns base, or base with a numeric suffix, so a synthetic
  809. // relation name never collides with a durable table or index name.
  810. func uniqueCatalogName(base string, used map[string]bool) string {
  811. name := base
  812. for suffix := 2; used[strings.ToLower(name)]; suffix++ {
  813. name = fmt.Sprintf("%s%d", base, suffix)
  814. }
  815. used[strings.ToLower(name)] = true
  816. return name
  817. }
  818. func buildCatalogSnapshot(e *Executor) (*catalogSnapshot, error) {
  819. snapshot := &catalogSnapshot{
  820. database: e.schema.GetDatabaseName(),
  821. relationByKey: make(map[string]*catalogRelation),
  822. relationByOID: make(map[int64]*catalogRelation),
  823. tableByName: make(map[string]*catalogRelation),
  824. tableIndexes: make(map[string][]*catalogRelation),
  825. constraintByOID: make(map[int64]*catalogConstraint),
  826. rows: make(map[string][]storage.Row),
  827. attrdefOIDs: make(map[string]int64),
  828. procOIDs: make(map[string]int64),
  829. oidOwners: make(map[int64]string),
  830. }
  831. if snapshot.database == "" {
  832. snapshot.database = "pizzasql"
  833. }
  834. tables, err := e.session.ListTables()
  835. if err != nil {
  836. return nil, err
  837. }
  838. sort.Strings(tables)
  839. indexNames, err := e.session.ListIndexes()
  840. if err != nil {
  841. return nil, err
  842. }
  843. sort.Strings(indexNames)
  844. var descriptors []*catalogRelation
  845. // usedNames guards every synthetic name against the durable names it could
  846. // collide with. A table named <x>_pkey shadows the synthetic index name a
  847. // PRIMARY KEY on x would otherwise take.
  848. usedNames := make(map[string]bool, len(tables)+len(indexNames)+len(e.views))
  849. tableSchemas := make(map[string]*storage.Schema, len(tables))
  850. for _, tableName := range tables {
  851. schema, err := e.session.GetSchema(tableName)
  852. if err != nil {
  853. return nil, fmt.Errorf("pg_catalog: resolve table %q: %w", tableName, err)
  854. }
  855. tableSchemas[tableName] = schema
  856. usedNames[strings.ToLower(schema.Name)] = true
  857. descriptors = append(descriptors, &catalogRelation{
  858. schemaName: publicSchemaName,
  859. name: schema.Name,
  860. kind: 'r',
  861. columns: visibleCatalogColumns(schema),
  862. table: schema,
  863. })
  864. }
  865. for _, indexName := range indexNames {
  866. index, err := e.session.GetIndex(indexName)
  867. if err != nil {
  868. return nil, fmt.Errorf("pg_catalog: resolve index %q: %w", indexName, err)
  869. }
  870. usedNames[strings.ToLower(index.Name)] = true
  871. descriptors = append(descriptors, &catalogRelation{
  872. schemaName: publicSchemaName,
  873. name: index.Name,
  874. kind: 'i',
  875. columns: indexCatalogColumns(index),
  876. index: index,
  877. })
  878. }
  879. // Session views are part of the schema the connection observes, so they are
  880. // reported the same way PostgreSQL reports a view: a pg_class row with
  881. // relkind 'v' plus matching pg_attribute and information_schema.columns rows.
  882. viewNames := sortedViewNames(e.views)
  883. for _, viewName := range viewNames {
  884. columns := e.viewColumns[viewName]
  885. usedNames[viewName] = true
  886. descriptors = append(descriptors, &catalogRelation{
  887. schemaName: publicSchemaName,
  888. name: viewName,
  889. kind: 'v',
  890. columns: columns,
  891. })
  892. }
  893. // One synthetic index per primary key so pg_index/pg_constraint have a
  894. // stable conindid. Composite keys keep their declared order.
  895. for _, tableName := range tables {
  896. schema := tableSchemas[tableName]
  897. // A table without a declared PRIMARY KEY is addressed by the engine's
  898. // synthetic _rowid_ column, which is not a PostgreSQL attribute and has
  899. // no index.
  900. if schema.UsesSyntheticRowID() {
  901. continue
  902. }
  903. keyColumns := schema.PrimaryKeyList()
  904. if len(keyColumns) == 0 {
  905. continue
  906. }
  907. index := &storage.Index{Name: uniqueCatalogName(schema.Name+"_pkey", usedNames), Table: schema.Name, Unique: true}
  908. for _, column := range keyColumns {
  909. index.Columns = append(index.Columns, storage.IndexColumn{Name: column})
  910. }
  911. descriptors = append(descriptors, &catalogRelation{
  912. schemaName: publicSchemaName,
  913. name: index.Name,
  914. kind: 'i',
  915. columns: indexCatalogColumns(index),
  916. index: index,
  917. primaryIndex: true,
  918. })
  919. }
  920. for _, def := range pgCatalogRelationDefs {
  921. descriptors = append(descriptors, &catalogRelation{
  922. schemaName: def.schema,
  923. name: def.name,
  924. kind: 'v',
  925. columns: pgCatalogRelationIndex[def.schema+"."+def.name].schema.Columns,
  926. virtual: true,
  927. })
  928. }
  929. for _, def := range informationSchemaRelationDefs {
  930. descriptors = append(descriptors, &catalogRelation{
  931. schemaName: def.schema,
  932. name: def.name,
  933. kind: 'v',
  934. columns: pgCatalogRelationIndex[def.schema+"."+def.name].schema.Columns,
  935. virtual: true,
  936. })
  937. }
  938. sort.SliceStable(descriptors, func(i, j int) bool {
  939. if descriptors[i].schemaName != descriptors[j].schemaName {
  940. return descriptors[i].schemaName < descriptors[j].schemaName
  941. }
  942. if descriptors[i].name != descriptors[j].name {
  943. return descriptors[i].name < descriptors[j].name
  944. }
  945. return descriptors[i].kind < descriptors[j].kind
  946. })
  947. for _, relation := range descriptors {
  948. relation.oid = snapshot.allocateOID("relation", catalogRelationKey(relation))
  949. snapshot.relations = append(snapshot.relations, relation)
  950. snapshot.relationByKey[catalogRelationKey(relation)] = relation
  951. snapshot.relationByOID[relation.oid] = relation
  952. if relation.kind == 'r' {
  953. snapshot.tableByName[strings.ToLower(relation.name)] = relation
  954. }
  955. if relation.kind == 'i' {
  956. tableKey := strings.ToLower(relation.index.Table)
  957. snapshot.tableIndexes[tableKey] = append(snapshot.tableIndexes[tableKey], relation)
  958. }
  959. }
  960. // Constraints are allocated after relations so conindid can point at the
  961. // durable or synthetic index OID.
  962. for _, relation := range snapshot.relations {
  963. if relation.kind != 'r' {
  964. continue
  965. }
  966. usedConstraintNames := make(map[string]bool)
  967. addConstraint := func(constraint *catalogConstraint) {
  968. constraint.table = relation
  969. constraint.oid = snapshot.allocateOID("constraint", relation.name+"."+constraint.name)
  970. snapshot.constraints = append(snapshot.constraints, constraint)
  971. snapshot.constraintByOID[constraint.oid] = constraint
  972. }
  973. for _, indexRelation := range snapshot.tableIndexes[strings.ToLower(relation.name)] {
  974. if !indexRelation.primaryIndex {
  975. continue
  976. }
  977. usedConstraintNames[strings.ToLower(indexRelation.name)] = true
  978. addConstraint(&catalogConstraint{
  979. name: indexRelation.name,
  980. contype: 'p',
  981. indexOID: indexRelation.oid,
  982. columns: indexColumnNames(indexRelation.index),
  983. })
  984. }
  985. for _, indexRelation := range snapshot.tableIndexes[strings.ToLower(relation.name)] {
  986. if indexRelation.primaryIndex || !indexRelation.index.Unique {
  987. continue
  988. }
  989. if usedConstraintNames[strings.ToLower(indexRelation.name)] {
  990. continue
  991. }
  992. usedConstraintNames[strings.ToLower(indexRelation.name)] = true
  993. addConstraint(&catalogConstraint{
  994. name: indexRelation.name,
  995. contype: 'u',
  996. indexOID: indexRelation.oid,
  997. columns: indexColumnNames(indexRelation.index),
  998. })
  999. }
  1000. for i := range relation.table.ForeignKeys {
  1001. fk := &relation.table.ForeignKeys[i]
  1002. name := fk.Name
  1003. if name == "" {
  1004. name = relation.name + "_" + strings.Join(fk.Columns, "_") + "_fkey"
  1005. }
  1006. name = uniqueCatalogName(name, usedConstraintNames)
  1007. addConstraint(&catalogConstraint{name: name, contype: 'f', columns: fk.Columns, fk: fk})
  1008. }
  1009. for i := range relation.table.Checks {
  1010. check := &relation.table.Checks[i]
  1011. name := check.Name
  1012. if name == "" {
  1013. name = relation.name + "_check"
  1014. }
  1015. name = uniqueCatalogName(name, usedConstraintNames)
  1016. addConstraint(&catalogConstraint{name: name, contype: 'c', check: check})
  1017. }
  1018. }
  1019. // Default expressions, the database row, and function rows are allocated in
  1020. // sorted/declared order so their OIDs do not depend on which relation a
  1021. // query reads first.
  1022. for _, relation := range snapshot.relations {
  1023. if relation.kind != 'r' {
  1024. continue
  1025. }
  1026. for _, column := range relation.columns {
  1027. if column.DefaultLiteral() == nil {
  1028. continue
  1029. }
  1030. snapshot.attrdefOIDs[attrdefKey(relation.name, column.Name)] = snapshot.allocateOID("attrdef", relation.name+"."+column.Name)
  1031. }
  1032. }
  1033. snapshot.databaseOID = snapshot.allocateOID("database", snapshot.database)
  1034. for _, function := range pgCatalogFunctions {
  1035. snapshot.procOIDs[function.name] = snapshot.allocateOID("proc", function.name)
  1036. }
  1037. return snapshot, nil
  1038. }
  1039. // attrdefKey identifies a column default in the snapshot's OID table.
  1040. func attrdefKey(table, column string) string {
  1041. return strings.ToLower(table) + "." + strings.ToLower(column)
  1042. }
  1043. // sortedViewNames returns the session's view names in deterministic order.
  1044. func sortedViewNames(views map[string]*parser.SelectStmt) []string {
  1045. names := make([]string, 0, len(views))
  1046. for name := range views {
  1047. names = append(names, name)
  1048. }
  1049. sort.Strings(names)
  1050. return names
  1051. }
  1052. func indexColumnNames(index *storage.Index) []string {
  1053. names := make([]string, len(index.Columns))
  1054. for i, column := range index.Columns {
  1055. names[i] = column.Name
  1056. }
  1057. return names
  1058. }
  1059. // regclassOID resolves a relation name the way a regclass literal does:
  1060. // an explicit schema or the public search path, with pg_catalog implicit.
  1061. func (s *catalogSnapshot) regclassOID(name string) (int64, bool) {
  1062. name = strings.TrimSpace(name)
  1063. name = strings.Trim(name, `"`)
  1064. if name == "" {
  1065. return 0, false
  1066. }
  1067. if dot := strings.IndexByte(name, '.'); dot >= 0 {
  1068. schemaName := strings.Trim(strings.TrimSpace(name[:dot]), `"`)
  1069. tableName := strings.Trim(strings.TrimSpace(name[dot+1:]), `"`)
  1070. if relation := s.regclassRelation(schemaName, tableName); relation != nil {
  1071. return relation.oid, true
  1072. }
  1073. return 0, false
  1074. }
  1075. if relation := s.regclassRelation(publicSchemaName, name); relation != nil {
  1076. return relation.oid, true
  1077. }
  1078. if relation := s.regclassRelation(pgCatalogSchemaName, name); relation != nil {
  1079. return relation.oid, true
  1080. }
  1081. return 0, false
  1082. }
  1083. // regclassRelation resolves a schema-qualified relation name to the row a
  1084. // regclass literal names. PostgreSQL keeps relation names unique inside a
  1085. // schema, but the engine lets an index share its table's name, so the lookup
  1086. // prefers a table, then a session view, then an index.
  1087. func (s *catalogSnapshot) regclassRelation(schemaName, name string) *catalogRelation {
  1088. key := strings.ToLower(schemaName + "." + name)
  1089. for _, kind := range []byte{'r', 'v', 'i'} {
  1090. if relation, ok := s.relationByKey[key+"#"+string(kind)]; ok {
  1091. return relation
  1092. }
  1093. }
  1094. return nil
  1095. }
  1096. // regclassName renders a relation OID the way regclass output does.
  1097. func (s *catalogSnapshot) regclassName(oid int64) (string, bool) {
  1098. relation, ok := s.relationByOID[oid]
  1099. if !ok {
  1100. return "", false
  1101. }
  1102. return relation.name, true
  1103. }
  1104. // tableRelationFor resolves a table name (unqualified or schema-qualified) to
  1105. // its public relation row.
  1106. func (s *catalogSnapshot) tableRelationFor(name string) *catalogRelation {
  1107. name = strings.TrimSpace(name)
  1108. if dot := strings.IndexByte(name, '.'); dot >= 0 {
  1109. name = name[dot+1:]
  1110. }
  1111. return s.tableByName[strings.ToLower(name)]
  1112. }
  1113. func catalogAttributeNumbers(schema *storage.Schema) map[string]int64 {
  1114. numbers := make(map[string]int64, len(schema.Columns))
  1115. position := int64(0)
  1116. for _, column := range visibleCatalogColumns(schema) {
  1117. position++
  1118. numbers[strings.ToLower(column.Name)] = position
  1119. }
  1120. return numbers
  1121. }
  1122. func oidListText(values []int64) string {
  1123. parts := make([]string, len(values))
  1124. for i, value := range values {
  1125. parts[i] = strconv.FormatInt(value, 10)
  1126. }
  1127. return "{" + strings.Join(parts, ",") + "}"
  1128. }
  1129. func defaultExpressionText(column storage.Column) interface{} {
  1130. value := column.DefaultLiteral()
  1131. if value == nil {
  1132. return nil
  1133. }
  1134. return sqlLiteral(value)
  1135. }
  1136. // ---------------------------------------------------------------------------
  1137. // Row builders
  1138. func (s *catalogSnapshot) relationRows(key string) []storage.Row {
  1139. key = strings.ToLower(key)
  1140. if rows, ok := s.rows[key]; ok {
  1141. return rows
  1142. }
  1143. var rows []storage.Row
  1144. switch key {
  1145. case "pg_catalog.pg_namespace":
  1146. rows = s.pgNamespaceRows()
  1147. case "pg_catalog.pg_class":
  1148. rows = s.pgClassRows()
  1149. case "pg_catalog.pg_attribute":
  1150. rows = s.pgAttributeRows()
  1151. case "pg_catalog.pg_type":
  1152. rows = s.pgTypeRows()
  1153. case "pg_catalog.pg_index":
  1154. rows = s.pgIndexRows()
  1155. case "pg_catalog.pg_constraint":
  1156. rows = s.pgConstraintRows()
  1157. case "pg_catalog.pg_attrdef":
  1158. rows = s.pgAttrdefRows()
  1159. case "pg_catalog.pg_database":
  1160. rows = s.pgDatabaseRows()
  1161. case "pg_catalog.pg_tablespace":
  1162. rows = s.pgTablespaceRows()
  1163. case "pg_catalog.pg_proc":
  1164. rows = s.pgProcRows()
  1165. case "pg_catalog.pg_am":
  1166. rows = s.pgAmRows()
  1167. case "pg_catalog.pg_description":
  1168. rows = []storage.Row{}
  1169. case "pg_catalog.pg_tables":
  1170. rows = s.pgTablesRows()
  1171. case "pg_catalog.pg_indexes":
  1172. rows = s.pgIndexesRows()
  1173. case "information_schema.tables":
  1174. rows = s.informationSchemaTablesRows()
  1175. case "information_schema.columns":
  1176. rows = s.informationSchemaColumnsRows()
  1177. case "information_schema.table_constraints":
  1178. rows = s.informationSchemaTableConstraintsRows()
  1179. case "information_schema.key_column_usage":
  1180. rows = s.informationSchemaKeyColumnUsageRows()
  1181. case "information_schema.referential_constraints":
  1182. rows = s.informationSchemaReferentialConstraintsRows()
  1183. case "information_schema.constraint_column_usage":
  1184. rows = s.informationSchemaConstraintColumnUsageRows()
  1185. case "information_schema.schemata":
  1186. rows = s.informationSchemaSchemataRows()
  1187. case "information_schema.sequences":
  1188. rows = []storage.Row{}
  1189. case "information_schema.views":
  1190. rows = s.informationSchemaViewsRows()
  1191. default:
  1192. rows = []storage.Row{}
  1193. }
  1194. s.rows[key] = rows
  1195. return rows
  1196. }
  1197. func (s *catalogSnapshot) pgNamespaceRows() []storage.Row {
  1198. return []storage.Row{
  1199. {"oid": pgCatalogNamespaceOID, "nspname": pgCatalogSchemaName, "nspowner": catalogOwnerOID, "nspacl": nil},
  1200. {"oid": publicNamespaceOID, "nspname": publicSchemaName, "nspowner": catalogOwnerOID, "nspacl": nil},
  1201. {"oid": infoSchemaNamespaceOID, "nspname": informationSchemaName, "nspowner": catalogOwnerOID, "nspacl": nil},
  1202. }
  1203. }
  1204. func (s *catalogSnapshot) pgClassRows() []storage.Row {
  1205. rows := make([]storage.Row, 0, len(s.relations))
  1206. for _, relation := range s.relations {
  1207. hasIndex := false
  1208. checks := int64(0)
  1209. relfilenode := int64(0)
  1210. relam := int64(0)
  1211. switch relation.kind {
  1212. case 'r':
  1213. hasIndex = len(s.tableIndexes[strings.ToLower(relation.name)]) > 0
  1214. checks = int64(len(relation.table.Checks))
  1215. relfilenode = relation.oid
  1216. case 'i':
  1217. relfilenode = relation.oid
  1218. relam = pgBtreeAMOID
  1219. }
  1220. rows = append(rows, storage.Row{
  1221. "oid": relation.oid,
  1222. "relname": relation.name,
  1223. "relnamespace": relationNamespaceOID(relation.schemaName),
  1224. "reltype": int64(0),
  1225. "reloftype": int64(0),
  1226. "relowner": catalogOwnerOID,
  1227. "relam": relam,
  1228. "relfilenode": relfilenode,
  1229. "reltablespace": int64(0),
  1230. "relpages": int64(0),
  1231. "reltuples": float64(0),
  1232. "relallvisible": int64(0),
  1233. "reltoastrelid": int64(0),
  1234. "relhasindex": hasIndex,
  1235. "relisshared": false,
  1236. "relpersistence": "p",
  1237. "relkind": string(relation.kind),
  1238. "relnatts": int64(len(relation.columns)),
  1239. "relchecks": checks,
  1240. "relhasrules": false,
  1241. "relhastriggers": false,
  1242. "relhassubclass": false,
  1243. "relrowsecurity": false,
  1244. "relforcerowsecurity": false,
  1245. "relispopulated": true,
  1246. "relreplident": "d",
  1247. "relispartition": false,
  1248. "relrewrite": int64(0),
  1249. "relfrozenxid": int64(0),
  1250. "relminmxid": int64(0),
  1251. "relacl": nil,
  1252. "reloptions": nil,
  1253. "relpartbound": nil,
  1254. })
  1255. }
  1256. return rows
  1257. }
  1258. func (s *catalogSnapshot) relationAttributeType(relation *catalogRelation, column storage.Column) pgBuiltinType {
  1259. if relation.kind == 'i' && relation.index != nil {
  1260. if table := s.tableRelationFor(relation.index.Table); table != nil {
  1261. for _, tableColumn := range table.columns {
  1262. if strings.EqualFold(tableColumn.Name, column.Name) {
  1263. return pgTypeForDeclaredName(tableColumn.Type)
  1264. }
  1265. }
  1266. }
  1267. }
  1268. return pgTypeForDeclaredName(column.Type)
  1269. }
  1270. func (s *catalogSnapshot) pgAttributeRows() []storage.Row {
  1271. var rows []storage.Row
  1272. for _, relation := range s.relations {
  1273. for i, column := range relation.columns {
  1274. builtin := s.relationAttributeType(relation, column)
  1275. notNull := false
  1276. hasDefault := false
  1277. generated := ""
  1278. if relation.kind == 'r' {
  1279. notNull = !column.Nullable
  1280. hasDefault = column.DefaultLiteral() != nil
  1281. if column.GeneratedExpr != "" {
  1282. generated = "s"
  1283. }
  1284. }
  1285. arrayDimensions := int64(0)
  1286. if builtin.isArray() {
  1287. arrayDimensions = 1
  1288. }
  1289. rows = append(rows, storage.Row{
  1290. "attrelid": relation.oid,
  1291. "attname": column.Name,
  1292. "atttypid": builtin.oid,
  1293. "attstattarget": int64(-1),
  1294. "attlen": builtin.length,
  1295. "attnum": int64(i + 1),
  1296. "attndims": arrayDimensions,
  1297. "attcacheoff": int64(-1),
  1298. "atttypmod": int64(-1),
  1299. "attbyval": builtin.byval,
  1300. "attalign": builtin.align,
  1301. "attstorage": builtin.storage,
  1302. "attcompression": "",
  1303. "attnotnull": notNull,
  1304. "atthasdef": hasDefault,
  1305. "atthasmissing": false,
  1306. "attidentity": "",
  1307. "attgenerated": generated,
  1308. "attisdropped": false,
  1309. "attislocal": true,
  1310. "attinhcount": int64(0),
  1311. "attcollation": int64(0),
  1312. "attacl": nil,
  1313. "attoptions": nil,
  1314. "attfdwoptions": nil,
  1315. "attmissingval": nil,
  1316. })
  1317. }
  1318. }
  1319. return rows
  1320. }
  1321. func (s *catalogSnapshot) pgTypeRows() []storage.Row {
  1322. rows := make([]storage.Row, 0, len(pgBuiltinTypes))
  1323. for _, t := range pgBuiltinTypes {
  1324. rows = append(rows, storage.Row{
  1325. "oid": t.oid,
  1326. "typname": t.name,
  1327. "typnamespace": pgCatalogNamespaceOID,
  1328. "typowner": catalogOwnerOID,
  1329. "typlen": t.length,
  1330. "typbyval": t.byval,
  1331. "typtype": "b",
  1332. "typcategory": t.category,
  1333. "typispreferred": false,
  1334. "typisdefined": true,
  1335. "typdelim": t.delim,
  1336. "typrelid": int64(0),
  1337. "typsubscript": nil,
  1338. "typelem": t.elem,
  1339. "typarray": t.array,
  1340. "typinput": int64(0),
  1341. "typoutput": int64(0),
  1342. "typreceive": int64(0),
  1343. "typsend": int64(0),
  1344. "typmodin": int64(0),
  1345. "typmodout": int64(0),
  1346. "typanalyze": int64(0),
  1347. "typalign": t.align,
  1348. "typstorage": t.storage,
  1349. "typnotnull": false,
  1350. "typbasetype": int64(0),
  1351. "typtypmod": int64(-1),
  1352. "typndims": int64(0),
  1353. "typcollation": int64(0),
  1354. "typdefaultbin": nil,
  1355. "typdefault": nil,
  1356. "typacl": nil,
  1357. })
  1358. }
  1359. return rows
  1360. }
  1361. func (s *catalogSnapshot) indexAttributeNumbers(indexRelation *catalogRelation) []int64 {
  1362. numbers := make([]int64, len(indexRelation.index.Columns))
  1363. table := s.tableRelationFor(indexRelation.index.Table)
  1364. if table == nil {
  1365. return numbers
  1366. }
  1367. attnums := catalogAttributeNumbers(table.table)
  1368. for i, column := range indexRelation.index.Columns {
  1369. if column.Name == "" {
  1370. continue
  1371. }
  1372. numbers[i] = attnums[strings.ToLower(column.Name)]
  1373. }
  1374. return numbers
  1375. }
  1376. func (s *catalogSnapshot) pgIndexRows() []storage.Row {
  1377. var rows []storage.Row
  1378. for _, relation := range s.relations {
  1379. if relation.kind != 'i' || relation.index == nil {
  1380. continue
  1381. }
  1382. table := s.tableRelationFor(relation.index.Table)
  1383. tableOID := int64(0)
  1384. if table != nil {
  1385. tableOID = table.oid
  1386. }
  1387. attnums := s.indexAttributeNumbers(relation)
  1388. options := make([]int64, len(attnums))
  1389. var expressions []string
  1390. hasExpression := false
  1391. for _, column := range relation.index.Columns {
  1392. if column.Expression != "" {
  1393. expressions = append(expressions, column.Expression)
  1394. hasExpression = true
  1395. }
  1396. }
  1397. var indexprs interface{}
  1398. if hasExpression {
  1399. indexprs = strings.Join(expressions, ", ")
  1400. }
  1401. rows = append(rows, storage.Row{
  1402. "indexrelid": relation.oid,
  1403. "indrelid": tableOID,
  1404. "indnatts": int64(len(attnums)),
  1405. "indnkeyatts": int64(len(attnums)),
  1406. "indisunique": relation.index.Unique,
  1407. "indisprimary": relation.primaryIndex,
  1408. "indisexclusion": false,
  1409. "indimmediate": true,
  1410. "indisclustered": false,
  1411. "indisvalid": true,
  1412. "indcheckxmin": false,
  1413. "indisready": true,
  1414. "indislive": true,
  1415. "indisreplident": false,
  1416. "indkey": oidListText(attnums),
  1417. "indcollation": oidListText(make([]int64, len(attnums))),
  1418. "indclass": oidListText(make([]int64, len(attnums))),
  1419. "indoption": oidListText(options),
  1420. "indexprs": indexprs,
  1421. "indpred": nil,
  1422. })
  1423. }
  1424. return rows
  1425. }
  1426. func constraintActionCode(action string) string {
  1427. switch strings.ToUpper(strings.TrimSpace(action)) {
  1428. case "CASCADE":
  1429. return "c"
  1430. case "RESTRICT":
  1431. return "r"
  1432. case "SET NULL":
  1433. return "n"
  1434. case "SET DEFAULT":
  1435. return "d"
  1436. default:
  1437. return "a"
  1438. }
  1439. }
  1440. func (s *catalogSnapshot) pgConstraintRows() []storage.Row {
  1441. rows := make([]storage.Row, 0, len(s.constraints))
  1442. for _, constraint := range s.constraints {
  1443. var conkey interface{}
  1444. if len(constraint.columns) > 0 {
  1445. attnums := catalogAttributeNumbers(constraint.table.table)
  1446. key := make([]int64, 0, len(constraint.columns))
  1447. for _, name := range constraint.columns {
  1448. key = append(key, attnums[strings.ToLower(name)])
  1449. }
  1450. conkey = oidListText(key)
  1451. }
  1452. var confrelid, confupdtype, confdeltype, confmatchtype, confkey interface{}
  1453. if constraint.fk != nil {
  1454. if parent := s.tableRelationFor(constraint.fk.RefTable); parent != nil {
  1455. confrelid = parent.oid
  1456. parentAttnums := catalogAttributeNumbers(parent.table)
  1457. key := make([]int64, 0, len(constraint.fk.RefColumns))
  1458. for _, name := range constraint.fk.RefColumns {
  1459. key = append(key, parentAttnums[strings.ToLower(name)])
  1460. }
  1461. confkey = oidListText(key)
  1462. } else {
  1463. confrelid = int64(0)
  1464. }
  1465. confupdtype = constraintActionCode(constraint.fk.OnUpdate)
  1466. confdeltype = constraintActionCode(constraint.fk.OnDelete)
  1467. confmatchtype = "s"
  1468. }
  1469. var conbin interface{}
  1470. if constraint.check != nil {
  1471. conbin = constraint.check.Expression
  1472. }
  1473. rows = append(rows, storage.Row{
  1474. "oid": constraint.oid,
  1475. "conname": constraint.name,
  1476. "connamespace": publicNamespaceOID,
  1477. "contype": string(constraint.contype),
  1478. "condeferrable": false,
  1479. "condeferred": false,
  1480. "convalidated": true,
  1481. "conrelid": constraint.table.oid,
  1482. "contypid": int64(0),
  1483. "conindid": constraint.indexOID,
  1484. "conparentid": int64(0),
  1485. "confrelid": confrelid,
  1486. "confupdtype": confupdtype,
  1487. "confdeltype": confdeltype,
  1488. "confmatchtype": confmatchtype,
  1489. "conislocal": true,
  1490. "coninhcount": int64(0),
  1491. "connoinherit": false,
  1492. "conkey": conkey,
  1493. "confkey": confkey,
  1494. "conpfeqop": nil,
  1495. "conppeqop": nil,
  1496. "conffeqop": nil,
  1497. "conexclop": nil,
  1498. "conbin": conbin,
  1499. "consrc": conbin,
  1500. })
  1501. }
  1502. return rows
  1503. }
  1504. func (s *catalogSnapshot) pgAttrdefRows() []storage.Row {
  1505. var rows []storage.Row
  1506. for _, relation := range s.relations {
  1507. if relation.kind != 'r' {
  1508. continue
  1509. }
  1510. attnums := catalogAttributeNumbers(relation.table)
  1511. for _, column := range relation.columns {
  1512. text := defaultExpressionText(column)
  1513. if text == nil {
  1514. continue
  1515. }
  1516. adnum := attnums[strings.ToLower(column.Name)]
  1517. rows = append(rows, storage.Row{
  1518. "oid": s.attrdefOIDs[attrdefKey(relation.name, column.Name)],
  1519. "adrelid": relation.oid,
  1520. "adnum": adnum,
  1521. "adbin": text,
  1522. })
  1523. }
  1524. }
  1525. return rows
  1526. }
  1527. func (s *catalogSnapshot) pgDatabaseRows() []storage.Row {
  1528. return []storage.Row{{
  1529. "oid": s.databaseOID,
  1530. "datname": s.database,
  1531. "datdba": catalogOwnerOID,
  1532. "encoding": int64(6), // UTF8
  1533. "datlocprovider": "c",
  1534. "datistemplate": false,
  1535. "datallowconn": true,
  1536. "datconnlimit": int64(-1),
  1537. "datlastsysoid": int64(0),
  1538. "datfrozenxid": int64(0),
  1539. "datminmxid": int64(0),
  1540. "dattablespace": pgDefaultTablespaceOID,
  1541. "datcollate": "C",
  1542. "datctype": "C",
  1543. "datlocale": nil,
  1544. "daticurules": nil,
  1545. "datcollversion": nil,
  1546. "datacl": nil,
  1547. }}
  1548. }
  1549. func (s *catalogSnapshot) pgTablespaceRows() []storage.Row {
  1550. return []storage.Row{
  1551. {"oid": pgDefaultTablespaceOID, "spcname": "pg_default", "spcowner": catalogOwnerOID, "spcacl": nil, "spcoptions": nil},
  1552. {"oid": pgGlobalTablespaceOID, "spcname": "pg_global", "spcowner": catalogOwnerOID, "spcacl": nil, "spcoptions": nil},
  1553. }
  1554. }
  1555. // pgCatalogFunctions is the pg_proc surface the executor answers. It mirrors
  1556. // evalCatalogFunction; names not listed here never appear in pg_proc.
  1557. var pgCatalogFunctions = []struct {
  1558. name string
  1559. nargs int64
  1560. rettype int64
  1561. }{
  1562. {"current_database", 0, 19},
  1563. {"current_schema", 0, 19},
  1564. {"format_type", 2, 25},
  1565. {"has_table_privilege", 3, 16},
  1566. {"obj_description", 2, 25},
  1567. {"col_description", 2, 25},
  1568. {"pg_get_constraintdef", 2, 25},
  1569. {"pg_get_expr", 3, 25},
  1570. {"pg_get_indexdef", 3, 25},
  1571. {"pg_get_serial_sequence", 2, 25},
  1572. {"pg_get_userbyid", 1, 19},
  1573. {"pg_table_is_visible", 1, 16},
  1574. {"to_regclass", 1, 2205},
  1575. {"to_regtype", 1, 2206},
  1576. }
  1577. func (s *catalogSnapshot) pgProcRows() []storage.Row {
  1578. rows := make([]storage.Row, 0, len(pgCatalogFunctions))
  1579. for _, function := range pgCatalogFunctions {
  1580. rows = append(rows, storage.Row{
  1581. "oid": s.procOIDs[function.name],
  1582. "proname": function.name,
  1583. "pronamespace": pgCatalogNamespaceOID,
  1584. "proowner": catalogOwnerOID,
  1585. "prolang": int64(12), // internal
  1586. "procost": float64(1),
  1587. "prorows": float64(0),
  1588. "provariadic": int64(0),
  1589. "prosupport": nil,
  1590. "prokind": "f",
  1591. "prosecdef": false,
  1592. "proleakproof": false,
  1593. "proisstrict": true,
  1594. "proretset": false,
  1595. "provolatile": "s",
  1596. "proparallel": "s",
  1597. "pronargs": function.nargs,
  1598. "pronargdefaults": int64(0),
  1599. "prorettype": function.rettype,
  1600. "proargtypes": "",
  1601. "proallargtypes": nil,
  1602. "proargmodes": nil,
  1603. "proargnames": nil,
  1604. "proargdefaults": nil,
  1605. "protrftypes": nil,
  1606. "prosrc": function.name,
  1607. "probin": nil,
  1608. "prosqlbody": nil,
  1609. "proconfig": nil,
  1610. "proacl": nil,
  1611. })
  1612. }
  1613. return rows
  1614. }
  1615. func (s *catalogSnapshot) pgAmRows() []storage.Row {
  1616. return []storage.Row{
  1617. {"oid": pgHeapAMOID, "amname": "heap", "amhandler": int64(0), "amtype": "t"},
  1618. {"oid": pgBtreeAMOID, "amname": "btree", "amhandler": int64(0), "amtype": "i"},
  1619. }
  1620. }
  1621. func (s *catalogSnapshot) pgTablesRows() []storage.Row {
  1622. var rows []storage.Row
  1623. for _, relation := range s.relations {
  1624. if relation.kind != 'r' {
  1625. continue
  1626. }
  1627. hasIndex := len(s.tableIndexes[strings.ToLower(relation.name)]) > 0
  1628. rows = append(rows, storage.Row{
  1629. "schemaname": relation.schemaName,
  1630. "tablename": relation.name,
  1631. "tableowner": "pizzasql",
  1632. "tablespace": nil,
  1633. "hasindexes": hasIndex,
  1634. "hasrules": false,
  1635. "hastriggers": false,
  1636. "rowsecurity": false,
  1637. })
  1638. }
  1639. return rows
  1640. }
  1641. func (s *catalogSnapshot) pgIndexesRows() []storage.Row {
  1642. var rows []storage.Row
  1643. for _, relation := range s.relations {
  1644. if relation.kind != 'i' || relation.index == nil {
  1645. continue
  1646. }
  1647. rows = append(rows, storage.Row{
  1648. "schemaname": relation.schemaName,
  1649. "tablename": relation.index.Table,
  1650. "indexname": relation.name,
  1651. "tablespace": nil,
  1652. "indexdef": s.indexDefinition(relation.index),
  1653. })
  1654. }
  1655. return rows
  1656. }
  1657. // ---------------------------------------------------------------------------
  1658. // information_schema row builders
  1659. func (s *catalogSnapshot) informationSchemaTablesRows() []storage.Row {
  1660. var rows []storage.Row
  1661. for _, relation := range s.relations {
  1662. if relation.kind == 'i' {
  1663. continue
  1664. }
  1665. tableType := "BASE TABLE"
  1666. if relation.kind != 'r' {
  1667. tableType = "VIEW"
  1668. }
  1669. insertable := "NO"
  1670. if relation.kind == 'r' {
  1671. insertable = "YES"
  1672. }
  1673. rows = append(rows, storage.Row{
  1674. "table_catalog": s.database,
  1675. "table_schema": relation.schemaName,
  1676. "table_name": relation.name,
  1677. "table_type": tableType,
  1678. "self_referencing_column_name": nil,
  1679. "reference_generation": nil,
  1680. "user_defined_type_catalog": nil,
  1681. "user_defined_type_schema": nil,
  1682. "user_defined_type_name": nil,
  1683. "is_insertable_into": insertable,
  1684. "is_typed": "NO",
  1685. "commit_action": nil,
  1686. })
  1687. }
  1688. return rows
  1689. }
  1690. func informationSchemaColumn(relation *catalogRelation, column storage.Column, position int) storage.Row {
  1691. builtin := pgTypeForDeclaredName(column.Type)
  1692. dataType := builtin.sqlName
  1693. if builtin.isArray() {
  1694. dataType = "ARRAY"
  1695. }
  1696. generated := "NEVER"
  1697. generationExpression := interface{}(nil)
  1698. if column.GeneratedExpr != "" {
  1699. generated = "ALWAYS"
  1700. generationExpression = column.GeneratedExpr
  1701. }
  1702. return storage.Row{
  1703. "table_catalog": "", // filled by the caller
  1704. "table_schema": relation.schemaName,
  1705. "table_name": relation.name,
  1706. "column_name": column.Name,
  1707. "ordinal_position": int64(position),
  1708. "column_default": defaultExpressionText(column),
  1709. "is_nullable": map[bool]string{true: "YES", false: "NO"}[column.Nullable],
  1710. "data_type": dataType,
  1711. "character_maximum_length": nil,
  1712. "character_octet_length": nil,
  1713. "numeric_precision": nil,
  1714. "numeric_precision_radix": nil,
  1715. "numeric_scale": nil,
  1716. "datetime_precision": nil,
  1717. "interval_type": nil,
  1718. "interval_precision": nil,
  1719. "character_set_catalog": nil,
  1720. "character_set_schema": nil,
  1721. "character_set_name": nil,
  1722. "collation_catalog": nil,
  1723. "collation_schema": nil,
  1724. "collation_name": nil,
  1725. "domain_catalog": nil,
  1726. "domain_schema": nil,
  1727. "domain_name": nil,
  1728. "udt_catalog": "", // filled by the caller
  1729. "udt_schema": pgCatalogSchemaName,
  1730. "udt_name": builtin.name,
  1731. "scope_catalog": nil,
  1732. "scope_schema": nil,
  1733. "scope_name": nil,
  1734. "maximum_cardinality": nil,
  1735. "dtd_identifier": strconv.Itoa(position),
  1736. "is_self_referencing": "NO",
  1737. "is_identity": "NO",
  1738. "identity_generation": nil,
  1739. "identity_start": nil,
  1740. "identity_increment": nil,
  1741. "identity_maximum": nil,
  1742. "identity_minimum": nil,
  1743. "identity_cycle": "NO",
  1744. "is_generated": generated,
  1745. "generation_expression": generationExpression,
  1746. "is_updatable": "YES",
  1747. }
  1748. }
  1749. func (s *catalogSnapshot) informationSchemaColumnsRows() []storage.Row {
  1750. var rows []storage.Row
  1751. for _, relation := range s.relations {
  1752. if relation.kind == 'i' || relation.virtual {
  1753. continue
  1754. }
  1755. for i, column := range relation.columns {
  1756. row := informationSchemaColumn(relation, column, i+1)
  1757. row["table_catalog"] = s.database
  1758. row["udt_catalog"] = s.database
  1759. rows = append(rows, row)
  1760. }
  1761. }
  1762. return rows
  1763. }
  1764. func constraintTypeName(contype byte) string {
  1765. switch contype {
  1766. case 'p':
  1767. return "PRIMARY KEY"
  1768. case 'u':
  1769. return "UNIQUE"
  1770. case 'f':
  1771. return "FOREIGN KEY"
  1772. case 'c':
  1773. return "CHECK"
  1774. default:
  1775. return "UNKNOWN"
  1776. }
  1777. }
  1778. func (s *catalogSnapshot) informationSchemaTableConstraintsRows() []storage.Row {
  1779. rows := make([]storage.Row, 0, len(s.constraints))
  1780. for _, constraint := range s.constraints {
  1781. rows = append(rows, storage.Row{
  1782. "constraint_catalog": s.database,
  1783. "constraint_schema": publicSchemaName,
  1784. "constraint_name": constraint.name,
  1785. "table_catalog": s.database,
  1786. "table_schema": publicSchemaName,
  1787. "table_name": constraint.table.name,
  1788. "constraint_type": constraintTypeName(constraint.contype),
  1789. "is_deferrable": "NO",
  1790. "initially_deferred": "NO",
  1791. "enforced": "YES",
  1792. "nulls_distinct": nil,
  1793. })
  1794. }
  1795. return rows
  1796. }
  1797. func (s *catalogSnapshot) informationSchemaKeyColumnUsageRows() []storage.Row {
  1798. var rows []storage.Row
  1799. for _, constraint := range s.constraints {
  1800. var columns []string
  1801. switch constraint.contype {
  1802. case 'p', 'u':
  1803. columns = constraint.columns
  1804. case 'f':
  1805. columns = constraint.fk.Columns
  1806. default:
  1807. continue
  1808. }
  1809. for i, column := range columns {
  1810. var position interface{}
  1811. if constraint.contype == 'f' {
  1812. position = int64(i + 1)
  1813. }
  1814. rows = append(rows, storage.Row{
  1815. "constraint_catalog": s.database,
  1816. "constraint_schema": publicSchemaName,
  1817. "constraint_name": constraint.name,
  1818. "table_catalog": s.database,
  1819. "table_schema": publicSchemaName,
  1820. "table_name": constraint.table.name,
  1821. "column_name": column,
  1822. "ordinal_position": int64(i + 1),
  1823. "position_in_unique_constraint": position,
  1824. })
  1825. }
  1826. }
  1827. return rows
  1828. }
  1829. func (s *catalogSnapshot) uniqueConstraintFor(parent *catalogRelation, columns []string) string {
  1830. for _, constraint := range s.constraints {
  1831. if constraint.table != parent || (constraint.contype != 'p' && constraint.contype != 'u') {
  1832. continue
  1833. }
  1834. keyColumns := constraint.columns
  1835. if constraint.contype == 'u' && constraint.indexOID != 0 {
  1836. for _, indexRelation := range s.relations {
  1837. if indexRelation.oid == constraint.indexOID && indexRelation.index != nil {
  1838. keyColumns = indexColumnNames(indexRelation.index)
  1839. break
  1840. }
  1841. }
  1842. }
  1843. if len(keyColumns) != len(columns) {
  1844. continue
  1845. }
  1846. matches := true
  1847. for i := range columns {
  1848. if !strings.EqualFold(keyColumns[i], columns[i]) {
  1849. matches = false
  1850. break
  1851. }
  1852. }
  1853. if matches {
  1854. return constraint.name
  1855. }
  1856. }
  1857. return ""
  1858. }
  1859. func referentialRule(action string) string {
  1860. if strings.TrimSpace(action) == "" {
  1861. return "NO ACTION"
  1862. }
  1863. return strings.ToUpper(strings.TrimSpace(action))
  1864. }
  1865. func (s *catalogSnapshot) informationSchemaReferentialConstraintsRows() []storage.Row {
  1866. var rows []storage.Row
  1867. for _, constraint := range s.constraints {
  1868. if constraint.contype != 'f' || constraint.fk == nil {
  1869. continue
  1870. }
  1871. parent := s.tableRelationFor(constraint.fk.RefTable)
  1872. var uniqueName interface{}
  1873. if parent != nil {
  1874. if name := s.uniqueConstraintFor(parent, constraint.fk.RefColumns); name != "" {
  1875. uniqueName = name
  1876. }
  1877. }
  1878. rows = append(rows, storage.Row{
  1879. "constraint_catalog": s.database,
  1880. "constraint_schema": publicSchemaName,
  1881. "constraint_name": constraint.name,
  1882. "unique_constraint_catalog": s.database,
  1883. "unique_constraint_schema": publicSchemaName,
  1884. "unique_constraint_name": uniqueName,
  1885. "match_option": "NONE",
  1886. "update_rule": referentialRule(constraint.fk.OnUpdate),
  1887. "delete_rule": referentialRule(constraint.fk.OnDelete),
  1888. "is_deferrable": "NO",
  1889. "initially_deferred": "NO",
  1890. "enforced": "YES",
  1891. })
  1892. }
  1893. return rows
  1894. }
  1895. func (s *catalogSnapshot) informationSchemaConstraintColumnUsageRows() []storage.Row {
  1896. var rows []storage.Row
  1897. for _, constraint := range s.constraints {
  1898. switch constraint.contype {
  1899. case 'f':
  1900. if constraint.fk == nil {
  1901. continue
  1902. }
  1903. for _, column := range constraint.fk.RefColumns {
  1904. rows = append(rows, storage.Row{
  1905. "table_catalog": s.database,
  1906. "table_schema": publicSchemaName,
  1907. "table_name": constraint.fk.RefTable,
  1908. "constraint_catalog": s.database,
  1909. "constraint_schema": publicSchemaName,
  1910. "constraint_name": constraint.name,
  1911. "column_name": column,
  1912. })
  1913. }
  1914. case 'c':
  1915. if constraint.check == nil {
  1916. continue
  1917. }
  1918. expr, err := parser.ParseExpr(constraint.check.Expression)
  1919. if err != nil {
  1920. continue
  1921. }
  1922. for _, column := range collectColumnRefs(expr) {
  1923. rows = append(rows, storage.Row{
  1924. "table_catalog": s.database,
  1925. "table_schema": publicSchemaName,
  1926. "table_name": constraint.table.name,
  1927. "constraint_catalog": s.database,
  1928. "constraint_schema": publicSchemaName,
  1929. "constraint_name": constraint.name,
  1930. "column_name": column,
  1931. })
  1932. }
  1933. }
  1934. }
  1935. return rows
  1936. }
  1937. func (s *catalogSnapshot) informationSchemaSchemataRows() []storage.Row {
  1938. return []storage.Row{
  1939. {"catalog_name": s.database, "schema_name": pgCatalogSchemaName, "schema_owner": "pizzasql", "default_character_set_catalog": nil, "default_character_set_schema": nil, "default_character_set_name": nil, "sql_path": nil},
  1940. {"catalog_name": s.database, "schema_name": publicSchemaName, "schema_owner": "pizzasql", "default_character_set_catalog": nil, "default_character_set_schema": nil, "default_character_set_name": nil, "sql_path": nil},
  1941. {"catalog_name": s.database, "schema_name": informationSchemaName, "schema_owner": "pizzasql", "default_character_set_catalog": nil, "default_character_set_schema": nil, "default_character_set_name": nil, "sql_path": nil},
  1942. }
  1943. }
  1944. // catalogSchemaByName resolves an unqualified pg_catalog relation name that is
  1945. // not shadowed by a durable table or a CTE.
  1946. func (e *Executor) catalogSchemaByName(name string) (*storage.Schema, bool) {
  1947. entry, ok := pgCatalogRelationIndex[pgCatalogSchemaName+"."+strings.ToLower(name)]
  1948. if !ok || e.catalogTableExists(name) || e.cteTableExists(name) {
  1949. return nil, false
  1950. }
  1951. return entry.schema, true
  1952. }
  1953. // fromResolvesToCatalogRelations reports whether every FROM entry is a virtual
  1954. // catalog relation or a materialized CTE, so the statement can be evaluated
  1955. // without reading the durable schema. A statement with no FROM needs no schema
  1956. // either.
  1957. func (e *Executor) fromResolvesToCatalogRelations(from []parser.TableRef) bool {
  1958. for i := range from {
  1959. ref := &from[i]
  1960. if e.cteTableExists(ref.Name) {
  1961. continue
  1962. }
  1963. if _, ok := e.catalogRelationFor(*ref); !ok {
  1964. return false
  1965. }
  1966. for join := ref.Join; join != nil && join.Table != nil; join = join.Table.Join {
  1967. if e.cteTableExists(join.Table.Name) {
  1968. continue
  1969. }
  1970. if _, ok := e.catalogRelationFor(*join.Table); !ok {
  1971. return false
  1972. }
  1973. }
  1974. }
  1975. return true
  1976. }
  1977. // catalogTableExists reports whether a durable table shadows an unqualified
  1978. // catalog relation name. A scan that already holds the session lock cannot ask
  1979. // the session, so the statement's pre-built snapshot answers instead; without
  1980. // one the virtual catalog relation is assumed, which makes the catalog path
  1981. // report the locked-scan guard error instead of deadlocking.
  1982. func (e *Executor) catalogTableExists(name string) bool {
  1983. if e.lockedScanDepth > 0 {
  1984. if e.pgCatalog == nil {
  1985. return false
  1986. }
  1987. _, ok := e.pgCatalog.tableByName[strings.ToLower(name)]
  1988. return ok
  1989. }
  1990. return e.session.TableExists(name)
  1991. }
  1992. func (s *catalogSnapshot) informationSchemaViewsRows() []storage.Row {
  1993. // A session view is listed here exactly when it is listed in pg_class with
  1994. // relkind 'v'. The engine does not retain the view's SQL text, so the
  1995. // definition is NULL rather than invented.
  1996. var rows []storage.Row
  1997. for _, relation := range s.relations {
  1998. if relation.kind != 'v' || relation.virtual {
  1999. continue
  2000. }
  2001. rows = append(rows, storage.Row{
  2002. "table_catalog": s.database,
  2003. "table_schema": relation.schemaName,
  2004. "table_name": relation.name,
  2005. "view_definition": nil,
  2006. "check_option": "NONE",
  2007. "is_updatable": "NO",
  2008. "is_insertable_into": "NO",
  2009. "is_trigger_updatable": "NO",
  2010. "is_trigger_deletable": "NO",
  2011. "is_trigger_insertable_into": "NO",
  2012. })
  2013. }
  2014. return rows
  2015. }
  2016. // ---------------------------------------------------------------------------
  2017. // Function/relation helpers used by the executor's expression evaluator
  2018. // indexDefinition renders CREATE INDEX statement text, used by pg_indexes and
  2019. // pg_get_indexdef.
  2020. func (s *catalogSnapshot) indexDefinition(index *storage.Index) string {
  2021. var builder strings.Builder
  2022. builder.WriteString("CREATE ")
  2023. if index.Unique {
  2024. builder.WriteString("UNIQUE ")
  2025. }
  2026. builder.WriteString("INDEX ")
  2027. builder.WriteString(index.Name)
  2028. builder.WriteString(" ON ")
  2029. builder.WriteString(publicSchemaName)
  2030. builder.WriteByte('.')
  2031. builder.WriteString(index.Table)
  2032. builder.WriteString(" USING btree (")
  2033. for i, column := range index.Columns {
  2034. if i > 0 {
  2035. builder.WriteString(", ")
  2036. }
  2037. if column.Expression != "" {
  2038. builder.WriteString("(")
  2039. builder.WriteString(column.Expression)
  2040. builder.WriteString(")")
  2041. continue
  2042. }
  2043. builder.WriteString(column.Name)
  2044. if column.Desc {
  2045. builder.WriteString(" DESC")
  2046. }
  2047. }
  2048. builder.WriteString(")")
  2049. return builder.String()
  2050. }
  2051. func (s *catalogSnapshot) indexDefinitionForOID(oid int64) (string, bool) {
  2052. relation, ok := s.relationByOID[oid]
  2053. if !ok || relation.kind != 'i' || relation.index == nil {
  2054. return "", false
  2055. }
  2056. return s.indexDefinition(relation.index), true
  2057. }
  2058. func (s *catalogSnapshot) constraintDefinition(constraint *catalogConstraint) string {
  2059. switch constraint.contype {
  2060. case 'p':
  2061. return "PRIMARY KEY (" + strings.Join(constraint.columns, ", ") + ")"
  2062. case 'u':
  2063. return "UNIQUE (" + strings.Join(constraint.columns, ", ") + ")"
  2064. case 'f':
  2065. if constraint.fk == nil {
  2066. return ""
  2067. }
  2068. clause := "FOREIGN KEY (" + strings.Join(constraint.fk.Columns, ", ") + ") REFERENCES " + constraint.fk.RefTable + "(" + strings.Join(constraint.fk.RefColumns, ", ") + ")"
  2069. if constraint.fk.OnDelete != "" {
  2070. clause += " ON DELETE " + strings.ToUpper(constraint.fk.OnDelete)
  2071. }
  2072. if constraint.fk.OnUpdate != "" {
  2073. clause += " ON UPDATE " + strings.ToUpper(constraint.fk.OnUpdate)
  2074. }
  2075. return clause
  2076. case 'c':
  2077. if constraint.check == nil {
  2078. return ""
  2079. }
  2080. return "CHECK ((" + constraint.check.Expression + "))"
  2081. default:
  2082. return ""
  2083. }
  2084. }
  2085. func (s *catalogSnapshot) constraintDefinitionForOID(oid int64) (string, bool) {
  2086. constraint, ok := s.constraintByOID[oid]
  2087. if !ok {
  2088. return "", false
  2089. }
  2090. return s.constraintDefinition(constraint), true
  2091. }
  2092. // formatType renders a type OID the way format_type() does. Precision modifiers
  2093. // are not persisted by the engine, so callers pass -1.
  2094. func (s *catalogSnapshot) formatType(oid int64, typmod int64) (string, bool) {
  2095. builtin, ok := pgBuiltinTypeByOID[oid]
  2096. if !ok {
  2097. return "???", false
  2098. }
  2099. name := builtin.sqlName
  2100. if typmod < 0 {
  2101. return name, true
  2102. }
  2103. switch oid {
  2104. case 1043, 1042: // varchar, bpchar
  2105. return fmt.Sprintf("%s(%d)", name, typmod-4), true
  2106. case 1700: // numeric
  2107. modifier := typmod - 4
  2108. precision := (modifier >> 16) & 0xffff
  2109. scale := modifier & 0xffff
  2110. return fmt.Sprintf("numeric(%d,%d)", precision, scale), true
  2111. default:
  2112. return name, true
  2113. }
  2114. }
  2115. // typeOIDForName resolves a regtype literal.
  2116. func (s *catalogSnapshot) typeOIDForName(name string) (int64, bool) {
  2117. name = strings.TrimSpace(name)
  2118. name = strings.Trim(name, `"`)
  2119. upper := strings.ToUpper(name)
  2120. if strings.HasSuffix(upper, "[]") || strings.HasSuffix(upper, " ARRAY") {
  2121. elementName := strings.TrimSuffix(strings.TrimSuffix(upper, " ARRAY"), "[]")
  2122. element := pgTypeForDeclaredName(elementName)
  2123. if array, ok := pgBuiltinTypeByOID[element.array]; ok && element.array != 0 {
  2124. return array.oid, true
  2125. }
  2126. return 0, false
  2127. }
  2128. if !knownDeclaredTypeName(upper) {
  2129. if builtin, ok := pgBuiltinTypeByName[strings.ToLower(name)]; ok {
  2130. return builtin.oid, true
  2131. }
  2132. return 0, false
  2133. }
  2134. return pgTypeForDeclaredName(upper).oid, true
  2135. }
  2136. // knownDeclaredTypeName reports whether a type spelling maps to a built-in.
  2137. func knownDeclaredTypeName(upper string) bool {
  2138. switch upper {
  2139. case "INTEGER", "INT", "INT4", "BIGINT", "INT8", "SMALLINT", "INT2", "TINYINT", "MEDIUMINT",
  2140. "TEXT", "CLOB", "NCHAR", "NVARCHAR", "VARCHAR", "CHARACTER VARYING", "CHAR", "CHARACTER",
  2141. "BOOLEAN", "BOOL", "REAL", "FLOAT", "FLOAT4", "DOUBLE", "DOUBLE PRECISION", "FLOAT8",
  2142. "NUMERIC", "DECIMAL", "JSONB", "JSON", "BLOB", "BYTEA", "DATETIME", "TIMESTAMP",
  2143. "TIMESTAMPTZ", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITHOUT TIME ZONE", "DATE",
  2144. "TIME", "TIME WITHOUT TIME ZONE", "TIME WITH TIME ZONE", "UUID", "OID", "NAME",
  2145. "REGCLASS", "REGTYPE":
  2146. return true
  2147. default:
  2148. return false
  2149. }
  2150. }
  2151. func (s *catalogSnapshot) typeNameForOID(oid int64) (string, bool) {
  2152. builtin, ok := pgBuiltinTypeByOID[oid]
  2153. if !ok {
  2154. return "", false
  2155. }
  2156. return builtin.sqlName, true
  2157. }
  2158. func (s *catalogSnapshot) relationVisible(oid int64) bool {
  2159. relation, ok := s.relationByOID[oid]
  2160. if !ok {
  2161. return false
  2162. }
  2163. switch relation.schemaName {
  2164. case publicSchemaName, pgCatalogSchemaName, informationSchemaName:
  2165. return true
  2166. default:
  2167. return false
  2168. }
  2169. }
  2170. // numericArg converts a function argument that denotes an OID.
  2171. func numericArg(value interface{}) (int64, bool) {
  2172. switch v := value.(type) {
  2173. case RegOID:
  2174. return v.oid, true
  2175. case int64:
  2176. return v, true
  2177. case int:
  2178. return int64(v), true
  2179. case float64:
  2180. return int64(v), true
  2181. case string:
  2182. parsed, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64)
  2183. if err != nil {
  2184. return 0, false
  2185. }
  2186. return parsed, true
  2187. default:
  2188. return 0, false
  2189. }
  2190. }
  2191. // RegOID is the value of a regclass or regtype cast. Numeric contexts use the
  2192. // OID; text output renders the resolved name, matching PostgreSQL's symbolic
  2193. // type rendering.
  2194. type RegOID struct {
  2195. oid int64
  2196. name string
  2197. }
  2198. // OID returns the numeric OID the value carries.
  2199. func (r RegOID) OID() int64 { return r.oid }
  2200. // String renders the symbolic name.
  2201. func (r RegOID) String() string { return r.name }
  2202. // evalCatalogFunction answers the PostgreSQL catalog-introspection builtins.
  2203. // handled is false for every other function so evalFunctionCall keeps them.
  2204. func (e *Executor) evalCatalogFunction(name string, fn *parser.FunctionCall, args []interface{}) (interface{}, bool, error) {
  2205. switch name {
  2206. case "CURRENT_SCHEMA":
  2207. return e.currentSchemaName(), true, nil
  2208. case "CURRENT_DATABASE":
  2209. if e.schema == nil {
  2210. return "pizzasql", true, nil
  2211. }
  2212. database := e.schema.GetDatabaseName()
  2213. if database == "" {
  2214. database = "pizzasql"
  2215. }
  2216. return database, true, nil
  2217. case "PG_GET_SERIAL_SEQUENCE", "OBJ_DESCRIPTION", "COL_DESCRIPTION":
  2218. // The engine has no sequences and stores no catalog comments.
  2219. return nil, true, nil
  2220. case "PG_GET_USERBYID":
  2221. return "pizzasql", true, nil
  2222. case "CURRENT_SETTING":
  2223. if len(args) == 0 || args[0] == nil {
  2224. return nil, true, nil
  2225. }
  2226. value, err := e.settingValue(toString(args[0]))
  2227. if err != nil {
  2228. return nil, true, err
  2229. }
  2230. return value, true, nil
  2231. case "PG_GET_EXPR":
  2232. if len(args) == 0 || args[0] == nil {
  2233. return nil, true, nil
  2234. }
  2235. if text, ok := args[0].(string); ok {
  2236. return text, true, nil
  2237. }
  2238. return toString(args[0]), true, nil
  2239. }
  2240. switch name {
  2241. case "FORMAT_TYPE", "PG_TABLE_IS_VISIBLE", "PG_GET_INDEXDEF", "PG_GET_CONSTRAINTDEF", "HAS_TABLE_PRIVILEGE", "TO_REGCLASS", "TO_REGTYPE":
  2242. default:
  2243. return nil, false, nil
  2244. }
  2245. snapshot, err := e.catalogSnapshotForQuery()
  2246. if err != nil {
  2247. return nil, true, err
  2248. }
  2249. switch name {
  2250. case "TO_REGCLASS", "TO_REGTYPE":
  2251. // PostgreSQL's to_regclass/to_regtype return NULL for a name that does
  2252. // not exist instead of failing the statement.
  2253. if len(args) == 0 || args[0] == nil {
  2254. return nil, true, nil
  2255. }
  2256. if reg, ok := args[0].(RegOID); ok {
  2257. return reg, true, nil
  2258. }
  2259. text, ok := args[0].(string)
  2260. if !ok {
  2261. return nil, true, pgerror.InvalidText("%s requires a text argument", strings.ToLower(name))
  2262. }
  2263. var oid int64
  2264. var found bool
  2265. if name == "TO_REGTYPE" {
  2266. oid, found = snapshot.typeOIDForName(text)
  2267. } else {
  2268. oid, found = snapshot.regclassOID(text)
  2269. }
  2270. if !found {
  2271. return nil, true, nil
  2272. }
  2273. var resolved string
  2274. if name == "TO_REGTYPE" {
  2275. resolved, _ = snapshot.typeNameForOID(oid)
  2276. } else {
  2277. resolved, _ = snapshot.regclassName(oid)
  2278. }
  2279. return RegOID{oid: oid, name: resolved}, true, nil
  2280. case "FORMAT_TYPE":
  2281. if len(args) == 0 {
  2282. return nil, true, pgerror.Unsupported("format_type requires a type OID")
  2283. }
  2284. oid, ok := numericArg(args[0])
  2285. if !ok {
  2286. return nil, true, pgerror.InvalidText("format_type requires a numeric type OID")
  2287. }
  2288. typmod := int64(-1)
  2289. if len(args) > 1 && args[1] != nil {
  2290. if value, ok := numericArg(args[1]); ok {
  2291. typmod = value
  2292. }
  2293. }
  2294. rendered, _ := snapshot.formatType(oid, typmod)
  2295. return rendered, true, nil
  2296. case "PG_TABLE_IS_VISIBLE":
  2297. if len(args) == 0 || args[0] == nil {
  2298. return nil, true, nil
  2299. }
  2300. oid, ok := numericArg(args[0])
  2301. if !ok {
  2302. return false, true, nil
  2303. }
  2304. return snapshot.relationVisible(oid), true, nil
  2305. case "PG_GET_INDEXDEF":
  2306. if len(args) == 0 || args[0] == nil {
  2307. return nil, true, nil
  2308. }
  2309. oid, ok := numericArg(args[0])
  2310. if !ok {
  2311. return nil, true, pgerror.InvalidText("pg_get_indexdef requires an index OID")
  2312. }
  2313. definition, found := snapshot.indexDefinitionForOID(oid)
  2314. if !found {
  2315. return nil, true, nil
  2316. }
  2317. return definition, true, nil
  2318. case "PG_GET_CONSTRAINTDEF":
  2319. if len(args) == 0 || args[0] == nil {
  2320. return nil, true, nil
  2321. }
  2322. oid, ok := numericArg(args[0])
  2323. if !ok {
  2324. return nil, true, pgerror.InvalidText("pg_get_constraintdef requires a constraint OID")
  2325. }
  2326. definition, found := snapshot.constraintDefinitionForOID(oid)
  2327. if !found {
  2328. return nil, true, nil
  2329. }
  2330. return definition, true, nil
  2331. case "HAS_TABLE_PRIVILEGE":
  2332. tableArg := interface{}(nil)
  2333. switch len(args) {
  2334. case 2:
  2335. tableArg = args[0]
  2336. case 3:
  2337. tableArg = args[1]
  2338. default:
  2339. return false, true, nil
  2340. }
  2341. if tableArg == nil {
  2342. return nil, true, nil
  2343. }
  2344. if oid, ok := numericArg(tableArg); ok {
  2345. return snapshot.relationVisible(oid), true, nil
  2346. }
  2347. _, ok := snapshot.regclassOID(toString(tableArg))
  2348. return ok, true, nil
  2349. default:
  2350. return nil, false, nil
  2351. }
  2352. }
  2353. // currentSchemaName reports the first schema in the effective search path. The
  2354. // engine only materializes public, pg_catalog, and information_schema, so a
  2355. // search path naming anything else falls back to public.
  2356. func (e *Executor) currentSchemaName() string {
  2357. path := e.effectiveSearchPath()
  2358. if len(path) > 0 && path[0] != "" {
  2359. return path[0]
  2360. }
  2361. return publicSchemaName
  2362. }
  2363. // catalogCast handles regclass/regtype casts and text casts of their values.
  2364. func (e *Executor) catalogCast(expr *parser.CastExpr, value interface{}) (interface{}, bool, error) {
  2365. typeName := strings.ToUpper(strings.TrimSpace(expr.Type.Name))
  2366. switch typeName {
  2367. case "REGCLASS", "REGTYPE":
  2368. snapshot, err := e.catalogSnapshotForQuery()
  2369. if err != nil {
  2370. return nil, true, err
  2371. }
  2372. if reg, ok := value.(RegOID); ok {
  2373. return reg, true, nil
  2374. }
  2375. if text, ok := value.(string); ok {
  2376. if typeName == "REGTYPE" {
  2377. oid, found := snapshot.typeOIDForName(text)
  2378. if !found {
  2379. return nil, true, pgerror.UndefinedTable("type %q does not exist", text)
  2380. }
  2381. name, _ := snapshot.typeNameForOID(oid)
  2382. return RegOID{oid: oid, name: name}, true, nil
  2383. }
  2384. oid, found := snapshot.regclassOID(text)
  2385. if !found {
  2386. return nil, true, pgerror.UndefinedTable("relation %q does not exist", text)
  2387. }
  2388. name, _ := snapshot.regclassName(oid)
  2389. return RegOID{oid: oid, name: name}, true, nil
  2390. }
  2391. oid, ok := numericArg(value)
  2392. if !ok {
  2393. return nil, true, pgerror.InvalidText("cannot cast %T to %s", value, typeName)
  2394. }
  2395. var name string
  2396. if typeName == "REGTYPE" {
  2397. name, _ = snapshot.typeNameForOID(oid)
  2398. } else {
  2399. name, _ = snapshot.regclassName(oid)
  2400. }
  2401. if name == "" {
  2402. name = strconv.FormatInt(oid, 10)
  2403. }
  2404. return RegOID{oid: oid, name: name}, true, nil
  2405. case "TEXT", "VARCHAR", "CHAR", "CHARACTER", "CLOB", "NCHAR", "NVARCHAR":
  2406. if reg, ok := value.(RegOID); ok {
  2407. return reg.name, true, nil
  2408. }
  2409. case "OID":
  2410. if reg, ok := value.(RegOID); ok {
  2411. return reg.oid, true, nil
  2412. }
  2413. }
  2414. return nil, false, nil
  2415. }
  2416. // isCatalogWriteTarget reports a DML/DDL statement aimed at a virtual relation.
  2417. func (e *Executor) rejectCatalogWriteTarget(stmt parser.Statement) error {
  2418. var refs []parser.TableRef
  2419. switch s := stmt.(type) {
  2420. case *parser.InsertStmt:
  2421. if s.Table != nil {
  2422. refs = append(refs, *s.Table)
  2423. }
  2424. case *parser.UpdateStmt:
  2425. if s.Table != nil {
  2426. refs = append(refs, *s.Table)
  2427. }
  2428. case *parser.DeleteStmt:
  2429. if s.Table != nil {
  2430. refs = append(refs, *s.Table)
  2431. }
  2432. case *parser.CreateTableStmt:
  2433. if s.Table != nil {
  2434. refs = append(refs, *s.Table)
  2435. }
  2436. case *parser.CreateIndexStmt:
  2437. refs = append(refs, parser.TableRef{Name: s.Table})
  2438. case *parser.AlterTableStmt:
  2439. refs = append(refs, parser.TableRef{Name: s.Table})
  2440. case *parser.CreateViewStmt:
  2441. if s.View != nil {
  2442. refs = append(refs, *s.View)
  2443. }
  2444. case *parser.DropTableStmt:
  2445. for _, table := range s.Tables {
  2446. if table != nil {
  2447. refs = append(refs, *table)
  2448. }
  2449. }
  2450. }
  2451. for _, ref := range refs {
  2452. if _, ok := e.catalogRelationFor(ref); !ok {
  2453. continue
  2454. }
  2455. schemaName := strings.ToLower(ref.Schema)
  2456. if schemaName == "" || schemaName == publicSchemaName {
  2457. schemaName = pgCatalogSchemaName
  2458. }
  2459. return pgerror.Unsupported("%s.%s is a read-only virtual relation; catalog relations are synthesized from the durable schema and cannot be written", schemaName, strings.ToLower(ref.Name))
  2460. }
  2461. return nil
  2462. }
  2463. // ---------------------------------------------------------------------------
  2464. // SELECT over virtual catalog relations
  2465. // catalogSelectRelation is the column metadata of one FROM entry.
  2466. type catalogSelectRelation struct {
  2467. qualifier string
  2468. columns []storage.Column
  2469. }
  2470. // catalogFlatRefs flattens a FROM clause, including JOIN chains, preserving the
  2471. // schema qualifier of every entry.
  2472. func catalogFlatRefs(from []parser.TableRef) []parser.TableRef {
  2473. var refs []parser.TableRef
  2474. for _, ref := range from {
  2475. cur := ref
  2476. for {
  2477. flat := cur
  2478. flat.Join = nil
  2479. flat.Subquery = cur.Subquery
  2480. flat.Function = cur.Function
  2481. refs = append(refs, flat)
  2482. if cur.Join == nil || cur.Join.Table == nil {
  2483. break
  2484. }
  2485. cur = *cur.Join.Table
  2486. }
  2487. }
  2488. return refs
  2489. }
  2490. func catalogRefQualifier(ref parser.TableRef) string {
  2491. if ref.Alias != "" {
  2492. return ref.Alias
  2493. }
  2494. return ref.Name
  2495. }
  2496. // catalogSelectMetadata resolves the column list of every FROM relation so
  2497. // SELECT * and table.* expand, and so projection types stay accurate.
  2498. func (e *Executor) catalogSelectMetadata(from []parser.TableRef) ([]catalogSelectRelation, error) {
  2499. var relations []catalogSelectRelation
  2500. for _, ref := range catalogFlatRefs(from) {
  2501. if ref.Subquery != nil || ref.Function != nil {
  2502. continue
  2503. }
  2504. var columns []storage.Column
  2505. if entry, ok := e.catalogRelationFor(ref); ok {
  2506. columns = entry.schema.Columns
  2507. } else if cte, ok := e.cteTableFor(ref.Name); ok {
  2508. columns = schemaFromColumns(cte.columns).Columns
  2509. } else {
  2510. schema, err := e.session.GetSchema(ref.Name)
  2511. if err != nil {
  2512. return nil, err
  2513. }
  2514. columns = visibleCatalogColumns(schema)
  2515. }
  2516. relations = append(relations, catalogSelectRelation{qualifier: catalogRefQualifier(ref), columns: columns})
  2517. }
  2518. return relations, nil
  2519. }
  2520. // materializeCatalogTableRef reads one FROM entry. Catalog relations come from
  2521. // the statement's virtual snapshot; everything else goes through the ordinary
  2522. // materializer so a catalog query can still join a real table or read a
  2523. // derived table.
  2524. func (e *Executor) materializeCatalogTableRef(ref parser.TableRef) ([]storage.Row, error) {
  2525. if entry, ok := e.catalogRelationFor(ref); ok {
  2526. snapshot, err := e.catalogSnapshotForQuery()
  2527. if err != nil {
  2528. return nil, err
  2529. }
  2530. rows := cloneRows(snapshot.relationRows(entry.def.schema + "." + entry.def.name))
  2531. alias := catalogRefQualifier(ref)
  2532. for i := range rows {
  2533. rows[i] = e.addTableAlias(rows[i], alias)
  2534. }
  2535. return rows, nil
  2536. }
  2537. if cte, ok := e.cteTableFor(ref.Name); ok {
  2538. rows := cloneRows(cte.rows)
  2539. alias := catalogRefQualifier(ref)
  2540. for i := range rows {
  2541. rows[i] = e.addTableAlias(rows[i], alias)
  2542. }
  2543. return rows, nil
  2544. }
  2545. return e.materializeTableRef(ref)
  2546. }
  2547. // materializeCatalogFrom materializes the whole FROM list, applying each
  2548. // entry's JOIN chain and cross-joining comma-separated entries.
  2549. func (e *Executor) materializeCatalogFrom(from []parser.TableRef) ([]storage.Row, error) {
  2550. rows, err := e.materializeCatalogTableRef(from[0])
  2551. if err != nil {
  2552. return nil, err
  2553. }
  2554. if from[0].Join != nil {
  2555. rows, err = e.executeJoins(from[0], rows)
  2556. if err != nil {
  2557. return nil, err
  2558. }
  2559. }
  2560. for _, ref := range from[1:] {
  2561. right, err := e.materializeCatalogTableRef(ref)
  2562. if err != nil {
  2563. return nil, err
  2564. }
  2565. if ref.Join != nil {
  2566. right, err = e.executeJoins(ref, right)
  2567. if err != nil {
  2568. return nil, err
  2569. }
  2570. }
  2571. joined := make([]storage.Row, 0, len(rows)*len(right))
  2572. for _, leftRow := range rows {
  2573. for _, rightRow := range right {
  2574. combined := make(storage.Row, len(leftRow)+len(rightRow))
  2575. for key, value := range leftRow {
  2576. combined[key] = value
  2577. }
  2578. for key, value := range rightRow {
  2579. combined[key] = value
  2580. }
  2581. joined = append(joined, combined)
  2582. }
  2583. }
  2584. rows = joined
  2585. }
  2586. return rows, nil
  2587. }
  2588. // expandCatalogTableStars rewrites table.* projections into explicit column
  2589. // references so the shared materialized projection can read qualified keys.
  2590. func expandCatalogTableStars(stmt *parser.SelectStmt, relations []catalogSelectRelation) (*parser.SelectStmt, error) {
  2591. expanded := *stmt
  2592. if len(stmt.Columns) == 0 {
  2593. return &expanded, nil
  2594. }
  2595. columns := make([]parser.SelectColumn, 0, len(stmt.Columns))
  2596. for _, projection := range stmt.Columns {
  2597. if projection.TableStar == "" {
  2598. columns = append(columns, projection)
  2599. continue
  2600. }
  2601. var matched *catalogSelectRelation
  2602. for i := range relations {
  2603. if strings.EqualFold(relations[i].qualifier, projection.TableStar) {
  2604. matched = &relations[i]
  2605. break
  2606. }
  2607. }
  2608. if matched == nil {
  2609. return nil, fmt.Errorf("cannot expand %s.*: relation columns are not available", projection.TableStar)
  2610. }
  2611. for _, column := range matched.columns {
  2612. columns = append(columns, parser.SelectColumn{
  2613. Expr: &parser.ColumnRef{Table: matched.qualifier, Column: column.Name},
  2614. Alias: column.Name,
  2615. })
  2616. }
  2617. }
  2618. expanded.Columns = columns
  2619. return &expanded, nil
  2620. }
  2621. func catalogJoinKeyParts(key string) (string, string) {
  2622. if dot := strings.LastIndexByte(key, '.'); dot >= 0 {
  2623. return key[:dot], key[dot+1:]
  2624. }
  2625. return "", key
  2626. }
  2627. // catalogProjectionTypes computes result types parallel to the projection. The
  2628. // resolver follows starKeys, so both qualified and unqualified references keep
  2629. // the declared catalog type (OID, NAME, BOOL, ...) instead of falling back to
  2630. // TEXT over the wire.
  2631. func catalogProjectionTypes(stmt *parser.SelectStmt, starKeys, types []string) []string {
  2632. resolve := func(table, column string) (string, bool) {
  2633. for i, key := range starKeys {
  2634. qualifier, name := catalogJoinKeyParts(key)
  2635. if !strings.EqualFold(name, column) {
  2636. continue
  2637. }
  2638. if table != "" && !strings.EqualFold(table, qualifier) {
  2639. continue
  2640. }
  2641. if i < len(types) && types[i] != "" {
  2642. return types[i], true
  2643. }
  2644. return "", true
  2645. }
  2646. return "", false
  2647. }
  2648. result := make([]string, 0, len(stmt.Columns))
  2649. for _, projection := range stmt.Columns {
  2650. if projection.Star {
  2651. result = append(result, types...)
  2652. continue
  2653. }
  2654. result = append(result, inferExprType(projection.Expr, resolve))
  2655. }
  2656. return result
  2657. }
  2658. // executeSelectOnCatalogRelations answers a SELECT whose FROM clause reads at
  2659. // least one virtual relation. Rows are materialized from the session's schema
  2660. // view, so staged transactional DDL is visible to the issuing connection only.
  2661. func (e *Executor) executeSelectOnCatalogRelations(stmt *parser.SelectStmt) (*Result, error) {
  2662. relations, err := e.catalogSelectMetadata(stmt.From)
  2663. if err != nil {
  2664. return nil, err
  2665. }
  2666. expanded, err := expandCatalogTableStars(stmt, relations)
  2667. if err != nil {
  2668. return nil, err
  2669. }
  2670. rows, err := e.materializeCatalogFrom(stmt.From)
  2671. if err != nil {
  2672. return nil, err
  2673. }
  2674. var columns, starKeys, types, qualifiers []string
  2675. for _, relation := range relations {
  2676. for _, column := range relation.columns {
  2677. columns = append(columns, column.Name)
  2678. starKeys = append(starKeys, relation.qualifier+"."+column.Name)
  2679. types = append(types, column.Type)
  2680. qualifiers = append(qualifiers, relation.qualifier)
  2681. }
  2682. }
  2683. // The JOIN chain is already applied by materializeCatalogFrom; hand the
  2684. // shared materialized path rows without a pending join.
  2685. tail := *expanded
  2686. tailFrom := make([]parser.TableRef, len(expanded.From))
  2687. copy(tailFrom, expanded.From)
  2688. tailFrom[0].Join = nil
  2689. tail.From = tailFrom
  2690. e.pushTypeScope(materializedTypeResolver(columns, types, qualifiers))
  2691. result, err := e.executeSelectOnMaterializedRows(&tail, columns, starKeys, rows)
  2692. e.popTypeScope()
  2693. if err != nil {
  2694. return nil, err
  2695. }
  2696. result.ColumnTypes = catalogProjectionTypes(&tail, starKeys, types)
  2697. if tail.Distinct {
  2698. result.Rows = e.applyDistinct(result.Rows)
  2699. }
  2700. return result, nil
  2701. }