Skip to content

Commit

Permalink
Split DDL processing into start and end hooks
Browse files Browse the repository at this point in the history
The ProcessUtility hook doesn't give any information on applied DDL
commands, which makes it hard to implement DDL processing that
requires the result of a DDL command on a hypertable (for instance,
adding a constraint or index without an explicit name).

This change splits the DDL processing over start and end hooks,
handling DDL commands before and after regular PostgreSQL processing,
respectively.

The start DDL hook is still based on the ProcessUtility hook, while
the end DDL hook is based on an event trigger that allows getting
information on the created/dropped/altered objects.
  • Loading branch information
erimatnor committed Sep 22, 2017
1 parent 48fbfaf commit 04d01ce
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 167 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SRCS = \
src/cache.c \
src/cache_invalidate.c \
src/process_utility.c \
src/event_trigger.c \
src/trigger.c \
src/chunk.c \
src/scanner.c \
Expand Down
5 changes: 5 additions & 0 deletions sql/ddl_triggers.sql
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,8 @@ BEGIN
END
$BODY$;

CREATE FUNCTION _timescaledb_internal.ddl_command_end() RETURNS event_trigger
AS '$libdir/timescaledb', 'timescaledb_ddl_command_end' LANGUAGE C IMMUTABLE STRICT;

CREATE EVENT TRIGGER timescaledb_ddl_command_end ON ddl_command_end
EXECUTE PROCEDURE _timescaledb_internal.ddl_command_end();
75 changes: 75 additions & 0 deletions src/event_trigger.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <postgres.h>
#include <commands/event_trigger.h>
#include <executor/executor.h>
#include <access/htup_details.h>

#include "event_trigger.h"

/* Function manager info for the event "pg_event_trigger_ddl_commands", which is
* used to retrieve information on executed DDL commands in an event
* trigger. The function manager info is initialized on extension load. */
static FmgrInfo ddl_commands_fmgrinfo;

/*
* Get a list of executed DDL commands in an event trigger.
*
* This function calls the function pg_event_trigger_ddl_commands(), which is
* part of the event trigger API, and retrieves the DDL commands executed in
* relation to the event trigger. It is only valid to call this function from
* within an event trigger.
*/
List *
event_trigger_ddl_commands(void)
{
ReturnSetInfo rsinfo;
FunctionCallInfoData fcinfo;
TupleTableSlot *slot;
EState *estate = CreateExecutorState();
List *objects = NIL;

InitFunctionCallInfoData(fcinfo, &ddl_commands_fmgrinfo, 1, InvalidOid, NULL, NULL);
MemSet(&rsinfo, 0, sizeof(rsinfo));
rsinfo.type = T_ReturnSetInfo;
rsinfo.allowedModes = SFRM_Materialize;
rsinfo.econtext = CreateExprContext(estate);
fcinfo.resultinfo = (fmNodePtr) &rsinfo;

FunctionCallInvoke(&fcinfo);

slot = MakeSingleTupleTableSlot(rsinfo.setDesc);

while (tuplestore_gettupleslot(rsinfo.setResult, true, false, slot))
{
HeapTuple tuple = ExecFetchSlotTuple(slot);
CollectedCommand *cmd;
Datum values[rsinfo.setDesc->natts];
bool nulls[rsinfo.setDesc->natts];

heap_deform_tuple(tuple, rsinfo.setDesc, values, nulls);

if (rsinfo.setDesc->natts > 8 && !nulls[8])
{
cmd = (CollectedCommand *) DatumGetPointer(values[8]);
objects = lappend(objects, cmd);
}
}

FreeExprContext(rsinfo.econtext, false);
FreeExecutorState(estate);
ExecDropSingleTupleTableSlot(slot);

return objects;
}

void
_event_trigger_init(void)
{
fmgr_info(fmgr_internal_function("pg_event_trigger_ddl_commands"),
&ddl_commands_fmgrinfo);
}

void
_event_trigger_fini(void)
{
/* Nothing to do */
}
11 changes: 11 additions & 0 deletions src/event_trigger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef TIMESCALEDB_EVENT_TRIGGER_H
#define TIMESCALEDB_EVENT_TRIGGER_H

#include <postgres.h>
#include <nodes/pg_list.h>

extern List *event_trigger_ddl_commands(void);
extern void _event_trigger_init(void);
extern void _event_trigger_fini(void);

#endif /* TIMESCALEDB_EVENT_TRIGGER_H */
2 changes: 2 additions & 0 deletions src/hypertable.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,7 @@ hypertable_relid(RangeVar *rv)
bool
is_hypertable(Oid relid)
{
if (!OidIsValid(relid))
return false;
return hypertable_relid_lookup(relid) != InvalidOid;
}
5 changes: 5 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ extern void _planner_fini(void);
extern void _process_utility_init(void);
extern void _process_utility_fini(void);

extern void _event_trigger_init(void);
extern void _event_trigger_fini(void);

extern void _PG_init(void);
extern void _PG_fini(void);

Expand Down Expand Up @@ -76,6 +79,7 @@ _PG_init(void)
_cache_invalidate_init();
_planner_init();
_executor_init();
_event_trigger_init();
_process_utility_init();
_guc_init();
}
Expand All @@ -89,6 +93,7 @@ _PG_fini(void)
*/
_guc_fini();
_process_utility_fini();
_event_trigger_fini();
_executor_fini();
_planner_fini();
_cache_invalidate_fini();
Expand Down
Loading

0 comments on commit 04d01ce

Please sign in to comment.