pg_catalog.go 87 KB

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