Skip to main content

uqa_sql/catalog/
mod.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! `PostgreSQL` 18 row types for the virtual system-catalog relations implemented by the engine.
8
9use crate::ast::ColumnType;
10
11pub mod expression_text;
12pub mod node_tree;
13pub mod oids;
14pub mod resolution;
15pub mod result_type;
16pub mod type_metadata;
17
18/// Namespace of the Apache AGE catalog relations, types, and functions.
19pub const AG_CATALOG_SCHEMA: &str = "ag_catalog";
20
21mod virtual_relations;
22pub use virtual_relations::{resolve_virtual_relation, VirtualRelation};
23mod system_relations;
24pub use system_relations::SystemRelation;
25
26impl VirtualRelation {
27    pub const fn accepts_row_lock(self) -> bool {
28        matches!(
29            self,
30            Self::PgNamespace
31                | Self::PgClass
32                | Self::PgInherits
33                | Self::PgPartitionedTable
34                | Self::PgAttribute
35                | Self::PgAttrdef
36                | Self::PgConstraint
37                | Self::PgIndex
38                | Self::PgTrigger
39                | Self::PgRewrite
40                | Self::PgType
41                | Self::PgRange
42                | Self::PgProc
43                | Self::PgDatabase
44                | Self::PgAuthid
45                | Self::PgAuthMembers
46                | Self::PgDescription
47                | Self::AgGraph
48                | Self::AgLabel
49        )
50    }
51
52    #[expect(
53        clippy::too_many_lines,
54        reason = "preserves catalog column and OID order"
55    )]
56    pub fn schema(self) -> Vec<(String, ColumnType)> {
57        macro_rules! columns {
58            ($($name:literal => $ty:expr),* $(,)?) => {
59                vec![$(($name.to_string(), $ty)),*]
60            };
61        }
62
63        match self {
64            Self::InformationSchemaCatalogName => columns![
65                "catalog_name" => sql_identifier(),
66            ],
67            Self::InformationSchemata => columns![
68                "catalog_name" => sql_identifier(),
69                "schema_name" => sql_identifier(),
70                "schema_owner" => sql_identifier(),
71                "default_character_set_catalog" => sql_identifier(),
72                "default_character_set_schema" => sql_identifier(),
73                "default_character_set_name" => sql_identifier(),
74                "sql_path" => character_data(),
75            ],
76            Self::InformationTables => columns![
77                "table_catalog" => sql_identifier(),
78                "table_schema" => sql_identifier(),
79                "table_name" => sql_identifier(),
80                "table_type" => character_data(),
81                "self_referencing_column_name" => sql_identifier(),
82                "reference_generation" => character_data(),
83                "user_defined_type_catalog" => sql_identifier(),
84                "user_defined_type_schema" => sql_identifier(),
85                "user_defined_type_name" => sql_identifier(),
86                "is_insertable_into" => yes_or_no(),
87                "is_typed" => yes_or_no(),
88                "commit_action" => character_data(),
89            ],
90            Self::InformationColumns => columns![
91                "table_catalog" => sql_identifier(),
92                "table_schema" => sql_identifier(),
93                "table_name" => sql_identifier(),
94                "column_name" => sql_identifier(),
95                "ordinal_position" => cardinal_number(),
96                "column_default" => character_data(),
97                "is_nullable" => yes_or_no(),
98                "data_type" => character_data(),
99                "character_maximum_length" => cardinal_number(),
100                "character_octet_length" => cardinal_number(),
101                "numeric_precision" => cardinal_number(),
102                "numeric_precision_radix" => cardinal_number(),
103                "numeric_scale" => cardinal_number(),
104                "datetime_precision" => cardinal_number(),
105                "interval_type" => character_data(),
106                "interval_precision" => cardinal_number(),
107                "character_set_catalog" => sql_identifier(),
108                "character_set_schema" => sql_identifier(),
109                "character_set_name" => sql_identifier(),
110                "collation_catalog" => sql_identifier(),
111                "collation_schema" => sql_identifier(),
112                "collation_name" => sql_identifier(),
113                "domain_catalog" => sql_identifier(),
114                "domain_schema" => sql_identifier(),
115                "domain_name" => sql_identifier(),
116                "udt_catalog" => sql_identifier(),
117                "udt_schema" => sql_identifier(),
118                "udt_name" => sql_identifier(),
119                "scope_catalog" => sql_identifier(),
120                "scope_schema" => sql_identifier(),
121                "scope_name" => sql_identifier(),
122                "maximum_cardinality" => cardinal_number(),
123                "dtd_identifier" => sql_identifier(),
124                "is_self_referencing" => yes_or_no(),
125                "is_identity" => yes_or_no(),
126                "identity_generation" => character_data(),
127                "identity_start" => character_data(),
128                "identity_increment" => character_data(),
129                "identity_maximum" => character_data(),
130                "identity_minimum" => character_data(),
131                "identity_cycle" => yes_or_no(),
132                "is_generated" => character_data(),
133                "generation_expression" => character_data(),
134                "is_updatable" => yes_or_no(),
135            ],
136            Self::InformationColumnPrivileges | Self::InformationRoleColumnGrants => columns![
137                "grantor" => sql_identifier(),
138                "grantee" => sql_identifier(),
139                "table_catalog" => sql_identifier(),
140                "table_schema" => sql_identifier(),
141                "table_name" => sql_identifier(),
142                "column_name" => sql_identifier(),
143                "privilege_type" => character_data(),
144                "is_grantable" => yes_or_no(),
145            ],
146            Self::InformationViews => columns![
147                "table_catalog" => sql_identifier(),
148                "table_schema" => sql_identifier(),
149                "table_name" => sql_identifier(),
150                "view_definition" => character_data(),
151                "check_option" => character_data(),
152                "is_updatable" => yes_or_no(),
153                "is_insertable_into" => yes_or_no(),
154                "is_trigger_updatable" => yes_or_no(),
155                "is_trigger_deletable" => yes_or_no(),
156                "is_trigger_insertable_into" => yes_or_no(),
157            ],
158            Self::InformationRoutines => information_routines_schema(),
159            Self::InformationSequences => columns![
160                "sequence_catalog" => sql_identifier(),
161                "sequence_schema" => sql_identifier(),
162                "sequence_name" => sql_identifier(),
163                "data_type" => character_data(),
164                "numeric_precision" => cardinal_number(),
165                "numeric_precision_radix" => cardinal_number(),
166                "numeric_scale" => cardinal_number(),
167                "start_value" => character_data(),
168                "minimum_value" => character_data(),
169                "maximum_value" => character_data(),
170                "increment" => character_data(),
171                "cycle_option" => yes_or_no(),
172            ],
173            Self::InformationTableConstraints => columns![
174                "constraint_catalog" => sql_identifier(),
175                "constraint_schema" => sql_identifier(),
176                "constraint_name" => sql_identifier(),
177                "table_catalog" => sql_identifier(),
178                "table_schema" => sql_identifier(),
179                "table_name" => sql_identifier(),
180                "constraint_type" => character_data(),
181                "is_deferrable" => yes_or_no(),
182                "initially_deferred" => yes_or_no(),
183                "enforced" => yes_or_no(),
184                "nulls_distinct" => yes_or_no(),
185            ],
186            Self::InformationKeyColumnUsage => columns![
187                "constraint_catalog" => sql_identifier(),
188                "constraint_schema" => sql_identifier(),
189                "constraint_name" => sql_identifier(),
190                "table_catalog" => sql_identifier(),
191                "table_schema" => sql_identifier(),
192                "table_name" => sql_identifier(),
193                "column_name" => sql_identifier(),
194                "ordinal_position" => cardinal_number(),
195                "position_in_unique_constraint" => cardinal_number(),
196            ],
197            Self::PgNamespace => columns![
198                "oid" => ColumnType::Oid,
199                "nspname" => ColumnType::Name,
200                "nspowner" => ColumnType::Oid,
201                "nspacl" => array(ColumnType::AclItem),
202            ],
203            Self::PgClass => columns![
204                "oid" => ColumnType::Oid,
205                "relname" => ColumnType::Name,
206                "relnamespace" => ColumnType::Oid,
207                "reltype" => ColumnType::Oid,
208                "reloftype" => ColumnType::Oid,
209                "relowner" => ColumnType::Oid,
210                "relam" => ColumnType::Oid,
211                "relfilenode" => ColumnType::Oid,
212                "reltablespace" => ColumnType::Oid,
213                "relpages" => ColumnType::Integer,
214                "reltuples" => ColumnType::Real,
215                "relallvisible" => ColumnType::Integer,
216                "relallfrozen" => ColumnType::Integer,
217                "reltoastrelid" => ColumnType::Oid,
218                "relhasindex" => ColumnType::Boolean,
219                "relisshared" => ColumnType::Boolean,
220                "relpersistence" => ColumnType::InternalChar,
221                "relkind" => ColumnType::InternalChar,
222                "relnatts" => ColumnType::SmallInteger,
223                "relchecks" => ColumnType::SmallInteger,
224                "relhasrules" => ColumnType::Boolean,
225                "relhastriggers" => ColumnType::Boolean,
226                "relhassubclass" => ColumnType::Boolean,
227                "relrowsecurity" => ColumnType::Boolean,
228                "relforcerowsecurity" => ColumnType::Boolean,
229                "relispopulated" => ColumnType::Boolean,
230                "relreplident" => ColumnType::InternalChar,
231                "relispartition" => ColumnType::Boolean,
232                "relrewrite" => ColumnType::Oid,
233                "relfrozenxid" => ColumnType::Xid,
234                "relminmxid" => ColumnType::Xid,
235                "relacl" => array(ColumnType::AclItem),
236                "reloptions" => array(ColumnType::Text),
237                "relpartbound" => ColumnType::PgNodeTree,
238            ],
239            Self::PgInherits => columns![
240                "inhrelid" => ColumnType::Oid,
241                "inhparent" => ColumnType::Oid,
242                "inhseqno" => ColumnType::Integer,
243                "inhdetachpending" => ColumnType::Boolean,
244            ],
245            Self::PgPartitionedTable => columns![
246                "partrelid" => ColumnType::Oid,
247                "partstrat" => ColumnType::InternalChar,
248                "partnatts" => ColumnType::SmallInteger,
249                "partdefid" => ColumnType::Oid,
250                "partattrs" => ColumnType::Int2Vector,
251                "partclass" => ColumnType::OidVector,
252                "partcollation" => ColumnType::OidVector,
253                "partexprs" => ColumnType::PgNodeTree,
254            ],
255            Self::PgAttribute => columns![
256                "attrelid" => ColumnType::Oid,
257                "attname" => ColumnType::Name,
258                "atttypid" => ColumnType::Oid,
259                "attlen" => ColumnType::SmallInteger,
260                "attnum" => ColumnType::SmallInteger,
261                "atttypmod" => ColumnType::Integer,
262                "attndims" => ColumnType::SmallInteger,
263                "attbyval" => ColumnType::Boolean,
264                "attalign" => ColumnType::InternalChar,
265                "attstorage" => ColumnType::InternalChar,
266                "attcompression" => ColumnType::InternalChar,
267                "attnotnull" => ColumnType::Boolean,
268                "atthasdef" => ColumnType::Boolean,
269                "atthasmissing" => ColumnType::Boolean,
270                "attidentity" => ColumnType::InternalChar,
271                "attgenerated" => ColumnType::InternalChar,
272                "attisdropped" => ColumnType::Boolean,
273                "attislocal" => ColumnType::Boolean,
274                "attinhcount" => ColumnType::SmallInteger,
275                "attcollation" => ColumnType::Oid,
276                "attstattarget" => ColumnType::SmallInteger,
277                "attacl" => array(ColumnType::AclItem),
278                "attoptions" => array(ColumnType::Text),
279                "attfdwoptions" => array(ColumnType::Text),
280                "attmissingval" => ColumnType::AnyArray,
281            ],
282            Self::PgAttrdef => columns![
283                "oid" => ColumnType::Oid,
284                "adrelid" => ColumnType::Oid,
285                "adnum" => ColumnType::SmallInteger,
286                "adbin" => ColumnType::PgNodeTree,
287            ],
288            Self::PgConstraint => columns![
289                "oid" => ColumnType::Oid,
290                "conname" => ColumnType::Name,
291                "connamespace" => ColumnType::Oid,
292                "contype" => ColumnType::InternalChar,
293                "condeferrable" => ColumnType::Boolean,
294                "condeferred" => ColumnType::Boolean,
295                "conenforced" => ColumnType::Boolean,
296                "convalidated" => ColumnType::Boolean,
297                "conrelid" => ColumnType::Oid,
298                "contypid" => ColumnType::Oid,
299                "conindid" => ColumnType::Oid,
300                "conparentid" => ColumnType::Oid,
301                "confrelid" => ColumnType::Oid,
302                "confupdtype" => ColumnType::InternalChar,
303                "confdeltype" => ColumnType::InternalChar,
304                "confmatchtype" => ColumnType::InternalChar,
305                "conislocal" => ColumnType::Boolean,
306                "coninhcount" => ColumnType::SmallInteger,
307                "connoinherit" => ColumnType::Boolean,
308                "conperiod" => ColumnType::Boolean,
309                "conkey" => array(ColumnType::SmallInteger),
310                "confkey" => array(ColumnType::SmallInteger),
311                "conpfeqop" => array(ColumnType::Oid),
312                "conppeqop" => array(ColumnType::Oid),
313                "conffeqop" => array(ColumnType::Oid),
314                "confdelsetcols" => array(ColumnType::SmallInteger),
315                "conexclop" => array(ColumnType::Oid),
316                "conbin" => ColumnType::PgNodeTree,
317            ],
318            Self::PgIndex => columns![
319                "indexrelid" => ColumnType::Oid,
320                "indrelid" => ColumnType::Oid,
321                "indnatts" => ColumnType::SmallInteger,
322                "indnkeyatts" => ColumnType::SmallInteger,
323                "indisunique" => ColumnType::Boolean,
324                "indnullsnotdistinct" => ColumnType::Boolean,
325                "indisprimary" => ColumnType::Boolean,
326                "indisexclusion" => ColumnType::Boolean,
327                "indimmediate" => ColumnType::Boolean,
328                "indisclustered" => ColumnType::Boolean,
329                "indisvalid" => ColumnType::Boolean,
330                "indcheckxmin" => ColumnType::Boolean,
331                "indisready" => ColumnType::Boolean,
332                "indislive" => ColumnType::Boolean,
333                "indisreplident" => ColumnType::Boolean,
334                "indkey" => ColumnType::Int2Vector,
335                "indcollation" => ColumnType::OidVector,
336                "indclass" => ColumnType::OidVector,
337                "indoption" => ColumnType::Int2Vector,
338                "indexprs" => ColumnType::PgNodeTree,
339                "indpred" => ColumnType::PgNodeTree,
340            ],
341            Self::PgTrigger => columns![
342                "oid" => ColumnType::Oid,
343                "tgrelid" => ColumnType::Oid,
344                "tgparentid" => ColumnType::Oid,
345                "tgname" => ColumnType::Name,
346                "tgfoid" => ColumnType::Oid,
347                "tgtype" => ColumnType::SmallInteger,
348                "tgenabled" => ColumnType::InternalChar,
349                "tgisinternal" => ColumnType::Boolean,
350                "tgconstrrelid" => ColumnType::Oid,
351                "tgconstrindid" => ColumnType::Oid,
352                "tgconstraint" => ColumnType::Oid,
353                "tgdeferrable" => ColumnType::Boolean,
354                "tginitdeferred" => ColumnType::Boolean,
355                "tgnargs" => ColumnType::SmallInteger,
356                "tgattr" => ColumnType::Int2Vector,
357                "tgargs" => ColumnType::Bytea,
358                "tgqual" => ColumnType::PgNodeTree,
359                "tgoldtable" => ColumnType::Name,
360                "tgnewtable" => ColumnType::Name,
361            ],
362            Self::PgRewrite => columns![
363                "oid" => ColumnType::Oid,
364                "rulename" => ColumnType::Name,
365                "ev_class" => ColumnType::Oid,
366                "ev_type" => ColumnType::InternalChar,
367                "ev_enabled" => ColumnType::InternalChar,
368                "is_instead" => ColumnType::Boolean,
369                "ev_qual" => ColumnType::PgNodeTree,
370                "ev_action" => ColumnType::PgNodeTree,
371            ],
372            Self::PgRules => columns![
373                "schemaname" => ColumnType::Name,
374                "tablename" => ColumnType::Name,
375                "rulename" => ColumnType::Name,
376                "definition" => ColumnType::Text,
377            ],
378            Self::PgTables => columns![
379                "schemaname" => ColumnType::Name,
380                "tablename" => ColumnType::Name,
381                "tableowner" => ColumnType::Name,
382                "tablespace" => ColumnType::Name,
383                "hasindexes" => ColumnType::Boolean,
384                "hasrules" => ColumnType::Boolean,
385                "hastriggers" => ColumnType::Boolean,
386                "rowsecurity" => ColumnType::Boolean,
387            ],
388            Self::PgViews => columns![
389                "schemaname" => ColumnType::Name,
390                "viewname" => ColumnType::Name,
391                "viewowner" => ColumnType::Name,
392                "definition" => ColumnType::Text,
393            ],
394            Self::PgIndexes => columns![
395                "schemaname" => ColumnType::Name,
396                "tablename" => ColumnType::Name,
397                "indexname" => ColumnType::Name,
398                "tablespace" => ColumnType::Name,
399                "indexdef" => ColumnType::Text,
400            ],
401            Self::PgType => columns![
402                "oid" => ColumnType::Oid,
403                "typname" => ColumnType::Name,
404                "typnamespace" => ColumnType::Oid,
405                "typowner" => ColumnType::Oid,
406                "typlen" => ColumnType::SmallInteger,
407                "typbyval" => ColumnType::Boolean,
408                "typtype" => ColumnType::InternalChar,
409                "typcategory" => ColumnType::InternalChar,
410                "typispreferred" => ColumnType::Boolean,
411                "typisdefined" => ColumnType::Boolean,
412                "typdelim" => ColumnType::InternalChar,
413                "typrelid" => ColumnType::Oid,
414                "typsubscript" => ColumnType::Regproc,
415                "typelem" => ColumnType::Oid,
416                "typarray" => ColumnType::Oid,
417                "typinput" => ColumnType::Regproc,
418                "typoutput" => ColumnType::Regproc,
419                "typreceive" => ColumnType::Regproc,
420                "typsend" => ColumnType::Regproc,
421                "typmodin" => ColumnType::Regproc,
422                "typmodout" => ColumnType::Regproc,
423                "typanalyze" => ColumnType::Regproc,
424                "typalign" => ColumnType::InternalChar,
425                "typstorage" => ColumnType::InternalChar,
426                "typnotnull" => ColumnType::Boolean,
427                "typbasetype" => ColumnType::Oid,
428                "typtypmod" => ColumnType::Integer,
429                "typndims" => ColumnType::Integer,
430                "typcollation" => ColumnType::Oid,
431                "typdefaultbin" => ColumnType::PgNodeTree,
432                "typdefault" => ColumnType::Text,
433                "typacl" => array(ColumnType::AclItem),
434            ],
435            Self::PgRange => columns![
436                "rngtypid" => ColumnType::Oid,
437                "rngsubtype" => ColumnType::Oid,
438                "rngmultitypid" => ColumnType::Oid,
439                "rngcollation" => ColumnType::Oid,
440                "rngsubopc" => ColumnType::Oid,
441                "rngcanonical" => ColumnType::Regproc,
442                "rngsubdiff" => ColumnType::Regproc,
443            ],
444            Self::PgProc => columns![
445                "oid" => ColumnType::Oid,
446                "proname" => ColumnType::Name,
447                "pronamespace" => ColumnType::Oid,
448                "proowner" => ColumnType::Oid,
449                "prolang" => ColumnType::Oid,
450                "procost" => ColumnType::Real,
451                "prorows" => ColumnType::Real,
452                "provariadic" => ColumnType::Oid,
453                "prosupport" => ColumnType::Regproc,
454                "prokind" => ColumnType::InternalChar,
455                "prosecdef" => ColumnType::Boolean,
456                "proleakproof" => ColumnType::Boolean,
457                "proisstrict" => ColumnType::Boolean,
458                "proretset" => ColumnType::Boolean,
459                "provolatile" => ColumnType::InternalChar,
460                "proparallel" => ColumnType::InternalChar,
461                "pronargs" => ColumnType::SmallInteger,
462                "pronargdefaults" => ColumnType::SmallInteger,
463                "prorettype" => ColumnType::Oid,
464                "proargtypes" => ColumnType::OidVector,
465                "proallargtypes" => array(ColumnType::Oid),
466                "proargmodes" => array(ColumnType::InternalChar),
467                "proargnames" => array(ColumnType::Text),
468                "proargdefaults" => ColumnType::PgNodeTree,
469                "protrftypes" => array(ColumnType::Oid),
470                "prosrc" => ColumnType::Text,
471                "probin" => ColumnType::Text,
472                "prosqlbody" => ColumnType::PgNodeTree,
473                "proconfig" => array(ColumnType::Text),
474                "proacl" => array(ColumnType::AclItem),
475            ],
476            Self::PgDatabase => columns![
477                "oid" => ColumnType::Oid,
478                "datname" => ColumnType::Name,
479                "datdba" => ColumnType::Oid,
480                "encoding" => ColumnType::Integer,
481                "datlocprovider" => ColumnType::InternalChar,
482                "datistemplate" => ColumnType::Boolean,
483                "datallowconn" => ColumnType::Boolean,
484                "dathasloginevt" => ColumnType::Boolean,
485                "datconnlimit" => ColumnType::Integer,
486                "datfrozenxid" => ColumnType::Xid,
487                "datminmxid" => ColumnType::Xid,
488                "dattablespace" => ColumnType::Oid,
489                "datcollate" => ColumnType::Text,
490                "datctype" => ColumnType::Text,
491                "datlocale" => ColumnType::Text,
492                "daticurules" => ColumnType::Text,
493                "datcollversion" => ColumnType::Text,
494                "datacl" => array(ColumnType::AclItem),
495            ],
496            Self::PgAuthid => columns![
497                "oid" => ColumnType::Oid,
498                "rolname" => ColumnType::Name,
499                "rolsuper" => ColumnType::Boolean,
500                "rolinherit" => ColumnType::Boolean,
501                "rolcreaterole" => ColumnType::Boolean,
502                "rolcreatedb" => ColumnType::Boolean,
503                "rolcanlogin" => ColumnType::Boolean,
504                "rolreplication" => ColumnType::Boolean,
505                "rolbypassrls" => ColumnType::Boolean,
506                "rolconnlimit" => ColumnType::Integer,
507                "rolpassword" => ColumnType::Text,
508                "rolvaliduntil" => ColumnType::TimestampTz,
509            ],
510            Self::PgAuthMembers => columns![
511                "oid" => ColumnType::Oid,
512                "roleid" => ColumnType::Oid,
513                "member" => ColumnType::Oid,
514                "grantor" => ColumnType::Oid,
515                "admin_option" => ColumnType::Boolean,
516                "inherit_option" => ColumnType::Boolean,
517                "set_option" => ColumnType::Boolean,
518            ],
519            Self::PgRoles => columns![
520                "rolname" => ColumnType::Name,
521                "rolsuper" => ColumnType::Boolean,
522                "rolinherit" => ColumnType::Boolean,
523                "rolcreaterole" => ColumnType::Boolean,
524                "rolcreatedb" => ColumnType::Boolean,
525                "rolcanlogin" => ColumnType::Boolean,
526                "rolreplication" => ColumnType::Boolean,
527                "rolconnlimit" => ColumnType::Integer,
528                "rolpassword" => ColumnType::Text,
529                "rolvaliduntil" => ColumnType::TimestampTz,
530                "rolbypassrls" => ColumnType::Boolean,
531                "rolconfig" => array(ColumnType::Text),
532                "oid" => ColumnType::Oid,
533            ],
534            Self::PgUser => columns![
535                "usename" => ColumnType::Name,
536                "usesysid" => ColumnType::Oid,
537                "usecreatedb" => ColumnType::Boolean,
538                "usesuper" => ColumnType::Boolean,
539                "userepl" => ColumnType::Boolean,
540                "usebypassrls" => ColumnType::Boolean,
541                "passwd" => ColumnType::Text,
542                "valuntil" => ColumnType::TimestampTz,
543                "useconfig" => array(ColumnType::Text),
544            ],
545            Self::PgCursors => columns![
546                "name" => ColumnType::Text,
547                "statement" => ColumnType::Text,
548                "is_holdable" => ColumnType::Boolean,
549                "is_binary" => ColumnType::Boolean,
550                "is_scrollable" => ColumnType::Boolean,
551                "creation_time" => ColumnType::TimestampTz,
552            ],
553            Self::PgPreparedStatements => columns![
554                "name" => ColumnType::Text,
555                "statement" => ColumnType::Text,
556                "prepare_time" => ColumnType::TimestampTz,
557                "parameter_types" => array(ColumnType::Regtype),
558                "result_types" => array(ColumnType::Regtype),
559                "from_sql" => ColumnType::Boolean,
560                "generic_plans" => ColumnType::BigInteger,
561                "custom_plans" => ColumnType::BigInteger,
562            ],
563            Self::PgSettings => columns![
564                "name" => ColumnType::Text,
565                "setting" => ColumnType::Text,
566                "unit" => ColumnType::Text,
567                "category" => ColumnType::Text,
568                "short_desc" => ColumnType::Text,
569                "extra_desc" => ColumnType::Text,
570                "context" => ColumnType::Text,
571                "vartype" => ColumnType::Text,
572                "source" => ColumnType::Text,
573                "min_val" => ColumnType::Text,
574                "max_val" => ColumnType::Text,
575                "enumvals" => array(ColumnType::Text),
576                "boot_val" => ColumnType::Text,
577                "reset_val" => ColumnType::Text,
578                "sourcefile" => ColumnType::Text,
579                "sourceline" => ColumnType::Integer,
580                "pending_restart" => ColumnType::Boolean,
581            ],
582            Self::PgDescription => columns![
583                "objoid" => ColumnType::Oid,
584                "classoid" => ColumnType::Oid,
585                "objsubid" => ColumnType::Integer,
586                "description" => ColumnType::Text,
587            ],
588            Self::PgMatviews => columns![
589                "schemaname" => ColumnType::Name,
590                "matviewname" => ColumnType::Name,
591                "matviewowner" => ColumnType::Name,
592                "tablespace" => ColumnType::Name,
593                "hasindexes" => ColumnType::Boolean,
594                "ispopulated" => ColumnType::Boolean,
595                "definition" => ColumnType::Text,
596            ],
597            Self::PgSequences => columns![
598                "schemaname" => ColumnType::Name,
599                "sequencename" => ColumnType::Name,
600                "sequenceowner" => ColumnType::Name,
601                "data_type" => ColumnType::Regtype,
602                "start_value" => ColumnType::BigInteger,
603                "min_value" => ColumnType::BigInteger,
604                "max_value" => ColumnType::BigInteger,
605                "increment_by" => ColumnType::BigInteger,
606                "cycle" => ColumnType::Boolean,
607                "cache_size" => ColumnType::BigInteger,
608                "last_value" => ColumnType::BigInteger,
609            ],
610            Self::AgGraph => columns![
611                "graphid" => ColumnType::Oid,
612                "name" => ColumnType::Name,
613                "namespace" => ColumnType::Regnamespace,
614            ],
615            Self::AgLabel => columns![
616                "name" => ColumnType::Name,
617                "graph" => ColumnType::Oid,
618                "id" => ag_label_id(),
619                "kind" => ag_label_kind(),
620                "relation" => ColumnType::Regclass,
621                "seq_name" => ColumnType::Name,
622            ],
623        }
624    }
625}
626
627fn ag_catalog_domain(name: &str, base: ColumnType) -> ColumnType {
628    ColumnType::Domain {
629        schema: AG_CATALOG_SCHEMA.into(),
630        name: name.into(),
631        oid: ag_catalog_type_oid(name),
632        base: Box::new(base),
633    }
634}
635
636/// Stable OID of an `ag_catalog` type; the extension assigns these from
637/// the OID counter, so any collision-free assignment is faithful.
638pub fn ag_catalog_type_oid(name: &str) -> u32 {
639    let oid = oids::stable_oid("type", &format!("{AG_CATALOG_SCHEMA}.{name}"));
640    u32::try_from(oid).unwrap_or(0)
641}
642
643/// AGE `label_id`: `int NOT NULL CHECK (VALUE > 0 AND VALUE <= 65535)`.
644pub fn ag_label_id() -> ColumnType {
645    ag_catalog_domain("label_id", ColumnType::Integer)
646}
647
648/// AGE `label_kind`: `"char" NOT NULL CHECK (VALUE = 'v' OR VALUE = 'e')`.
649pub fn ag_label_kind() -> ColumnType {
650    ag_catalog_domain("label_kind", ColumnType::InternalChar)
651}
652
653/// Internal type carrier for AGE's fixed-width `graphid` base type.
654pub fn age_graphid() -> ColumnType {
655    ag_catalog_domain("graphid", ColumnType::BigInteger)
656}
657
658/// Internal type carrier for AGE's JSONB-shaped `agtype` base type.
659pub fn age_agtype() -> ColumnType {
660    ag_catalog_domain("agtype", ColumnType::JsonB)
661}
662
663pub fn ag_catalog_domains() -> Vec<ColumnType> {
664    vec![ag_label_id(), ag_label_kind()]
665}
666
667fn array(element: ColumnType) -> ColumnType {
668    ColumnType::Array(Box::new(element))
669}
670
671fn information_schema_domain(name: &str, oid: u32, base: ColumnType) -> ColumnType {
672    ColumnType::Domain {
673        schema: "information_schema".into(),
674        name: name.into(),
675        oid,
676        base: Box::new(base),
677    }
678}
679
680fn cardinal_number() -> ColumnType {
681    information_schema_domain("cardinal_number", 13_307, ColumnType::Integer)
682}
683
684fn character_data() -> ColumnType {
685    information_schema_domain("character_data", 13_310, ColumnType::Varchar(None))
686}
687
688fn sql_identifier() -> ColumnType {
689    information_schema_domain("sql_identifier", 13_312, ColumnType::Name)
690}
691
692fn time_stamp() -> ColumnType {
693    information_schema_domain("time_stamp", 13_318, ColumnType::TimestampTz)
694}
695
696fn yes_or_no() -> ColumnType {
697    information_schema_domain("yes_or_no", 13_320, ColumnType::Varchar(Some(3)))
698}
699
700pub fn information_schema_domains() -> Vec<ColumnType> {
701    vec![
702        cardinal_number(),
703        character_data(),
704        sql_identifier(),
705        time_stamp(),
706        yes_or_no(),
707    ]
708}
709
710fn information_routines_schema() -> Vec<(String, ColumnType)> {
711    macro_rules! columns {
712        ($($name:literal => $ty:expr),* $(,)?) => {
713            vec![$(($name.to_string(), $ty)),*]
714        };
715    }
716
717    columns![
718        "specific_catalog" => sql_identifier(),
719        "specific_schema" => sql_identifier(),
720        "specific_name" => sql_identifier(),
721        "routine_catalog" => sql_identifier(),
722        "routine_schema" => sql_identifier(),
723        "routine_name" => sql_identifier(),
724        "routine_type" => character_data(),
725        "module_catalog" => sql_identifier(),
726        "module_schema" => sql_identifier(),
727        "module_name" => sql_identifier(),
728        "udt_catalog" => sql_identifier(),
729        "udt_schema" => sql_identifier(),
730        "udt_name" => sql_identifier(),
731        "data_type" => character_data(),
732        "character_maximum_length" => cardinal_number(),
733        "character_octet_length" => cardinal_number(),
734        "character_set_catalog" => sql_identifier(),
735        "character_set_schema" => sql_identifier(),
736        "character_set_name" => sql_identifier(),
737        "collation_catalog" => sql_identifier(),
738        "collation_schema" => sql_identifier(),
739        "collation_name" => sql_identifier(),
740        "numeric_precision" => cardinal_number(),
741        "numeric_precision_radix" => cardinal_number(),
742        "numeric_scale" => cardinal_number(),
743        "datetime_precision" => cardinal_number(),
744        "interval_type" => character_data(),
745        "interval_precision" => cardinal_number(),
746        "type_udt_catalog" => sql_identifier(),
747        "type_udt_schema" => sql_identifier(),
748        "type_udt_name" => sql_identifier(),
749        "scope_catalog" => sql_identifier(),
750        "scope_schema" => sql_identifier(),
751        "scope_name" => sql_identifier(),
752        "maximum_cardinality" => cardinal_number(),
753        "dtd_identifier" => sql_identifier(),
754        "routine_body" => character_data(),
755        "routine_definition" => character_data(),
756        "external_name" => character_data(),
757        "external_language" => character_data(),
758        "parameter_style" => character_data(),
759        "is_deterministic" => yes_or_no(),
760        "sql_data_access" => character_data(),
761        "is_null_call" => yes_or_no(),
762        "sql_path" => character_data(),
763        "schema_level_routine" => yes_or_no(),
764        "max_dynamic_result_sets" => cardinal_number(),
765        "is_user_defined_cast" => yes_or_no(),
766        "is_implicitly_invocable" => yes_or_no(),
767        "security_type" => character_data(),
768        "to_sql_specific_catalog" => sql_identifier(),
769        "to_sql_specific_schema" => sql_identifier(),
770        "to_sql_specific_name" => sql_identifier(),
771        "as_locator" => yes_or_no(),
772        "created" => time_stamp(),
773        "last_altered" => time_stamp(),
774        "new_savepoint_level" => yes_or_no(),
775        "is_udt_dependent" => yes_or_no(),
776        "result_cast_from_data_type" => character_data(),
777        "result_cast_as_locator" => yes_or_no(),
778        "result_cast_char_max_length" => cardinal_number(),
779        "result_cast_char_octet_length" => cardinal_number(),
780        "result_cast_char_set_catalog" => sql_identifier(),
781        "result_cast_char_set_schema" => sql_identifier(),
782        "result_cast_char_set_name" => sql_identifier(),
783        "result_cast_collation_catalog" => sql_identifier(),
784        "result_cast_collation_schema" => sql_identifier(),
785        "result_cast_collation_name" => sql_identifier(),
786        "result_cast_numeric_precision" => cardinal_number(),
787        "result_cast_numeric_precision_radix" => cardinal_number(),
788        "result_cast_numeric_scale" => cardinal_number(),
789        "result_cast_datetime_precision" => cardinal_number(),
790        "result_cast_interval_type" => character_data(),
791        "result_cast_interval_precision" => cardinal_number(),
792        "result_cast_type_udt_catalog" => sql_identifier(),
793        "result_cast_type_udt_schema" => sql_identifier(),
794        "result_cast_type_udt_name" => sql_identifier(),
795        "result_cast_scope_catalog" => sql_identifier(),
796        "result_cast_scope_schema" => sql_identifier(),
797        "result_cast_scope_name" => sql_identifier(),
798        "result_cast_maximum_cardinality" => cardinal_number(),
799        "result_cast_dtd_identifier" => sql_identifier(),
800    ]
801}
802
803#[cfg(test)]
804mod tests;
805
806pub mod analysis;
807
808pub mod domain;
809pub mod events;
810pub mod index;
811pub mod roles;
812
813/// Namespaces the engine implements without a durable schema row: the
814/// `PostgreSQL` system schemas and the Apache AGE catalog schema.
815pub fn is_virtual_system_schema(name: &str) -> bool {
816    matches!(name, "pg_catalog" | "information_schema" | "ag_catalog")
817}
818
819pub mod view;
820
821pub mod session;
822
823pub mod constraints;
824
825pub const DATABASE_NAME: &str = "uqa";
826pub const DATABASE_OID: i64 = 5;
827
828pub mod stored_ast;
829
830pub mod regrole_dependencies;
831
832pub mod security;
833
834pub mod stored_view;
835
836pub mod errors;
837
838pub mod sequence_functions;