pg_catalog.go 84 KB

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