Skip to main content

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:
Support Numbers (from constants.hh): GIN:
  • GIN_COMPARE = 1 - Compare function
  • GIN_EXTRACTVALUE = 2 - Extract keys from indexed value
  • GIN_EXTRACTQUERY = 3 - Extract keys from query
  • GIN_CONSISTENT = 4 - Check if entry matches query
  • GIN_COMPARE_PARTIAL = 5 - Partial match comparison
  • GIN_TRICONSISTENT = 6 - Ternary consistency check
  • GIN_OPTIONS = 7 - Index options
GIST:
  • GIST_CONSISTENT = 1 - Check consistency
  • GIST_UNION = 2 - Union/merge predicates
  • GIST_COMPRESS = 3 - Compress leaf value
  • GIST_DECOMPRESS = 4 - Decompress value
  • GIST_PENALTY = 5 - Calculate insertion penalty
  • GIST_PICKSPLIT = 6 - Split page algorithm
  • GIST_EQUAL = 7 - Equality check
  • GIST_DISTANCE = 8 - Distance for KNN
  • GIST_FETCH = 9 - Fetch tuple
  • GIST_OPTIONS = 10 - Index options
  • GIST_SORTSUPPORT = 11 - Sort support

Library Management

init_libraries()

Load an extension shared library and register it.
Parameters:
  • db_id: Database ID
  • extension: Extension name (e.g., “pg_trgm”)
  • extension_lib_path: Full path to .so file (e.g., “/usr/lib/postgresql/16/lib/pg_trgm.so”)
Behavior:
  • Calls dlopen(lib_path, RTLD_NOW | RTLD_GLOBAL)
  • Stores library handle in _library_map[extension]
  • Throws error if library cannot be loaded
Example:

Type Management APIs

add_type()

Register an extension type and its I/O functions.
Parameters:
  • extension: Extension name
  • oid: PostgreSQL type OID
  • typinput: Text input function name
  • typoutput: Text output function name
  • typreceive: Binary receive function name
  • typsend: Binary send function name
Behavior:
  • Uses dlsym() to load all four I/O functions from extension library
  • Stores functions in _type_func_name_to_func map
  • Stores type metadata in _type_oid_to_type map
Example:

get_type_by_oid()

Retrieve type metadata by OID.
Returns: PgType structure or empty struct if not found Example:

get_type_func_by_type_name()

Get a type I/O function by name.
Parameters:
  • type_name: Function name (e.g., “int4in”, “gtrgmrecv”)
Returns: Function pointer or nullptr if not found

binary_to_datum()

Convert binary wire format to PostgreSQL Datum using typreceive function.
Parameters:
  • value: Binary data from PostgreSQL wire protocol
  • pg_oid: Type OID
  • atttypmod: Type modifier (e.g., varchar length)
Returns: Datum representation of the value Implementation:
Example:

datum_to_string()

Convert Datum to string representation using typoutput function.
Parameters:
  • value: Datum to convert
  • pg_oid: Type OID
Returns: String representation of the value Implementation:
Example:

Operator Management APIs

add_operator()

Register an extension operator.
Parameters:
  • extension: Extension name
  • oid: Operator OID from pg_operator
  • oper_name: Operator symbol (e.g., =, <@, &&)
  • oper_proc: Implementation function name
Behavior:
  • Uses dlsym() to load operator function from extension library
  • Stores in _oper_name_to_func and _proc_name_to_func maps
  • Stores OID mappings in _oper_oid_to_name and _proc_oid_to_name
Example:

get_operator_func_by_oid()

Get operator function by OID.
Returns: Function pointer or nullptr if not found

get_operator_func_by_oper_name()

Get operator function by operator symbol.
Parameters:
  • oper_name: Operator symbol (e.g., =, %, <@)
Returns: Function pointer or nullptr if not found Example:

get_operator_func_by_proc_name()

Get operator function by procedure name.
Example:

comparator_func()

Compare two values using an extension operator.
Parameters:
  • context: Contains type_oid and op_str (operator name)
  • lhval: Left-hand value (binary format)
  • rhval: Right-hand value (binary format)
Returns: Boolean result of comparison Implementation:
Example:

Operator Class APIs

add_opclass()

Register an operator class method.
Parameters:
  • extension: Extension name
  • opclass: OpClass metadata
  • method: Method metadata including support number and function name
Behavior:
  • Uses dlsym() to load support function
  • Stores in nested map: _opclass_function_map[opclass_name][support_number]
Example:

get_opclass_method_by_method_name()

Retrieve an opclass method by name and support number.
Parameters:
  • opclass_name: OpClass name (e.g., “gin_trgm_ops”)
  • support_number: Support procedure number (e.g., GIN_EXTRACTVALUE = 2)
Returns: 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.
Returns: Function pointer or nullptr if not found Example:

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-safe
  • dlopen() and dlsym() calls are not synchronized
  • Registry maps are accessed without locks
  • Singleton instance is not thread-safe
Recommendations:
  • 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 return nullptr / empty struct on failure:
Best Practice: Always check for nullptr before using function pointers:

Performance Considerations

  1. Function Pointer Caching: Frequently-used functions should be cached at call site
  2. OID Lookups: Type/operator OID lookups involve map lookups; cache results when possible
  3. Datum Conversions: Binary ↔ Datum conversions invoke extension functions; minimize conversions
  4. dlsym() Cost: Symbol lookups are relatively expensive; done once during registration