CUBRID Class Object — In-Memory Schema, Attributes, Methods, Partitions, and the OODB Heritage
Contents:
- Theoretical Background
- Common DBMS Design
- CUBRID’s Approach
- Source Walkthrough
- Cross-check Notes
- Open Questions
- Sources
Theoretical Background
Section titled “Theoretical Background”In a relational database, the catalog tells the engine what shape every row has. But the engine never reads catalog rows from disk on every attribute access — that would slow every SELECT down to two heap fetches per column. Instead each engine builds an in-memory schema representation: a runtime data structure, keyed by class identity, that the parser, planner, executor, and locator consult cheaply. Database System Concepts (Silberschatz/Korth/Sudarshan, 7th ed., Ch. 24 “Object-Based Databases”) frames this as the “metadata cache” and observes that for object and object-relational engines the cache must hold not only column shapes but also class hierarchies, methods, and inheritance lattices.
CUBRID’s heritage forces this cache to be richer than a pure relational
engine’s. CUBRID started life as UniSQL/X, a true object-oriented
database (OODB) with classes, single inheritance, methods (C functions
linked into the server), shared attributes, class attributes, and a
metaclass distinction between root class (the class of classes) and
ordinary classes. The product later transitioned to ORDB and then to a
SQL-first relational engine, but it never deleted the OODB scaffolding
— it shadowed the relational features on top of it. Every CUBRID
table is implemented as a class; every row is an instance object with
an OID; every column is an attribute slot in a memory layout
determined by an SM_REPRESENTATION. This is why class_object.c is
220 KB and class_object.h is 46 KB: the file holds, in one graph,
the union of relational schema (columns, constraints, indexes,
partitions) and OODB schema (methods, signatures, resolutions, class
hierarchy).
Two textbook ingredients shape the rest of this document:
- Class as a graph of components. The conventional treatment
(Database System Concepts, Ch. 24 §“Object-Relational
Databases”, and Atkinson et al., “The Object-Oriented Database
System Manifesto”) models a class as a labelled graph: the class
node carries header metadata, and edges run out to attribute
nodes, method nodes, signature nodes, partition nodes, constraint
nodes, and (transitively) to super- and sub-classes. CUBRID’s
SM_CLASSis exactly this graph, allocated on the client-side workspace heap rather than the server heap. - Schema versioning by representation. When ALTER TABLE adds a
column, existing rows must remain readable. The textbook answer
is to keep a list of historical representations keyed by
REPR_ID, and have each row carry itsREPR_IDin its header. CUBRID’sSM_REPRESENTATIONchain is the in-memory mirror of the on-diskDISK_REPRchain incubrid-catalog-manager.md— the class object holds the latest representation eagerly and prior ones lazily for instance conversion.
The remainder of this document tracks how CUBRID realizes this
in-memory class graph, how it gets populated from disk via
catcls_*, how obj_get/obj_set walk it for instance attribute
access, and how DDL mutates it through the SM_TEMPLATE shadow
structure.
Common DBMS Design
Section titled “Common DBMS Design”Every relational engine that respects performance reaches for the same set of patterns around in-memory schema.
A relcache keyed by class identity
Section titled “A relcache keyed by class identity”The engine wants class_oid → SM_CLASS * lookups in O(1) and the
result memoized for the lifetime of the process (or until DDL
invalidates). Postgres calls it the relcache (Relation struct
in src/include/utils/rel.h); the cache is per-backend, populated
on first access and invalidated through shared-memory invalidation
messages (RelationCacheInvalidateEntry). MySQL (the InnoDB layer)
calls it the dictionary cache (dict_table_t from
storage/innobase/dict/dict0dict.cc). CUBRID’s equivalent is the
workspace (work_space.h): the class object is a real
MOP (Most Persistent Object Pointer / “managed object pointer”)
managed by the same machinery that manages user instances, so its
lifecycle and invalidation reuse instance-level workspace logic
rather than a bespoke schema cache.
Tuple descriptor as a flat record-decoding table
Section titled “Tuple descriptor as a flat record-decoding table”To decode a heap row, the engine needs a flat array of
(offset, length, type, nullable) per column. Postgres calls it a
TupleDesc; SQL Server calls it the row schema. The engine does
not want to walk a linked list of attribute structs every time it
decodes a row, because hot loops decode billions of rows. CUBRID
keeps the decode-friendly form on the on-disk side (DISK_REPR from
system_catalog.h, with fixed[] and variable[] packed arrays
ready to drive a row-decoding loop) and the manipulation-friendly
form (linked list of SM_ATTRIBUTE) in the in-memory class object,
synchronized through catcls_*.
Pre-1995 OODB heritage echoes
Section titled “Pre-1995 OODB heritage echoes”ODMG (the Object Database Management Group) standardized the OODB
data model in the early 1990s. UniSQL (CUBRID’s predecessor),
Itasca, ObjectStore, GemStone, and O2 all implemented variants of
it. The runtime structures looked alike across all of them: a
class node with separate lists for instance attributes, shared
attributes (single value across all instances of the class),
class attributes (per-class values reachable through the metaclass),
and methods (callable behavior). When SQL became the dominant
query language, these engines did not delete the OODB scaffolding —
they layered SQL on top. CUBRID is the surviving open-source
representative of that lineage. SM_CLASS reflects this: it has all
four lists even though SM_VCLASS_CT (virtual class) and modern
relational tables only use two of them.
Class hierarchy as a doubly-linked DAG
Section titled “Class hierarchy as a doubly-linked DAG”Single-inheritance OODBs need both directions of the hierarchy
walked: super-classes for attribute resolution (which class owns
which attribute), sub-classes for invalidation when a super-class
changes. The convention is two OBJLISTs on the class node: one for
super-classes (inheritance) and one for direct sub-classes
(users). Multiple inheritance, when supported, complicates name
resolution; CUBRID’s SM_RESOLUTION records hold the disambiguation
rules. Modern CUBRID tables don’t use multiple inheritance, but the
machinery remains.
Templates as DDL shadow objects
Section titled “Templates as DDL shadow objects”DDL mutates schema. The engine needs to assemble the new class
state, validate it (constraints don’t conflict, types are
compatible, partitions are well-formed), and then atomically swap it
in. Engines do this with a template or builder: a parallel
struct that mirrors SM_CLASS but is mutable. Postgres uses
AlteredTableInfo; CUBRID uses SM_TEMPLATE. The original class
object is held read-only until the template commits via
classobj_install_template.
Catalog ↔ memory bridge
Section titled “Catalog ↔ memory bridge”The catalog rows on disk and the class object in memory have
different shapes: the disk side packs for compactness and
versioning (DISK_REPR.fixed[] and variable[] arrays plus
inline BTREE_STATS), the memory side is a graph optimized for
manipulation. Translating between the two is its own subsystem.
Postgres has RelationBuildDesc plus pg_class, pg_attribute,
pg_index reads. CUBRID has the catcls_* family in
catalog_class.c, working through 4-5 K of source to walk the
on-disk _db_* records and assemble an OR_VALUE tree that the
client side then turns into SM_CLASS.
Theory ↔ CUBRID mapping
Section titled “Theory ↔ CUBRID mapping”| Theoretical concept | CUBRID name |
|---|---|
| Class header / metaclass tag | SM_CLASS_HEADER { ch_obj_header, ch_type, ch_name, ch_rep_dir, ch_heap } |
| Class node | SM_CLASS (class_object.h) |
| Instance attribute | SM_ATTRIBUTE (linked through SM_COMPONENT::next) |
| Shared attribute (single value per class) | class_->shared list |
| Class attribute (metaclass slot) | class_->class_attributes list |
| Method definition | SM_METHOD |
| Method signature | SM_METHOD_SIGNATURE |
| Method argument | SM_METHOD_ARGUMENT |
| Method file (C source/object loaded at link) | SM_METHOD_FILE |
| Inheritance (super classes) | class_->inheritance (DB_OBJLIST) |
| Sub-classes | class_->users (DB_OBJLIST) |
| Multiple-inheritance disambiguation | SM_RESOLUTION |
| Constraint cache | SM_CLASS_CONSTRAINT |
| Foreign-key info | SM_FOREIGN_KEY_INFO |
| Partial-index predicate | SM_PREDICATE_INFO |
| Function index info | SM_FUNCTION_INFO |
| Partitioning | SM_PARTITION |
| Trigger cache | tr_schema_cache *triggers |
| View / virtual class definition | SM_QUERY_SPEC list |
| Old-row decoding scaffolding | SM_REPRESENTATION + SM_REPR_ATTRIBUTE |
| DDL builder | SM_TEMPLATE |
| Read-only browsing copy | SM_CLASS_INFO |
| Repeated-access shortcut | SM_DESCRIPTOR + SM_DESCRIPTOR_LIST |
| Disk ↔ memory bridge family | catcls_* (catalog_class.c) |
| Top-level disk OR_VALUE builder | catcls_get_or_value_from_class |
| Instance attribute getter | obj_get (object_accessor.c) |
| Instance attribute setter | obj_set |
| Generic instance create | obj_create |
| Generic instance delete | obj_delete |
| Class pretty-printer | class_description::init (class_description.cpp) |
CUBRID’s Approach
Section titled “CUBRID’s Approach”The class object subsystem has six moving parts: the SM_CLASS
graph, the attribute / method component lists, the constraint
and partition annotations, the SM_TEMPLATE builder, the
catcls_* disk bridge, and the obj_get/obj_set instance
accessors. We walk them in that order. Throughout, keep in mind
that this code is client-side only — class_object.h opens with
#if defined (SERVER_MODE) #error Does not belong to server module.
The class object lives in workspace memory on the client; the server
sees only OIDs, heap rows, and disk representations.
Overall structure
Section titled “Overall structure”flowchart LR
subgraph DISK["Disk (system_catalog + _db_class)"]
DRP["DISK_REPR rows"]
CLI["CLS_INFO rows"]
DBC["_db_class row"]
DBA["_db_attribute rows"]
DBI["_db_index rows"]
DBM["_db_method rows"]
DBP["_db_partition rows"]
end
subgraph BRIDGE["Catalog bridge — catcls_∗"]
GOV["catcls_get_or_value_from_class"]
GOVA["catcls_get_or_value_from_attribute"]
GOVM["catcls_get_or_value_from_method"]
PUT["catcls_put_or_value_into_record"]
INS["catcls_insert_catalog_classes"]
end
subgraph WS["Workspace memory (client-side)"]
SMC["SM_CLASS"]
ATT["SM_ATTRIBUTE list"]
MET["SM_METHOD list"]
CON["SM_CLASS_CONSTRAINT list"]
PART["SM_PARTITION"]
REPR["SM_REPRESENTATION chain"]
TMP["SM_TEMPLATE (DDL only)"]
end
subgraph CALLER["Callers"]
OG["obj_get / obj_set"]
DESC["class_description (CSQL print)"]
AUTH["au_fetch_class"]
EXEC["executor / scan_manager"]
end
DRP --> GOV
CLI --> GOV
DBC --> GOV
DBA --> GOVA
DBM --> GOVM
DBI --> GOV
DBP --> GOV
GOV --> SMC
GOVA --> ATT
GOVM --> MET
SMC --> ATT
SMC --> MET
SMC --> CON
SMC --> PART
SMC --> REPR
SMC -. swap on commit .- TMP
TMP --> PUT --> INS --> DBC
AUTH --> SMC
OG --> SMC
DESC --> SMC
EXEC --> SMC
The figure encodes three boundaries. (disk / memory) the
catalog rows on disk are read by the catcls_* family in
catalog_class.c — server-side code that builds an OR_VALUE tree,
then ships it across to the client where the class object is
materialized. (read / write) read paths terminate at the
existing SM_CLASS; write paths construct an SM_TEMPLATE,
validate it, and only then mutate the on-disk and in-memory
representations. (class / instance) the class object describes
shape; obj_get/obj_set apply that shape to instance memory
fetched separately.
SM_CLASS — the top-level node
Section titled “SM_CLASS — the top-level node”SM_CLASS is the hub. Its layout (condensed):
// SM_CLASS — src/object/class_object.hstruct sm_class{ SM_CLASS_HEADER header; /* metaclass tag, name, ch_rep_dir, ch_heap */
DB_OBJLIST *users; /* immediate sub classes */ SM_CLASS_TYPE class_type; /* SM_CLASS_CT | SM_VCLASS_CT | SM_ADT_CT */ int repid; /* current representation id */ SM_REPRESENTATION *representations; /* old representations for instance conversion */
DB_OBJLIST *inheritance; /* immediate super classes */ int object_size; /* memory size of an instance in bytes */ int att_count; /* number of instance attributes */ SM_ATTRIBUTE *attributes; /* instance attribute definitions */ SM_ATTRIBUTE *shared; /* shared attribute definitions */ int shared_count; int class_attribute_count; SM_ATTRIBUTE *class_attributes; /* metaclass attribute definitions */
SM_METHOD_FILE *method_files; const char *loader_commands; SM_METHOD *methods; /* instance methods */ int method_count; int class_method_count; SM_METHOD *class_methods; SM_RESOLUTION *resolutions; /* multi-inheritance disambiguation */
int fixed_count; /* number of fixed-length attributes */ int variable_count; /* number of variable-length attributes */ int fixed_size; /* byte size of fixed area */
int att_ids; /* attribute id counter */ int method_ids; /* method id counter */
SM_QUERY_SPEC *query_spec; /* virtual-class query specification */ SM_TEMPLATE *new_; /* edit-in-progress template */ CLASS_STATS *stats; /* lazy-loaded statistics */
MOP owner; /* authorization object */ int collation_id; void *auth_cache;
SM_ATTRIBUTE *ordered_attributes; /* see classobj_fixup_loaded_class () */ DB_SEQ *properties; /* property list, holds constraint metadata */ struct parser_context *virtual_query_cache; struct tr_schema_cache *triggers; /* trigger cache */ SM_CLASS_CONSTRAINT *constraints; /* constraint cache */ const char *comment; SM_CLASS_CONSTRAINT *fk_ref; /* foreign-key references *to* this class */ SM_PARTITION *partition; /* partition info */
unsigned int flags; unsigned int virtual_cache_local_schema_id; unsigned int virtual_cache_global_schema_id; unsigned int virtual_cache_snapshot_version;
int tde_algorithm;
unsigned methods_loaded:1; unsigned post_load_cleanup:1; unsigned triggers_validated:1; unsigned has_active_triggers:1; unsigned dont_decache_constraints_or_flush:1; unsigned recache_constraints:1; unsigned load_index_from_heap:1;};The structure is bigger than it has to be for a relational table — that’s the OODB heritage. Field-by-field commentary on the non-obvious parts:
-
header— embedsSM_CLASS_HEADER, which begins withWS_OBJECT_HEADER(cache hash number) plus the metaclass tagSM_METATYPE(SM_META_ROOTfor the root class,SM_META_CLASSotherwise). Thech_rep_dirfield is the OID of the directory record on disk that lists allDISK_REPRrecords for this class (cubrid-catalog-manager.md §“Per-class info”);ch_heapis the HFID of the class’s instance heap. Class-level metadata thus carries enough to reach both catalog and heap. -
users/inheritance— the bidirectional class-hierarchy edges.userslists direct subclasses only (multi-level descent walks transitively);inheritancelists direct superclasses. These areDB_OBJLIST(linked list of MOPs), notSM_CLASS *, so the dependents are loaded lazily throughau_fetch_classwhen needed. -
class_type— three values:SM_CLASS_CT(regular class / table),SM_VCLASS_CT(virtual class / view),SM_ADT_CT(abstract data type / pseudo-class). The pretty-printer inclass_description.cppuses this to label output (MSGCAT_HELP_*message ids). -
repid+representations— the latest representation id and the chain of historicalSM_REPRESENTATIONs. Each historical representation holds onlySM_REPR_ATTRIBUTEentries (attid, type, domain) — enough to decode old-format rows and convert them to the latest layout. -
attributes/shared/class_attributes— the three attribute lists, each linked throughSM_COMPONENT::next. The invariant: every attribute’sidis unique across all three lists for the class, soobj_locate_attributecan search any list it likes:// obj_locate_attribute — src/object/object_accessor.c (condensed)intobj_locate_attribute (MOP op, int attid, int for_write,char **memp, SM_ATTRIBUTE **attp){// ... fetch the class via au_fetch_class ...if (is_class){for (att = class_->class_attributes; att != NULL && found == NULL;att = (SM_ATTRIBUTE *) att->header.next)if (att->id == attid)found = att;}else{// search instance and shared attributes}// ...} -
fixed_count/variable_count/fixed_size— derived counts that mirror the on-diskDISK_REPRsplit. Hot read paths use these to skip header parsing when only the count is needed. -
att_ids/method_ids— per-class monotonic counters used when assigning ids to newly-added components. Old representations retain their dead ids for backwards row decoding. -
new_— non-NULL only during DDL: points at theSM_TEMPLATEcurrently being edited. This is howclassobj_install_templatefinds its target and how concurrent DDL is detected. -
stats— lazy-loadedCLASS_STATS(cubrid-catalog-manager.md §“Statistics — separate cadence”). The optimizer asks for stats on demand and caches them here;ci_time_stampinvalidates. -
ordered_attributes— a parallel pointer chain that walks all instance attributes (own + inherited) in definition order, hooked through the dedicatedorder_linkfield ofSM_ATTRIBUTE. The baseattributeslist reflects storage order, not definition order; pretty-printers and DESC output need definition order.classobj_fixup_loaded_classbuilds this list after the class is loaded. -
properties— aDB_SEQholding constraint metadata in a serialized form (*U,*P,*F,*Ikeys for unique/primary/foreign/index families). The cachedSM_CLASS_CONSTRAINT *constraintslist is decoded frompropertiesbyclassobj_cache_constraintson first use; that’s the entire reason for therecache_constraints:1bit-flag. -
virtual_cache_*fields — optimization for views: when the virtual class’s underlying tables haven’t changed schema, re-compiling the view’s query is unnecessary. The triple oflocal_schema_id,global_schema_id,snapshot_versionis the cache-validity token compared against current schema state. -
tde_algorithm— Transparent Data Encryption mode for the class’s heap. Stored alongside class metadata so heap row reads can decrypt without an extra catalog fetch. -
bit-flag tail —
methods_loadedrecords whetherdlopen-style method loading has completed for this class (SM_METHOD_FILEfiles actually linked).triggers_validated,has_active_triggers,recache_constraintsare similar validity tokens.dont_decache_constraints_or_flushis set during specific re-entrant operations to prevent invalidation loops.load_index_from_heapis consulted when an index is allocated: normally true (rebuild from existing heap rows), but TRUNCATE clears it so a fresh empty index is allocated without a full heap scan.
SM_CLASS — visualized
Section titled “SM_CLASS — visualized”classDiagram
class SM_CLASS {
+SM_CLASS_HEADER header
+DB_OBJLIST* users
+DB_OBJLIST* inheritance
+SM_CLASS_TYPE class_type
+int repid
+SM_REPRESENTATION* representations
+SM_ATTRIBUTE* attributes
+SM_ATTRIBUTE* shared
+SM_ATTRIBUTE* class_attributes
+SM_ATTRIBUTE* ordered_attributes
+SM_METHOD* methods
+SM_METHOD* class_methods
+SM_METHOD_FILE* method_files
+SM_RESOLUTION* resolutions
+SM_QUERY_SPEC* query_spec
+SM_PARTITION* partition
+SM_CLASS_CONSTRAINT* constraints
+SM_CLASS_CONSTRAINT* fk_ref
+tr_schema_cache* triggers
+DB_SEQ* properties
+SM_TEMPLATE* new_
+CLASS_STATS* stats
+MOP owner
}
class SM_CLASS_HEADER {
+WS_OBJECT_HEADER ch_obj_header
+SM_METATYPE ch_type
+const char* ch_name
+OID ch_rep_dir
+HFID ch_heap
}
class SM_ATTRIBUTE {
+SM_COMPONENT header
+pr_type* type
+TP_DOMAIN* domain
+MOP class_mop
+int id
+int offset
+SM_DEFAULT_VALUE default_value
+SM_CONSTRAINT* constraints
+DB_SEQ* properties
+unsigned flags
+int order
+SM_ATTRIBUTE* order_link
+tr_schema_cache* triggers
+MOP auto_increment
+int storage_order
+const char* comment
}
class SM_METHOD {
+SM_COMPONENT header
+SM_METHOD_SIGNATURE* signatures
+METHOD_FUNCTION function
+MOP class_mop
+int id
}
class SM_CLASS_CONSTRAINT {
+const char* name
+SM_ATTRIBUTE** attributes
+int* asc_desc
+SM_PREDICATE_INFO* filter_predicate
+SM_FOREIGN_KEY_INFO* fk_info
+BTID index_btid
+SM_CONSTRAINT_TYPE type
+SM_FUNCTION_INFO* func_index_info
+SM_INDEX_STATUS index_status
}
class SM_PARTITION {
+const char* pname
+int partition_type
+DB_CLASS_PARTITION_TYPE class_partition_type
+DB_SEQ* values
+const char* expr
}
class SM_REPRESENTATION {
+SM_REPR_ATTRIBUTE* attributes
+int id
+int fixed_count
+int variable_count
}
SM_CLASS *-- SM_CLASS_HEADER
SM_CLASS *-- "many" SM_ATTRIBUTE : attributes / shared / class_attributes
SM_CLASS *-- "many" SM_METHOD : methods / class_methods
SM_CLASS *-- "many" SM_CLASS_CONSTRAINT : constraints
SM_CLASS *-- SM_PARTITION : partition
SM_CLASS *-- "many" SM_REPRESENTATION : representations
SM_ATTRIBUTE — the column / instance-variable record
Section titled “SM_ATTRIBUTE — the column / instance-variable record”// SM_ATTRIBUTE — src/object/class_object.hstruct sm_attribute{ SM_COMPONENT header; /* next, name, name_space */
const struct pr_type *type; /* basic type */ TP_DOMAIN *domain; /* allowable types (precision/scale/setdomain) */
MOP class_mop; /* origin class — for inherited attrs */
int id; /* unique id across all lists in this class */ int offset; /* memory offset inside an instance */
SM_DEFAULT_VALUE default_value; /* original_value + value + default_expr */ DB_DEFAULT_EXPR_TYPE on_update_default_expr;
SM_CONSTRAINT *constraints; /* cached constraint list */ DB_SEQ *properties; /* property list */
unsigned int flags; /* SM_ATTFLAG_* (UNIQUE, PRIMARY_KEY, NON_NULL, ...) */ int order; /* definition order */ struct sm_attribute *order_link; /* list in definition order */
struct tr_schema_cache *triggers; /* per-attribute trigger cache */
MOP auto_increment; /* instance of _db_serial */ int storage_order; /* on-disk storage order */ const char *comment;};The interesting fields:
typevsdomain—typeis the primitivepr_type(int, varchar, …);domainis the parameterized domain (varchar(20) collate utf8_bin, set of int, …). The two are always consistent —domain->type == attribute->type— but kept separate so the type-handling code (object_primitive.c) can switch ontypecheaply without dereferencing the domain.class_mop— the class that originally defined this attribute. For inherited attributes,attribute->class_mop != containing_class->op; the pretty-printer (class_description::init) uses this to skip inherited columns whenprt_type == SHOW_CREATE_TABLE.id— globally unique within the class, and persistently bound: once allocated, the attribute id never changes for the lifetime of the schema (even across DROP/ADD with the same name, the id is freshly allocated). OldSM_REPRESENTATIONentries carry these ids so old rows decode correctly.offset— byte offset inside an instance’s memory image. Computed by the layout pass (classobj_fixup_loaded_class) when the class is loaded.default_value— see the long comment in the header. Two values:original_value(initial default, used when reading rows from older representations that lacked the column) andvalue(current default for newly-inserted rows).flags— bitmask ofSM_CLASSFLAG_*-style attribute flags. Macros likeSM_IS_ATTFLAG_UNIQUE_FAMILYandSM_MAP_INDEX_ATTFLAG_TO_CONSTRAINT(top ofclass_object.h) test and convert these.auto_increment— forAUTO_INCREMENTcolumns, points at the_db_serialinstance carrying the sequence state. The MOP is dereferenced lazily on insert.
SM_METHOD — the OODB heritage made explicit
Section titled “SM_METHOD — the OODB heritage made explicit”// SM_METHOD — src/object/class_object.hstruct sm_method{ SM_COMPONENT header; SM_METHOD_SIGNATURE *signatures; /* signature list (currently only one) */ METHOD_FUNCTION function; /* cached C function pointer */ MOP class_mop; /* defining class */ int id; int order; DB_SEQ *properties; unsigned unused:1;};Methods are CUBRID’s most visible OODB tribute. A method is a C
function compiled into a shared object, listed in
SM_METHOD_FILE entries on the class, and dlopen’d at first
invocation (methods_loaded:1 records the load). The signature
chain SM_METHOD_SIGNATURE → SM_METHOD_ARGUMENT carries return-type
and per-argument types. class_object.h defines METHOD_FUNC_ARG4
through METHOD_FUNC_ARG33 (28 distinct typedefs) for methods
taking 4 to 33 arguments, all returning void and taking
DB_VALUE * arguments. The header comments suggest “currently only
one signature” — overloading was an aspirational future direction
that never landed.
In modern CUBRID, methods are rarely used by application
developers, but the engine still validates them through SQL grammar
and continues to load the supporting structures. This is why
SM_METHOD-related code makes up a non-trivial fraction of
class_object.c.
SM_CLASS_CONSTRAINT — PK, FK, UNIQUE, INDEX cache
Section titled “SM_CLASS_CONSTRAINT — PK, FK, UNIQUE, INDEX cache”// SM_CLASS_CONSTRAINT — src/object/class_object.hstruct sm_class_constraint{ struct sm_class_constraint *next; const char *name; SM_ATTRIBUTE **attributes; /* NULL-terminated array of attrs in key order */ int *asc_desc; /* one per attribute */ int *attrs_prefix_length; /* prefix-key info */ SM_PREDICATE_INFO *filter_predicate; /* CREATE INDEX ... WHERE */ SM_FOREIGN_KEY_INFO *fk_info; /* FK referent + actions */ char *shared_cons_name; /* name of shared constraint, if any */ BTID index_btid; SM_CONSTRAINT_TYPE type; /* UNIQUE / PRIMARY_KEY / FOREIGN_KEY / INDEX / ... */ SM_FUNCTION_INFO *func_index_info; /* function index */ const char *comment; SM_CONSTRAINT_EXTRA_FLAG extra_status; SM_INDEX_STATUS index_status; /* NORMAL / INVISIBLE / BUILDING-IN-PROGRESS */ SM_INDEX_TYPE index_type; /* always SM_BTREE_TYPE today */ int options; /* deduplicate level + reserved */};Constraints are stored on disk in a serialized DB_SEQ form on
SM_CLASS::properties keyed by *U, *P, *F, *I etc.
classobj_cache_constraints decodes this DB_SEQ into the linked
list of SM_CLASS_CONSTRAINT exactly once per class load, then
sets the cache. classobj_make_class_constraints is the workhorse
constructor; it walks every property name family and produces the
constraint list (class_object.c:3164).
SM_FOREIGN_KEY_INFO carries delete_action and update_action
(CASCADE / SET NULL / RESTRICT / NO ACTION) plus a ref_match_option.
SM_PREDICATE_INFO carries the partial-index WHERE predicate as
both pred_string (textual) and pred_stream (compiled XASL).
SM_FUNCTION_INFO is the analogous structure for function indexes
(CREATE INDEX … ON t (lower(col))).
The SM_INDEX_STATUS enum is worth noting:
SM_NORMAL_INDEX = 1, SM_INVISIBLE_INDEX = 2,
SM_ONLINE_INDEX_BUILDING_IN_PROGRESS = 3, plus six reserved
slots through SM_LAST_INDEX_STATUS = 10. Online index build is a
recent-ish feature; the reservations were added all-at-once to
avoid future on-disk reformatting when more states are needed.
SM_PARTITION — partition metadata
Section titled “SM_PARTITION — partition metadata”// SM_PARTITION — src/object/class_object.hstruct sm_partition{ struct sm_partition *next; /* currently always NULL */ const char *pname; /* partition name; NULL on parent */ int partition_type; /* PT_PARTITION_RANGE / LIST / HASH */ DB_CLASS_PARTITION_TYPE class_partition_type; /* parent vs child */ DB_SEQ *values; /* range bounds or list members */ const char *expr; /* partition expression text */ const char *comment;};The partitioned-class story has two flavours: the parent (which
holds the partition info with pname == NULL and class_partition_type == DB_PARTITIONED_CLASS) and the child partitions, each its own
SM_CLASS with its own SM_PARTITION carrying pname and
class_partition_type == DB_PARTITION_CLASS. The relationship is
encoded through class_->users (parent → children) and inheritance
(child → parent). The pretty-printer’s
describe_partition_info / describe_partition_parts (in
object_printer.cpp) walks both faces.
SM_TEMPLATE — the DDL builder
Section titled “SM_TEMPLATE — the DDL builder”// SM_TEMPLATE — src/object/class_object.hstruct sm_template{ MOP op; /* class MOP, NULL for new class */ SM_CLASS *current; /* read-only handle to current state */ SM_CLASS_TYPE class_type; int tran_index; /* DDL must run in one transaction */
const char *name; DB_OBJLIST *inheritance; SM_ATTRIBUTE *attributes; SM_METHOD *methods; SM_RESOLUTION *resolutions; SM_ATTRIBUTE *class_attributes; SM_METHOD *class_methods; SM_RESOLUTION *class_resolutions; SM_METHOD_FILE *method_files; const char *loader_commands; SM_QUERY_SPEC *query_spec; SM_ATTRIBUTE *instance_attributes; SM_ATTRIBUTE *shared_attributes; DB_OBJLIST *ext_references; DB_SEQ *properties; int *super_id_map; void *triggers; DB_ATTRIBUTE *partition_parent_atts; SM_PARTITION *partition;};A template is built (classobj_make_template /
classobj_make_template_like), mutated by the DDL parser, then
flattened (inheritance fully resolved, super-class attributes
copied in, conflicts disambiguated by resolutions). The flattened
template becomes the new SM_CLASS content via
classobj_install_template:
// classobj_install_template — src/object/class_object.c (excerpt)intclassobj_install_template (SM_CLASS *class_, SM_TEMPLATE *flat, int saverep){ // ... save current representation if schema actually changed ... // ... copy template fields back into class_ ... // ... bump class_->repid if attributes changed ... // ... rebuild class_->ordered_attributes ... // ... mark class_->recache_constraints if constraints touched ...}The saverep flag controls whether the previous representation
is appended to class_->representations — done when attribute
storage layout changed, skipped when only metadata (comments,
collation, owner) changed.
Catalog ↔ memory bridge — the catcls_* family
Section titled “Catalog ↔ memory bridge — the catcls_* family”The bridge runs in the server, unlike everything else in
src/object/. catalog_class.c is conceptually paired with
class_object.c but is server-side because the disk records live in
the server’s heap files. The bridge has two directions.
Disk → memory (read direction). Triggered when the client
fetches a class through au_fetch_class:
// catcls_get_or_value_from_class — src/storage/catalog_class.c (sketch)catcls_get_or_value_from_class (THREAD_ENTRY *thread_p, OR_BUF *buf_p, OR_VALUE *value_p){ // For each field of the _db_class row, decode it from buf_p, // and place it into value_p->sub.value[i] as an OR_VALUE. // Recurse into sub-records for attributes, methods, indexes, // partitions through helpers like // catcls_get_or_value_from_attribute, catcls_get_or_value_from_method, // catcls_get_or_value_from_method_signiture, // catcls_get_or_value_from_indexes, catcls_get_or_value_from_partition.}The output OR_VALUE tree is essentially the same shape as
SM_CLASS would be, but in a generic
“sequence-of-attribute-name-and-DB_VALUE” form. The result is
shipped to the client (server-mode) or used in-process (SA-mode,
where parser and server share an address space). On the client
side, schema-manager code (in schema_manager.c, not covered in
detail here) walks the OR_VALUE tree and constructs the
SM_CLASS.
Memory → disk (write direction). DDL goes the other way:
catcls_insert_catalog_classes— for a newly-created class, write the new_db_classrow plus subordinate rows in_db_attribute,_db_index,_db_method,_db_partition.catcls_update_catalog_classes— for ALTER, replace the existing rows.catcls_delete_catalog_classes— for DROP.
These run server-side under the same system-op bracket as the
internal catalog updates (cubrid-catalog-manager.md §“One ALTER, end
to end”). The serialization helpers catcls_put_or_value_into_buffer
and catcls_put_or_value_into_record translate OR_VALUE trees
back into raw RECDES bytes.
Two server-resident caches matter:
catcls_class_oid_to_oid_hash_table— maps_db_classclass oid (the OID that points at_db_classitself) to the instance oid of the row in_db_classthat describes a given user class. Without it, every catalog class lookup would scan_db_class. Initialized bycatcls_initialize_class_oid_to_oid_hash_table; finalized bycatcls_finalize_class_oid_to_oid_hash_table.catcls_Btid— cached BTID of the index on_db_class.class_name, found viacatcls_find_btid_of_class_nameonce and reused.
Catalog ↔ memory flow
Section titled “Catalog ↔ memory flow”sequenceDiagram
participant CL as Client (parser, executor)
participant WS as Workspace cache
participant AU as au_fetch_class
participant SVR as Server (catalog)
participant CC as catcls_*
CL->>WS: lookup MOP for class C
alt cached
WS-->>CL: SM_CLASS *
else miss
WS->>AU: fetch C with intent (R/W)
AU->>SVR: locator request (with S/X lock)
SVR->>CC: catcls_get_or_value_from_class
CC->>CC: walk _db_attribute, _db_index, _db_method,<br/>_db_partition rows
CC-->>SVR: OR_VALUE tree
SVR-->>AU: serialized OR_VALUE
AU->>WS: build SM_CLASS, run classobj_fixup_loaded_class
WS-->>CL: SM_CLASS *
end
Object accessor — obj_get / obj_set on instances
Section titled “Object accessor — obj_get / obj_set on instances”The class object describes instance shape; object_accessor.c
applies that shape to actual instance memory. Two entry points:
// obj_get — src/object/object_accessor.c (excerpt)intobj_get (MOP op, const char *name, DB_VALUE *value){ int error; SM_ATTRIBUTE *att; SM_CLASS *class_;
error = find_attribute (&class_, &att, op, name, 0); if (error == NO_ERROR) error = obj_get_att (op, class_, att, value); return error;}find_attribute does an au_fetch_class plus a name lookup
through the three attribute lists (attributes, shared,
class_attributes). obj_get_att then walks to the instance memory
through au_fetch_instance and copies the value out using the
attribute’s offset and type. The setter mirror is:
// obj_set — src/object/object_accessor.c (excerpt)intobj_set (MOP op, const char *name, DB_VALUE *value){ int error; SM_ATTRIBUTE *att; SM_CLASS *class_; // ... error = find_attribute (&class_, &att, op, name, 1); // 1 = for_write if (error == NO_ERROR) error = obj_set_att (op, class_, att, value, NULL); return error;}obj_set_att (large function, ~200 lines) handles four sub-cases
keyed on the attribute’s name_space:
- instance attribute — find the byte offset, run validation
through
tp_value_cast, write into instance memory, mark dirty. - shared attribute — write into the class object’s
per-attribute
default_value.value(shared attrs have a single store on the class, not per-instance). - class attribute — same as shared but reached via the metaclass.
- set / multiset / sequence — recurse into collection update;
may take a path through
obj_setagain on a referenced object.
The “descriptor” variant (obj_desc_get / obj_desc_set) is the
fast path: a pre-computed SM_DESCRIPTOR that caches the
(class_mop, attribute) pair so repeated access on the same
attribute over many instances avoids name lookups. The descriptor
keeps a SM_DESCRIPTOR_LIST of subclass-specific overrides for
when an instance happens to be of a derived class.
obj_create / obj_delete are the lifecycle pair:
// obj_create — src/object/object_accessor.c (excerpt)MOPobj_create (MOP classop){ MOP new_mop; OBJ_TEMPLATE *obj_template;
obj_template = obt_def_object (classop); // build a fresh template // ... apply default values for each attribute ... obt_update (obj_template, &new_mop); // commit, get back the new MOP return new_mop;}CUBRID’s instance creation goes through an object template
(OBJ_TEMPLATE from object_template.h) — like SM_TEMPLATE but
for instances rather than classes. The template gathers all the
attribute writes, runs constraint validation in a single pass, and
emits one heap insert at the end.
One ALTER end-to-end
Section titled “One ALTER end-to-end”sequenceDiagram participant P as Parser participant SM as schema_manager participant TMPL as SM_TEMPLATE participant CO as classobj_* participant AU as au_fetch_class participant SVR as Server participant CC as catcls_* P->>SM: ALTER TABLE t ADD COLUMN c SM->>AU: au_fetch_class (t, FETCH_WRITE) AU-->>SM: SM_CLASS *t_class SM->>CO: classobj_make_template (t_class) CO-->>SM: SM_TEMPLATE *tmpl SM->>TMPL: append SM_ATTRIBUTE for c SM->>SM: flatten template (inheritance + resolutions) SM->>SM: validate (no name clash, types compatible) SM->>CO: classobj_install_template (t_class, flat, saverep=1) CO->>CO: append previous SM_REPRESENTATION,<br/>bump repid, rebuild ordered_attributes SM->>SVR: send updated _db_class row SVR->>CC: catcls_update_catalog_classes (t, new record) CC->>SVR: write _db_class, _db_attribute, _db_index<br/>under one system-op SVR-->>SM: ack SM->>AU: invalidate cached t_class on all clients
Two invariants worth highlighting. First, SM_TEMPLATE is flattened
before installation: super-class attributes are copied into the
template’s instance_attributes list, and resolutions are applied
to disambiguate names. The template thus carries the complete
schema as the class will see it, not just the locally-declared
parts. Second, classobj_install_template saves the prior
representation when storage layout changed; the saved
SM_REPRESENTATION will be needed later if the engine encounters
old-format rows during scans (see
SM_REPR_ATTRIBUTE and the long comment on SM_REPRESENTATION).
Pretty-printer — class_description
Section titled “Pretty-printer — class_description”class_description.cpp is the human-readable face. It produces two
flavours through the type enum:
CSQL_SCHEMA_COMMAND— the output of CSQL’s;sc <name>and;schema <name>commands. Includes inherited attributes, triggers, partitions.SHOW_CREATE_TABLE— SQL-compatibleSHOW CREATE TABLEoutput. Excludes inherited attributes (they belong to the super-class’s CREATE TABLE), bracket-quotes identifiers, formats default expressions as SQL.
The flow is: class_description::init(op, prt_type) → au_fetch_class
→ sm_clean_class → walk the SM_CLASS lists, calling
object_printer::describe_attribute, describe_method,
describe_constraint, describe_partition_info etc. for each
component, accumulating into class_description’s string-array
fields (attributes[], methods[], constraints[], partition[]).
The walk respects ordered_attributes for stable output ordering,
and uses class_mop != op to distinguish own vs inherited
components.
Identifier validation — identifier_store
Section titled “Identifier validation — identifier_store”identifier_store.cpp is a small utility used by DDL paths to
validate sets of identifiers (column names, index names) at once.
The class is constructed from a std::vector<std::string>,
optionally with check_valid which walks each entry and applies
the rule “must begin with letter, ASCII alnum + underscore for the
rest, exception for _db system class prefix”:
// check_identifier_is_valid — src/object/identifier_store.cppboolidentifier_store::check_identifier_is_valid (const std::string_view str, bool is_enclosed){ if (is_enclosed) { if (std::any_of (str.begin (), str.end (), [] (char c) { return c == '.' || c == '[' || c == ']'; })) return false; } else { if (strncasecmp (str.data (), SYSTEM_CLASS_PREFIX.c_str (), SYSTEM_CLASS_PREFIX.length ()) != 0) { int size = str.size (); for (int i = 0; i < size; i++) if ((i == 0 && !char_isalpha (str[0])) || (i >= 1 && (!char_isalnum (str[i]) && str[i] != '_'))) return false; } } return true;}The internal storage is cubbase::string_set_ci_lower — a
case-insensitive set, so is_exists accepts any-case lookups.
The class is immutable and not thread-safe (built once during a
DDL operation, consulted to detect duplicate identifiers, then
dropped).
Source Walkthrough
Section titled “Source Walkthrough”Anchor on symbol names. Line numbers go in the position table.
Top-level types (in class_object.h)
Section titled “Top-level types (in class_object.h)”SM_CLASS— the in-memory class node.SM_CLASS_HEADER— common header for class and root class (carriesWS_OBJECT_HEADER,SM_METATYPE,ch_name,ch_rep_dir,ch_heap).SM_CLASS_TYPEenum —SM_CLASS_CT/SM_VCLASS_CT/SM_ADT_CT.SM_METATYPEenum —SM_META_ROOTvsSM_META_CLASS.SM_CLASS_FLAGenum —SYSTEM,WITHCHECKOPTION,LOCALCHECKOPTION,REUSE_OID,SUPPLEMENTAL_LOG.SM_COMPONENT— generic header (next, name, name_space) for attributes and methods.SM_NAME_SPACEenum — name-space tag identifying instance attribute, shared attribute, class attribute, method, etc.SM_ATTRIBUTE— attribute definition.SM_DEFAULT_VALUE— initial + current default + default expr.SM_CONSTRAINT(per-attribute cached) vsSM_CLASS_CONSTRAINT(class-level, multi-attribute).SM_CONSTRAINT_TYPEenum — UNIQUE, INDEX, NOT_NULL, REVERSE_UNIQUE, REVERSE_INDEX, PRIMARY_KEY, FOREIGN_KEY.SM_FOREIGN_KEY_INFO— referenced class, ref attrs, actions, match option, ref BTID.SM_FOREIGN_KEY_ACTIONenum — CASCADE / SET NULL / RESTRICT / NO ACTION.SM_PREDICATE_INFO— partial-indexWHEREpredicate.SM_FUNCTION_INFO— function-index expression metadata.SM_INDEX_STATUSenum — NORMAL, INVISIBLE, ONLINE_BUILDING_IN_PROGRESS, plus six reserved.SM_METHOD,SM_METHOD_SIGNATURE,SM_METHOD_ARGUMENT,SM_METHOD_FILE— method machinery.METHOD_FUNC_ARG4..ARG33typedefs — variadic-arity method function pointer types (28 of them).SM_RESOLUTION— multi-inheritance disambiguation.SM_REPRESENTATION+SM_REPR_ATTRIBUTE— historical row layouts.SM_QUERY_SPEC— virtual class query specification.SM_PARTITION— partition metadata.SM_TEMPLATE— DDL builder.SM_CLASS_INFO— read-only browsing copy.SM_DESCRIPTOR+SM_DESCRIPTOR_LIST— fast attribute-access cache for repeated access patterns.SM_VALIDATION— type/domain validation cache embedded in descriptor.
Construction / destruction (in class_object.c)
Section titled “Construction / destruction (in class_object.c)”classobj_area_init/classobj_area_final— area allocator setup atdb_open/db_shutdown.classobj_make_class— allocate emptySM_CLASS.classobj_free_class— deep free of all linked lists.classobj_make_template/classobj_make_template_like/classobj_free_template.classobj_make_attribute/classobj_copy_attribute/classobj_free_attribute.classobj_make_method/classobj_copy_method/classobj_free_method.classobj_make_method_signature/classobj_make_method_arg.classobj_make_method_file.classobj_make_resolution/classobj_free_resolution.classobj_make_query_spec/classobj_free_query_spec.classobj_make_repattribute/classobj_make_representation/classobj_free_representation.classobj_make_partition_info/classobj_copy_partition_info/classobj_free_partition_info.
Lookup
Section titled “Lookup”classobj_find_attribute(by name) /classobj_find_attribute_id(by id).classobj_find_method.classobj_find_component/classobj_complist_search.classobj_find_class_constraint(by type+name) /classobj_find_class_constraint_by_btid.classobj_find_class_index/classobj_find_constraint_by_name/classobj_find_constraint_by_attrs.classobj_find_class_primary_key/classobj_find_cons_primary_key.classobj_find_resolution.classobj_find_representation.
Constraint cache
Section titled “Constraint cache”classobj_make_class_constraints— decode property list intoSM_CLASS_CONSTRAINTlist.classobj_cache_constraints/classobj_cache_class_constraints/classobj_decache_class_constraints.classobj_get_cached_constraint— per-attribute cached BTID lookup.classobj_has_class_unique_constraint/classobj_has_unique_constraint/classobj_has_function_constraint.classobj_class_has_indexes.classobj_check_attr_in_unique_constraint.classobj_check_index_exist.classobj_change_constraint_status/classobj_change_constraint_comment.classobj_populate_class_properties.classobj_remove_class_constraint_node.classobj_is_pk_referred.classobj_describe_foreign_key_action.classobj_map_constraint_to_property.classobj_free_foreign_key_ref/classobj_free_function_index_ref.
Property list (DB_SEQ-encoded)
Section titled “Property list (DB_SEQ-encoded)”classobj_make_prop/classobj_copy_props/classobj_free_prop.classobj_put_prop/classobj_drop_prop.classobj_put_index— append index entry.classobj_find_prop_constraint.classobj_btid_from_property_value/classobj_oid_from_property_value.
Template lifecycle
Section titled “Template lifecycle”classobj_install_template— atomic swap on commit.classobj_fixup_loaded_class— post-load layout pass; buildsordered_attributes, computesoffsetper attribute.classobj_filter_components— split a component list by name-space.classobj_annotate_method_files— setclass_mopon inherited method files.classobj_initialize_attributes/classobj_initialize_methods.classobj_copy_attlist/classobj_copy_reslist/classobj_copy_methfiles.classobj_copy_default_expr.classobj_class_size— compute SM_CLASS heap footprint (debugging).
Descriptor (fast access cache)
Section titled “Descriptor (fast access cache)”classobj_make_descriptor/classobj_make_desclist.classobj_free_descriptor/classobj_free_desclist.
Pretty-print (debug only)
Section titled “Pretty-print (debug only)”classobj_print— under#if defined (CUBRID_DEBUG).
Catalog bridge (in catalog_class.c)
Section titled “Catalog bridge (in catalog_class.c)”catcls_Enable— global flag enabling catalog-class maintenance.catcls_initialize_class_oid_to_oid_hash_table/catcls_finalize_class_oid_to_oid_hash_table.catcls_find_oid/catcls_put_entry/catcls_remove_entry/catcls_replace_entry_oid.catcls_get_or_value_from_class— top-level read decoder.catcls_get_or_value_from_attribute/catcls_get_or_value_from_attrid/catcls_get_or_value_from_domain.catcls_get_or_value_from_method/catcls_get_or_value_from_method_signiture/catcls_get_or_value_from_method_argument/catcls_get_or_value_from_method_file.catcls_get_or_value_from_resolution.catcls_get_or_value_from_query_spec.catcls_get_or_value_from_indexes.catcls_get_or_value_from_partition.catcls_get_subset/catcls_get_object_set/catcls_get_property_set.catcls_reorder_attributes_by_repr/catcls_expand_or_value_by_repr/catcls_expand_or_value_by_subset/catcls_expand_or_value_by_def.catcls_get_or_value_from_buffer/catcls_put_or_value_into_buffer/catcls_put_or_value_into_record.catcls_insert_subset/catcls_delete_subset/catcls_update_subset.catcls_insert_instance/catcls_delete_instance/catcls_update_instance.catcls_insert_catalog_classes/catcls_update_catalog_classes/catcls_delete_catalog_classes.catcls_compile_catalog_classes— install-time schema build.catcls_get_server_compat_info/catcls_get_db_collation.catcls_update_class_stats.catcls_find_class_oid_by_class_name/catcls_find_btid_of_class_name/catcls_find_oid_by_class_name.catcls_convert_class_oid_to_oid/catcls_convert_attr_id_to_name.catcls_apply_component_type/catcls_apply_resolutions/catcls_resolution_space.catcls_set_or_value_timestamps/catcls_update_or_value_updated_time/catcls_copy_or_value_times_and_statistics/catcls_update_or_value_class_stats_fields.catcls_cache_fixed_attr_indexes.
Object accessor (in object_accessor.c)
Section titled “Object accessor (in object_accessor.c)”obj_get/obj_set— public attribute access by name.obj_get_att/obj_set_att— bySM_ATTRIBUTE *.obj_desc_get/obj_desc_set— bySM_DESCRIPTOR *(fast).obj_locate_attribute— by id; returns memory pointer.obj_assign_value— generic setter, used by templates.obj_get_value/obj_get_path/obj_get_temp/obj_set_temp— variants for collections, paths, temporary objs.obj_get_shared/obj_set_shared— shared-attribute force.obj_alloc— instance memory allocation given class layout.obj_create/obj_create_by_name/obj_copy/obj_delete/obj_free_memory— instance lifecycle.
Pretty-printer (in class_description.cpp)
Section titled “Pretty-printer (in class_description.cpp)”class_description::class_description()— ctor (zeroes).class_description::~class_description()— dtor (frees all string arrays and vectors).class_description::init(const char *name)— by class name.class_description::init(db_object *, type)— by MOP.class_description::init(db_object *, type, string_buffer &)— shared-buffer variant for embedded use.init_triggers(file-static) — populate trigger list.describe_trigger_list(file-static).
Identifier store (in identifier_store.cpp)
Section titled “Identifier store (in identifier_store.cpp)”cubbase::identifier_store::identifier_store(vector, check_valid)— ctor.identifier_store::~identifier_store()— dtor.identifier_store::is_exists— case-insensitive lookup.identifier_store::is_valid— overall validity (set at construction).identifier_store::get_size.identifier_store::check_identifier_condition(private).identifier_store::check_identifier_is_valid(static) — single identifier rule check.identifier_store::is_enclosed(static) — quotes / brackets / backticks predicate.
Position hints as of 2026-04-30
Section titled “Position hints as of 2026-04-30”| Symbol | File | Line |
|---|---|---|
SM_CONSTRAINT_TYPE (enum) | class_object.h | 281 |
SM_CLASS_TYPE (enum) | class_object.h | 296 |
SM_CLASS_FLAG (enum) | class_object.h | 305 |
SM_METATYPE (enum) | class_object.h | 318 |
SM_CLASS_HEADER (struct) | class_object.h | 351 |
SM_CONSTRAINT (struct) | class_object.h | 370 |
SM_COMPONENT (struct) | class_object.h | 387 |
SM_DEFAULT_VALUE (struct) | class_object.h | 397 |
SM_ATTRIBUTE (struct) | class_object.h | 445 |
SM_FOREIGN_KEY_INFO (struct) | class_object.h | 478 |
SM_PREDICATE_INFO (struct) | class_object.h | 497 |
SM_FUNCTION_INFO (struct) | class_object.h | 508 |
SM_INDEX_STATUS (enum) | class_object.h | 518 |
SM_CLASS_CONSTRAINT (struct) | class_object.h | 553 |
SM_METHOD_ARGUMENT (struct) | class_object.h | 591 |
SM_METHOD_SIGNATURE (struct) | class_object.h | 603 |
SM_METHOD (struct) | class_object.h | 626 |
SM_METHOD_FILE (struct) | class_object.h | 650 |
SM_RESOLUTION (struct) | class_object.h | 663 |
SM_REPR_ATTRIBUTE (struct) | class_object.h | 683 |
SM_REPRESENTATION (struct) | class_object.h | 702 |
SM_QUERY_SPEC (struct) | class_object.h | 718 |
SM_PARTITION (struct) | class_object.h | 728 |
SM_CLASS (struct) | class_object.h | 746 |
SM_TEMPLATE (struct) | class_object.h | 819 |
SM_CLASS_INFO (struct) | class_object.h | 867 |
SM_DESCRIPTOR_LIST (struct) | class_object.h | 903 |
SM_VALIDATION (struct) | class_object.h | 916 |
SM_DESCRIPTOR (struct) | class_object.h | 933 |
classobj_cache_constraints | class_object.c | 2528 |
classobj_make_class_constraint | class_object.c | 2631 |
classobj_free_class_constraints | class_object.c | 2690 |
classobj_make_class_constraints | class_object.c | 3164 |
classobj_make_class | class_object.c | 6832 |
classobj_free_class | class_object.c | 6928 |
classobj_fixup_loaded_class | class_object.c | 7109 |
classobj_install_template | class_object.c | 7349 |
classobj_make_partition_info | class_object.c | 8638 |
obj_locate_attribute | object_accessor.c | 321 |
obj_assign_value | object_accessor.c | 645 |
obj_set_att | object_accessor.c | 721 |
obj_set | object_accessor.c | 931 |
obj_set_shared | object_accessor.c | 1012 |
obj_get_value | object_accessor.c | 1307 |
obj_get_att | object_accessor.c | 1387 |
obj_desc_get | object_accessor.c | 1470 |
obj_get | object_accessor.c | 1508 |
obj_get_shared | object_accessor.c | 1549 |
obj_alloc | object_accessor.c | 1863 |
obj_create | object_accessor.c | 1921 |
obj_copy | object_accessor.c | 1983 |
obj_delete | object_accessor.c | 2090 |
class_description::init (3-arg) | class_description.cpp | 192 |
catcls_finalize_class_oid_to_oid_hash_table | catalog_class.c | 286 |
catcls_find_oid | catalog_class.c | 321 |
catcls_put_entry | catalog_class.c | 353 |
catcls_remove_entry | catalog_class.c | 391 |
catcls_get_or_value_from_class | catalog_class.c | 999 |
catcls_get_or_value_from_attribute | catalog_class.c | 1273 |
catcls_get_or_value_from_attrid | catalog_class.c | 1622 |
catcls_get_or_value_from_domain | catalog_class.c | 1690 |
catcls_get_or_value_from_method | catalog_class.c | 1834 |
identifier_store::check_identifier_is_valid | identifier_store.cpp | 95 |
Cross-check Notes
Section titled “Cross-check Notes”- Disk vs memory representation are deliberately not the same
shape.
cubrid-catalog-manager.mddescribesDISK_REPRas having packedfixed[]andvariable[]arrays for fast row-decoding; the in-memorySM_ATTRIBUTEchain is a linked list throughSM_COMPONENT::nextordered by storage. The two representations exist for different consumers (decoder vs editor) and are synchronized exclusively through thecatcls_*family. Any bug or inconsistency lives at that bridge, never inside one side alone. SM_CLASS::statsis the sameCLASS_STATSdefined instatistics.h(cubrid-catalog-manager.md §“Statistics”). The field isNULLuntil the optimizer asks for stats; first request triggers a server fetch of the per-classDISK_ATTR::bt_stats[]and friends. Cache invalidation is byci_time_stampcomparison identical to what the catalog manager uses.class_->header.ch_heapis the canonical HFID for heap-side scans. This is the same HFID stored onCLS_INFO::ci_hfid— cubrid-heap-manager.md §“Heap file identifier”. The class object holds it inline so heap scans don’t need a catalog round-trip after the class is loaded.class_->header.ch_rep_diris the directory-record OID — the same OIDCLS_INFO::ci_rep_dirstores. From it you can walk the catalog’s representation directory to enumerate allDISK_REPRs for the class.- Constraints are cached on
SM_CLASS::constraintsbut authoritative onSM_CLASS::properties. Theconstraintslist is decoded frompropertieslazily byclassobj_cache_constraints. DDL writes updatepropertiesfirst, then callclassobj_decache_class_constraintsto force a re-decode on next access. - The “method” subsystem is mostly dormant in modern usage.
CUBRID’s stored-procedure feature (cubrid-pl-javasp.md and
cubrid-pl-plcsql.md) is the modern replacement, with Java/PL-CSQL
rather than C methods. The
SM_METHODmachinery still exists because legacy schemas may use it and the parser still accepts the syntax.
Open Questions
Section titled “Open Questions”- When does
classobj_fixup_loaded_classrecomputeobject_size? The field changes when attributes are added or their domains’ size grows. Investigation path: traceclassobj_install_templatefor the size-recompute call site. - What is the exact ordering of operations during ALTER TABLE
when partitions are involved? A partitioned parent + N
children is N+1 classes; whose template installs first?
Investigation path:
do_alter_partitioning_*indo_partition.c. catcls_compile_catalog_classesvsschema_system_catalog_install.cpp. The header comment incubrid-catalog-manager.mdclaims the install-time compiler builds system classes, but the schema definitions live inschema_system_catalog_install.cpp. Which writes which? Likely the install file is the C++ source of truth andcatcls_compile_catalog_classesconsumes it, but the call chain is worth confirming.- How does the workspace cache invalidate
SM_CLASSafter a remote DDL? When another client commits ALTER, this client’s cachedSM_CLASSbecomes stale. Investigation path:ws_decachecalls plus the OID invalidation message stream. - TDE + class_object interaction.
SM_CLASS::tde_algorithmis read by the heap on every page decrypt. Where is the hot accessor and how does it avoid an indirect through the workspace cache on every page fetch? Investigation path: heap page fetch inheap_file.cversus how class TDE state is reached. SM_CLASS::auth_cachelifecycle. Authorization is cached per-class as avoid *— opaque toclass_object.c. What compiles into it, and when is it invalidated? Investigation path:au_*functions inauthenticate*.cpp.- Online index build status transitions.
SM_INDEX_STATUShas six reserved slots beyond the three named values. What were the planned states? Investigation path: ML history /git log -- src/object/class_object.h. - Dedup-level
optionsfield onSM_CLASS_CONSTRAINT. Bits 0–3 hold a deduplicate level (0–14). What does each level mean and where is it consumed? Investigation path:deduplicate_key.{c,h}andIS_DEDUPLICATE_KEY_ATTR_ID.
Sources
Section titled “Sources”Sibling docs
Section titled “Sibling docs”knowledge/code-analysis/cubrid/cubrid-catalog-manager.md— on-disk catalog representation;DISK_REPR,CLS_INFO,CTIDmatch the bridge endpoints in this document.knowledge/code-analysis/cubrid/cubrid-heap-manager.md— class instances live as heap rows;class_->header.ch_heapis the HFID this layer uses.knowledge/code-analysis/cubrid/cubrid-btree.md—SM_CLASS_CONSTRAINT::index_btidand FK BTIDs target B+tree indexes described there.knowledge/code-analysis/cubrid/cubrid-authentication.md—class_->ownerandclass_->auth_cacheare entry points into authorization.knowledge/code-analysis/cubrid/cubrid-pl-javasp.mdandcubrid-pl-plcsql.md— modern stored-procedure replacement for the dormantSM_METHODsubsystem.knowledge/code-analysis/cubrid/cubrid-parser.md— DDL parse trees that driveSM_TEMPLATEconstruction.
Textbook chapters (under knowledge/research/dbms-general/)
Section titled “Textbook chapters (under knowledge/research/dbms-general/)”- Database System Concepts (Silberschatz/Korth/Sudarshan, 7th ed.), Ch. 24 §“Object-Based Databases” — class graph model and catalog cache for object-relational engines.
- Database Internals (Petrov), Ch. 1 §“Database storage” and Ch. 7 §“Storage Engines” — schema cache and storage layout.
- Atkinson, Bancilhon, DeWitt, Dittrich, Maier, Zdonik — The Object-Oriented Database System Manifesto (1989) — the feature set that shaped UniSQL/CUBRID’s class graph.
CUBRID source (/data/hgryoo/references/cubrid/)
Section titled “CUBRID source (/data/hgryoo/references/cubrid/)”src/object/class_object.h— type definitions, 1155 lines.src/object/class_object.c— implementation, 8872 lines.src/object/object_accessor.c—obj_get/obj_setand instance lifecycle, 4495 lines.src/object/class_description.{cpp,hpp}— pretty-printer.src/object/identifier_store.{cpp,hpp}— identifier validation utility.src/object/object_template.h—OBJ_TEMPLATE(instance template), parallel toSM_TEMPLATE(class template).src/storage/catalog_class.{c,h}—catcls_*disk bridge, 5823 lines.src/object/schema_manager.c(not directly read in this pass) — the “DDL driver” that builds and installsSM_TEMPLATEs.src/object/schema_system_catalog_install.cpp(not directly read; cross-referenced from CUBRID AGENTS.md §“Add info schema view”) — install-time hard-coded schemas for_db_*system classes.