Oninit® UDR — ONI UDR Debug: Install
Everything needed to build ONI UDR Debug and register it against a real Informix instance — shown here as it's actually deployed for the tsapi project. Once it's installed, the Usage guide covers configuring and operating it day to day.
Requirements
- An IBM Informix Dynamic Server instance, with the DataBlade SDK
headers available (
$INFORMIXDIR/incl/public). - A C compiler (
cc/gcc) — the module builds as a plaincc -sharedobject; nothing else to link against. - Enough DBA privilege on the target database to run
CREATE FUNCTION/CREATE PROCEDURE/CREATE ROW TYPE.
1. Build
make check # portable test suite — no Informix instance needed
make udr-check # compiles the Informix-facing sources against the real
# DataBlade SDK headers (syntax/API check only, no link)
make udr-build # links the module into oni_debug.bld
make udr-build takes IDS_INCL as an override if
your SDK headers live somewhere other than the default path. The build
compiles nine source files (oni_debug.c,
oni_debug_config.c, oni_debug_flush.c,
oni_debug_status.c, oni_debug_config_file.c,
oni_debug_mem_informix.c, oni_udr_support.c,
oni_debug_udr.c, oni_debug_verify_udr.c) with
-fvisibility=hidden — load-bearing, not cosmetic: it keeps
this module's helper symbols from colliding with another .bld
sharing the same server process.
2. Deploy
Place the built module under a version-numbered directory in your
instance's extend/ tree:
mkdir -p $INFORMIXDIR/extend/oni_debug.9.0 cp oni_debug.bld $INFORMIXDIR/extend/oni_debug.9.0/
Use a fresh version directory (.2.0, .3.0, ...)
for every subsequent rebuild rather than overwriting the file in place
— a module a running server process has already loaded won't pick up
an in-place file replacement, and a version bump avoids needing to restart
the instance to deploy an update. (tsapi's own deployment is at
.9.0 as of this writing — each register script's
EXTERNAL NAME lines are updated to match whichever version is
actually on disk.)
3. Register
Register the SQL admin surface against your target database. This is the real, current set — ten routines, not the seven or eight you'll see in an older snapshot of this page:
CREATE PROCEDURE oni_debug_on() EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_on_udr)" LANGUAGE C; CREATE PROCEDURE oni_debug_off() EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_off_udr)" LANGUAGE C; CREATE FUNCTION oni_debug_why() RETURNS LVARCHAR EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_why_udr)" LANGUAGE C; -- oni_debug_status() returns a real named ROW type, not formatted text -- -- the CREATE ROW TYPE must exist before the function that returns it. CREATE ROW TYPE oni_debug_status_t ( debug_enabled BOOLEAN, capture LVARCHAR, queue_capacity INTEGER, queue_count BIGINT, queue_full BOOLEAN, flush_active BOOLEAN, debug_io_failed BOOLEAN, start_seq BIGINT, end_seq BIGINT, queue_generation INTEGER, last_successful_flush_ms BIGINT, consecutive_flush_failures INTEGER, flush_failure_limit INTEGER, last_flush_error LVARCHAR, debug_file LVARCHAR, debug_file_size BIGINT, files_rotated BIGINT, messages_queued BIGINT, messages_flushed BIGINT, messages_suppressed BIGINT, messages_truncated BIGINT, messages_filtered_by_class BIGINT, messages_filtered_by_capture_scope BIGINT, queue_full_events BIGINT, flush_count BIGINT, flush_failures BIGINT ); CREATE FUNCTION oni_debug_status() RETURNS oni_debug_status_t EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_status_udr)" LANGUAGE C; CREATE FUNCTION oni_debug_dump() RETURNS LVARCHAR EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_dump_udr)" LANGUAGE C; CREATE FUNCTION oni_debug_classes() RETURNS LVARCHAR EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_classes_udr)" LANGUAGE C; CREATE FUNCTION oni_debug_class_set(class LVARCHAR, level INT) RETURNS INT EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_class_set_udr)" LANGUAGE C; CREATE PROCEDURE oni_debug_queue_flush() EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_queue_flush_udr)" LANGUAGE C; CREATE PROCEDURE oni_debug_queue_clear() EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_queue_clear_udr)" LANGUAGE C; CREATE PROCEDURE oni_debug_config_reload() EXTERNAL NAME "$INFORMIXDIR/extend/oni_debug.9.0/oni_debug.bld(oni_debug_config_reload_udr)" LANGUAGE C;
Grant execute on each routine to whichever roles need to call it.
Don't register with a custom VP class unless one is already provisioned in
onconfig — the default CPU VP class is correct for
virtually every deployment; a custom class needs a matching, separately
provisioned onconfig entry or every call fails with
-9799 VP switch failed.
oni_debug_classes()/oni_debug_dump() still
return formatted text rather than a structured type — both are
naturally variable-row result sets, a different problem than the scalar
ROW oni_debug_status() now has.
What's actually running
Every EXTERNAL NAME line above points at a real exported C
function in oni_debug.bld. There's no code generation and no
magic in between — the SQL surface is these functions, one
CREATE FUNCTION/CREATE PROCEDURE per exported
symbol. oni_debug_status_udr() (src/oni_debug_udr.c)
is the one worth seeing in full, since it's the function the
CREATE ROW TYPE oni_debug_status_t block above exists for
— there's no mi_new_row()/setter API in the DataBlade
SDK, so building a real named-ROW-typed return means doing it
by hand, column by column:
UDREXPORT MI_ROW *oni_debug_status_udr(void)
{
oni_debug_status_t st;
oni_debug_status(&st);
MI_CONNECTION *conn = mi_open(NULL, NULL, NULL);
if (conn == NULL)
ONI_DEBUG_ERR_001("mi_open() failed");
/* Resolve the CREATE ROW TYPE above to a real MI_TYPEID, then a
* column-addressable MI_ROW_DESC -- this is why the row type has
* to exist in the catalog before this function is registered. */
MI_TYPEID *row_type_id = mi_typestring_to_id(conn, "oni_debug_status_t");
MI_ROW_DESC *rowdesc = mi_row_desc_create(row_type_id);
mi_integer colcnt = mi_column_count(rowdesc);
if (colcnt != ONI_DEBUG_STATUS_NCOLS)
ONI_DEBUG_ERR_001("column count drifted from this file's own COL_* enum");
/* The row is only serialized by Informix AFTER this function
* returns, so every value built into it must outlive the return --
* PER_COMMAND, not the PER_ROUTINE default. */
MI_MEMORY_DURATION prev = mi_switch_mem_duration(PER_COMMAND);
MI_DATUM *coldata = mi_alloc((mi_integer)(colcnt * sizeof(MI_DATUM)));
mi_boolean *colisnull = mi_alloc((mi_integer)(colcnt * sizeof(mi_boolean)));
memset(colisnull, MI_FALSE, (size_t)colcnt * sizeof(mi_boolean));
/* BOOLEAN/INTEGER fit directly in an MI_DATUM (a plain void*);
* BIGINT/LVARCHAR need a genuine allocated pointer instead. */
coldata[COL_DEBUG_ENABLED] = (MI_DATUM)(intptr_t)(st.debug_enabled ? MI_TRUE : MI_FALSE);
coldata[COL_CAPTURE] =
(MI_DATUM)new_lvarchar(st.capture == ONI_DEBUG_CAPTURE_SESSION ? "session" : "system");
coldata[COL_QUEUE_COUNT] = (MI_DATUM)new_bigint((int64_t)st.queue_count);
/* ... one line per remaining column, same two patterns ... */
coldata[COL_FLUSH_FAILURES] = (MI_DATUM)new_bigint((int64_t)st.flush_failures);
MI_ROW *row = mi_row_create(conn, rowdesc, coldata, colisnull);
(void)mi_switch_mem_duration(prev);
if (row == NULL)
ONI_DEBUG_ERR_001("mi_row_create() failed");
return row;
}
The pattern generalizes to any admin-style UDR that needs to return
structured data instead of formatted text: resolve the type, size the
column arrays off the type's own mi_column_count() rather
than a hardcoded number, build each column by SQL-type (direct cast for
anything that fits in a machine word, an allocated pointer for anything
that doesn't), then hand the whole thing to mi_row_create()
once. oni_debug_why_udr()/oni_debug_dump_udr()
are simpler by comparison — they build one mi_lvarchar
and return it, no row descriptor involved, which is still the shape
oni_debug_classes()/oni_debug_dump() use today.
Module installed and registered? The Usage guide covers configuration, the SQL surface day to day, worked examples, and troubleshooting.