Reputation: 89
I am working on creating a postgresql extension, till now I only wanted to test if one of table's columns is bytea type to store the table's name , but when I test it with :
CREATE TABLE test_table (
id SERIAL PRIMARY KEY,
data bytea
);
it says that no bytea columns found in table...
here's my c code :
#include "postgres.h"
#include "fmgr.h"
#include "commands/event_trigger.h"
#include "parser/parse_node.h"
#include "executor/spi.h"
#include "utils/builtins.h"
#include "catalog/pg_type.h"
#include "nodes/pg_list.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(log_table_creation);
Datum
log_table_creation(PG_FUNCTION_ARGS)
{
EventTriggerData *trigdata;
const char *tag;
int ret;
if (!CALLED_AS_EVENT_TRIGGER(fcinfo))
elog(ERROR, "not fired by event trigger manager");
trigdata = (EventTriggerData *) fcinfo->context;
tag = GetCommandTagName(trigdata->tag);
if (strcmp(tag, "CREATE TABLE") != 0)
PG_RETURN_NULL();
// Cast parsetree to CreateStmt to access the table structure
CreateStmt *createStmt = (CreateStmt *) trigdata->parsetree;
RangeVar *relation = createStmt->relation;
// Check if any column has type `bytea`
bool has_bytea_column = false;
ListCell *cell;
foreach(cell, createStmt->tableElts)
{
ColumnDef *colDef = (ColumnDef *) lfirst(cell);
// Check for type name "bytea" explicitly
if (list_length(colDef->typeName->names) == 2) // {"pg_catalog", "bytea"}
{
// Extract schema and type as strings
const char *schema = strVal(linitial(colDef->typeName->names));
const char *type = strVal(lsecond(colDef->typeName->names));
if (strcmp(schema, "pg_catalog") == 0 && strcmp(type, "bytea") == 0)
{
has_bytea_column = true;
break;
}
}
}
// Only log the table if it has a `bytea` column
if (has_bytea_column)
{
// Prepare and execute the insertion into table_log
SPI_connect();
char *query = psprintf("INSERT INTO table_log (table_name) VALUES ('%s')", relation->relname);
ret = SPI_execute(query, false, 0);
SPI_finish();
if (ret != SPI_OK_INSERT)
elog(ERROR, "Failed to insert into table_log");
}
else
{
elog(NOTICE, "No BYTEA columns found in table %s", relation->relname);
}
PG_RETURN_NULL();
}
and her's the sql script:
CREATE TABLE table_log (
id SERIAL PRIMARY KEY,
table_name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE FUNCTION log_table_creation()
RETURNS event_trigger
LANGUAGE c
AS 'MODULE_PATHNAME', 'log_table_creation';
CREATE EVENT TRIGGER table_creation_logger
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE FUNCTION log_table_creation();
it all new to me,so if anyone could help me with it, and if there's tutorials it would be the best. thank you
Upvotes: 0
Views: 49
Reputation: 89
this is how i fixed it
// Event trigger function to log tables created with a bytea column
Datum
log_table_creation(PG_FUNCTION_ARGS)
{
EventTriggerData *trigdata;
const char *tag;
int ret;
if (!CALLED_AS_EVENT_TRIGGER(fcinfo))
elog(ERROR, "not fired by event trigger manager");
trigdata = (EventTriggerData *) fcinfo->context;
tag = GetCommandTagName(trigdata->tag);
if (strcmp(tag, "CREATE TABLE") != 0)
PG_RETURN_NULL();
// Cast parsetree to CreateStmt to access the table structure
CreateStmt *createStmt = (CreateStmt *) trigdata->parsetree;
RangeVar *relation = createStmt->relation;
// Check if any column has type `bytea`
bool has_bytea_column = false;
ListCell *cell;
foreach(cell, createStmt->tableElts)
{
ColumnDef *colDef = (ColumnDef *) lfirst(cell);
// Retrieve the type OID directly
Oid typeOid = typenameTypeId(NULL, colDef->typeName);
// Log the OID of each column's type for debugging
elog(INFO, "Column %s has type OID: %u", colDef->colname, typeOid);
// Check if the type OID matches `BYTEAOID`
if (typeOid == BYTEAOID)
{
has_bytea_column = true;
break;
}
}
// Only log the table if it has a `bytea` column
if (has_bytea_column)
{
SPI_connect();
char *query = psprintf("INSERT INTO table_log (table_name) VALUES ('%s')", relation->relname);
ret = SPI_execute(query, false, 0);
SPI_finish();
if (ret != SPI_OK_INSERT)
elog(ERROR, "Failed to insert into table_log");
else
elog(INFO, "Table %s with BYTEA column logged successfully", relation->relname);
}
else
{
elog(NOTICE, "No BYTEA columns found in table %s", relation->relname);
}
PG_RETURN_NULL();
}
Upvotes: 0