CUBRID System Catalog Classes — Data-Driven Definition, Bootstrap Install, and System View Query Specs
Contents:
- Theoretical Background
- Common DBMS Design
- CUBRID’s Approach
- Source Walkthrough
- Cross-check Notes
- Open Questions
- Sources
Theoretical Background
Section titled “Theoretical Background”A relational engine has to expose its own schema to SQL. Which classes exist? What columns? What indexes? Who owns each one? Which users have what privileges? The answers must be queryable through ordinary SELECTs — otherwise tools like \d (psql), DESCRIBE (MySQL), or any GUI client cannot work. This is the system catalog as a relation principle, traceable to System R 1979 (Astrahan et al., System R: Relational Approach to Database Management, ACM TODS) and crystallised by Hellerstein and Stonebraker in Anatomy of a Database System Ch. 4 — the catalog is just another set of tables, accessed through the same execution stack as user tables.
Three textbook ideas frame how an engine actually delivers that surface.
Schema-as-data. Every system catalog table has a fixed shape: _db_class has columns class_name, owner, class_type, inst_attr_count, etc. That shape can be expressed in two ways. The hand-coded approach scatters db_add_attribute (db_class, "class_name", "varchar(255)", NULL) calls across imperative C, one call per column per table; the resulting code is correct but unreadable, hard to evolve, and impossible to validate as a whole. The data-driven approach instead represents each class as a value — a struct holding name, an attributes vector, a constraints vector, an authorization block — and a single generic builder consumes the vector to produce the class. Codd’s relational model already says schema is data; this is the implementation expression of that idea inside the engine itself.
Bootstrap chicken-and-egg. The catalog has to exist before the catalog can be read. _db_class describes the class _db_class — to read its definition you have to already know how to read it. Every engine cuts the cycle the same way: at createdb time, the engine seeds a root anchor with hardcoded knowledge (System R’s SYSTABLES, Oracle’s bootstrap segment, PostgreSQL’s pg_class initial heap, CUBRID’s root class) and uses that anchor to install all subsequent system classes by issuing the same DDL operations a user would. The install path is therefore the same db_create_class / smt_add_attribute / sm_update_class that user CREATE TABLE calls — only the data driving the calls is privileged.
Separation of disk catalog and SQL catalog. Petrov’s Database Internals §1 distinguishes the engine-internal metadata (compact disk records the optimiser and executor consume directly — OR_CLASSREP, CLS_INFO, BTREE_STATS) from the SQL-visible catalog (_db_class, _db_attribute, _db_index) that exposes the same information to the SQL surface. The two are not redundant: the disk catalog is read on every plan compile and must be cheap to deserialise; the SQL catalog is queried through ordinary scans and joins, so it must look like any other table. CUBRID makes the split explicit by keeping cubrid-catalog-manager (disk side) under DDL infrastructure and this module (SQL-visible system classes) as the catalog facade — two layers of the same metadata, kept in sync by the DDL pipeline.
The three combine into one design: encode each system class as a system_catalog_definition value, install it through a generic builder that issues normal DDL, and run the install once at createdb against the root-class anchor. schema_system_catalog_install.cpp is the data; schema_system_catalog_builder.cpp is the engine; catcls_install is the orchestration.
Common DBMS Design
Section titled “Common DBMS Design”The four major engines reach the same SQL-visible catalog surface through different bootstrap mechanics.
PostgreSQL uses pg_class, pg_attribute, pg_index, pg_constraint as ordinary heap tables under the pg_catalog schema. Bootstrap is run by genbki.pl: a Perl script reads C structs annotated with BKI_* macros from src/include/catalog/pg_*.h, emits a postgres.bki script of create/insert directives, and the standalone --bootstrap mode of the postgres backend executes that script against an empty cluster to seed every system table. After bootstrap, the catalog is read through standard RelationCacheLookup over the same heap-and-btree access methods that user tables use. The point: schema-as-data is solved at build time by a code generator, with no runtime framework.
MySQL ships two parallel surfaces. INFORMATION_SCHEMA.* is the SQL-standard self-description: each INFORMATION_SCHEMA table is implemented by a custom storage engine (ha_information_schema) that synthesises rows from the data dictionary on demand. The actual on-disk catalog (since 8.0) lives in InnoDB tables under the mysql schema (mysql.tables, mysql.columns, …) and is bootstrapped by SQL DDL scripts run by mysqld --initialize. performance_schema is a separate runtime-state surface implemented as ring-buffer storage engine. Three layers — bootstrap DDL, InnoDB-backed data dictionary, virtual INFORMATION_SCHEMA — for the same conceptual catalog.
Oracle keeps its data dictionary in a fixed set of SYS-owned tables (OBJ$, COL$, IND$, USER$) plus a layer of fixed tables (X$KQFTA, X$KQFCO) that project C arrays as relations. The user-facing surface is the DBA_*/ALL_*/USER_* view family, all defined in $ORACLE_HOME/rdbms/admin/catalog.sql — a 100K-line SQL script run at CREATE DATABASE that builds the SYS.* tables, populates the seed rows, then defines the dictionary views as SQL CREATE VIEW statements layered on top.
SQL Server uses the same shape: a fixed set of base catalog tables (mostly inaccessible — sys.sysschobjs) plus a published surface of sys.* catalog views and INFORMATION_SCHEMA.* defined in mssqlsystemresource.mdf, the read-only resource database that ships with the server install.
The engines differ in where the schema-as-data lives — Postgres’s BKI files (build time), MySQL’s mysql/InnoDB tables (initialize time), Oracle’s catalog.sql (createdb time), SQL Server’s resource db (install time) — but the move is the same: encode the meta-schema as data, run a one-time install that uses normal DDL primitives, and from then on treat the catalog like any other table.
Where CUBRID lands. CUBRID encodes the meta-schema in C++ code at runtime: a cubschema::system_catalog_definition value per class, registered into a std::vector in catcls_init, consumed by a single system_catalog_builder in catcls_install. The data lives next to the engine (no external scripts to ship and version), and the install runs through ordinary db_create_class / smt_add_attribute / sm_update_class calls — the same code path a user CREATE TABLE takes. System views (db_class, db_attribute, …) carry their query spec as a SQL string literal compiled into the binary, installed via db_add_query_spec after the underlying class is built. The result is a catalog facade that is part of the engine, evolved with the rest of the C++ tree under one PR, and reachable for inspection through SELECT * FROM _db_class like any other table.
CUBRID’s Approach
Section titled “CUBRID’s Approach”The module is split into four pieces that together implement the data-driven framework.
flowchart TB
subgraph constants["Names — schema_system_catalog_constants.h"]
CN["CT_CLASS_NAME = '_db_class'<br/>CT_ATTRIBUTE_NAME = '_db_attribute'<br/>CT_INDEX_NAME = '_db_index'<br/>... 24 class names + 22 view names"]
end
subgraph defs["Meta-schema — schema_system_catalog_definition.hpp"]
A["struct attribute<br/>(COLUMN | CLASS_METHOD | QUERY_SPEC)"]
C["struct constraint<br/>(PK | UNIQUE | INDEX | NOT_NULL)"]
G["struct grant<br/>+ struct authorization"]
SD["struct system_catalog_definition<br/>{ name, attributes[], constraints[],<br/>auth, row_initializer }"]
A --> SD
C --> SD
G --> SD
end
subgraph install["Data — schema_system_catalog_install.cpp + _query_spec.cpp"]
INIT["system_catalog_initializer::<br/>get_class() / get_attribute() / get_index() / ..."]
CLIST["std::vector clist (24 classes)"]
VCLIST["std::vector vclist (22 views)"]
INIT --> CLIST
INIT --> VCLIST
end
subgraph builder["Engine — schema_system_catalog_builder.cpp"]
B["system_catalog_builder::<br/>create_and_mark_system_class<br/>build_class<br/>build_vclass"]
end
subgraph entry["Entry — schema_system_catalog.cpp + install.cpp"]
INITFN["catcls_init()"]
INSTALLFN["catcls_install()"]
INITFN --> CLIST
INITFN --> VCLIST
INSTALLFN --> B
end
SD --> INIT
CN --> INIT
CLIST --> INSTALLFN
VCLIST --> INSTALLFN
Three properties make this design legible.
One representation, two consumers. The same system_catalog_definition describes a class (consumed by build_class) and a view (consumed by build_vclass). The attribute_kind discriminator selects the path: COLUMN and CLASS_METHOD go through smt_add_attribute / smt_add_class_method; QUERY_SPEC goes through db_add_query_spec. The view’s query spec is just another attribute kind, so views and tables share the same definition shape — a quiet but expressive choice.
Definitions are values, not functions. Legacy CUBRID code had per-class functions (boot_define_class, boot_define_attribute, …) that issued a long sequence of imperative db_add_* calls. The current module replaces those with system_catalog_initializer::get_class() returning a system_catalog_definition value. The builder then re-derives the same imperative sequence from the value. The redundancy is intentional: when the meta-schema needs a new feature (say, default values, expressed via the dvalue_func lambda already present), it goes once into the definition struct and once into the builder, rather than into 46 sites.
Install is a stable pipeline; data is the variable. catcls_install does the same three things every time: register all class definitions, build all classes, build all views. The order matters — classes must exist before views can reference them in query specs, and the first pass creates empty MOPs so the second pass can install attributes that reference other system classes (e.g. _db_class.owner is of type db_user, which has to be a known MOP first). This two-phase pattern is the same mutual-recursion fix the catalog-manager uses for its disk catalog (allocating the catalog file before writing rows that reference it).
// catcls_install — schema_system_catalog_install.cpp (condensed)int catcls_install (void){ AU_DISABLE (save); au_set_user (Au_dba_user);
// Pass 1: create empty MOPs for every system class for (i = 0; i < clist.size (); i++) class_mop[i] = catalog_builder::create_and_mark_system_class (clist[i].name);
// Pass 2: install attributes, constraints, grants, row initialisers for (i = 0; i < clist.size (); i++) catalog_builder::build_class (class_mop[i], clist[i].definition);
// Pass 3: install system views (their query specs may reference system classes) for (i = 0; i < vclist.size (); i++) { MOP class_mop = catalog_builder::create_and_mark_system_class (vclist[i].name); catalog_builder::build_vclass (class_mop, vclist[i].definition); }
AU_ENABLE (save); clist.clear (); vclist.clear (); return error_code;}The AU_DISABLE / AU_ENABLE bracket and the au_set_user (Au_dba_user) are not optional bookkeeping. The install runs DDL against tables that do not yet have authorization rows, and the DBA principal is the only user that exists at this point in createdb; suppressing the auth check for the install duration is what lets the recursion terminate.
The 24 system classes and 22 system views
Section titled “The 24 system classes and 22 system views”The catalog surface CUBRID exposes splits along two axes — kind (real class on a heap vs. SQL view layered on top) and concern (schema, authorization, statistics, partitioning, PL, replication, i18n, server federation).
| Class (24) | Concern | Notes |
|---|---|---|
_db_class, _db_attribute, _db_domain, _db_method, _db_meth_sig, _db_meth_arg, _db_meth_file, _db_query_spec, _db_index, _db_index_key, _db_data_type | core schema | Self-describes every user class. _db_class is itself one of the 24. |
db_root, db_user, db_password, db_authorization | authorization | The only ones without leading underscore — they are user-facing for direct DDL (CREATE USER). |
_db_auth, _db_partition, _db_trigger, _db_serial | feature surfaces | Privileges per object, partition map, trigger registry, sequence state. |
_db_stored_procedure, _db_stored_procedure_args, _db_stored_procedure_code | PL family | Stored procedure registry (consumed by cubrid-pl-javasp.md, cubrid-pl-plcsql.md). |
_db_ha_apply_info | replication | log-applier checkpoint state. |
_db_collation, _db_charset | i18n | Loaded from the per-platform libcubrid_collations.so (cubrid-charset-collation.md). |
_db_server | federation | DBLink server catalog. |
_db_synonym | naming | Object aliases. |
dual | utility | One-row table for SELECT 1 FROM dual — Oracle compatibility. |
| View (22) | Underlying class | Note |
|---|---|---|
db_class, db_direct_super_class, db_vclass | _db_class | Filters by class type and ownership. |
db_attribute, db_attr_setdomain_elm | _db_attribute + _db_domain | Joins set-domain elements through _db_domain. |
db_method, db_meth_arg, db_meth_arg_setdomain_elm, db_meth_file | method family | Mostly disabled in modern usage but kept for compatibility. |
db_index, db_index_key | index family | Extracts B+Tree metadata into ordered rows. |
db_auth | _db_auth | Resolves class_of/grantor/grantee MOPs to readable names. |
db_trigger, db_partition | trigger / partition | Decode catalog flags into human-readable enums. |
db_stored_procedure, db_stored_procedure_args | SP family | The signatures users \sp against. |
db_serial, db_ha_apply_info | feature views | Cached state. |
db_collation, db_charset | i18n views | UTF-8/ICU decoded. |
db_server, db_synonym | federation views | DBLink server map. |
The 24/22 split is also the bilingual surface CUBRID inherits from Oracle vs. ANSI/ISO conventions: leading-underscore tables are the engine-private storage; non-underscore views are the user-facing read surface.
Where it sits relative to neighbouring modules
Section titled “Where it sits relative to neighbouring modules”flowchart LR DDL["DDL pipeline<br/>(cubrid-ddl-execution)"] CM["Catalog manager<br/>(cubrid-catalog-manager)<br/>disk: OR_CLASSREP, CTID"] SC["This module<br/>(system-catalog-classes)<br/>SQL-visible: _db_class et al."] SHOW["SHOW commands<br/>(cubrid-show-commands)<br/>runtime: virtual scans"] SM["Schema manager<br/>(cubrid-class-object)<br/>in-memory: SM_CLASS"] BOOT["boot_sr / createdb<br/>(cubrid-boot)"] BOOT -->|catcls_init + catcls_install| SC SC -->|builds rows in| CM SC -.surfaces as.-> SHOW DDL -->|reads to compile| CM DDL -->|reads to update| SC SM -->|consumes _db_class rows from| SC
- Upstream from this module:
cubrid-bootcallscatcls_initonce duringcreatedbto register the meta-schema, thencatcls_installto actually run the DDL. - Builds into:
cubrid-catalog-manager. Everydb_create_classultimately writes anOR_CLASSREPinto the disk catalog — that is where the rows physically live. This module is the facade; catalog-manager is the storage. - Adjacent in DDL & Schema:
cubrid-class-object(schema graph,SM_CLASS) reads the same rows on every plan compile to materialise its in-memory representation;cubrid-ddl-executionwrites new rows when the user issuesCREATE TABLE. - Surfaces upward as:
cubrid-show-commandsexposes runtime state through virtual scans; this module exposes static schema through real heap scans on_db_classetc. The two together form the system-catalog section’s full “self-description through SQL” surface.
Source Walkthrough
Section titled “Source Walkthrough”The module’s symbols cluster cleanly by file role.
schema_system_catalog_constants.h — string constants for every system class and view name. Both raw class names (CT_CLASS_NAME = "_db_class") and view names (CTV_CLASS_NAME = "db_class") live here. Used everywhere the catalog is referenced by name (DDL parsing, SHOW, info schema, this module).
schema_system_catalog.hpp/cpp — top-level API. catcls_init (registers definitions), catcls_install (runs the install), sm_is_system_class / sm_is_system_vclass (name-membership tests against the sm_system_class_names / sm_system_vclass_names vectors). The catcls_add_data_type, catcls_add_charsets, catcls_add_collations row-initialiser entry points are also declared here and called from _db_data_type, _db_charset, _db_collation definitions through system_catalog_definition::row_initializer.
schema_system_catalog_definition.hpp/cpp — the meta-schema structs.
// Meta-schema — schema_system_catalog_definition.hpp (condensed)enum class attribute_kind { COLUMN, CLASS_METHOD, QUERY_SPEC };
struct attribute { attribute_kind kind; std::string name; std::string type; // SQL type string: "varchar(255)", "integer", ... std::function<int (DB_VALUE *)> dvalue_func; // optional default};
struct constraint { DB_CONSTRAINT_TYPE type; // PK | UNIQUE | INDEX | NOT_NULL std::string name; std::vector<const char *> attribute_names; bool is_class_attributes;};
struct authorization { struct db_object *owner; // typically Au_dba_user std::vector<grant> grants; // (target_user, auth, with_grant_option)};
struct system_catalog_definition { std::string name; std::vector<attribute> attributes; std::vector<constraint> constraints; authorization auth; std::function<int (db_object *)> row_initializer; // optional seed data};The attribute::type field is a SQL type string, not a TP_DOMAIN. The string is parsed by smt_add_attribute exactly as if the user had written it in CREATE TABLE, which is what makes the install path identical to user DDL. The lambdas in dvalue_func and row_initializer capture by value — that is why the definitions can sit in a static std::vector from catcls_init until catcls_install runs.
schema_system_catalog_builder.hpp/cpp — the install engine.
create_and_mark_system_class (name)—db_create_classordb_create_vclassbased on the name lookup insm_is_system_class/sm_is_system_vclass, thensm_mark_system_classto flag the resulting MOP as system-owned.build_class (mop, def)— the heart of the framework: opens anSM_TEMPLATEviasmt_edit_class_mop, walksdef.attributescallingsmt_add_attribute(orsmt_add_class_methodforCLASS_METHOD), invokesdvalue_functo set defaults, callssm_update_classto commit the template, then walksdef.constraintscallingdb_add_constraint, sets owner viaau_change_class_owner_including_partitions, applies grants viaau_grant, and finally invokesdef.row_initializerif present.build_vclass (mop, def)— view variant:db_add_attributeforCOLUMNkinds,db_add_query_specforQUERY_SPECkinds,db_add_class_methodfor the rareCLASS_METHOD(preserved for legacy compat).
schema_system_catalog_install.cpp — the data file. Two parts:
- Static helper functions (
make_int_value_fn,make_double_value_fn,make_numeric_value_fn,format_varchar,format_numeric,format_sequence) that produce default-value lambdas and SQL type strings. catcls_init(registers everything intoclistandvclist) andcatcls_install(runs the three-pass install).- The
cubschema::system_catalog_initializernamespace — a static class withget_class(),get_attribute(),get_domain(), … factory functions that each return asystem_catalog_definitionvalue for one class. This is where the actual schema lives in code; ~50K of the file is these factories.
The get_class() excerpt:
// system_catalog_initializer::get_class — schema_system_catalog_install.cpp (condensed)system_catalog_definition system_catalog_initializer::get_class () { return system_catalog_definition ( CT_CLASS_NAME, // "_db_class" { // attributes {"class_of", "object"}, // self-reference MOP {"unique_name", format_varchar (255)}, {"class_name", format_varchar (255)}, {"class_type", "integer"}, {"is_system_class", "integer"}, {"owner", AU_USER_CLASS_NAME}, // "db_user" -> object // ... 25 more columns ... }, /* constraints */ { /* PK on (owner, unique_name), INDEXes on class_name, etc. */ }, /* auth */ { Au_dba_user, /* grants */ }, /* row_initializer */ nullptr // _db_class has no seed data );}The same shape applies to all 24 class factories. Differences: _db_data_type carries catcls_add_data_type as its row initializer (which inserts the 24 type-name rows: INTEGER, FLOAT, …); _db_charset and _db_collation carry catcls_add_charsets / catcls_add_collations (which read libcubrid_collations.so and insert one row per loaded locale).
schema_system_catalog_install_query_spec.cpp — the view data file. One sm_define_view_* helper per view (e.g. sm_define_view_class_spec, sm_define_view_attribute_spec), each returning a static SQL string baked at compile time. These strings are the SELECT statements installed via db_add_query_spec in build_vclass. The header comment lists 13 formatting rules for the SQL literals (indent two tabs, lines end with a space, AND/OR newlines, etc.) — the rules are intentionally strict because git blame on this file is the canonical “schema-changed” signal for downstream tooling.
// sm_define_view_class_spec — schema_system_catalog_install_query_spec.cpp (condensed)const char *sm_define_view_class_spec (void) { static char stmt [2048]; sprintf (stmt, "SELECT " "[c].[class_name] AS [class_name], " "CAST ([c].[owner].[name] AS VARCHAR(255)) AS [owner_name], " "CASE [c].[class_type] WHEN 0 THEN 'CLASS' WHEN 1 THEN 'VCLASS' " "ELSE 'UNKNOWN' END AS [class_type], " // ... "FROM [%s] [c] " // "_db_class" "WHERE [c].[is_system_class] = 0 OR ...", CT_CLASS_NAME); return stmt;}The sprintf parameterisation with %s and CT_CLASS_NAME is what couples this module to schema_system_catalog_constants.h — renaming a class would require coordinated edits in both files.
Position hints (as of 2026-05-06)
Section titled “Position hints (as of 2026-05-06)”| Symbol | File | Line |
|---|---|---|
catcls_init | src/object/schema_system_catalog_install.cpp | 257 |
catcls_install | src/object/schema_system_catalog_install.cpp | 315 |
system_catalog_initializer::get_class | src/object/schema_system_catalog_install.cpp | ~415 |
system_catalog_builder::create_and_mark_system_class | src/object/schema_system_catalog_builder.cpp | 33 |
system_catalog_builder::build_class | src/object/schema_system_catalog_builder.cpp | 64 |
system_catalog_builder::build_vclass | src/object/schema_system_catalog_builder.cpp | 204 |
sm_is_system_class | src/object/schema_system_catalog.cpp | 126 |
sm_system_class_names (24 entries) | src/object/schema_system_catalog.cpp | 33 |
sm_system_vclass_names (22 entries) | src/object/schema_system_catalog.cpp | 86 |
sm_define_view_class_spec | src/object/schema_system_catalog_install_query_spec.cpp | 62 |
Cross-check Notes
Section titled “Cross-check Notes”- Definitions are runtime values, not compile-time constants. The 24 class definitions and 22 view definitions are constructed when
catcls_initruns, not at static initialisation. Thestatic std::vector<catcls_function> clistdeclarations ininstall.cppare populated bycatcls_init’sADD_TABLE_DEFINITIONmacros at runtime, then drained bycatcls_install. Consequence:catcls_initmust be called beforecatcls_install, and both must be called inside thecreatedbboot path — there is no static-initialiser shortcut. Theclist.clear ()/vclist.clear ()at the end ofcatcls_installis intentional: the definitions are freed once installed, since they exist only to feed the builder. - The framework is invoked exactly once, at
createdb.catcls_installis called fromboot_create_db(cubrid-boot.md) on first-time database creation. On every subsequent restart, the system classes are already on disk in the catalog, and the engine reads them throughcubrid-class-object’sSM_CLASSgraph machinery — this module is dormant after createdb. AU_DISABLEis required, not optional. During install the auth tables (db_user,db_authorization,_db_auth) themselves are being created; running auth checks against an in-construction catalog would wedge the install. The install runs asAu_dba_userwithAU_DISABLEprecisely because the access checks would otherwise loop on tables that do not yet exist.- Two-phase MOP creation matters because of cross-class references.
_db_class.owneris of typedb_user,_db_attribute.class_ofis of type_db_class, etc. If the install built each class fully before moving to the next, the very first class would fail trying to declare an attribute of a not-yet-existent type. Pass 1 creates empty MOPs for all 24 classes so that Pass 2’ssmt_add_attributecalls always find the type names they need. - The view query specs reference table names through
sprintf %s. This is fragile: changingCT_CLASS_NAMEfrom_db_classto anything else requires editing both the constant and any view query spec that names the table directly. The strict formatting comment at the top ofinstall_query_spec.cppis partly to ensure such changes are visible ingit diff. - Legacy
boot_define_*functions still exist.boot_sr.cretains aboot_define_class,boot_define_attribute, etc. family that predates this module. They are no longer called from the install path, butgit blameshows they were deprecated incrementally — some are still referenced by older tooling. The// new routinecomments incatcls_installmark where the new builder replaced the old direct calls. row_initializeris the only place where seed data lives. Schema (columns, constraints, grants) is data inside the definition struct, but actual seed rows (the 24 type-name rows in_db_data_type, the locale rows in_db_collation) live as imperative C++ inside the row-initializer callbacks. There is no declarative way to express “and here are the initial rows” — the framework stops at schema and hands off row population to a lambda.
Open Questions
Section titled “Open Questions”- Why not generate the install code at build time (Postgres BKI style) rather than at runtime? The runtime approach pays a one-time cost on
createdbbut keeps the meta-schema in plain C++ next to the rest of the engine, which a Perl-style code-gen does not. The trade-off is real — the BKI approach can validate the meta-schema at compile time — but CUBRID has chosen runtime for unification with the normal DDL path. - Should
_db_charset/_db_collationbe elsewhere? Their row initializers read the i18n shared libraries; they are catalog tables but their content is owned bycubrid-charset-collation.mdandcubrid-timezone.md(no_db_timezoneexists; timezones surface only through SHOW). The current placement keeps the schema-bootstrap story unified. - The 13 query-spec formatting rules are partly self-enforced. No CI lint runs against
install_query_spec.cppshape; the rules live as a header comment. A strict diff in code review is the only enforcement. dualanddb_rootare exposed names. Most catalog classes use the leading-underscore convention (_db_class);db_user,db_password,db_authorization,db_root,dualdo not. The boundary is historical (Oracledualfor compatibility, the auth tables predating the underscore convention) but it is observable by users and worth keeping in mind when reading client code that filters system tables by name prefix.
Sources
Section titled “Sources”src/object/schema_system_catalog.hpp/cpp— top-level API,catcls_init/catcls_install, name-membership predicatessrc/object/schema_system_catalog_builder.hpp/cpp— generic install engine (create_and_mark_system_class,build_class,build_vclass)src/object/schema_system_catalog_definition.hpp/cpp— meta-schema structs (attribute,constraint,grant,system_catalog_definition)src/object/schema_system_catalog_constants.h— class and view name constantssrc/object/schema_system_catalog_install.cpp— definition data for all 24 system classes + the 3-pass install orchestrationsrc/object/schema_system_catalog_install_query_spec.cpp— SQL literal query specs for all 22 system viewssrc/object/schema_manager.h,src/object/schema_template.h— DDL primitives the builder calls intosrc/transaction/boot_sr.c—boot_create_dbinvokescatcls_init+catcls_installonce at createdb- Adjacent CUBRID docs:
cubrid-catalog-manager.md,cubrid-class-object.md,cubrid-ddl-execution.md,cubrid-show-commands.md,cubrid-boot.md,cubrid-charset-collation.md - Textbook references: System R 1979 (Astrahan et al.); Hellerstein and Stonebraker, Anatomy of a Database System Ch. 4; Petrov, Database Internals Ch. 1; Selinger 1979 (Access Path Selection in a Relational DBMS)