PgExtnRegistry API Reference
Overview
PgExtnRegistry is a singleton class that manages PostgreSQL extension metadata and function pointers. It serves as the central registry for all loaded extensions, providing lookup and invocation APIs for extension types, operators, and operator classes.
Location: src/pg_ext/extn_registry.cc, include/pg_ext/extn_registry.hh
Key Responsibilities:
- Load extension shared libraries via
dlopen() - Maintain mappings from OIDs and names to function pointers
- Provide type conversion utilities (binary ↔ Datum ↔ string)
- Support opclass method invocation for GIN/GIST indexes
- Enable extension operator comparisons
Core Data Structures
PgType
Represents a PostgreSQL type with its I/O functions:PgOpsClass
Represents an operator class (e.g.,gin_trgm_ops, gist_point_ops):
PgOpsClassMethod
Represents a support function for an operator class:constants.hh):
GIN:
GIN_COMPARE = 1- Compare functionGIN_EXTRACTVALUE = 2- Extract keys from indexed valueGIN_EXTRACTQUERY = 3- Extract keys from queryGIN_CONSISTENT = 4- Check if entry matches queryGIN_COMPARE_PARTIAL = 5- Partial match comparisonGIN_TRICONSISTENT = 6- Ternary consistency checkGIN_OPTIONS = 7- Index options
GIST_CONSISTENT = 1- Check consistencyGIST_UNION = 2- Union/merge predicatesGIST_COMPRESS = 3- Compress leaf valueGIST_DECOMPRESS = 4- Decompress valueGIST_PENALTY = 5- Calculate insertion penaltyGIST_PICKSPLIT = 6- Split page algorithmGIST_EQUAL = 7- Equality checkGIST_DISTANCE = 8- Distance for KNNGIST_FETCH = 9- Fetch tupleGIST_OPTIONS = 10- Index optionsGIST_SORTSUPPORT = 11- Sort support
Library Management
init_libraries()
Load an extension shared library and register it.db_id: Database IDextension: Extension name (e.g., “pg_trgm”)extension_lib_path: Full path to .so file (e.g., “/usr/lib/postgresql/16/lib/pg_trgm.so”)
- Calls
dlopen(lib_path, RTLD_NOW | RTLD_GLOBAL) - Stores library handle in
_library_map[extension] - Throws error if library cannot be loaded
Type Management APIs
add_type()
Register an extension type and its I/O functions.extension: Extension nameoid: PostgreSQL type OIDtypinput: Text input function nametypoutput: Text output function nametypreceive: Binary receive function nametypsend: Binary send function name
- Uses
dlsym()to load all four I/O functions from extension library - Stores functions in
_type_func_name_to_funcmap - Stores type metadata in
_type_oid_to_typemap
get_type_by_oid()
Retrieve type metadata by OID.PgType structure or empty struct if not found
Example:
get_type_func_by_type_name()
Get a type I/O function by name.type_name: Function name (e.g., “int4in”, “gtrgmrecv”)
nullptr if not found
binary_to_datum()
Convert binary wire format to PostgreSQL Datum usingtypreceive function.
value: Binary data from PostgreSQL wire protocolpg_oid: Type OIDatttypmod: Type modifier (e.g., varchar length)
Datum representation of the value
Implementation:
datum_to_string()
Convert Datum to string representation usingtypoutput function.
value: Datum to convertpg_oid: Type OID
Operator Management APIs
add_operator()
Register an extension operator.extension: Extension nameoid: Operator OID frompg_operatoroper_name: Operator symbol (e.g.,=,<@,&&)proc_name: Implementation function name
- Uses
dlsym()to load operator function from extension library - Stores in
_oper_name_to_funcand_proc_name_to_funcmaps - Stores OID mappings in
_oper_oid_to_nameand_proc_oid_to_name
get_operator_func_by_oid()
Get operator function by OID.nullptr if not found
get_operator_func_by_oper_name()
Get operator function by operator symbol.oper_name: Operator symbol (e.g.,=,%,<@)
nullptr if not found
Example:
get_operator_func_by_proc_name()
Get operator function by procedure name.comparator_func()
Compare two values using an extension operator.context: Containstype_oidandop_str(operator name)lhval: Left-hand value (binary format)rhval: Right-hand value (binary format)
Operator Class APIs
add_opclass()
Register an operator class method.extension: Extension nameopclass: OpClass metadatamethod: Method metadata including support number and function name
- Uses
dlsym()to load support function - Stores in nested map:
_opclass_function_map[opclass_name][support_number]
get_opclass_method_by_method_name()
Retrieve an opclass method by name and support number.opclass_name: OpClass name (e.g., “gin_trgm_ops”)support_number: Support procedure number (e.g.,GIN_EXTRACTVALUE = 2)
PgOpsClassMethod structure with function pointer, or empty struct if not found
Example:
get_opclass_method_func_ptr_by_method_name()
Get opclass method function pointer (static convenience method).nullptr if not found
Example:
invoke_opclass_method()
Invoke an opclass method with a single Datum argument.opclass_name: OpClass namesupport_number: Support procedure numbervalue: Input Datum
Internal Data Structures
Registry Maps
Usage Patterns
Pattern 1: Type I/O Conversion
Pattern 2: Opclass Method Invocation
Pattern 3: Extension Operator Comparison
Thread Safety
Current Status: Not thread-safedlopen()anddlsym()calls are not synchronized- Registry maps are accessed without locks
- Singleton instance is not thread-safe
- Initialize all extensions before starting worker threads
- Treat registry as read-only after initialization
- Add mutex protection if runtime extension loading is needed
Error Handling
All lookup methods log errors and returnnullptr / empty struct on failure:
nullptr before using function pointers:
Performance Considerations
- Function Pointer Caching: Frequently-used functions should be cached at call site
- OID Lookups: Type/operator OID lookups involve map lookups; cache results when possible
- Datum Conversions: Binary ↔ Datum conversions invoke extension functions; minimize conversions
- dlsym() Cost: Symbol lookups are relatively expensive; done once during registration