diff --git a/sql/ddl_triggers.sql b/sql/ddl_triggers.sql index 7a55fad9a..b945e3772 100644 --- a/sql/ddl_triggers.sql +++ b/sql/ddl_triggers.sql @@ -1,8 +1,12 @@ -CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_command_end() RETURNS event_trigger -AS '@MODULE_PATHNAME@', 'timescaledb_ddl_command_end' LANGUAGE C; +CREATE OR REPLACE FUNCTION _timescaledb_internal.process_ddl_event() RETURNS event_trigger +AS '@MODULE_PATHNAME@', 'timescaledb_process_ddl_event' LANGUAGE C; DROP EVENT TRIGGER IF EXISTS timescaledb_ddl_command_end; --EVENT TRIGGER MUST exclude the ALTER EXTENSION tag. CREATE EVENT TRIGGER timescaledb_ddl_command_end ON ddl_command_end WHEN TAG IN ('ALTER TABLE','CREATE TRIGGER','CREATE TABLE','CREATE INDEX','ALTER INDEX') -EXECUTE PROCEDURE _timescaledb_internal.ddl_command_end(); +EXECUTE PROCEDURE _timescaledb_internal.process_ddl_event(); + +DROP EVENT TRIGGER IF EXISTS timescaledb_ddl_sql_drop; +CREATE EVENT TRIGGER timescaledb_ddl_sql_drop ON sql_drop +EXECUTE PROCEDURE _timescaledb_internal.process_ddl_event(); diff --git a/sql/updates/post-0.8.0--0.9.0-dev.sql b/sql/updates/post-0.8.0--0.9.0-dev.sql index e69de29bb..a703efd25 100644 --- a/sql/updates/post-0.8.0--0.9.0-dev.sql +++ b/sql/updates/post-0.8.0--0.9.0-dev.sql @@ -0,0 +1 @@ +DROP FUNCTION _timescaledb_internal.ddl_command_end(); diff --git a/src/catalog.c b/src/catalog.c index d7e8fa32c..e15a31071 100644 --- a/src/catalog.c +++ b/src/catalog.c @@ -71,6 +71,7 @@ static const TableIndexDef catalog_table_index_definitions[_MAX_CATALOG_TABLES] [CHUNK_CONSTRAINT] = { .length = _MAX_CHUNK_CONSTRAINT_INDEX, .names = (char *[]) { + [CHUNK_CONSTRAINT_CHUNK_ID_CONSTRAINT_NAME_IDX] = "chunk_constraint_chunk_id_constraint_name_key", [CHUNK_CONSTRAINT_CHUNK_ID_DIMENSION_SLICE_ID_IDX] = "chunk_constraint_chunk_id_dimension_slice_id_idx", } }, diff --git a/src/catalog.h b/src/catalog.h index f02d72c1d..056815d7f 100644 --- a/src/catalog.h +++ b/src/catalog.h @@ -34,6 +34,10 @@ typedef enum CatalogTable } CatalogTable; #define INVALID_CATALOG_TABLE _MAX_CATALOG_TABLES +#define INVALID_INDEXID -1 + +#define CATALOG_INDEX(catalog, tableid, indexid) \ + (indexid == INVALID_INDEXID ? InvalidOid : (catalog)->tables[tableid].index_ids[indexid]) #define CatalogInternalCall1(func, datum1) \ OidFunctionCall1(catalog_get_internal_function_id(catalog_get(), func), datum1) @@ -329,7 +333,8 @@ typedef FormData_chunk_constraint *Form_chunk_constraint; enum { - CHUNK_CONSTRAINT_CHUNK_ID_DIMENSION_SLICE_ID_IDX = 0, + CHUNK_CONSTRAINT_CHUNK_ID_CONSTRAINT_NAME_IDX = 0, + CHUNK_CONSTRAINT_CHUNK_ID_DIMENSION_SLICE_ID_IDX, _MAX_CHUNK_CONSTRAINT_INDEX, }; @@ -340,6 +345,13 @@ enum Anum_chunk_constraint_chunk_id_dimension_slice_id_idx _Anum_chunk_constraint_chunk_id_dimension_slice_id_idx_max, }; +enum Anum_chunk_constraint_chunk_id_constraint_name_idx +{ + Anum_chunk_constraint_chunk_id_constraint_name_idx_chunk_id = 1, + Anum_chunk_constraint_chunk_id_constraint_name_idx_constraint_name, + _Anum_chunk_constraint_chunk_id_constraint_name_idx_max, +}; + /************************************ * * Chunk index table definitions diff --git a/src/chunk.c b/src/chunk.c index 69543546c..ec64a7c1b 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -566,7 +566,6 @@ chunk_fill_stub(Chunk *chunk_stub, bool tuplock) ScannerCtx ctx = { .table = catalog->tables[CHUNK].id, .index = catalog->tables[CHUNK].index_ids[CHUNK_ID_INDEX], - .scantype = ScannerTypeIndex, .nkeys = 1, .scankey = scankey, .data = chunk_stub, @@ -868,7 +867,6 @@ chunk_scan_internal(int indexid, ScannerCtx ctx = { .table = catalog->tables[CHUNK].id, .index = catalog->tables[CHUNK].index_ids[indexid], - .scantype = ScannerTypeIndex, .nkeys = nkeys, .data = data, .scankey = scankey, diff --git a/src/chunk_constraint.c b/src/chunk_constraint.c index 1de14956c..c52f6f7e7 100644 --- a/src/chunk_constraint.c +++ b/src/chunk_constraint.c @@ -356,8 +356,6 @@ chunk_constraint_tuple_found(TupleInfo *ti, void *data) return true; } -#define NO_INDEXSCAN -1 - static int chunk_constraint_scan_internal(int indexid, ScanKeyData *scankey, @@ -370,7 +368,7 @@ chunk_constraint_scan_internal(int indexid, Catalog *catalog = catalog_get(); ScannerCtx scanctx = { .table = catalog->tables[CHUNK_CONSTRAINT].id, - .scantype = (indexid == NO_INDEXSCAN) ? ScannerTypeHeap : ScannerTypeIndex, + .index = CATALOG_INDEX(catalog, CHUNK_CONSTRAINT, indexid), .nkeys = nkeys, .scankey = scankey, .data = data, @@ -380,9 +378,6 @@ chunk_constraint_scan_internal(int indexid, .scandirection = ForwardScanDirection, }; - if (indexid != NO_INDEXSCAN) - scanctx.index = catalog->tables[CHUNK_CONSTRAINT].index_ids[indexid]; - return scanner_scan(&scanctx); } @@ -413,6 +408,38 @@ chunk_constraint_scan_by_chunk_id_internal(int32 chunk_id, lockmode); } +static int +chunk_constraint_scan_by_chunk_id_constraint_name_internal(int32 chunk_id, + const char *constraint_name, + tuple_found_func tuple_found, + tuple_found_func tuple_filter, + void *data, + LOCKMODE lockmode) +{ + ScanKeyData scankey[2]; + + + ScanKeyInit(&scankey[0], + Anum_chunk_constraint_chunk_id_constraint_name_idx_chunk_id, + BTEqualStrategyNumber, + F_INT4EQ, + Int32GetDatum(chunk_id)); + + ScanKeyInit(&scankey[1], + Anum_chunk_constraint_chunk_id_constraint_name_idx_constraint_name, + BTEqualStrategyNumber, + F_NAMEEQ, + DirectFunctionCall1(namein, CStringGetDatum(constraint_name))); + + return chunk_constraint_scan_internal(CHUNK_CONSTRAINT_CHUNK_ID_CONSTRAINT_NAME_IDX, + scankey, + 2, + tuple_found, + tuple_filter, + data, + lockmode); +} + /* * Scan all the chunk's constraints given its chunk ID. * @@ -625,6 +652,8 @@ typedef struct ConstraintInfo { const char *hypertable_constraint_name; ChunkConstraints *ccs; + bool delete_metadata; + bool drop_constraint; } ConstraintInfo; typedef struct RenameHypertableConstraintInfo @@ -652,24 +681,29 @@ chunk_constraint_delete_tuple(TupleInfo *ti, void *data) ObjectAddress constrobj = { .classId = ConstraintRelationId, .objectId = get_relation_constraint_oid(chunk->table_id, - NameStr(*DatumGetName(constrname)), false), + NameStr(*DatumGetName(constrname)), true), }; Oid index_relid = get_constraint_index(constrobj.objectId); /* Collect the deleted constraints */ - if (NULL != info && NULL != info->ccs) + if (NULL != info->ccs) chunk_constraint_tuple_found(ti, info->ccs); - /* - * If this is an index constraint, we need to cleanup the index metadata. - * Don't drop the index though, since that will happend when the - * constraint is dropped. - */ - if (OidIsValid(index_relid)) - chunk_index_delete(chunk, index_relid, false); + if (info->delete_metadata) + { + /* + * If this is an index constraint, we need to cleanup the index + * metadata. Don't drop the index though, since that will happend when + * the constraint is dropped. + */ + if (OidIsValid(index_relid)) + chunk_index_delete(chunk, index_relid, false); - catalog_delete(ti->scanrel, ti->tuple); - performDeletion(&constrobj, DROP_RESTRICT, 0); + catalog_delete(ti->scanrel, ti->tuple); + } + + if (info->drop_constraint && OidIsValid(constrobj.objectId)) + performDeletion(&constrobj, DROP_RESTRICT, 0); return true; } @@ -695,10 +729,13 @@ hypertable_constraint_tuple_filter(TupleInfo *ti, void *data) int chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id, - char *hypertable_constraint_name) + char *hypertable_constraint_name, + bool delete_metadata, bool drop_constraint) { ConstraintInfo info = { .hypertable_constraint_name = hypertable_constraint_name, + .delete_metadata = delete_metadata, + .drop_constraint = drop_constraint }; return chunk_constraint_scan_by_chunk_id_internal(chunk_id, @@ -708,6 +745,23 @@ chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id, RowExclusiveLock); } +int +chunk_constraint_delete_by_constraint_name(int32 chunk_id, const char *constraint_name, + bool delete_metadata, bool drop_constraint) +{ + ConstraintInfo info = { + .delete_metadata = delete_metadata, + .drop_constraint = drop_constraint + }; + + return chunk_constraint_scan_by_chunk_id_constraint_name_internal(chunk_id, + constraint_name, + chunk_constraint_delete_tuple, + NULL, + &info, + RowExclusiveLock); +} + /* * Delete all constraints for a chunk. Optionally, collect the deleted constraints. */ @@ -716,6 +770,8 @@ chunk_constraint_delete_by_chunk_id(int32 chunk_id, ChunkConstraints *ccs) { ConstraintInfo info = { .ccs = ccs, + .delete_metadata = true, + .drop_constraint = true, }; return chunk_constraint_scan_by_chunk_id_internal(chunk_id, @@ -728,6 +784,11 @@ chunk_constraint_delete_by_chunk_id(int32 chunk_id, ChunkConstraints *ccs) int chunk_constraint_delete_by_dimension_slice_id(int32 dimension_slice_id) { + ConstraintInfo info = { + .delete_metadata = true, + .drop_constraint = true, + }; + ScanKeyData scankey[1]; ScanKeyInit(&scankey[0], @@ -736,12 +797,12 @@ chunk_constraint_delete_by_dimension_slice_id(int32 dimension_slice_id) F_INT4EQ, Int32GetDatum(dimension_slice_id)); - return chunk_constraint_scan_internal(NO_INDEXSCAN, + return chunk_constraint_scan_internal(INVALID_INDEXID, scankey, 1, chunk_constraint_delete_tuple, NULL, - NULL, + &info, RowExclusiveLock); } diff --git a/src/chunk_constraint.h b/src/chunk_constraint.h index e611f89fb..c2b0c6208 100644 --- a/src/chunk_constraint.h +++ b/src/chunk_constraint.h @@ -42,9 +42,10 @@ extern int chunk_constraints_add_dimension_constraints(ChunkConstraints *ccs, in extern int chunk_constraints_add_inheritable_constraints(ChunkConstraints *ccs, int32 chunk_id, Oid hypertable_oid); extern void chunk_constraints_create(ChunkConstraints *ccs, Oid chunk_oid, int32 chunk_id, Oid hypertable_oid, int32 hypertable_id); extern void chunk_constraint_create_on_chunk(Chunk *chunk, Oid constraint_oid); -extern int chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id, char *hypertable_constraint_name); +extern int chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id, char *hypertable_constraint_name, bool delete_metadata, bool drop_constraint); extern int chunk_constraint_delete_by_chunk_id(int32 chunk_id, ChunkConstraints *ccs); extern int chunk_constraint_delete_by_dimension_slice_id(int32 dimension_slice_id); +extern int chunk_constraint_delete_by_constraint_name(int32 chunk_id, const char *constraint_name, bool delete_metadata, bool drop_constraint); extern void chunk_constraint_recreate(ChunkConstraint *cc, Oid chunk_oid); extern int chunk_constraint_rename_hypertable_constraint(int32 chunk_id, const char *oldname, const char *newname); diff --git a/src/chunk_index.c b/src/chunk_index.c index 686ce5fa6..08ea24f7a 100644 --- a/src/chunk_index.c +++ b/src/chunk_index.c @@ -507,16 +507,16 @@ chunk_index_create_all(int32 hypertable_id, Oid hypertable_relid, int32 chunk_id static int chunk_index_scan(int indexid, ScanKeyData scankey[], int nkeys, - tuple_found_func tuple_found, void *data, LOCKMODE lockmode) + tuple_found_func tuple_found, tuple_filter_func tuple_filter, void *data, LOCKMODE lockmode) { Catalog *catalog = catalog_get(); ScannerCtx scanCtx = { .table = catalog->tables[CHUNK_INDEX].id, - .index = catalog->tables[CHUNK_INDEX].index_ids[indexid], - .scantype = ScannerTypeIndex, + .index = CATALOG_INDEX(catalog, CHUNK_INDEX, indexid), .nkeys = nkeys, .scankey = scankey, .tuple_found = tuple_found, + .filter = tuple_filter, .data = data, .lockmode = lockmode, .scandirection = ForwardScanDirection, @@ -525,8 +525,8 @@ chunk_index_scan(int indexid, ScanKeyData scankey[], int nkeys, return scanner_scan(&scanCtx); } -#define chunk_index_scan_update(idxid, scankey, nkeys, tuple_found, data) \ - chunk_index_scan(idxid, scankey, nkeys, tuple_found, data, RowExclusiveLock) +#define chunk_index_scan_update(idxid, scankey, nkeys, tuple_found, tuple_filter, data) \ + chunk_index_scan(idxid, scankey, nkeys, tuple_found, tuple_filter, data, RowExclusiveLock) static ChunkIndexMapping * chunk_index_mapping_from_tuple(TupleInfo *ti, ChunkIndexMapping *cim) @@ -575,40 +575,78 @@ chunk_index_get_mappings(Hypertable *ht, Oid hypertable_indexrelid) DirectFunctionCall1(namein, CStringGetDatum((indexname)))); chunk_index_scan(CHUNK_INDEX_HYPERTABLE_ID_HYPERTABLE_INDEX_NAME_IDX, - scankey, 2, chunk_index_collect, &mappings, AccessShareLock); + scankey, 2, chunk_index_collect, NULL, &mappings, AccessShareLock); return mappings; } +typedef struct ChunkIndexDeleteData +{ + const char *index_name; + const char *schema; + bool drop_index; +} ChunkIndexDeleteData; + static bool chunk_index_tuple_delete(TupleInfo *ti, void *data) { FormData_chunk_index *chunk_index = (FormData_chunk_index *) GETSTRUCT(ti->tuple); Oid schemaid = chunk_index_get_schemaid(chunk_index); - bool *should_drop = data; + ChunkIndexDeleteData *cid = data; catalog_delete(ti->scanrel, ti->tuple); - if (*should_drop) + if (cid->drop_index) { ObjectAddress idxobj = { .classId = RelationRelationId, .objectId = get_relname_relid(NameStr(chunk_index->index_name), schemaid), }; - Assert(OidIsValid(idxobj.objectId)); - performDeletion(&idxobj, DROP_RESTRICT, 0); + if (OidIsValid(idxobj.objectId)) + performDeletion(&idxobj, DROP_RESTRICT, 0); } return true; } +static bool +chunk_index_name_and_schema_filter(TupleInfo *ti, void *data) +{ + FormData_chunk_index *chunk_index = (FormData_chunk_index *) GETSTRUCT(ti->tuple); + ChunkIndexDeleteData *cid = data; + + if (namestrcmp(&chunk_index->index_name, cid->index_name) == 0) + { + Chunk *chunk = chunk_get_by_id(chunk_index->chunk_id, 0, false); + + if (NULL != chunk && namestrcmp(&chunk->fd.schema_name, cid->schema) == 0) + return true; + } + + if (namestrcmp(&chunk_index->hypertable_index_name, cid->index_name) == 0) + { + Hypertable *ht; + + ht = hypertable_get_by_id(chunk_index->hypertable_id); + + if (NULL != ht && namestrcmp(&ht->fd.schema_name, cid->schema) == 0) + return true; + } + + return false; +} + int chunk_index_delete_children_of(Hypertable *ht, Oid hypertable_indexrelid, bool should_drop) { ScanKeyData scankey[2]; const char *indexname = get_rel_name(hypertable_indexrelid); + ChunkIndexDeleteData data = { + .drop_index = should_drop, + }; + ScanKeyInit(&scankey[0], Anum_chunk_index_hypertable_id_hypertable_index_name_idx_hypertable_id, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(ht->fd.id)); @@ -618,7 +656,7 @@ chunk_index_delete_children_of(Hypertable *ht, Oid hypertable_indexrelid, bool s DirectFunctionCall1(namein, CStringGetDatum((indexname)))); return chunk_index_scan_update(CHUNK_INDEX_HYPERTABLE_ID_HYPERTABLE_INDEX_NAME_IDX, - scankey, 2, chunk_index_tuple_delete, &should_drop); + scankey, 2, chunk_index_tuple_delete, NULL, &data); } int @@ -626,6 +664,10 @@ chunk_index_delete(Chunk *chunk, Oid chunk_indexrelid, bool drop_index) { ScanKeyData scankey[2]; const char *indexname = get_rel_name(chunk_indexrelid); + ChunkIndexDeleteData data = { + .drop_index = drop_index, + }; + ScanKeyInit(&scankey[0], Anum_chunk_index_chunk_id_index_name_idx_chunk_id, @@ -636,33 +678,54 @@ chunk_index_delete(Chunk *chunk, Oid chunk_indexrelid, bool drop_index) DirectFunctionCall1(namein, CStringGetDatum(indexname))); return chunk_index_scan_update(CHUNK_INDEX_CHUNK_ID_INDEX_NAME_IDX, - scankey, 2, chunk_index_tuple_delete, &drop_index); + scankey, 2, chunk_index_tuple_delete, NULL, &data); +} + +void +chunk_index_delete_by_name(const char *schema, const char *index_name, bool drop_index) +{ + ChunkIndexDeleteData data = { + .index_name = index_name, + .drop_index = drop_index, + .schema = schema, + }; + + chunk_index_scan_update(INVALID_INDEXID, + NULL, 0, chunk_index_tuple_delete, chunk_index_name_and_schema_filter, &data); } int chunk_index_delete_by_chunk_id(int32 chunk_id, bool drop_index) { ScanKeyData scankey[1]; + ChunkIndexDeleteData data = { + .drop_index = drop_index, + }; + ScanKeyInit(&scankey[0], Anum_chunk_index_chunk_id_index_name_idx_chunk_id, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(chunk_id)); return chunk_index_scan_update(CHUNK_INDEX_CHUNK_ID_INDEX_NAME_IDX, - scankey, 1, chunk_index_tuple_delete, &drop_index); + scankey, 1, chunk_index_tuple_delete, NULL, &data); } int chunk_index_delete_by_hypertable_id(int32 hypertable_id, bool drop_index) { ScanKeyData scankey[1]; + ChunkIndexDeleteData data = { + .drop_index = drop_index, + }; + ScanKeyInit(&scankey[0], Anum_chunk_index_hypertable_id_hypertable_index_name_idx_hypertable_id, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(hypertable_id)); return chunk_index_scan_update(CHUNK_INDEX_HYPERTABLE_ID_HYPERTABLE_INDEX_NAME_IDX, - scankey, 1, chunk_index_tuple_delete, &drop_index); + scankey, 1, chunk_index_tuple_delete, NULL, &data); } static bool @@ -690,7 +753,7 @@ chunk_index_get_by_indexrelid(Chunk *chunk, Oid chunk_indexrelid) BTEqualStrategyNumber, F_NAMEEQ, DirectFunctionCall1(namein, CStringGetDatum(indexname))); chunk_index_scan(CHUNK_INDEX_CHUNK_ID_INDEX_NAME_IDX, - scankey, 2, chunk_index_tuple_found, cim, AccessShareLock); + scankey, 2, chunk_index_tuple_found, NULL, cim, AccessShareLock); return cim; } @@ -759,7 +822,7 @@ chunk_index_rename(Chunk *chunk, Oid chunk_indexrelid, const char *newname) BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(indexname)); return chunk_index_scan_update(CHUNK_INDEX_CHUNK_ID_INDEX_NAME_IDX, - scankey, 2, chunk_index_tuple_rename, &renameinfo); + scankey, 2, chunk_index_tuple_rename, NULL, &renameinfo); } int @@ -781,7 +844,7 @@ chunk_index_rename_parent(Hypertable *ht, Oid hypertable_indexrelid, const char BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(indexname)); return chunk_index_scan_update(CHUNK_INDEX_HYPERTABLE_ID_HYPERTABLE_INDEX_NAME_IDX, - scankey, 2, chunk_index_tuple_rename, &renameinfo); + scankey, 2, chunk_index_tuple_rename, NULL, &renameinfo); } static bool @@ -817,7 +880,7 @@ chunk_index_set_tablespace(Hypertable *ht, Oid hypertable_indexrelid, const char BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(indexname)); return chunk_index_scan_update(CHUNK_INDEX_HYPERTABLE_ID_HYPERTABLE_INDEX_NAME_IDX, - scankey, 2, chunk_index_tuple_set_tablespace, + scankey, 2, chunk_index_tuple_set_tablespace, NULL, (char *) tablespace); } diff --git a/src/chunk_index.h b/src/chunk_index.h index 3448eb293..51b6d4810 100644 --- a/src/chunk_index.h +++ b/src/chunk_index.h @@ -22,6 +22,7 @@ extern int chunk_index_delete_children_of(Hypertable *ht, Oid hypertable_indexre extern int chunk_index_delete(Chunk *chunk, Oid chunk_indexrelid, bool drop_index); extern int chunk_index_delete_by_chunk_id(int32 chunk_id, bool drop_index); extern int chunk_index_delete_by_hypertable_id(int32 hypertable_id, bool drop_index); +extern void chunk_index_delete_by_name(const char *schema, const char *index_name, bool drop_index); extern int chunk_index_rename(Chunk *chunk, Oid chunk_indexrelid, const char *newname); extern int chunk_index_rename_parent(Hypertable *ht, Oid hypertable_indexrelid, const char *newname); extern int chunk_index_set_tablespace(Hypertable *ht, Oid hypertable_indexrelid, const char *tablespace); diff --git a/src/compat.c b/src/compat.c index 4d659715e..62c182852 100644 --- a/src/compat.c +++ b/src/compat.c @@ -2,6 +2,7 @@ #include #include "compat.h" +#include "extension.h" /* Old functions that are no longer used but are needed for compatibility when * updating the extension. */ @@ -58,3 +59,15 @@ hypertable_validate_triggers(PG_FUNCTION_ARGS) elog(ERROR, "Deprecated function should not be invoked"); PG_RETURN_NULL(); } + +TS_FUNCTION_INFO_V1(timescaledb_ddl_command_end); + +Datum +timescaledb_ddl_command_end(PG_FUNCTION_ARGS) +{ + if (!extension_is_loaded()) + PG_RETURN_NULL(); + + elog(ERROR, "Deprecated function should not be invoked"); + PG_RETURN_NULL(); +} diff --git a/src/dimension.c b/src/dimension.c index 1bf98ec9c..4f35f1b20 100644 --- a/src/dimension.c +++ b/src/dimension.c @@ -321,7 +321,6 @@ dimension_scan_internal(ScanKeyData *scankey, ScannerCtx scanctx = { .table = catalog->tables[DIMENSION].id, .index = catalog->tables[DIMENSION].index_ids[DIMENSION_HYPERTABLE_ID_IDX], - .scantype = ScannerTypeIndex, .nkeys = nkeys, .limit = limit, .scankey = scankey, @@ -367,7 +366,6 @@ dimension_scan_update(int32 dimension_id, tuple_found_func tuple_found, void *da ScannerCtx scanctx = { .table = catalog->tables[DIMENSION].id, .index = catalog->tables[DIMENSION].index_ids[DIMENSION_ID_IDX], - .scantype = ScannerTypeIndex, .nkeys = 1, .limit = 1, .scankey = scankey, diff --git a/src/dimension_slice.c b/src/dimension_slice.c index b6e231d6d..430be6ff0 100644 --- a/src/dimension_slice.c +++ b/src/dimension_slice.c @@ -119,7 +119,6 @@ dimension_slice_scan_limit_internal(int indexid, ScannerCtx scanCtx = { .table = catalog->tables[DIMENSION_SLICE].id, .index = catalog->tables[DIMENSION_SLICE].index_ids[indexid], - .scantype = ScannerTypeIndex, .nkeys = nkeys, .scankey = scankey, .data = scandata, diff --git a/src/event_trigger.c b/src/event_trigger.c index ff261d32a..857bdf532 100644 --- a/src/event_trigger.c +++ b/src/event_trigger.c @@ -1,16 +1,22 @@ #include #include +#include #include #include +#include +#include +#include #include "event_trigger.h" #define DDL_INFO_NATTS 9 +#define DROPPED_OBJECTS_NATTS 12 /* 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; +static FmgrInfo dropped_objects_fmgrinfo; /* * Get a list of executed DDL commands in an event trigger. @@ -63,11 +69,145 @@ event_trigger_ddl_commands(void) return objects; } +/* Given a TEXT[] of addrnames return a list of heap allocated char * + * + * similar to textarray_to_strvaluelist */ +static List * +extract_addrnames(ArrayType *arr) +{ + Datum *elems; + bool *nulls; + int nelems; + List *list = NIL; + int i; + + deconstruct_array(arr, TEXTOID, -1, false, 'i', + &elems, &nulls, &nelems); + + for (i = 0; i < nelems; i++) + { + if (nulls[i]) + elog(ERROR, "unexpected null in name list"); + + /* TextDatumGetCString heap allocates the string */ + list = lappend(list, TextDatumGetCString(elems[i])); + } + + return list; +} + +static EventTriggerDropTableConstraint * +makeEventTriggerDropTableConstraint(char *constraint_name, char *schema, char *table) +{ + EventTriggerDropTableConstraint *obj = palloc(sizeof(EventTriggerDropTableConstraint)); + + *obj = (EventTriggerDropTableConstraint) + { + .obj = + { + .type = EVENT_TRIGGER_DROP_TABLE_CONSTRAINT + }, + .constraint_name = constraint_name, + .schema = schema, + .table = table + }; + + return obj; +} + +static EventTriggerDropIndex * +makeEventTriggerDropIndex(char *index_name, char *schema) +{ + EventTriggerDropIndex *obj = palloc(sizeof(EventTriggerDropIndex)); + + *obj = (EventTriggerDropIndex) + { + .obj = + { + .type = EVENT_TRIGGER_DROP_INDEX + }, + .index_name = index_name, + .schema = schema, + }; + return obj; +} + +List * +event_trigger_dropped_objects(void) +{ + ReturnSetInfo rsinfo; + FunctionCallInfoData fcinfo; + TupleTableSlot *slot; + EState *estate = CreateExecutorState(); + List *objects = NIL; + + InitFunctionCallInfoData(fcinfo, &dropped_objects_fmgrinfo, 0, 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); + Datum values[DROPPED_OBJECTS_NATTS]; + bool nulls[DROPPED_OBJECTS_NATTS]; + Oid class_id; + char *objtype; + + heap_deform_tuple(tuple, rsinfo.setDesc, values, nulls); + + class_id = DatumGetObjectId(values[0]); + + switch (class_id) + { + case ConstraintRelationId: + objtype = TextDatumGetCString(values[6]); + if (objtype != NULL && strcmp(objtype, "table constraint") == 0) + { + List *addrnames = extract_addrnames(DatumGetArrayTypeP(values[10])); + + objects = lappend(objects, + makeEventTriggerDropTableConstraint(lthird(addrnames), + linitial(addrnames), + lsecond(addrnames))); + } + break; + case RelationRelationId: + objtype = TextDatumGetCString(values[6]); + if (objtype != NULL && strcmp(objtype, "index") == 0) + { + List *addrnames = extract_addrnames(DatumGetArrayTypeP(values[10])); + + objects = lappend(objects, + makeEventTriggerDropIndex(lsecond(addrnames), + linitial(addrnames))); + } + break; + default: + break; + } + } + + 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); + fmgr_info(fmgr_internal_function("pg_event_trigger_dropped_objects"), + &dropped_objects_fmgrinfo); } void diff --git a/src/event_trigger.h b/src/event_trigger.h index e2c6c4424..c1dd0ae85 100644 --- a/src/event_trigger.h +++ b/src/event_trigger.h @@ -4,6 +4,33 @@ #include #include +typedef enum EventTriggerDropType +{ + EVENT_TRIGGER_DROP_TABLE_CONSTRAINT, + EVENT_TRIGGER_DROP_INDEX, +} EventTriggerDropType; + +typedef struct EventTriggerDropObject +{ + EventTriggerDropType type; +} EventTriggerDropObject; + +typedef struct EventTriggerDropTableConstraint +{ + EventTriggerDropObject obj; + char *constraint_name; + char *schema; + char *table; +} EventTriggerDropTableConstraint; + +typedef struct EventTriggerDropIndex +{ + EventTriggerDropObject obj; + char *index_name; + char *schema; +} EventTriggerDropIndex; + +extern List *event_trigger_dropped_objects(void); extern List *event_trigger_ddl_commands(void); extern void _event_trigger_init(void); extern void _event_trigger_fini(void); diff --git a/src/hypertable.c b/src/hypertable.c index ae23bdfd2..6421a48fb 100644 --- a/src/hypertable.c +++ b/src/hypertable.c @@ -112,7 +112,6 @@ hypertable_id_to_relid(int32 hypertable_id) ScannerCtx scanctx = { .table = catalog->tables[HYPERTABLE].id, .index = catalog->tables[HYPERTABLE].index_ids[HYPERTABLE_ID_INDEX], - .scantype = ScannerTypeIndex, .nkeys = 1, .scankey = scankey, .tuple_found = hypertable_tuple_get_relid, @@ -143,8 +142,6 @@ chunk_cache_entry_free(void *cce) MemoryContextDelete(((ChunkCacheEntry *) cce)->mcxt); } -#define NOINDEX -1 - static int hypertable_scan_limit_internal(ScanKeyData *scankey, int num_scankeys, @@ -158,8 +155,7 @@ hypertable_scan_limit_internal(ScanKeyData *scankey, Catalog *catalog = catalog_get(); ScannerCtx scanctx = { .table = catalog->tables[HYPERTABLE].id, - .index = (indexid == NOINDEX) ? 0 : catalog->tables[HYPERTABLE].index_ids[indexid], - .scantype = (indexid == NOINDEX) ? ScannerTypeHeap : ScannerTypeIndex, + .index = CATALOG_INDEX(catalog, HYPERTABLE, indexid), .nkeys = num_scankeys, .scankey = scankey, .data = scandata, @@ -353,7 +349,7 @@ hypertable_reset_associated_schema_name(const char *associated_schema) return hypertable_scan_limit_internal(scankey, 1, - NOINDEX, + INVALID_INDEXID, reset_associated_tuple_found, NULL, 0, @@ -518,6 +514,51 @@ hypertable_insert(Name schema_name, heap_close(rel, RowExclusiveLock); } +static bool +hypertable_tuple_found(TupleInfo *ti, void *data) +{ + Hypertable **entry = data; + + *entry = hypertable_from_tuple(ti->tuple); + return false; +} + +Hypertable * +hypertable_get_by_name(char *schema, char *name) +{ + Hypertable *ht = NULL; + + hypertable_scan(schema, + name, + hypertable_tuple_found, + &ht, + AccessShareLock, + false); + + return ht; +} + +Hypertable * +hypertable_get_by_id(int32 hypertable_id) +{ + ScanKeyData scankey[1]; + Hypertable *ht = NULL; + + ScanKeyInit(&scankey[0], Anum_hypertable_pkey_idx_id, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(hypertable_id)); + + hypertable_scan_limit_internal(scankey, + 1, + HYPERTABLE_ID_INDEX, + hypertable_tuple_found, + &ht, + 1, + AccessShareLock, + false); + return ht; +} + Chunk * hypertable_get_chunk(Hypertable *h, Point *point) { diff --git a/src/hypertable.h b/src/hypertable.h index 0591c189f..9fc405ce3 100644 --- a/src/hypertable.h +++ b/src/hypertable.h @@ -23,6 +23,8 @@ typedef struct Hypertable extern Oid rel_get_owner(Oid relid); +extern Hypertable *hypertable_get_by_id(int32 hypertable_id); +extern Hypertable *hypertable_get_by_name(char *schema, char *name); extern bool hypertable_has_privs_of(Oid hypertable_oid, Oid userid); extern Oid hypertable_permissions_check(Oid hypertable_oid, Oid userid); extern Hypertable *hypertable_from_tuple(HeapTuple tuple); diff --git a/src/process_utility.c b/src/process_utility.c index ebac04de8..7bec1e003 100644 --- a/src/process_utility.c +++ b/src/process_utility.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -564,53 +565,6 @@ process_drop_trigger(DropStmt *stmt) cache_release(hcache); } -static void -process_drop_index(DropStmt *stmt) -{ - ListCell *lc; - - foreach(lc, stmt->objects) - { - List *object = lfirst(lc); - RangeVar *relation = makeRangeVarFromNameList(object); - Oid idxrelid; - - if (NULL == relation) - continue; - - idxrelid = RangeVarGetRelid(relation, NoLock, true); - - if (OidIsValid(idxrelid)) - { - Oid tblrelid = IndexGetRelation(idxrelid, false); - Cache *hcache = hypertable_cache_pin(); - Hypertable *ht = hypertable_cache_get_entry(hcache, tblrelid); - - /* - * Drop a hypertable index, i.e., all corresponding indexes on all - * chunks - */ - if (NULL != ht) - chunk_index_delete_children_of(ht, idxrelid, true); - else - { - /* Drop an index on a chunk */ - Chunk *chunk = chunk_get_by_relid(tblrelid, 0, false); - - if (NULL != chunk) - - /* - * No need DROP the index here since DDL statement drops - * (hence 'false' parameter), just delete the metadata - */ - chunk_index_delete(chunk, idxrelid, false); - } - - cache_release(hcache); - } - } -} - static void process_drop_tablespace(Node *parsetree) { @@ -693,9 +647,6 @@ process_drop(Node *parsetree) case OBJECT_TRIGGER: process_drop_trigger(stmt); break; - case OBJECT_INDEX: - process_drop_index(stmt); - break; default: break; } @@ -945,44 +896,6 @@ process_altertable_add_constraint(Hypertable *ht, const char *constraint_name) foreach_chunk(ht, process_add_constraint_chunk, &hypertable_constraint_oid); } -static void -process_drop_constraint_chunk(Hypertable *ht, Oid chunk_relid, void *arg) -{ - char *hypertable_constraint_name = arg; - Chunk *chunk = chunk_get_by_relid(chunk_relid, ht->space->num_dimensions, true); - - chunk_constraint_delete_by_hypertable_constraint_name(chunk->fd.id, hypertable_constraint_name); -} - -static void -process_altertable_drop_constraint(Hypertable *ht, AlterTableCmd *cmd) -{ - char *constraint_name = NULL; - CatalogSecurityContext sec_ctx; - Oid hypertable_constraint_oid, - hypertable_constraint_index_oid; - - constraint_name = cmd->name; - Assert(constraint_name != NULL); - - hypertable_constraint_oid = get_relation_constraint_oid(ht->main_table_relid, constraint_name, false); - hypertable_constraint_index_oid = get_constraint_index(hypertable_constraint_oid); - - catalog_become_owner(catalog_get(), &sec_ctx); - - /* Recurse to each chunk and drop the corresponding constraint */ - foreach_chunk(ht, process_drop_constraint_chunk, constraint_name); - - /* - * If this is a constraint backed by and index, we need to delete - * index-related metadata as well - */ - if (OidIsValid(hypertable_constraint_index_oid)) - chunk_index_delete_children_of(ht, hypertable_constraint_index_oid, false); - - catalog_restore_user(&sec_ctx); -} - static void process_altertable_drop_not_null(Hypertable *ht, AlterTableCmd *cmd) { @@ -1547,11 +1460,6 @@ process_altertable_start_table(Node *parsetree) if (ht != NULL) process_altertable_drop_not_null(ht, cmd); break; - case AT_DropConstraint: - case AT_DropConstraintRecurse: - if (ht != NULL) - process_altertable_drop_constraint(ht, cmd); - break; case AT_AddConstraint: case AT_AddConstraintRecurse: Assert(IsA(cmd->def, Constraint)); @@ -1886,6 +1794,75 @@ process_ddl_command_end(CollectedCommand *cmd) } } +static void +process_drop_constraint_on_chunk(Hypertable *ht, Oid chunk_relid, void *arg) +{ + char *hypertable_constraint_name = arg; + Chunk *chunk = chunk_get_by_relid(chunk_relid, ht->space->num_dimensions, true); + + /* drop both metadata and table; sql_drop won't be called recursively */ + chunk_constraint_delete_by_hypertable_constraint_name(chunk->fd.id, hypertable_constraint_name, true, true); +} + +static void +process_drop_table_constraint(EventTriggerDropObject *obj) +{ + EventTriggerDropTableConstraint *constraint; + Hypertable *ht; + + Assert(obj->type == EVENT_TRIGGER_DROP_TABLE_CONSTRAINT); + constraint = (EventTriggerDropTableConstraint *) obj; + + /* do not use relids because underlying table could be gone */ + ht = hypertable_get_by_name(constraint->schema, constraint->table); + + if (ht != NULL) + { + CatalogSecurityContext sec_ctx; + + catalog_become_owner(catalog_get(), &sec_ctx); + + /* Recurse to each chunk and drop the corresponding constraint */ + foreach_chunk(ht, process_drop_constraint_on_chunk, constraint->constraint_name); + + catalog_restore_user(&sec_ctx); + } + else + { + Chunk *chunk = chunk_get_by_name(constraint->schema, constraint->table, 0, false); + + if (NULL != chunk) + { + chunk_constraint_delete_by_constraint_name(chunk->fd.id, constraint->constraint_name, true, false); + } + } +} + +static void +process_drop_index(EventTriggerDropObject *obj) +{ + EventTriggerDropIndex *index; + + Assert(obj->type == EVENT_TRIGGER_DROP_INDEX); + index = (EventTriggerDropIndex *) obj; + + chunk_index_delete_by_name(index->schema, index->index_name, true); +} + +static void +process_ddl_sql_drop(EventTriggerDropObject *obj) +{ + switch (obj->type) + { + case EVENT_TRIGGER_DROP_TABLE_CONSTRAINT: + process_drop_table_constraint(obj); + break; + case EVENT_TRIGGER_DROP_INDEX: + process_drop_index(obj); + break; + } +} + /* * ProcessUtility hook for DDL commands that have not yet been processed by * PostgreSQL. @@ -1943,26 +1920,12 @@ timescaledb_ddl_command_start( prev_ProcessUtility(&args); } -TS_FUNCTION_INFO_V1(timescaledb_ddl_command_end); - -/* - * Event trigger hook for DDL commands that have alread been handled by - * PostgreSQL (i.e., "ddl_command_end" events). - */ -Datum -timescaledb_ddl_command_end(PG_FUNCTION_ARGS) +static +void +process_ddl_event_command_end(EventTriggerData *trigdata) { - EventTriggerData *trigdata = (EventTriggerData *) fcinfo->context; ListCell *lc; - if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) - elog(ERROR, "not fired by event trigger manager"); - - if (!extension_is_loaded()) - PG_RETURN_NULL(); - - Assert(strcmp("ddl_command_end", trigdata->event) == 0); - /* Inhibit collecting new commands while in the trigger */ EventTriggerInhibitCommandCollection(); @@ -1980,6 +1943,32 @@ timescaledb_ddl_command_end(PG_FUNCTION_ARGS) } EventTriggerUndoInhibitCommandCollection(); +} + +TS_FUNCTION_INFO_V1(timescaledb_process_ddl_event); +/* + * Event trigger hook for DDL commands that have alread been handled by + * PostgreSQL (i.e., "ddl_command_end" and "sql_drop" events). + */ +Datum +timescaledb_process_ddl_event(PG_FUNCTION_ARGS) +{ + EventTriggerData *trigdata = (EventTriggerData *) fcinfo->context; + ListCell *lc; + + if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) + elog(ERROR, "not fired by event trigger manager"); + + if (!extension_is_loaded()) + PG_RETURN_NULL(); + + if (strcmp("ddl_command_end", trigdata->event) == 0) + process_ddl_event_command_end(trigdata); + else if (strcmp("sql_drop", trigdata->event) == 0) + { + foreach(lc, event_trigger_dropped_objects()) + process_ddl_sql_drop(lfirst(lc)); + } PG_RETURN_NULL(); } diff --git a/src/scanner.c b/src/scanner.c index 4e91190a8..09eaa3377 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -154,11 +154,17 @@ scanner_scan(ScannerCtx *ctx) { TupleDesc tuple_desc; bool is_valid; - Scanner *scanner = &scanners[ctx->scantype]; + Scanner *scanner; + InternalScannerCtx ictx = { .sctx = ctx, }; + if (OidIsValid(ctx->index)) + scanner = &scanners[ScannerTypeIndex]; + else + scanner = &scanners[ScannerTypeHeap]; + scanner->openheap(&ictx); scanner->beginscan(&ictx); diff --git a/src/scanner.h b/src/scanner.h index 1a8054209..6c6bf11ed 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -11,7 +11,7 @@ typedef enum ScannerType { ScannerTypeHeap, ScannerTypeIndex, -} ScannerType; +} ScannerType; /* Tuple information passed on to handlers when scanning for tuples. */ typedef struct TupleInfo @@ -32,12 +32,12 @@ typedef struct TupleInfo } TupleInfo; typedef bool (*tuple_found_func) (TupleInfo *ti, void *data); +typedef bool (*tuple_filter_func) (TupleInfo *ti, void *data); typedef struct ScannerCtx { Oid table; Oid index; - ScannerType scantype; ScanKey scankey; int nkeys, norderbys, diff --git a/src/tablespace.c b/src/tablespace.c index 4c51c0b69..4e8229a14 100644 --- a/src/tablespace.c +++ b/src/tablespace.c @@ -106,8 +106,6 @@ tablespace_tuple_found(TupleInfo *ti, void *data) return true; } -#define NO_INDEX -1 - static int tablespace_scan_internal(int indexid, ScanKeyData *scankey, @@ -121,8 +119,7 @@ tablespace_scan_internal(int indexid, Catalog *catalog = catalog_get(); ScannerCtx scanctx = { .table = catalog->tables[TABLESPACE].id, - .index = (indexid == NO_INDEX) ? 0 : catalog->tables[TABLESPACE].index_ids[indexid], - .scantype = (indexid == NO_INDEX) ? ScannerTypeHeap : ScannerTypeIndex, + .index = CATALOG_INDEX(catalog, TABLESPACE, indexid), .nkeys = nkeys, .scankey = scankey, .tuple_found = tuple_found, @@ -180,7 +177,7 @@ tablespace_scan_by_name(const char *tspcname, tuple_found_func tuple_found, void BTEqualStrategyNumber, F_NAMEEQ, DirectFunctionCall1(namein, CStringGetDatum(tspcname))); - return tablespace_scan_internal(NO_INDEX, + return tablespace_scan_internal(INVALID_INDEXID, scankey, nkeys, tuple_found, @@ -433,7 +430,7 @@ tablespace_delete_from_all(const char *tspcname, Oid userid) BTEqualStrategyNumber, F_NAMEEQ, DirectFunctionCall1(namein, CStringGetDatum(tspcname))); - num_deleted = tablespace_scan_internal(NO_INDEX, + num_deleted = tablespace_scan_internal(INVALID_INDEXID, scankey, 1, tablespace_tuple_delete, diff --git a/test/expected/alternate_users.out b/test/expected/alternate_users.out index 72134d0b0..1d8b271ba 100644 --- a/test/expected/alternate_users.out +++ b/test/expected/alternate_users.out @@ -407,13 +407,12 @@ SELECT * FROM _timescaledb_catalog.chunk_index; 5 | _hyper_3_5_chunk_Hypertable_1_time_Device_id_idx | 3 | Hypertable_1_time_Device_id_idx 5 | _hyper_3_5_chunk_Hypertable_1_time_idx | 3 | Hypertable_1_time_idx 5 | _hyper_3_5_chunk_Hypertable_1_Device_id_time_idx | 3 | Hypertable_1_Device_id_time_idx - 5 | _hyper_3_5_chunk_Hypertable_1_time_temp_c_idx | 3 | Hypertable_1_time_temp_c_idx 5 | _hyper_3_5_chunk_Unique1 | 3 | Unique1 6 | _hyper_4_6_chunk_Hypertable_1_time_Device_id_idx | 4 | Hypertable_1_time_Device_id_idx 6 | _hyper_4_6_chunk_Hypertable_1_time_idx | 4 | Hypertable_1_time_idx 6 | _hyper_4_6_chunk_Unique1 | 4 | Unique1 5 | _hyper_3_5_chunk_ind_humdity2 | 3 | ind_humdity2 -(28 rows) +(27 rows) --create column with same name as previously renamed one ALTER TABLE PUBLIC."Hypertable_1" ADD COLUMN sensor_3 BIGINT NOT NULL DEFAULT 131; diff --git a/test/expected/constraint.out b/test/expected/constraint.out index 6ee798497..96c59ebf8 100644 --- a/test/expected/constraint.out +++ b/test/expected/constraint.out @@ -63,6 +63,14 @@ SELECT * FROM _timescaledb_catalog.chunk_constraint; 5 | | 5_2_hyper_unique_with_looooooooooooooooooooooooooooooooooo_time | hyper_unique_with_looooooooooooooooooooooooooooooooooo_time_key (5 rows) +SELECT * FROM _timescaledb_catalog.chunk_index; + chunk_id | index_name | hypertable_id | hypertable_index_name +----------+-----------------------------------------------------------------+---------------+----------------------------------------------------------------- + 3 | _hyper_1_3_chunk_hyper_time_idx | 1 | hyper_time_idx + 4 | 4_1_hyper_unique_with_looooooooooooooooooooooooooooooooooo_time | 2 | hyper_unique_with_looooooooooooooooooooooooooooooooooo_time_key + 5 | 5_2_hyper_unique_with_looooooooooooooooooooooooooooooooooo_time | 2 | hyper_unique_with_looooooooooooooooooooooooooooooooooo_time_key +(3 rows) + SELECT * FROM test.show_constraints('hyper'); Constraint | Type | Columns | Index | Expr ----------------------+------+------------+-------+---------------------------- @@ -95,6 +103,13 @@ SELECT * FROM _timescaledb_catalog.chunk_constraint; 5 | 5 | constraint_5 | (3 rows) +-- The index should also have been removed +SELECT * FROM _timescaledb_catalog.chunk_index; + chunk_id | index_name | hypertable_id | hypertable_index_name +----------+---------------------------------+---------------+----------------------- + 3 | _hyper_1_3_chunk_hyper_time_idx | 1 | hyper_time_idx +(1 row) + SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_2_4_chunk'); Constraint | Type | Columns | Index | Expr -----------------------------------------------------------------+------+------------+-------+------------------------------------------------------------------------------------------ @@ -371,6 +386,72 @@ INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES (1257987700000000002, 'dev3', 11); ERROR: insert or update on table "_hyper_4_8_chunk" violates foreign key constraint "8_22_hyper_fk_device_id_fkey" \set ON_ERROR_STOP 1 +SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_4_8_chunk'); + Constraint | Type | Columns | Index | Expr +------------------------------+------+-------------+--------------------------------------------+------------------------------------------------------------------------------------------ + 8_20_hyper_fk_pkey | p | {time} | _timescaledb_internal."8_20_hyper_fk_pkey" | + 8_22_hyper_fk_device_id_fkey | f | {device_id} | devices_pkey | + constraint_8 | c | {time} | - | (("time" >= '1257987700000000000'::bigint) AND ("time" < '1257987700000000010'::bigint)) + hyper_fk_sensor_1_check | c | {sensor_1} | - | (sensor_1 > (10)::numeric) +(4 rows) + +SELECT * FROM _timescaledb_catalog.chunk_constraint; + chunk_id | dimension_slice_id | constraint_name | hypertable_constraint_name +----------+--------------------+------------------------------+---------------------------- + 3 | 3 | constraint_3 | + 4 | 4 | constraint_4 | + 5 | 5 | constraint_5 | + 4 | | 4_10_new_name2 | new_name2 + 5 | | 5_11_new_name2 | new_name2 + 6 | 6 | constraint_6 | + 6 | | 6_16_hyper_pk_pkey | hyper_pk_pkey + 8 | 8 | constraint_8 | + 8 | | 8_20_hyper_fk_pkey | hyper_fk_pkey + 8 | | 8_22_hyper_fk_device_id_fkey | hyper_fk_device_id_fkey +(10 rows) + +--test CASCADE drop behavior +DROP TABLE devices CASCADE; +NOTICE: drop cascades to 2 other objects +SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_4_8_chunk'); + Constraint | Type | Columns | Index | Expr +-------------------------+------+------------+--------------------------------------------+------------------------------------------------------------------------------------------ + 8_20_hyper_fk_pkey | p | {time} | _timescaledb_internal."8_20_hyper_fk_pkey" | + constraint_8 | c | {time} | - | (("time" >= '1257987700000000000'::bigint) AND ("time" < '1257987700000000010'::bigint)) + hyper_fk_sensor_1_check | c | {sensor_1} | - | (sensor_1 > (10)::numeric) +(3 rows) + +SELECT * FROM _timescaledb_catalog.chunk_constraint; + chunk_id | dimension_slice_id | constraint_name | hypertable_constraint_name +----------+--------------------+--------------------+---------------------------- + 3 | 3 | constraint_3 | + 4 | 4 | constraint_4 | + 5 | 5 | constraint_5 | + 4 | | 4_10_new_name2 | new_name2 + 5 | | 5_11_new_name2 | new_name2 + 6 | 6 | constraint_6 | + 6 | | 6_16_hyper_pk_pkey | hyper_pk_pkey + 8 | 8 | constraint_8 | + 8 | | 8_20_hyper_fk_pkey | hyper_fk_pkey +(9 rows) + +--the fk went away. +INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES +(1257987700000000002, 'dev3', 11); +CREATE TABLE devices( + device_id TEXT NOT NULL, + PRIMARY KEY (device_id) +); +INSERT INTO devices VALUES ('dev2'), ('dev3'); +ALTER TABLE hyper_fk ADD CONSTRAINT hyper_fk_device_id_fkey +FOREIGN KEY (device_id) REFERENCES devices(device_id); +\set ON_ERROR_STOP 0 +INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES +(1257987700000000003, 'dev4', 11); +ERROR: insert or update on table "_hyper_4_8_chunk" violates foreign key constraint "8_23_hyper_fk_device_id_fkey" +\set ON_ERROR_STOP 1 +--this tests that there are no extra chunk_constraints left on hyper_fk +TRUNCATE hyper_fk; ----------------------- FOREIGN KEY INTO A HYPERTABLE ------------------ --FOREIGN KEY references into a hypertable are currently broken. --The referencing table will never find the corresponding row in the hypertable @@ -423,7 +504,7 @@ INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES \set ON_ERROR_STOP 0 INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES (1257987700000000000, 'dev2', 12); -ERROR: conflicting key value violates exclusion constraint "9_24_hyper_ex_time_device_id_excl" +ERROR: conflicting key value violates exclusion constraint "9_25_hyper_ex_time_device_id_excl" \set ON_ERROR_STOP 1 ALTER TABLE hyper_ex DROP CONSTRAINT hyper_ex_time_device_id_excl; --can now add @@ -436,7 +517,7 @@ ALTER TABLE hyper_ex ADD CONSTRAINT hyper_ex_time_device_id_excl time WITH =, device_id WITH = ) WHERE (not canceled) ; -ERROR: could not create exclusion constraint "9_25_hyper_ex_time_device_id_excl" +ERROR: could not create exclusion constraint "9_26_hyper_ex_time_device_id_excl" \set ON_ERROR_STOP 1 DELETE FROM hyper_ex WHERE sensor_1 = 12; ALTER TABLE hyper_ex ADD CONSTRAINT hyper_ex_time_device_id_excl @@ -447,7 +528,7 @@ ALTER TABLE hyper_ex ADD CONSTRAINT hyper_ex_time_device_id_excl \set ON_ERROR_STOP 0 INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES (1257987700000000000, 'dev2', 12); -ERROR: conflicting key value violates exclusion constraint "9_26_hyper_ex_time_device_id_excl" +ERROR: conflicting key value violates exclusion constraint "9_27_hyper_ex_time_device_id_excl" \set ON_ERROR_STOP 1 --cannot add exclusion constraint without partition key. CREATE TABLE hyper_ex_invalid ( diff --git a/test/expected/ddl.out b/test/expected/ddl.out index 5be7b7557..b458e1289 100644 --- a/test/expected/ddl.out +++ b/test/expected/ddl.out @@ -336,13 +336,12 @@ SELECT * FROM _timescaledb_catalog.chunk_index; 1 | _hyper_1_1_chunk_Hypertable_1_time_Device_id_idx | 1 | Hypertable_1_time_Device_id_idx 1 | _hyper_1_1_chunk_Hypertable_1_time_idx | 1 | Hypertable_1_time_idx 1 | _hyper_1_1_chunk_Hypertable_1_Device_id_time_idx | 1 | Hypertable_1_Device_id_time_idx - 1 | _hyper_1_1_chunk_Hypertable_1_time_temp_c_idx | 1 | Hypertable_1_time_temp_c_idx 1 | _hyper_1_1_chunk_Unique1 | 1 | Unique1 2 | _hyper_2_2_chunk_Hypertable_1_time_Device_id_idx | 2 | Hypertable_1_time_Device_id_idx 2 | _hyper_2_2_chunk_Hypertable_1_time_idx | 2 | Hypertable_1_time_idx 2 | _hyper_2_2_chunk_Unique1 | 2 | Unique1 1 | _hyper_1_1_chunk_ind_humdity2 | 1 | ind_humdity2 -(9 rows) +(8 rows) --create column with same name as previously renamed one ALTER TABLE PUBLIC."Hypertable_1" ADD COLUMN sensor_3 BIGINT NOT NULL DEFAULT 131; diff --git a/test/expected/ddl_single.out b/test/expected/ddl_single.out index 1fc5892f1..87ae9af4a 100644 --- a/test/expected/ddl_single.out +++ b/test/expected/ddl_single.out @@ -299,13 +299,12 @@ SELECT * FROM _timescaledb_catalog.chunk_index; 1 | _hyper_1_1_chunk_Hypertable_1_time_Device_id_idx | 1 | Hypertable_1_time_Device_id_idx 1 | _hyper_1_1_chunk_Hypertable_1_time_idx | 1 | Hypertable_1_time_idx 1 | _hyper_1_1_chunk_Hypertable_1_Device_id_time_idx | 1 | Hypertable_1_Device_id_time_idx - 1 | _hyper_1_1_chunk_Hypertable_1_time_temp_c_idx | 1 | Hypertable_1_time_temp_c_idx 1 | _hyper_1_1_chunk_Unique1 | 1 | Unique1 2 | _hyper_2_2_chunk_Hypertable_1_time_Device_id_idx | 2 | Hypertable_1_time_Device_id_idx 2 | _hyper_2_2_chunk_Hypertable_1_time_idx | 2 | Hypertable_1_time_idx 2 | _hyper_2_2_chunk_Unique1 | 2 | Unique1 1 | _hyper_1_1_chunk_ind_humdity2 | 1 | ind_humdity2 -(9 rows) +(8 rows) --create column with same name as previously renamed one ALTER TABLE PUBLIC."Hypertable_1" ADD COLUMN sensor_3 BIGINT NOT NULL DEFAULT 131; diff --git a/test/expected/pg_dump.out b/test/expected/pg_dump.out index e1fc8ee53..dbbdac546 100644 --- a/test/expected/pg_dump.out +++ b/test/expected/pg_dump.out @@ -49,7 +49,7 @@ SELECT count(*) AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'timescaledb'); count ------- - 94 + 95 (1 row) SELECT * FROM test.show_columns('public."two_Partitions"'); @@ -235,7 +235,7 @@ SELECT count(*) AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'timescaledb'); count ------- - 94 + 95 (1 row) --main table and chunk schemas should be the same diff --git a/test/sql/constraint.sql b/test/sql/constraint.sql index 06101b2e1..eee0304eb 100644 --- a/test/sql/constraint.sql +++ b/test/sql/constraint.sql @@ -58,6 +58,7 @@ INSERT INTO hyper_unique_with_looooooooooooooooooooooooooooooooooooong_name(time -- Show constraints on main tables SELECT * FROM _timescaledb_catalog.chunk_constraint; +SELECT * FROM _timescaledb_catalog.chunk_index; SELECT * FROM test.show_constraints('hyper'); SELECT * FROM test.show_constraints('hyper_unique_with_looooooooooooooooooooooooooooooooooooong_name'); --should have unique constraint not just unique index @@ -66,6 +67,8 @@ SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_2_4_chunk'); ALTER TABLE hyper_unique_with_looooooooooooooooooooooooooooooooooooong_name DROP CONSTRAINT hyper_unique_with_looooooooooooooooooooooooooooooooooo_time_key; -- The constraint should have been removed from the chunk as well SELECT * FROM _timescaledb_catalog.chunk_constraint; +-- The index should also have been removed +SELECT * FROM _timescaledb_catalog.chunk_index; SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_2_4_chunk'); --uniqueness not enforced @@ -269,6 +272,37 @@ INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES (1257987700000000002, 'dev3', 11); \set ON_ERROR_STOP 1 +SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_4_8_chunk'); +SELECT * FROM _timescaledb_catalog.chunk_constraint; + +--test CASCADE drop behavior +DROP TABLE devices CASCADE; + +SELECT * FROM test.show_constraints('_timescaledb_internal._hyper_4_8_chunk'); +SELECT * FROM _timescaledb_catalog.chunk_constraint; + +--the fk went away. +INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES +(1257987700000000002, 'dev3', 11); + +CREATE TABLE devices( + device_id TEXT NOT NULL, + PRIMARY KEY (device_id) +); + +INSERT INTO devices VALUES ('dev2'), ('dev3'); + +ALTER TABLE hyper_fk ADD CONSTRAINT hyper_fk_device_id_fkey +FOREIGN KEY (device_id) REFERENCES devices(device_id); + +\set ON_ERROR_STOP 0 +INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES +(1257987700000000003, 'dev4', 11); +\set ON_ERROR_STOP 1 + +--this tests that there are no extra chunk_constraints left on hyper_fk +TRUNCATE hyper_fk; + ----------------------- FOREIGN KEY INTO A HYPERTABLE ------------------